1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 | import 'source-map-support/register';
|
13 |
|
14 | import * as fsExtra from 'fs-extra';
|
15 | import * as glob from 'glob';
|
16 | import * as path from 'path';
|
17 |
|
18 | import {Config, generateDeclarations} from './gen-ts';
|
19 | import {verifyTypings} from './verify';
|
20 |
|
21 | import commandLineArgs = require('command-line-args');
|
22 | import commandLineUsage = require('command-line-usage');
|
23 |
|
24 | const argDefs = [
|
25 | {
|
26 | name: 'help',
|
27 | type: Boolean,
|
28 | description: 'Print this help text.',
|
29 | },
|
30 | {
|
31 | name: 'version',
|
32 | type: Boolean,
|
33 | description: 'Print the installed version.',
|
34 | },
|
35 | {
|
36 | name: 'root',
|
37 | type: String,
|
38 | defaultValue: '.',
|
39 | description: 'Root directory of the package to analyze (default ".").',
|
40 | },
|
41 | {
|
42 | name: 'config',
|
43 | type: String,
|
44 | description:
|
45 | 'JSON configuration file (default "<root>/gen-tsd.json" if exists).',
|
46 | },
|
47 | {
|
48 | name: 'outDir',
|
49 | type: String,
|
50 | description: 'Type declarations output directory (required).',
|
51 | },
|
52 | {
|
53 | name: 'deleteExisting',
|
54 | type: Boolean,
|
55 | description: 'Recursively delete all .d.ts files in <outDir> before ' +
|
56 | 'writing new typings, excluding node_modules/, bower_components/, ' +
|
57 | 'or any file added using the <addReferences> or <autoImport> config ' +
|
58 | 'options.',
|
59 | },
|
60 | {
|
61 | name: 'verify',
|
62 | type: Boolean,
|
63 | description: 'Compile the generated types with TypeScript 3.0 and fail ' +
|
64 | 'if they are invalid.',
|
65 | },
|
66 | {
|
67 | name: 'googModules',
|
68 | type: Boolean,
|
69 | description: 'If true, outputs declarations in \'goog:\' modules instead' +
|
70 | ' of using simple ES modules. This is a temporary hack to account for' +
|
71 | ' how modules are resolved for TypeScript inside google3. This' +
|
72 | ' is probably not at all useful for anyone but the Polymer team.'
|
73 | }
|
74 | ];
|
75 |
|
76 | interface Args {
|
77 | help?: boolean;
|
78 | version?: boolean;
|
79 | root: string;
|
80 | config?: string;
|
81 | outDir?: string;
|
82 | deleteExisting?: boolean;
|
83 | verify?: boolean;
|
84 | googModules?: boolean;
|
85 | }
|
86 |
|
87 | async function run(argv: string[]) {
|
88 | const args = commandLineArgs(argDefs, {argv}) as Args;
|
89 |
|
90 | if (args.help) {
|
91 | console.log(commandLineUsage([
|
92 | {
|
93 | header: `gen-typescript-declarations`,
|
94 | content: 'https://github.com/Polymer/tools/tree/master/packages/' +
|
95 | 'gen-typescript-declarations',
|
96 | },
|
97 | {
|
98 | header: `Options`,
|
99 | optionList: argDefs,
|
100 | }
|
101 | ]));
|
102 | return;
|
103 | }
|
104 |
|
105 | if (args.version) {
|
106 | console.log(require('../package.json').version);
|
107 | return;
|
108 | }
|
109 |
|
110 | if (!args.outDir) {
|
111 | throw new Error('--outDir is required');
|
112 | }
|
113 | const outDir = path.resolve(args.outDir);
|
114 |
|
115 | if (!args.config) {
|
116 | const p = path.join(args.root, 'gen-tsd.json');
|
117 | if (await fsExtra.pathExists(p)) {
|
118 | args.config = p;
|
119 | }
|
120 | }
|
121 | let config: Config = {};
|
122 | if (args.config) {
|
123 | console.info(`Loading config from "${args.config}".`);
|
124 | config = JSON.parse(await fsExtra.readFile(args.config, 'utf8')) as Config;
|
125 | }
|
126 | if (args.googModules) {
|
127 | config.googModules = true;
|
128 | }
|
129 |
|
130 | const fileMap = await generateDeclarations(args.root, config);
|
131 |
|
132 | if (args.deleteExisting) {
|
133 | let dtsFiles = glob.sync('**/*.d.ts', {
|
134 | cwd: outDir,
|
135 | absolute: true,
|
136 | nodir: true,
|
137 | ignore: [
|
138 | 'node_modules/**',
|
139 | 'bower_components/**',
|
140 | ]
|
141 | });
|
142 |
|
143 |
|
144 |
|
145 |
|
146 | const dontDelete = new Set<string>();
|
147 | for (const dtsFilePaths of Object.values(config.addReferences || {})) {
|
148 | for (const dtsFilePath of dtsFilePaths) {
|
149 | dontDelete.add(path.resolve(args.root, dtsFilePath));
|
150 | }
|
151 | }
|
152 | for (const localModuleSpecifier of Object.keys(config.autoImport || {})) {
|
153 | const dtsFilePath = localModuleSpecifier.replace(/\.js$/, '') + '.d.ts';
|
154 | dontDelete.add(path.resolve(args.root, dtsFilePath));
|
155 | }
|
156 | dtsFiles = dtsFiles.filter((filepath) => !dontDelete.has(filepath));
|
157 |
|
158 | console.log(
|
159 | `Deleting ${dtsFiles.length} existing d.ts files from ${outDir}`);
|
160 | await Promise.all(dtsFiles.map((filepath) => fsExtra.remove(filepath)));
|
161 | }
|
162 |
|
163 | console.log(`Writing type declarations to ${outDir}`);
|
164 | await writeFileMap(args.outDir, fileMap);
|
165 |
|
166 | if (args.verify) {
|
167 | console.log('Verifying type declarations');
|
168 | const declarationFiles =
|
169 | [...fileMap.keys()].map((filePath) => path.join(outDir, filePath));
|
170 | const result = verifyTypings(declarationFiles);
|
171 | if (result.success === true) {
|
172 | console.log('Compilation successful');
|
173 | } else {
|
174 | console.log('Compilation failed');
|
175 | console.log(result.errorLog);
|
176 | process.exit(1);
|
177 | }
|
178 | }
|
179 | }
|
180 |
|
181 | async function writeFileMap(
|
182 | rootDir: string, files: Map<string, string>): Promise<void> {
|
183 | const promises = [];
|
184 | for (const [relPath, contents] of files) {
|
185 | const fullPath = path.join(rootDir, relPath);
|
186 | promises.push(fsExtra.outputFile(fullPath, contents));
|
187 | }
|
188 | await Promise.all(promises);
|
189 | }
|
190 |
|
191 | (async () => {
|
192 | try {
|
193 | await run(process.argv);
|
194 | } catch (e) {
|
195 | console.error(e);
|
196 | process.exit(1);
|
197 | }
|
198 | })();
|