如何向 DefinitelyTyped 贡献多个声明文件和文件夹
How to contribute multiple declaration files and folders to DefinitelyTyped
我已经为 PlayCanvas 游戏引擎编写了 TypeScript 声明文件。源代码在 pc
命名空间下具有全局结构。我在编写声明文件时复制了源代码的文件和文件夹结构。我有 50 多个单独的 d.ts 文件,它们都使用 declare namespace pc {}
。我现在想将这些声明文件贡献给 DefinitelyTyped,但查看文档似乎他们可能希望将所有内容都放在一个名为 index.d.ts
文件的大文件中。我怎样才能转换我所有的文件和文件夹,以便整个东西与 DefinitelyTyped 兼容?我真的必须将所有内容都塞进一个文件吗?我不能只保留与引擎源代码匹配的漂亮文件和文件夹结构吗?
这是为大型库创建类型定义的常见痛点。此时最好的解决方案是使用 dts-generator 等实用程序为 distribution/consumption 生成 index.d.ts(并保留您的个人 files/folders 作为来源)。
dts-generator 半盲地将所有内容转储到一个文件中。在我的例子中(它也恰好是一个游戏引擎,你可以看到 here),该文件需要一些 post 处理才能与我重新导出不同的 index.ts 文件兼容图书馆的一部分。这是一个命令行实用程序,可以是 运行 和 ts-node
(npm i ts-node -g
).
import * as fs from 'fs';
import * as readline from 'readline';
const moduleDeclaration = 'module-typings.d.ts'; // file created by dts-generator
const indexDeclartion = 'index.d.ts';
const distPath = './dist/';
const indexOut: string[] = [];
const reader = readline.createInterface({
input: fs.createReadStream(`${distPath}${moduleDeclaration}`),
});
const moduleDeclaration = /^declare module/;
const malletImport = /(import|export).+from 'mallet/;
function isExcluded(line: string) {
return moduleDeclaration.exec(line) || malletImport.exec(line) || line === '}';
}
const identifiers = [];
const importLine = /import {(.*)} (.*)/;
const importRequire = /import (.*) = (.*)/;
function stripDuplicateDeclarations(line) {
let importResult;
if ((importResult = importLine.exec(line))) { // tslint:disable-line:no-conditional-assignment
const imports = importResult[1].replace(/\s/g, '').split(',');
const newImports = imports.filter((variable) => identifiers.indexOf(variable) === -1);
Array.prototype.push.apply(identifiers, newImports);
const importString = newImports.join(', ');
return line.replace(importLine, `import {${importString}} `);
} else if ((importResult = importRequire.exec(line))) { // tslint:disable-line:no-conditional-assignment
const importName = importResult[1];
if (identifiers.indexOf(importName) === -1) {
identifiers.push(importName);
return line;
}
return ''; // return an empty line if the import exists
}
return line;
}
const constLine = /^\s{2}const .+:/;
function declareConst(line) {
if (constLine.exec(line) !== null) {
return (`declare${line}`).replace(/\s+/, ' ');
}
return line;
}
reader.on('line', (line) => {
if (!isExcluded(line)) {
const finalLine = [stripDuplicateDeclarations, declareConst]
.reduce((processedLine, processor) => processor(processedLine), line);
indexOut.push(finalLine);
}
});
reader.on('close', () => {
const indexContext = indexOut.join('\n');
fs.writeFileSync(`${distPath}${indexDeclartion}`, indexContext, {encoding: 'utf-8'});
});
此脚本删除了重复的声明和嵌套的命名空间,因此消费者可以轻松导入库组件。作为免责声明,此脚本只是适用于我的库的示例,并非旨在处理所有情况。使用 TypeScript API.
进行这种处理可能有更正确(也更复杂)的方法
我已经为 PlayCanvas 游戏引擎编写了 TypeScript 声明文件。源代码在 pc
命名空间下具有全局结构。我在编写声明文件时复制了源代码的文件和文件夹结构。我有 50 多个单独的 d.ts 文件,它们都使用 declare namespace pc {}
。我现在想将这些声明文件贡献给 DefinitelyTyped,但查看文档似乎他们可能希望将所有内容都放在一个名为 index.d.ts
文件的大文件中。我怎样才能转换我所有的文件和文件夹,以便整个东西与 DefinitelyTyped 兼容?我真的必须将所有内容都塞进一个文件吗?我不能只保留与引擎源代码匹配的漂亮文件和文件夹结构吗?
这是为大型库创建类型定义的常见痛点。此时最好的解决方案是使用 dts-generator 等实用程序为 distribution/consumption 生成 index.d.ts(并保留您的个人 files/folders 作为来源)。
dts-generator 半盲地将所有内容转储到一个文件中。在我的例子中(它也恰好是一个游戏引擎,你可以看到 here),该文件需要一些 post 处理才能与我重新导出不同的 index.ts 文件兼容图书馆的一部分。这是一个命令行实用程序,可以是 运行 和 ts-node
(npm i ts-node -g
).
import * as fs from 'fs';
import * as readline from 'readline';
const moduleDeclaration = 'module-typings.d.ts'; // file created by dts-generator
const indexDeclartion = 'index.d.ts';
const distPath = './dist/';
const indexOut: string[] = [];
const reader = readline.createInterface({
input: fs.createReadStream(`${distPath}${moduleDeclaration}`),
});
const moduleDeclaration = /^declare module/;
const malletImport = /(import|export).+from 'mallet/;
function isExcluded(line: string) {
return moduleDeclaration.exec(line) || malletImport.exec(line) || line === '}';
}
const identifiers = [];
const importLine = /import {(.*)} (.*)/;
const importRequire = /import (.*) = (.*)/;
function stripDuplicateDeclarations(line) {
let importResult;
if ((importResult = importLine.exec(line))) { // tslint:disable-line:no-conditional-assignment
const imports = importResult[1].replace(/\s/g, '').split(',');
const newImports = imports.filter((variable) => identifiers.indexOf(variable) === -1);
Array.prototype.push.apply(identifiers, newImports);
const importString = newImports.join(', ');
return line.replace(importLine, `import {${importString}} `);
} else if ((importResult = importRequire.exec(line))) { // tslint:disable-line:no-conditional-assignment
const importName = importResult[1];
if (identifiers.indexOf(importName) === -1) {
identifiers.push(importName);
return line;
}
return ''; // return an empty line if the import exists
}
return line;
}
const constLine = /^\s{2}const .+:/;
function declareConst(line) {
if (constLine.exec(line) !== null) {
return (`declare${line}`).replace(/\s+/, ' ');
}
return line;
}
reader.on('line', (line) => {
if (!isExcluded(line)) {
const finalLine = [stripDuplicateDeclarations, declareConst]
.reduce((processedLine, processor) => processor(processedLine), line);
indexOut.push(finalLine);
}
});
reader.on('close', () => {
const indexContext = indexOut.join('\n');
fs.writeFileSync(`${distPath}${indexDeclartion}`, indexContext, {encoding: 'utf-8'});
});
此脚本删除了重复的声明和嵌套的命名空间,因此消费者可以轻松导入库组件。作为免责声明,此脚本只是适用于我的库的示例,并非旨在处理所有情况。使用 TypeScript API.
进行这种处理可能有更正确(也更复杂)的方法