Skip to content

Commit

Permalink
Release 3.0.0; Support group, priority (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
shrinktofit committed Dec 12, 2020
1 parent f5a326e commit 783cbda
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 115 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tfig",
"version": "2.0.18",
"version": "3.0.0",
"description": "Yet another tool to generate .d.ts bundle.",
"main": "build/gift.js",
"types": "build/gift.d.ts",
Expand All @@ -17,9 +17,7 @@
"declaration",
"dts"
],
"bin": {
"gift-cli": "./build/gift-cli.js"
},
"bin": {},
"author": "Leslie Leigh",
"license": "MIT",
"dependencies": {
Expand Down
38 changes: 36 additions & 2 deletions source/distribute-exports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ import ts from 'typescript';
export function distributeExports(
moduleSymbols: ts.Symbol[],
typeChecker: ts.TypeChecker,
manualMainExports: Array<distributeExports.ManualMainExport>,
priorityList: string[] = [],
) {
const parsedPriorityList = priorityList.map((id) => `"${id[0]}"`);

const exportMap: Map<ts.Symbol, SymbolInfo> = new Map();

const moduleMetaList = moduleSymbols.map((moduleSymbol) => {
const moduleMeta: distributeExports.ModuleMeta = {
symbol: moduleSymbol,
mainExports: [],
aliasExports: [],
[prioritySymbol]: getExportPriority(moduleSymbol, parsedPriorityList),
};
iterateModuleExports(moduleSymbol, moduleMeta);
return moduleMeta;
Expand Down Expand Up @@ -82,6 +85,7 @@ export function distributeExports(
symbol: moduleSymbol,
mainExports: [],
aliasExports: [],
[prioritySymbol]: moduleMeta[prioritySymbol],
};
symbolInfo.children.push(nestedModule);
iterateModuleExports(originalSymbol, nestedModule);
Expand All @@ -98,7 +102,20 @@ export function distributeExports(
}

function findBestExportMeta(originalSymbol: ts.Symbol, exportPorts: ExportPort[]): number {
// We first search if there is an export is specified as 'main' by user.
// If there is only one export port, that's it.
if (exportPorts.length === 1) {
return 0;
}

// If any of the ports is specified with priority, we take the hightest specified one.
const iHighestPriorityPort = exportPorts
.map((_, index) => index)
.sort((a, b) => exportPorts[a].module[prioritySymbol] - exportPorts[b].module[prioritySymbol])[0];
if (!isNonSpecifiedPriority(exportPorts[iHighestPriorityPort].module[prioritySymbol], parsedPriorityList)) {
return iHighestPriorityPort;
}

// Otherwise, We first search if there is an export is specified as 'main' by user.
const iMatched = exportPorts.findIndex((exportPort) => matchExportPort(exportPort));
if (iMatched >= 0) {
return iMatched;
Expand All @@ -119,6 +136,17 @@ export function distributeExports(
}
}

const prioritySymbol = Symbol('Priority');

function getExportPriority(moduleSymbol: ts.Symbol, parsedPriorityList: string[]): number {
const index = parsedPriorityList.indexOf(moduleSymbol.getName());
return index >= 0 ? index : parsedPriorityList.length;
}

function isNonSpecifiedPriority(priority: number, parsedPriorityList: string[]) {
return priority === parsedPriorityList.length;
}

export namespace distributeExports {
export interface ModuleMeta extends InternalModuleMeta {
}
Expand All @@ -139,6 +167,12 @@ export namespace distributeExports {
mainExportIndex: number;
exportSymbol: ts.Symbol;
}>;

/**
* Index into the priority list indicates what priority this module has, to export a symbol.
* If this module is not in priority list, it's set to length of the priority list.
*/
[prioritySymbol]: number;
}

export type ManualMainExport = string | RegExp;
Expand Down
22 changes: 11 additions & 11 deletions source/gift-cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import * as fs from 'fs-extra';
import * as path from 'path';
import * as yargs from 'yargs';
import { bundle, GiftErrors, IOptions } from './gift';
import { bundle, IOptions } from './gift';

main();

function main() {
async function main() {
yargs.demandOption([ 'i', 'r' ]);
yargs.option('input', {
alias: 'i',
Expand Down Expand Up @@ -79,15 +79,15 @@ function main() {
entries,
};

const bundleResult = bundle(options);
// if (bundleResult.error !== GiftErrors.Ok) {
// console.error(`Error occurred: ${GiftErrors[bundleResult.error]}`);
// return -1;
// }

const outputPath = options.output;
fs.ensureDirSync(path.dirname(outputPath));
fs.writeFileSync(outputPath, bundleResult.code);
try {
const bundleResult = bundle(options);
await Promise.all(bundleResult.groups.map(async (group) => {
await fs.outputFile(group.path, group.code, { encoding: 'utf8' });
}));
} catch (err) {
console.error(err);
return -1;
}

return 0;
}
160 changes: 63 additions & 97 deletions source/gift.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { recastTopLevelModule } from './recast';
export interface IOptions {
input: string | string[];
rootDir?: string;
output: string;
output?: string;

name?: string;
rootModule?: string;
Expand All @@ -20,20 +20,24 @@ export interface IOptions {
exportPrivates?: string;
shelterName?: string;
verbose?: boolean;

priority?: string[];

groups?: Array<{
test: RegExp;
path: string;
}>;
}

export interface IBundleResult {
error: GiftErrors;
typeReferencePaths?: string[];
code?: string;
groups: GroupResult[];
}

export enum GiftErrors {
Ok,
InputFileNotFound,
RootModuleAbsent,
Fatal,
}
export interface GroupResult {
path: string;
typeReferencePaths?: string[];
code: string;
};

export function bundle(options: IOptions): IBundleResult {
if (options.verbose) {
Expand All @@ -45,7 +49,7 @@ export function bundle(options: IOptions): IBundleResult {
// Check the input.
const inputs = Array.isArray(options.input) ? options.input : [options.input];
if (!inputs.every(input => fs.existsSync(input))) {
return { error: GiftErrors.InputFileNotFound };
throw new Error(`Input file ${inputs} not found.`);
}

return rollupTypes(options);
Expand All @@ -72,8 +76,16 @@ export function rollupTypes(options: IOptions) {
const entries = getEntries();
const program = createProgram();
const typeChecker = program.getTypeChecker();
const statements = bundle();
return emit(statements);
const groupSources = bundle();
const groups = groupSources.map(emit);
return {
groups,
};

interface GroupSource {
path: string;
statements: ts.Statement[];
}

function getEntries() {
if (options.entries) {
Expand All @@ -100,7 +112,7 @@ export function rollupTypes(options: IOptions) {
});
}

function bundle() {
function bundle(): GroupSource[] {
const ambientModules = typeChecker.getAmbientModules();

const entryModules = Object.entries(entries).map(([entryModuleName, entryModuleId]) => {
Expand All @@ -117,7 +129,7 @@ export function rollupTypes(options: IOptions) {

const rEntityMap = new SymbolEntityMap();

const exportDistribution = distributeExports(entryModules.map((eM) => eM.symbol), typeChecker, []);
const exportDistribution = distributeExports(entryModules.map((eM) => eM.symbol), typeChecker, options.priority);

const distributionMap = new Map<distributeExports.InternalModuleMeta, rConcepts.NamespaceTraits>();

Expand Down Expand Up @@ -160,11 +172,37 @@ export function rollupTypes(options: IOptions) {
registerNonExportedSymbol,
});

const statements: ts.Statement[] = [];
const groupSources = new Map<number, GroupSource>();
for (const rModule of rExternalModules) {
statements.push(...myRecast(rModule.moduleTraits!));
let groupIndex = -1;
if (options.groups) {
const rModuleName = rModule.name;
const matchedGroup = options.groups.findIndex(groupOption => groupOption.test.test(rModuleName));
if (matchedGroup >= 0) {
groupIndex = matchedGroup;
}
}
let groupSource = groupSources.get(groupIndex);
if (!groupSource) {
let outputPath: string;
if (groupIndex >= 0) {
outputPath = options.groups![groupIndex].path;
} else {
if (!options.output) {
throw new Error(`You must specify <output> since there is a un-grouped module.`);
} else {
outputPath = options.output;
}
}
groupSource = {
statements: [],
path: outputPath,
};
groupSources.set(groupIndex, groupSource);
}
groupSource.statements.push(...myRecast(rModule.moduleTraits!));
}
return statements;
return Array.from(groupSources.values());

function createREntities(
moduleExportDistribution: distributeExports.InternalModuleMeta,
Expand Down Expand Up @@ -250,98 +288,26 @@ export function rollupTypes(options: IOptions) {
}
}

function emit(statements: ts.Statement[]) {
const outputPath = options.output;

// if (options.verbose) {
// console.log(`Referenced source files:[`);
// for (const referencedSourceFile of this._referencedSourceFiles) {
// console.log(` ${referencedSourceFile.fileName},`);
// }
// console.log(`]`);
// }

function emit(groupSource: GroupSource): GroupResult {
const printer = ts.createPrinter({
newLine: ts.NewLineKind.LineFeed,
});
const sourceFile = ts.createSourceFile(
path.basename(outputPath),
path.basename(groupSource.path),
'',
ts.ScriptTarget.Latest,
false,
ts.ScriptKind.TS,
);

const lines: string[] = [];
// const typeReferencePaths: string[] = [];
// if (rootModule.declarations && rootModule.declarations.length !== 0) {
// const declaration0 = rootModule.declarations[0];
// const rootSourceFile = declaration0.getSourceFile();
// const resolvedTypeReferenceDirectives: ts.Map<ts.ResolvedTypeReferenceDirective> =
// this._program.getResolvedTypeReferenceDirectives();
// resolvedTypeReferenceDirectives.forEach((trd, key) => {
// if (!trd.resolvedFileName) {
// return;
// }
// const trdSourceFile = this._program.getSourceFile(trd.resolvedFileName);
// if (!trdSourceFile || !this._referencedSourceFiles.has(trdSourceFile)) {
// return;
// }
// lines.push(`/// <reference types="${key}"/>`);
// typeReferencePaths.push(trd.resolvedFileName);
// });
// }
const statementsArray = ts.createNodeArray(statements);
const statementsArray = ts.createNodeArray(groupSource.statements);
const result = printer.printList(
ts.ListFormat.MultiLine, statementsArray, sourceFile);
lines.push(result);
// const expandTypeReferenceDirectives: Record<string, string> = {};
// const copyTypeReferenceDirectives: string[] = [];

// const typeReferencePaths: string[] = [];
// if (rootModule.declarations && rootModule.declarations.length !== 0) {
// const declaration0 = rootModule.declarations[0];
// const indexSourceFile = declaration0.getSourceFile();
// const indexSourceFileName = indexSourceFile.fileName;
// for (const typeReferenceDirective of indexSourceFile.typeReferenceDirectives) {
// const resolveResult = ts.resolveTypeReferenceDirective(
// typeReferenceDirective.fileName,
// indexSourceFileName,
// this._tsCompilerOptions, {
// fileExists: ts.sys.fileExists,
// readFile: ts.sys.readFile,
// });
// if (!resolveResult.resolvedTypeReferenceDirective ||
// resolveResult.resolvedTypeReferenceDirective.packageId ||
// resolveResult.resolvedTypeReferenceDirective.primary ||
// resolveResult.resolvedTypeReferenceDirective.isExternalLibraryImport ||
// !resolveResult.resolvedTypeReferenceDirective.resolvedFileName) {
// copyTypeReferenceDirectives.push(typeReferenceDirective.fileName);
// } else {
// expandTypeReferenceDirectives[typeReferenceDirective.fileName] = resolveResult.resolvedTypeReferenceDirective.resolvedFileName;
// }
// }
// }

// const lines: string[] = [];
// for (const trd of copyTypeReferenceDirectives) {
// lines.push(`/// <reference types="${trd}"/>`);
// }

// const statementsArray = ts.createNodeArray(statements);
// const result = printer.printList(ts.ListFormat.None, statementsArray, sourceFile);
// lines.push(result);

// for (const trd of Object.keys(expandTypeReferenceDirectives)) {
// // const referencedSource = fs.readFileSync(expandTypeReferenceDirectives[trd]).toString();
// // lines.push(`
// // /// Included from type reference directive ${trd}.

// // ${referencedSource}
// // `);
// typeReferencePaths.push(trd);
// }
const code = lines.join('\n');
return { error: GiftErrors.Ok, code };
return {
path: groupSource.path,
code,
};
}
}
2 changes: 2 additions & 0 deletions source/recast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,8 @@ export function recastTopLevelModule({
);
} else if (type.kind === ts.SyntaxKind.RestType) {
return ts.createRestTypeNode(recastTypeNode((type as ts.RestTypeNode).type));
} else if (ts.isOptionalTypeNode(type)) {
return ts.createOptionalTypeNode(type.type);
} else {
console.warn(`Don't know how to handle type ${type.getText()}(${tsUtils.stringifyNode(type)})`);
}
Expand Down
Loading

0 comments on commit 783cbda

Please sign in to comment.