UNPKG

13.5 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);
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 updateResult(__assign({}, updateResultCommonParams, { currentModule: module_info_1.getModuleInfo(sourceFile.fileName, criteria), statements: sourceFile.statements }), collectionResult);
73 if (collectionResult.statements.length === prevStatementsCount) {
74 logger_1.verboseLog("No output for file: " + sourceFile.fileName);
75 }
76 }
77 if (options.failOnClass) {
78 var isClassStatementFound = collectionResult.statements.some(function (statement) { return ts.isClassDeclaration(statement); });
79 if (isClassStatementFound) {
80 throw new Error('At least 1 class statement is found in generated dts.');
81 }
82 }
83 for (var _a = 0, _b = rootSourceFile.statements; _a < _b.length; _a++) {
84 var statement = _b[_a];
85 // add skipped by `updateResult` `export default` from root file if present
86 if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
87 collectionResult.statements.push(statement);
88 }
89 }
90 return generate_output_1.generateOutput(__assign({}, collectionResult, { needStripDefaultKeywordForStatement: function (statement) { return statement.getSourceFile() !== rootSourceFile; }, shouldStatementHasExportKeyword: function (statement) {
91 var result = true;
92 if (ts.isClassDeclaration(statement) || ts.isEnumDeclaration(statement) || ts.isFunctionDeclaration(statement)) {
93 // not every class, enum and function can be exported (only exported from root file can)
94 result = isDeclarationExported(rootFileExports, typeChecker, statement);
95 if (ts.isEnumDeclaration(statement)) {
96 // const enum always can be exported
97 result = result || typescript_helpers_1.hasNodeModifier(statement, ts.SyntaxKind.ConstKeyword);
98 }
99 }
100 else if (typescript_helpers_1.isDeclareGlobalStatement(statement)) {
101 result = false;
102 }
103 return result;
104 } }), {
105 sortStatements: options.sortNodes,
106 umdModuleName: options.umdModuleName,
107 });
108}
109exports.generateDtsBundle = generateDtsBundle;
110// tslint:disable-next-line:cyclomatic-complexity
111function updateResult(params, result) {
112 if (params.currentModule.type === 0 /* ShouldNotBeUsed */) {
113 return;
114 }
115 for (var _i = 0, _a = params.statements; _i < _a.length; _i++) {
116 var statement = _a[_i];
117 // we should skip import and exports statements
118 if (skippedNodes.indexOf(statement.kind) !== -1) {
119 continue;
120 }
121 if (typescript_helpers_1.isDeclareModuleStatement(statement)) {
122 updateResultForModuleDeclaration(statement, params, result);
123 continue;
124 }
125 if (params.currentModule.type === 4 /* ShouldBeUsedForModulesOnly */) {
126 continue;
127 }
128 if (typescript_helpers_1.isDeclareGlobalStatement(statement) && params.shouldDeclareGlobalBeInlined(params.currentModule, statement)) {
129 result.statements.push(statement);
130 continue;
131 }
132 if (ts.isExportAssignment(statement) && statement.isExportEquals && params.currentModule.type === 2 /* ShouldBeImported */) {
133 updateResultForImportedEqExportAssignment(statement, params, result);
134 continue;
135 }
136 if (!params.isStatementUsed(statement)) {
137 logger_1.verboseLog("Skip file member: " + statement.getText().replace(/(\n|\r)/g, '').slice(0, 50) + "...");
138 continue;
139 }
140 switch (params.currentModule.type) {
141 case 3 /* ShouldBeReferencedAsTypes */:
142 addTypesReference(params.currentModule.typesLibraryName, result.typesReferences);
143 break;
144 case 2 /* ShouldBeImported */:
145 if (params.shouldStatementBeImported(statement)) {
146 addImport(statement, params.currentModule.libraryName, result.imports);
147 }
148 break;
149 case 1 /* ShouldBeInlined */:
150 result.statements.push(statement);
151 break;
152 }
153 }
154}
155function updateResultForImportedEqExportAssignment(exportAssignment, params, result) {
156 var moduleDeclarations = params.getDeclarationsForExportedAssignment(exportAssignment)
157 .filter(typescript_helpers_1.isNamespaceStatement)
158 .filter(function (s) { return s.getSourceFile() === exportAssignment.getSourceFile(); });
159 // if we have `export =` somewhere so we can decide that every declaration of exported symbol in this way
160 // is "part of the exported module" and we need to update result according every member of each declaration
161 // but treat they as current module (we do not need to update module info)
162 for (var _i = 0, moduleDeclarations_1 = moduleDeclarations; _i < moduleDeclarations_1.length; _i++) {
163 var moduleDeclaration = moduleDeclarations_1[_i];
164 if (moduleDeclaration.body === undefined || !ts.isModuleBlock(moduleDeclaration.body)) {
165 continue;
166 }
167 updateResult(__assign({}, params, { statements: moduleDeclaration.body.statements }), result);
168 }
169}
170function updateResultForModuleDeclaration(moduleDecl, params, result) {
171 if (params.currentModule.type === 0 /* ShouldNotBeUsed */) {
172 return;
173 }
174 if (moduleDecl.body === undefined || !ts.isModuleBlock(moduleDecl.body)) {
175 return;
176 }
177 var moduleName = moduleDecl.name.text;
178 var moduleFileName = resolveModuleFileName(params.currentModule.fileName, moduleName);
179 var moduleInfo = params.getModuleInfo(moduleFileName);
180 if (moduleInfo.type === 0 /* ShouldNotBeUsed */) {
181 return;
182 }
183 // if we have declaration of external module inside internal one
184 // we need to just add it to result without any processing
185 if (!params.currentModule.isExternal && moduleInfo.isExternal) {
186 result.statements.push(moduleDecl);
187 return;
188 }
189 updateResult(__assign({}, params, { currentModule: moduleInfo, statements: moduleDecl.body.statements }), result);
190}
191function resolveModuleFileName(currentFileName, moduleName) {
192 return moduleName.startsWith('.') ? path.join(currentFileName, '..', moduleName) : "node_modules/" + moduleName + "/";
193}
194function addTypesReference(library, typesReferences) {
195 if (!typesReferences.has(library)) {
196 logger_1.normalLog("Library \"" + library + "\" will be added via reference directive");
197 typesReferences.add(library);
198 }
199}
200function addImport(statement, library, imports) {
201 if (statement.name === undefined) {
202 throw new Error("Import/usage unnamed declaration: " + statement.getText());
203 }
204 var libraryImports = imports.get(library);
205 if (libraryImports === undefined) {
206 libraryImports = new Set();
207 imports.set(library, libraryImports);
208 }
209 var importName = statement.name.getText();
210 if (!libraryImports.has(importName)) {
211 logger_1.normalLog("Adding import with name \"" + importName + "\" for library \"" + library + "\"");
212 libraryImports.add(importName);
213 }
214}
215function getRootSourceFile(program) {
216 var rootFiles = program.getRootFileNames();
217 if (rootFiles.length !== 1) {
218 logger_1.verboseLog("Root files:\n " + rootFiles.join('\n '));
219 throw new Error("There is not one root file - " + rootFiles.length);
220 }
221 var sourceFileName = rootFiles[0];
222 var sourceFile = program.getSourceFile(sourceFileName);
223 if (sourceFile === undefined) {
224 throw new Error("Cannot get source file for root file " + sourceFileName);
225 }
226 return sourceFile;
227}
228function isDeclarationExported(exportedSymbols, typeChecker, declaration) {
229 if (declaration.name === undefined) {
230 return false;
231 }
232 var declarationSymbol = typeChecker.getSymbolAtLocation(declaration.name);
233 return exportedSymbols.some(function (rootExport) { return rootExport === declarationSymbol; });
234}
235function isNodeUsed(node, rootFileExports, typesUsageEvaluator, typeChecker) {
236 if (typescript_helpers_1.isNodeNamedDeclaration(node)) {
237 return rootFileExports.some(function (rootExport) { return typesUsageEvaluator.isTypeUsedBySymbol(node, rootExport); });
238 }
239 else if (ts.isVariableStatement(node)) {
240 return node.declarationList.declarations.some(function (declaration) {
241 return isDeclarationExported(rootFileExports, typeChecker, declaration);
242 });
243 }
244 return false;
245}
246function shouldNodeBeImported(node, rootFileExports, typesUsageEvaluator) {
247 var symbolsUsingNode = typesUsageEvaluator.getSymbolsUsingNode(node);
248 if (symbolsUsingNode === null) {
249 throw new Error('Something went wrong - value cannot be null');
250 }
251 // we should import only symbols which are used in types directly
252 return Array.from(symbolsUsingNode).some(function (symbol) {
253 var symbolsDeclarations = getDeclarationsForSymbol(symbol);
254 if (symbolsDeclarations.length === 0 || symbolsDeclarations.every(isDeclarationFromExternalModule)) {
255 return false;
256 }
257 return rootFileExports.some(function (rootSymbol) { return typesUsageEvaluator.isSymbolUsedBySymbol(symbol, rootSymbol); });
258 });
259}
260function getDeclarationsForSymbol(symbol) {
261 var result = [];
262 if (symbol.valueDeclaration !== undefined) {
263 result.push(symbol.valueDeclaration);
264 }
265 if (symbol.declarations !== undefined) {
266 result.push.apply(result, symbol.declarations);
267 }
268 return result;
269}
270function isDeclarationFromExternalModule(node) {
271 return node_modules_helpers_1.getLibraryName(node.getSourceFile().fileName) !== null;
272}