1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var path = require("path");
|
4 | var typescript_1 = require("typescript");
|
5 | var helpers_1 = require("./helpers");
|
6 | function getTypescriptSourceFile(filePath, fileContent, languageVersion, setParentNodes) {
|
7 | if (languageVersion === void 0) { languageVersion = typescript_1.ScriptTarget.Latest; }
|
8 | if (setParentNodes === void 0) { setParentNodes = false; }
|
9 | return typescript_1.createSourceFile(filePath, fileContent, languageVersion, setParentNodes);
|
10 | }
|
11 | exports.getTypescriptSourceFile = getTypescriptSourceFile;
|
12 | function removeDecorators(fileName, source) {
|
13 | var sourceFile = typescript_1.createSourceFile(fileName, source, typescript_1.ScriptTarget.Latest);
|
14 | var decorators = findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.Decorator, true);
|
15 | decorators.sort(function (a, b) { return b.pos - a.pos; });
|
16 | decorators.forEach(function (d) {
|
17 | source = source.slice(0, d.pos) + source.slice(d.end);
|
18 | });
|
19 | return source;
|
20 | }
|
21 | exports.removeDecorators = removeDecorators;
|
22 | function findNodes(sourceFile, node, kind, keepGoing) {
|
23 | if (keepGoing === void 0) { keepGoing = false; }
|
24 | if (node.kind === kind && !keepGoing) {
|
25 | return [node];
|
26 | }
|
27 | return node.getChildren(sourceFile).reduce(function (result, n) {
|
28 | return result.concat(findNodes(sourceFile, n, kind, keepGoing));
|
29 | }, node.kind === kind ? [node] : []);
|
30 | }
|
31 | exports.findNodes = findNodes;
|
32 | function replaceNode(filePath, fileContent, node, replacement) {
|
33 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
34 | var startIndex = node.getStart(sourceFile);
|
35 | var endIndex = node.getEnd();
|
36 | var modifiedContent = helpers_1.rangeReplace(fileContent, startIndex, endIndex, replacement);
|
37 | return modifiedContent;
|
38 | }
|
39 | exports.replaceNode = replaceNode;
|
40 | function removeNode(filePath, fileContent, node) {
|
41 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
42 | var startIndex = node.getStart(sourceFile);
|
43 | var endIndex = node.getEnd();
|
44 | var modifiedContent = helpers_1.rangeReplace(fileContent, startIndex, endIndex, '');
|
45 | return modifiedContent;
|
46 | }
|
47 | exports.removeNode = removeNode;
|
48 | function getNodeStringContent(sourceFile, node) {
|
49 | return sourceFile.getFullText().substring(node.getStart(sourceFile), node.getEnd());
|
50 | }
|
51 | exports.getNodeStringContent = getNodeStringContent;
|
52 | function appendAfter(source, node, toAppend) {
|
53 | return helpers_1.stringSplice(source, node.getEnd(), 0, toAppend);
|
54 | }
|
55 | exports.appendAfter = appendAfter;
|
56 | function appendEmpty(source, position, toAppend) {
|
57 | return helpers_1.stringSplice(source, position, 0, toAppend);
|
58 | }
|
59 | exports.appendEmpty = appendEmpty;
|
60 | function appendBefore(filePath, fileContent, node, toAppend) {
|
61 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
62 | return helpers_1.stringSplice(fileContent, node.getStart(sourceFile), 0, toAppend);
|
63 | }
|
64 | exports.appendBefore = appendBefore;
|
65 | function insertNamedImportIfNeeded(filePath, fileContent, namedImport, fromModule) {
|
66 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
67 | var allImports = findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.ImportDeclaration);
|
68 | var maybeImports = allImports.filter(function (node) {
|
69 | return node.moduleSpecifier.kind === typescript_1.SyntaxKind.StringLiteral
|
70 | && node.moduleSpecifier.text === fromModule;
|
71 | }).filter(function (node) {
|
72 |
|
73 | var clause = node.importClause;
|
74 | if (!clause || clause.name || !clause.namedBindings) {
|
75 | return false;
|
76 | }
|
77 | return clause.namedBindings.kind === typescript_1.SyntaxKind.NamedImports;
|
78 | }).map(function (node) {
|
79 | return node.importClause.namedBindings;
|
80 | });
|
81 | if (maybeImports.length) {
|
82 |
|
83 |
|
84 | var hasImportAlready = maybeImports.some(function (node) {
|
85 | return node.elements.some(function (element) {
|
86 | return element.name.text === namedImport;
|
87 | });
|
88 | });
|
89 | if (hasImportAlready) {
|
90 |
|
91 | return fileContent;
|
92 | }
|
93 |
|
94 | fileContent = appendAfter(fileContent, maybeImports[0].elements[maybeImports[0].elements.length - 1], ", " + namedImport);
|
95 | }
|
96 | else {
|
97 |
|
98 | fileContent = appendAfter(fileContent, allImports[allImports.length - 1], "\nimport { " + namedImport + " } from '" + fromModule + "';");
|
99 | }
|
100 | return fileContent;
|
101 | }
|
102 | exports.insertNamedImportIfNeeded = insertNamedImportIfNeeded;
|
103 | function replaceNamedImport(filePath, fileContent, namedImportOriginal, namedImportReplacement) {
|
104 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
105 | var allImports = findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.ImportDeclaration);
|
106 | var modifiedContent = fileContent;
|
107 | allImports.filter(function (node) {
|
108 | if (node.importClause && node.importClause.namedBindings) {
|
109 | return node.importClause.namedBindings.kind === typescript_1.SyntaxKind.NamedImports;
|
110 | }
|
111 | }).map(function (importDeclaration) {
|
112 | return importDeclaration.importClause.namedBindings;
|
113 | }).forEach(function (namedImport) {
|
114 | return namedImport.elements.forEach(function (element) {
|
115 | if (element.name.text === namedImportOriginal) {
|
116 | modifiedContent = replaceNode(filePath, modifiedContent, element, namedImportReplacement);
|
117 | }
|
118 | });
|
119 | });
|
120 | return modifiedContent;
|
121 | }
|
122 | exports.replaceNamedImport = replaceNamedImport;
|
123 | function replaceImportModuleSpecifier(filePath, fileContent, moduleSpecifierOriginal, moduleSpecifierReplacement) {
|
124 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
125 | var allImports = findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.ImportDeclaration);
|
126 | var modifiedContent = fileContent;
|
127 | allImports.forEach(function (node) {
|
128 | if (node.moduleSpecifier.kind === typescript_1.SyntaxKind.StringLiteral && node.moduleSpecifier.text === moduleSpecifierOriginal) {
|
129 | modifiedContent = replaceNode(filePath, modifiedContent, node.moduleSpecifier, "'" + moduleSpecifierReplacement + "'");
|
130 | }
|
131 | });
|
132 | return modifiedContent;
|
133 | }
|
134 | exports.replaceImportModuleSpecifier = replaceImportModuleSpecifier;
|
135 | function checkIfFunctionIsCalled(filePath, fileContent, functionName) {
|
136 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
137 | var allCalls = findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.CallExpression, true);
|
138 | var functionCallList = allCalls.filter(function (call) { return call.expression && call.expression.kind === typescript_1.SyntaxKind.Identifier && call.expression.text === functionName; });
|
139 | return functionCallList.length > 0;
|
140 | }
|
141 | exports.checkIfFunctionIsCalled = checkIfFunctionIsCalled;
|
142 | function getClassDeclarations(sourceFile) {
|
143 | return findNodes(sourceFile, sourceFile, typescript_1.SyntaxKind.ClassDeclaration, true);
|
144 | }
|
145 | exports.getClassDeclarations = getClassDeclarations;
|
146 | function getNgModuleClassName(filePath, fileContent) {
|
147 | var ngModuleSourceFile = getTypescriptSourceFile(filePath, fileContent);
|
148 | var classDeclarations = getClassDeclarations(ngModuleSourceFile);
|
149 |
|
150 | var classNameList = [];
|
151 | classDeclarations.forEach(function (classDeclaration) {
|
152 | if (classDeclaration && classDeclaration.decorators) {
|
153 | classDeclaration.decorators.forEach(function (decorator) {
|
154 | if (decorator.expression && decorator.expression.expression && decorator.expression.expression.text === exports.NG_MODULE_DECORATOR_TEXT) {
|
155 | var className = classDeclaration.name.text;
|
156 | classNameList.push(className);
|
157 | }
|
158 | });
|
159 | }
|
160 | });
|
161 | if (classNameList.length === 0) {
|
162 | throw new Error("Could not find a class declaration in " + filePath);
|
163 | }
|
164 | if (classNameList.length > 1) {
|
165 | throw new Error("Multiple class declarations with NgModule in " + filePath + ". The correct class to use could not be determined.");
|
166 | }
|
167 | return classNameList[0];
|
168 | }
|
169 | exports.getNgModuleClassName = getNgModuleClassName;
|
170 | function getNgModuleDecorator(fileName, sourceFile) {
|
171 | var ngModuleDecorators = [];
|
172 | var classDeclarations = getClassDeclarations(sourceFile);
|
173 | classDeclarations.forEach(function (classDeclaration) {
|
174 | if (classDeclaration && classDeclaration.decorators) {
|
175 | classDeclaration.decorators.forEach(function (decorator) {
|
176 | if (decorator.expression && decorator.expression.expression && decorator.expression.expression.text === exports.NG_MODULE_DECORATOR_TEXT) {
|
177 | ngModuleDecorators.push(decorator);
|
178 | }
|
179 | });
|
180 | }
|
181 | });
|
182 | if (ngModuleDecorators.length === 0) {
|
183 | throw new Error("Could not find an \"NgModule\" decorator in " + fileName);
|
184 | }
|
185 | if (ngModuleDecorators.length > 1) {
|
186 | throw new Error("Multiple \"NgModule\" decorators found in " + fileName + ". The correct one to use could not be determined");
|
187 | }
|
188 | return ngModuleDecorators[0];
|
189 | }
|
190 | exports.getNgModuleDecorator = getNgModuleDecorator;
|
191 | function getNgModuleObjectLiteralArg(decorator) {
|
192 | var ngModuleArgs = decorator.expression.arguments;
|
193 | if (!ngModuleArgs || ngModuleArgs.length === 0 || ngModuleArgs.length > 1) {
|
194 | throw new Error("Invalid NgModule Argument");
|
195 | }
|
196 | return ngModuleArgs[0];
|
197 | }
|
198 | exports.getNgModuleObjectLiteralArg = getNgModuleObjectLiteralArg;
|
199 | function findObjectLiteralElementByName(properties, identifierToLookFor) {
|
200 | return properties.filter(function (propertyNode) {
|
201 | return propertyNode && propertyNode.name && propertyNode.name.text === identifierToLookFor;
|
202 | })[0];
|
203 | }
|
204 | exports.findObjectLiteralElementByName = findObjectLiteralElementByName;
|
205 | function appendNgModuleDeclaration(filePath, fileContent, declaration) {
|
206 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
207 | var decorator = getNgModuleDecorator(path.basename(filePath), sourceFile);
|
208 | var obj = getNgModuleObjectLiteralArg(decorator);
|
209 | var properties = findObjectLiteralElementByName(obj.properties, 'declarations');
|
210 | var declarations = properties.initializer.elements;
|
211 | if (declarations.length === 0) {
|
212 | return appendEmpty(fileContent, declarations['end'], declaration);
|
213 | }
|
214 | else {
|
215 | return appendAfter(fileContent, declarations[declarations.length - 1], ",\n " + declaration);
|
216 | }
|
217 | }
|
218 | exports.appendNgModuleDeclaration = appendNgModuleDeclaration;
|
219 | function appendNgModuleProvider(filePath, fileContent, declaration) {
|
220 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
221 | var decorator = getNgModuleDecorator(path.basename(filePath), sourceFile);
|
222 | var obj = getNgModuleObjectLiteralArg(decorator);
|
223 | var properties = findObjectLiteralElementByName(obj.properties, 'providers');
|
224 | var providers = properties.initializer.elements;
|
225 | if (providers.length === 0) {
|
226 | return appendEmpty(fileContent, providers['end'], declaration);
|
227 | }
|
228 | else {
|
229 | return appendAfter(fileContent, providers[providers.length - 1], ",\n " + declaration);
|
230 | }
|
231 | }
|
232 | exports.appendNgModuleProvider = appendNgModuleProvider;
|
233 | function appendNgModuleExports(filePath, fileContent, declaration) {
|
234 | var sourceFile = getTypescriptSourceFile(filePath, fileContent, typescript_1.ScriptTarget.Latest, false);
|
235 | var decorator = getNgModuleDecorator(path.basename(filePath), sourceFile);
|
236 | var obj = getNgModuleObjectLiteralArg(decorator);
|
237 | var properties = findObjectLiteralElementByName(obj.properties, 'exports');
|
238 | var exportsProp = properties.initializer.elements;
|
239 | if (exportsProp.length === 0) {
|
240 | return appendEmpty(fileContent, exportsProp['end'], declaration);
|
241 | }
|
242 | else {
|
243 | return appendAfter(fileContent, exportsProp[exportsProp.length - 1], ",\n " + declaration);
|
244 | }
|
245 | }
|
246 | exports.appendNgModuleExports = appendNgModuleExports;
|
247 | exports.NG_MODULE_DECORATOR_TEXT = 'NgModule';
|