UNPKG

5.41 kBJavaScriptView Raw
1"use strict";
2const fs = require('fs');
3const ts = require('typescript');
4const glob = require('glob');
5const path = require('path');
6const denodeify = require('denodeify');
7const readFile = denodeify(fs.readFile);
8const globSearch = denodeify(glob);
9/**
10 * Create a SourceFile as defined by Typescript Compiler API.
11 * Generate a AST structure from a source file.
12 *
13 * @param fileName source file for which AST is to be extracted
14 */
15function createTsSourceFile(fileName) {
16 return readFile(fileName, 'utf8')
17 .then((contents) => {
18 return ts.createSourceFile(fileName, contents, ts.ScriptTarget.Latest, true);
19 });
20}
21exports.createTsSourceFile = createTsSourceFile;
22/**
23 * Traverses through AST of a given file of kind 'ts.SourceFile', filters out child
24 * nodes of the kind 'ts.SyntaxKind.ImportDeclaration' and returns import clauses as
25 * ModuleImport[]
26 *
27 * @param {ts.SourceFile} node: Typescript Node of whose AST is being traversed
28 *
29 * @return {ModuleImport[]} traverses through ts.Node and returns an array of moduleSpecifiers.
30 */
31function getImportClauses(node) {
32 return node.statements
33 .filter(node => node.kind === ts.SyntaxKind.ImportDeclaration) // Only Imports.
34 .map((node) => {
35 let moduleSpecifier = node.moduleSpecifier;
36 return {
37 specifierText: moduleSpecifier.getText().slice(1, -1),
38 pos: moduleSpecifier.pos,
39 end: moduleSpecifier.end
40 };
41 });
42}
43exports.getImportClauses = getImportClauses;
44/**
45 * Find the file, 'index.ts' given the directory name and return boolean value
46 * based on its findings.
47 *
48 * @param dirPath
49 *
50 * @return a boolean value after it searches for a barrel (index.ts by convention) in a given path
51 */
52function hasIndexFile(dirPath) {
53 return globSearch(path.join(dirPath, 'index.ts'), { nodir: true })
54 .then((indexFile) => {
55 return indexFile.length > 0;
56 });
57}
58exports.hasIndexFile = hasIndexFile;
59/**
60 * Function to get all the templates, stylesheets, and spec files of a given component unit
61 * Assumption: When any component/service/pipe unit is generated, Angular CLI has a blueprint for
62 * creating associated files with the name of the generated unit. So, there are two
63 * assumptions made:
64 * a. the function only returns associated files that have names matching to the given unit.
65 * b. the function only looks for the associated files in the directory where the given unit
66 * exists.
67 *
68 * @todo read the metadata to look for the associated files of a given file.
69 *
70 * @param fileName
71 *
72 * @return absolute paths of '.html/.css/.sass/.spec.ts' files associated with the given file.
73 *
74 */
75function getAllAssociatedFiles(fileName) {
76 let fileDirName = path.dirname(fileName);
77 let componentName = path.basename(fileName, '.ts');
78 return globSearch(path.join(fileDirName, `${componentName}.*`), { nodir: true })
79 .then((files) => {
80 return files.filter((file) => {
81 return (path.basename(file) !== 'index.ts');
82 });
83 });
84}
85exports.getAllAssociatedFiles = getAllAssociatedFiles;
86/**
87 * Returns a map of all dependent file/s' path with their moduleSpecifier object
88 * (specifierText, pos, end).
89 *
90 * @param fileName file upon which other files depend
91 * @param rootPath root of the project
92 *
93 * @return {Promise<ModuleMap>} ModuleMap of all dependent file/s (specifierText, pos, end)
94 *
95 */
96function getDependentFiles(fileName, rootPath) {
97 return globSearch(path.join(rootPath, '**/*.ts'), { nodir: true })
98 .then((files) => Promise.all(files.map(file => createTsSourceFile(file)))
99 .then((tsFiles) => tsFiles.map(file => getImportClauses(file)))
100 .then((moduleSpecifiers) => {
101 let allFiles = {};
102 files.forEach((file, index) => {
103 let sourcePath = path.normalize(file);
104 allFiles[sourcePath] = moduleSpecifiers[index];
105 });
106 return allFiles;
107 })
108 .then((allFiles) => {
109 let relevantFiles = {};
110 Object.keys(allFiles).forEach(filePath => {
111 const tempModuleSpecifiers = allFiles[filePath]
112 .filter(importClause => {
113 // Filter only relative imports
114 let singleSlash = importClause.specifierText.charAt(0) === '/';
115 let currentDirSyntax = importClause.specifierText.slice(0, 2) === './';
116 let parentDirSyntax = importClause.specifierText.slice(0, 3) === '../';
117 return singleSlash || currentDirSyntax || parentDirSyntax;
118 })
119 .filter(importClause => {
120 let modulePath = path.resolve(path.dirname(filePath), importClause.specifierText);
121 let resolvedFileName = path.resolve(fileName);
122 let fileBaseName = path.basename(resolvedFileName, '.ts');
123 let parsedFilePath = path.join(path.dirname(resolvedFileName), fileBaseName);
124 return (parsedFilePath === modulePath) || (resolvedFileName === modulePath);
125 });
126 if (tempModuleSpecifiers.length > 0) {
127 relevantFiles[filePath] = tempModuleSpecifiers;
128 }
129 ;
130 });
131 return relevantFiles;
132 }));
133}
134exports.getDependentFiles = getDependentFiles;
135//# sourceMappingURL=/Users/hansl/Sources/angular-cli/packages/@angular/cli/utilities/get-dependent-files.js.map
\No newline at end of file