UNPKG

14.3 kBJavaScriptView Raw
1"use strict";
2var __assign = (this && this.__assign) || Object.assign || function(t) {
3 for (var s, i = 1, n = arguments.length; i < n; i++) {
4 s = arguments[i];
5 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6 t[p] = s[p];
7 }
8 return t;
9};
10Object.defineProperty(exports, "__esModule", { value: true });
11var ts = require("typescript");
12var path = require("path");
13var compile_dts_1 = require("./compile-dts");
14var types_usage_evaluator_1 = require("./types-usage-evaluator");
15var typescript_helpers_1 = require("./typescript-helpers");
16var node_modules_helpers_1 = require("./node-modules-helpers");
17var module_info_1 = require("./module-info");
18var generate_output_1 = require("./generate-output");
19var logger_1 = require("./logger");
20var skippedNodes = [
21 ts.SyntaxKind.ExportDeclaration,
22 ts.SyntaxKind.ImportDeclaration,
23 ts.SyntaxKind.ImportEqualsDeclaration,
24];
25function generateDtsBundle(filePath, options) {
26 if (options === void 0) { options = {}; }
27 if (!ts.sys.fileExists(filePath)) {
28 throw new Error("File \"" + filePath + "\" does not exist");
29 }
30 var program = compile_dts_1.compileDts(filePath, options.preferredConfigPath, options.followSymlinks);
31 var typeChecker = program.getTypeChecker();
32 var criteria = {
33 allowedTypesLibraries: options.allowedTypesLibraries,
34 importedLibraries: options.importedLibraries,
35 inlinedLibraries: options.inlinedLibraries || [],
36 typeRoots: ts.getEffectiveTypeRoots(program.getCompilerOptions(), {}),
37 };
38 var sourceFiles = program.getSourceFiles().filter(function (file) {
39 return module_info_1.getModuleInfo(file.fileName, criteria).type !== 0 /* ShouldNotBeUsed */;
40 });
41 logger_1.verboseLog("Input source files:\n " + sourceFiles.map(function (file) { return file.fileName; }).join('\n '));
42 var typesUsageEvaluator = new types_usage_evaluator_1.TypesUsageEvaluator(sourceFiles, typeChecker);
43 var rootSourceFile = getRootSourceFile(program);
44 var rootSourceFileSymbol = typeChecker.getSymbolAtLocation(rootSourceFile);
45 if (rootSourceFileSymbol === undefined) {
46 throw new Error('Symbol for root source file not found');
47 }
48 var rootFileExports = typeChecker.getExportsOfModule(rootSourceFileSymbol).map(function (symbol) { return typescript_helpers_1.getActualSymbol(symbol, typeChecker); });
49 var collectionResult = {
50 typesReferences: new Set(),
51 imports: new Map(),
52 statements: [],
53 };
54 var updateResultCommonParams = {
55 isStatementUsed: function (statement) { return isNodeUsed(statement, rootFileExports, typesUsageEvaluator, typeChecker); },
56 shouldStatementBeImported: function (statement) { return shouldNodeBeImported(statement, rootFileExports, typesUsageEvaluator); },
57 shouldDeclareGlobalBeInlined: function (currentModule) { return Boolean(options.inlineDeclareGlobals) && currentModule.type === 1 /* ShouldBeInlined */; },
58 getModuleInfo: function (fileName) { return module_info_1.getModuleInfo(fileName, criteria); },
59 getDeclarationsForExportedAssignment: function (exportAssignment) {
60 var symbolForExpression = typeChecker.getSymbolAtLocation(exportAssignment.expression);
61 if (symbolForExpression === undefined) {
62 return [];
63 }
64 var symbol = typescript_helpers_1.getActualSymbol(symbolForExpression, typeChecker);
65 return getDeclarationsForSymbol(symbol);
66 },
67 };
68 for (var _i = 0, sourceFiles_1 = sourceFiles; _i < sourceFiles_1.length; _i++) {
69 var sourceFile = sourceFiles_1[_i];
70 logger_1.verboseLog("\n\n======= Preparing file: " + sourceFile.fileName + " =======");
71 var prevStatementsCount = collectionResult.statements.length;
72 var updateFn = sourceFile === rootSourceFile ? updateResultForRootSourceFile : updateResult;
73 updateFn(__assign({}, updateResultCommonParams, { currentModule: module_info_1.getModuleInfo(sourceFile.fileName, criteria), statements: sourceFile.statements }), collectionResult);
74 if (collectionResult.statements.length === prevStatementsCount) {
75 logger_1.verboseLog("No output for file: " + sourceFile.fileName);
76 }
77 }
78 if (options.failOnClass) {
79 var isClassStatementFound = collectionResult.statements.some(function (statement) { return ts.isClassDeclaration(statement); });
80 if (isClassStatementFound) {
81 throw new Error('At least 1 class statement is found in generated dts.');
82 }
83 }
84 return generate_output_1.generateOutput(__assign({}, collectionResult, { needStripDefaultKeywordForStatement: function (statement) { return statement.getSourceFile() !== rootSourceFile; }, shouldStatementHasExportKeyword: function (statement) {
85 var result = true;
86 if (ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isFunctionDeclaration(statement)) {
87 // not every class, enum and function can be exported (only exported from root file can)
88 result = isDeclarationExported(rootFileExports, typeChecker, statement);
89 if (ts.isEnumDeclaration(statement)) {
90 // const enum always can be exported
91 result = result || typescript_helpers_1.hasNodeModifier(statement, ts.SyntaxKind.ConstKeyword);
92 }
93 }
94 else if (typescript_helpers_1.isDeclareGlobalStatement(statement) || ts.isExportDeclaration(statement)) {
95 result = false;
96 }
97 return result;
98 } }), {
99 sortStatements: options.sortNodes,
100 umdModuleName: options.umdModuleName,
101 });
102}
103exports.generateDtsBundle = generateDtsBundle;
104// tslint:disable-next-line:cyclomatic-complexity
105function updateResult(params, result) {
106 if (params.currentModule.type === 0 /* ShouldNotBeUsed */) {
107 return;
108 }
109 for (var _i = 0, _a = params.statements; _i < _a.length; _i++) {
110 var statement = _a[_i];
111 // we should skip import and exports statements
112 if (skippedNodes.indexOf(statement.kind) !== -1) {
113 continue;
114 }
115 if (typescript_helpers_1.isDeclareModuleStatement(statement)) {
116 updateResultForModuleDeclaration(statement, params, result);
117 continue;
118 }
119 if (params.currentModule.type === 4 /* ShouldBeUsedForModulesOnly */) {
120 continue;
121 }
122 if (typescript_helpers_1.isDeclareGlobalStatement(statement) && params.shouldDeclareGlobalBeInlined(params.currentModule, statement)) {
123 result.statements.push(statement);
124 continue;
125 }
126 if (ts.isExportAssignment(statement) && statement.isExportEquals && params.currentModule.type === 2 /* ShouldBeImported */) {
127 updateResultForImportedEqExportAssignment(statement, params, result);
128 continue;
129 }
130 if (!params.isStatementUsed(statement)) {
131 logger_1.verboseLog("Skip file member: " + statement.getText().replace(/(\n|\r)/g, '').slice(0, 50) + "...");
132 continue;
133 }
134 switch (params.currentModule.type) {
135 case 3 /* ShouldBeReferencedAsTypes */:
136 addTypesReference(params.currentModule.typesLibraryName, result.typesReferences);
137 break;
138 case 2 /* ShouldBeImported */:
139 if (params.shouldStatementBeImported(statement)) {
140 addImport(statement, params.currentModule.libraryName, result.imports);
141 }
142 break;
143 case 1 /* ShouldBeInlined */:
144 result.statements.push(statement);
145 break;
146 }
147 }
148}
149function updateResultForRootSourceFile(params, result) {
150 function isReExportFromImportableModule(statement) {
151 if (!ts.isExportDeclaration(statement) || statement.moduleSpecifier === undefined || !ts.isStringLiteral(statement.moduleSpecifier)) {
152 return false;
153 }
154 var moduleFileName = resolveModuleFileName(statement.getSourceFile().fileName, statement.moduleSpecifier.text);
155 return params.getModuleInfo(moduleFileName).type === 2 /* ShouldBeImported */;
156 }
157 updateResult(params, result);
158 // add skipped by `updateResult` exports
159 for (var _i = 0, _a = params.statements; _i < _a.length; _i++) {
160 var statement = _a[_i];
161 var isExportDefault = ts.isExportAssignment(statement) && !statement.isExportEquals;
162 var isReExportFromImportable = isReExportFromImportableModule(statement);
163 if (isExportDefault || isReExportFromImportable) {
164 result.statements.push(statement);
165 }
166 }
167}
168function updateResultForImportedEqExportAssignment(exportAssignment, params, result) {
169 var moduleDeclarations = params.getDeclarationsForExportedAssignment(exportAssignment)
170 .filter(typescript_helpers_1.isNamespaceStatement)
171 .filter(function (s) { return s.getSourceFile() === exportAssignment.getSourceFile(); });
172 // if we have `export =` somewhere so we can decide that every declaration of exported symbol in this way
173 // is "part of the exported module" and we need to update result according every member of each declaration
174 // but treat they as current module (we do not need to update module info)
175 for (var _i = 0, moduleDeclarations_1 = moduleDeclarations; _i < moduleDeclarations_1.length; _i++) {
176 var moduleDeclaration = moduleDeclarations_1[_i];
177 if (moduleDeclaration.body === undefined || !ts.isModuleBlock(moduleDeclaration.body)) {
178 continue;
179 }
180 updateResult(__assign({}, params, { statements: moduleDeclaration.body.statements }), result);
181 }
182}
183function updateResultForModuleDeclaration(moduleDecl, params, result) {
184 if (params.currentModule.type === 0 /* ShouldNotBeUsed */) {
185 return;
186 }
187 if (moduleDecl.body === undefined || !ts.isModuleBlock(moduleDecl.body)) {
188 return;
189 }
190 var moduleName = moduleDecl.name.text;
191 var moduleFileName = resolveModuleFileName(params.currentModule.fileName, moduleName);
192 var moduleInfo = params.getModuleInfo(moduleFileName);
193 if (moduleInfo.type === 0 /* ShouldNotBeUsed */) {
194 return;
195 }
196 // if we have declaration of external module inside internal one
197 // we need to just add it to result without any processing
198 if (!params.currentModule.isExternal && moduleInfo.isExternal) {
199 result.statements.push(moduleDecl);
200 return;
201 }
202 updateResult(__assign({}, params, { currentModule: moduleInfo, statements: moduleDecl.body.statements }), result);
203}
204function resolveModuleFileName(currentFileName, moduleName) {
205 return moduleName.startsWith('.') ? path.join(currentFileName, '..', moduleName) : "node_modules/" + moduleName + "/";
206}
207function addTypesReference(library, typesReferences) {
208 if (!typesReferences.has(library)) {
209 logger_1.normalLog("Library \"" + library + "\" will be added via reference directive");
210 typesReferences.add(library);
211 }
212}
213function addImport(statement, library, imports) {
214 if (statement.name === undefined) {
215 throw new Error("Import/usage unnamed declaration: " + statement.getText());
216 }
217 var libraryImports = imports.get(library);
218 if (libraryImports === undefined) {
219 libraryImports = new Set();
220 imports.set(library, libraryImports);
221 }
222 var importName = statement.name.getText();
223 if (!libraryImports.has(importName)) {
224 logger_1.normalLog("Adding import with name \"" + importName + "\" for library \"" + library + "\"");
225 libraryImports.add(importName);
226 }
227}
228function getRootSourceFile(program) {
229 var rootFiles = program.getRootFileNames();
230 if (rootFiles.length !== 1) {
231 logger_1.verboseLog("Root files:\n " + rootFiles.join('\n '));
232 throw new Error("There is not one root file - " + rootFiles.length);
233 }
234 var sourceFileName = rootFiles[0];
235 var sourceFile = program.getSourceFile(sourceFileName);
236 if (sourceFile === undefined) {
237 throw new Error("Cannot get source file for root file " + sourceFileName);
238 }
239 return sourceFile;
240}
241function isDeclarationExported(exportedSymbols, typeChecker, declaration) {
242 if (declaration.name === undefined) {
243 return false;
244 }
245 var declarationSymbol = typeChecker.getSymbolAtLocation(declaration.name);
246 return exportedSymbols.some(function (rootExport) { return rootExport === declarationSymbol; });
247}
248function isNodeUsed(node, rootFileExports, typesUsageEvaluator, typeChecker) {
249 if (typescript_helpers_1.isNodeNamedDeclaration(node)) {
250 return rootFileExports.some(function (rootExport) { return typesUsageEvaluator.isTypeUsedBySymbol(node, rootExport); });
251 }
252 else if (ts.isVariableStatement(node)) {
253 return node.declarationList.declarations.some(function (declaration) {
254 return isDeclarationExported(rootFileExports, typeChecker, declaration);
255 });
256 }
257 return false;
258}
259function shouldNodeBeImported(node, rootFileExports, typesUsageEvaluator) {
260 var symbolsUsingNode = typesUsageEvaluator.getSymbolsUsingNode(node);
261 if (symbolsUsingNode === null) {
262 throw new Error('Something went wrong - value cannot be null');
263 }
264 // we should import only symbols which are used in types directly
265 return Array.from(symbolsUsingNode).some(function (symbol) {
266 var symbolsDeclarations = getDeclarationsForSymbol(symbol);
267 if (symbolsDeclarations.length === 0 || symbolsDeclarations.every(isDeclarationFromExternalModule)) {
268 return false;
269 }
270 return rootFileExports.some(function (rootSymbol) { return typesUsageEvaluator.isSymbolUsedBySymbol(symbol, rootSymbol); });
271 });
272}
273function getDeclarationsForSymbol(symbol) {
274 var result = [];
275 if (symbol.valueDeclaration !== undefined) {
276 result.push(symbol.valueDeclaration);
277 }
278 if (symbol.declarations !== undefined) {
279 result.push.apply(result, symbol.declarations);
280 }
281 return result;
282}
283function isDeclarationFromExternalModule(node) {
284 return node_modules_helpers_1.getLibraryName(node.getSourceFile().fileName) !== null;
285}