@craft-ng/dev-tools 0.1.9 → 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -3
- package/package.json +1 -1
- package/src/eslint-rules/app-start-registry-match.cjs +357 -0
- package/src/eslint-rules/brand-angular-deps-match.cjs +214 -80
- package/src/eslint-rules/brand-angular-gen-deps-required.cjs +175 -0
- package/src/eslint-rules/index.cjs +10 -2
- package/src/eslint-rules/no-angular-inject.cjs +1 -78
- package/src/eslint-rules/no-angular-provide-app-initializer.cjs +79 -0
- package/src/eslint-rules/prefer-browser-boundaries.cjs +92 -0
- package/src/eslint-rules/prefer-craft-http-client.cjs +120 -0
- package/src/eslint-rules/prefer-craft-service.cjs +140 -0
- package/src/scripts/angular-brand-codemod.d.ts +25 -0
- package/src/scripts/angular-brand-codemod.js +450 -49
- package/src/scripts/angular-brand-codemod.js.map +1 -1
- package/src/scripts/angular-brand-codemod.spec.ts +716 -3
- package/src/scripts/angular-brand-codemod.ts +904 -61
- package/src/eslint-rules/no-direct-angular-class-export.cjs +0 -240
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { Node, Project, QuoteKind, SyntaxKind, ts, } from 'ts-morph';
|
|
3
|
-
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
|
-
import {
|
|
3
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { basename, dirname, extname, isAbsolute, join, resolve, } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
6
7
|
const SUPPORTED_DECORATORS = {
|
|
7
8
|
Component: 'component',
|
|
@@ -14,7 +15,53 @@ const DEFAULT_OPTIONS = {
|
|
|
14
15
|
transformOnlyStandaloneDeclarables: false,
|
|
15
16
|
includeProviders: true,
|
|
16
17
|
includeViewProviders: true,
|
|
18
|
+
config: undefined,
|
|
19
|
+
configFilePath: undefined,
|
|
17
20
|
};
|
|
21
|
+
const ANGULAR_BRAND_CONFIG_FILE_NAME = 'craft-brand.config.ts';
|
|
22
|
+
const DEFAULT_ANGULAR_BRAND_METADATA_CONTEXTS = [
|
|
23
|
+
'imports',
|
|
24
|
+
'hostDirectives',
|
|
25
|
+
];
|
|
26
|
+
const DEFAULT_ANGULAR_BRAND_CONFIG = defineAngularBrandConfig({
|
|
27
|
+
importAugmentations: [
|
|
28
|
+
{
|
|
29
|
+
match: {
|
|
30
|
+
module: '@angular/router',
|
|
31
|
+
},
|
|
32
|
+
deps: [
|
|
33
|
+
{
|
|
34
|
+
key: 'Router',
|
|
35
|
+
symbol: 'Router',
|
|
36
|
+
module: '@angular/router',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
missingProvider: [
|
|
40
|
+
{
|
|
41
|
+
key: 'Router',
|
|
42
|
+
symbol: 'Router',
|
|
43
|
+
module: '@angular/router',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
match: {
|
|
49
|
+
module: '@angular/forms/signals',
|
|
50
|
+
symbols: ['FormField'],
|
|
51
|
+
metadata: ['imports'],
|
|
52
|
+
},
|
|
53
|
+
deps: [
|
|
54
|
+
{
|
|
55
|
+
key: 'FormField',
|
|
56
|
+
symbol: 'FormField',
|
|
57
|
+
typeText: 'FormField<any>',
|
|
58
|
+
module: '@angular/forms/signals',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
const angularBrandConfigCache = new Map();
|
|
18
65
|
const PRIMITIVE_TYPE_TEXTS = new Set([
|
|
19
66
|
'any',
|
|
20
67
|
'bigint',
|
|
@@ -56,6 +103,194 @@ const IGNORED_DIRECTORIES = new Set([
|
|
|
56
103
|
'out-tsc',
|
|
57
104
|
'tmp',
|
|
58
105
|
]);
|
|
106
|
+
export function defineAngularBrandConfig(config) {
|
|
107
|
+
return config;
|
|
108
|
+
}
|
|
109
|
+
export function discoverAngularBrandConfigFilePath(searchFromDir, stopDir) {
|
|
110
|
+
const resolvedStopDir = stopDir ? resolve(stopDir) : undefined;
|
|
111
|
+
let currentDir = resolve(searchFromDir);
|
|
112
|
+
while (true) {
|
|
113
|
+
const candidatePath = join(currentDir, ANGULAR_BRAND_CONFIG_FILE_NAME);
|
|
114
|
+
if (existsSync(candidatePath) && statSync(candidatePath).isFile()) {
|
|
115
|
+
return candidatePath;
|
|
116
|
+
}
|
|
117
|
+
if (resolvedStopDir && currentDir === resolvedStopDir) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const parentDir = dirname(currentDir);
|
|
121
|
+
if (parentDir === currentDir) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
currentDir = parentDir;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export function loadAngularBrandConfigFromFile(configFilePath) {
|
|
128
|
+
var _a;
|
|
129
|
+
const resolvedConfigFilePath = resolve(configFilePath);
|
|
130
|
+
const cachedConfig = angularBrandConfigCache.get(resolvedConfigFilePath);
|
|
131
|
+
if (cachedConfig) {
|
|
132
|
+
return cachedConfig;
|
|
133
|
+
}
|
|
134
|
+
if (!existsSync(resolvedConfigFilePath) ||
|
|
135
|
+
!statSync(resolvedConfigFilePath).isFile()) {
|
|
136
|
+
throw new Error(`Angular brand config file not found at "${resolvedConfigFilePath}".`);
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const sourceText = readFileSync(resolvedConfigFilePath, 'utf8');
|
|
140
|
+
const transpiled = ts.transpileModule(sourceText, {
|
|
141
|
+
compilerOptions: {
|
|
142
|
+
module: ts.ModuleKind.CommonJS,
|
|
143
|
+
target: ts.ScriptTarget.ES2022,
|
|
144
|
+
esModuleInterop: true,
|
|
145
|
+
allowSyntheticDefaultImports: true,
|
|
146
|
+
},
|
|
147
|
+
fileName: resolvedConfigFilePath,
|
|
148
|
+
});
|
|
149
|
+
const module = { exports: {} };
|
|
150
|
+
const moduleRequire = createRequire(resolvedConfigFilePath);
|
|
151
|
+
const compiledModule = new Function('exports', 'require', 'module', '__filename', '__dirname', transpiled.outputText);
|
|
152
|
+
compiledModule(module.exports, (specifier) => {
|
|
153
|
+
if (specifier === '@craft-ng/dev-tools') {
|
|
154
|
+
return { defineAngularBrandConfig };
|
|
155
|
+
}
|
|
156
|
+
return moduleRequire(specifier);
|
|
157
|
+
}, module, resolvedConfigFilePath, dirname(resolvedConfigFilePath));
|
|
158
|
+
const exportedConfig = (_a = module.exports['default']) !== null && _a !== void 0 ? _a : (module.exports['__esModule']
|
|
159
|
+
? module.exports['default']
|
|
160
|
+
: module.exports);
|
|
161
|
+
const validatedConfig = validateAngularBrandConfig(exportedConfig, resolvedConfigFilePath);
|
|
162
|
+
angularBrandConfigCache.set(resolvedConfigFilePath, validatedConfig);
|
|
163
|
+
return validatedConfig;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
throw new Error(`Invalid Angular brand config at "${resolvedConfigFilePath}": ${getErrorMessage(error)}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function resolveAngularBrandConfig(sourceFile, options) {
|
|
170
|
+
var _a;
|
|
171
|
+
const explicitConfig = (_a = options.config) !== null && _a !== void 0 ? _a : (options.configFilePath
|
|
172
|
+
? loadAngularBrandConfigFromFile(options.configFilePath)
|
|
173
|
+
: loadDiscoveredAngularBrandConfig(dirname(sourceFile.getFilePath())));
|
|
174
|
+
return normalizeAngularBrandConfig(explicitConfig);
|
|
175
|
+
}
|
|
176
|
+
function loadDiscoveredAngularBrandConfig(searchFromDir, stopDir) {
|
|
177
|
+
const discoveredConfigPath = discoverAngularBrandConfigFilePath(searchFromDir, stopDir);
|
|
178
|
+
return discoveredConfigPath
|
|
179
|
+
? loadAngularBrandConfigFromFile(discoveredConfigPath)
|
|
180
|
+
: undefined;
|
|
181
|
+
}
|
|
182
|
+
function normalizeAngularBrandConfig(config) {
|
|
183
|
+
var _a, _b;
|
|
184
|
+
const builtInRules = ((_a = DEFAULT_ANGULAR_BRAND_CONFIG.importAugmentations) !== null && _a !== void 0 ? _a : []).map(normalizeAngularBrandImportAugmentationRule);
|
|
185
|
+
const configuredRules = ((_b = config === null || config === void 0 ? void 0 : config.importAugmentations) !== null && _b !== void 0 ? _b : []).map(normalizeAngularBrandImportAugmentationRule);
|
|
186
|
+
return {
|
|
187
|
+
importAugmentations: [...builtInRules, ...configuredRules],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function normalizeAngularBrandImportAugmentationRule(rule) {
|
|
191
|
+
return {
|
|
192
|
+
match: {
|
|
193
|
+
module: rule.match.module,
|
|
194
|
+
symbols: rule.match.symbols ? [...rule.match.symbols] : undefined,
|
|
195
|
+
metadata: rule.match.metadata
|
|
196
|
+
? [...rule.match.metadata]
|
|
197
|
+
: [...DEFAULT_ANGULAR_BRAND_METADATA_CONTEXTS],
|
|
198
|
+
},
|
|
199
|
+
deps: rule.deps ? [...rule.deps] : [],
|
|
200
|
+
missingProvider: rule.missingProvider ? [...rule.missingProvider] : [],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function validateAngularBrandConfig(value, configFilePath) {
|
|
204
|
+
var _a;
|
|
205
|
+
if (!isPlainObject(value)) {
|
|
206
|
+
throw new Error('Expected the default export to be an object.');
|
|
207
|
+
}
|
|
208
|
+
const importAugmentations = (_a = readOptionalArray(value['importAugmentations'], 'importAugmentations', configFilePath)) === null || _a === void 0 ? void 0 : _a.map((entry, index) => validateAngularBrandImportAugmentationRule(entry, `importAugmentations[${index}]`, configFilePath));
|
|
209
|
+
return {
|
|
210
|
+
importAugmentations: importAugmentations !== null && importAugmentations !== void 0 ? importAugmentations : [],
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function validateAngularBrandImportAugmentationRule(value, pathLabel, configFilePath) {
|
|
214
|
+
var _a, _b, _c, _d, _e, _f;
|
|
215
|
+
if (!isPlainObject(value)) {
|
|
216
|
+
throw new Error(`${pathLabel} must be an object.`);
|
|
217
|
+
}
|
|
218
|
+
if (!isPlainObject(value['match'])) {
|
|
219
|
+
throw new Error(`${pathLabel}.match must be an object.`);
|
|
220
|
+
}
|
|
221
|
+
const match = value['match'];
|
|
222
|
+
const moduleSpecifier = readRequiredString(match['module'], `${pathLabel}.match.module`, configFilePath);
|
|
223
|
+
const symbols = readOptionalStringArray(match['symbols'], `${pathLabel}.match.symbols`, configFilePath);
|
|
224
|
+
const metadata = (_b = (_a = readOptionalStringArray(match['metadata'], `${pathLabel}.match.metadata`, configFilePath)) === null || _a === void 0 ? void 0 : _a.map((context) => validateAngularBrandMetadataContext(context, pathLabel))) !== null && _b !== void 0 ? _b : undefined;
|
|
225
|
+
return {
|
|
226
|
+
match: {
|
|
227
|
+
module: moduleSpecifier,
|
|
228
|
+
symbols,
|
|
229
|
+
metadata,
|
|
230
|
+
},
|
|
231
|
+
deps: (_d = (_c = readOptionalArray(value['deps'], `${pathLabel}.deps`, configFilePath)) === null || _c === void 0 ? void 0 : _c.map((entry, index) => validateAngularBrandConfigEntry(entry, `${pathLabel}.deps[${index}]`, configFilePath))) !== null && _d !== void 0 ? _d : [],
|
|
232
|
+
missingProvider: (_f = (_e = readOptionalArray(value['missingProvider'], `${pathLabel}.missingProvider`, configFilePath)) === null || _e === void 0 ? void 0 : _e.map((entry, index) => validateAngularBrandConfigEntry(entry, `${pathLabel}.missingProvider[${index}]`, configFilePath))) !== null && _f !== void 0 ? _f : [],
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function validateAngularBrandConfigEntry(value, pathLabel, configFilePath) {
|
|
236
|
+
if (!isPlainObject(value)) {
|
|
237
|
+
throw new Error(`${pathLabel} must be an object.`);
|
|
238
|
+
}
|
|
239
|
+
const key = readRequiredString(value['key'], `${pathLabel}.key`, configFilePath);
|
|
240
|
+
const symbol = readRequiredString(value['symbol'], `${pathLabel}.symbol`, configFilePath);
|
|
241
|
+
const typeText = readOptionalString(value['typeText'], `${pathLabel}.typeText`, configFilePath);
|
|
242
|
+
const moduleSpecifier = readOptionalString(value['module'], `${pathLabel}.module`, configFilePath);
|
|
243
|
+
return {
|
|
244
|
+
key,
|
|
245
|
+
symbol,
|
|
246
|
+
typeText,
|
|
247
|
+
module: moduleSpecifier,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function validateAngularBrandMetadataContext(value, pathLabel) {
|
|
251
|
+
if (value === 'imports' || value === 'hostDirectives') {
|
|
252
|
+
return value;
|
|
253
|
+
}
|
|
254
|
+
throw new Error(`${pathLabel}.match.metadata must contain only "imports" or "hostDirectives".`);
|
|
255
|
+
}
|
|
256
|
+
function readOptionalArray(value, pathLabel, configFilePath) {
|
|
257
|
+
if (value === undefined) {
|
|
258
|
+
return undefined;
|
|
259
|
+
}
|
|
260
|
+
if (!Array.isArray(value)) {
|
|
261
|
+
throw new Error(`${pathLabel} in "${configFilePath}" must be an array.`);
|
|
262
|
+
}
|
|
263
|
+
return value;
|
|
264
|
+
}
|
|
265
|
+
function readRequiredString(value, pathLabel, configFilePath) {
|
|
266
|
+
const stringValue = readOptionalString(value, pathLabel, configFilePath);
|
|
267
|
+
if (!stringValue) {
|
|
268
|
+
throw new Error(`${pathLabel} in "${configFilePath}" must be a string.`);
|
|
269
|
+
}
|
|
270
|
+
return stringValue;
|
|
271
|
+
}
|
|
272
|
+
function readOptionalString(value, pathLabel, configFilePath) {
|
|
273
|
+
if (value === undefined) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
if (typeof value !== 'string') {
|
|
277
|
+
throw new Error(`${pathLabel} in "${configFilePath}" must be a string.`);
|
|
278
|
+
}
|
|
279
|
+
return value;
|
|
280
|
+
}
|
|
281
|
+
function readOptionalStringArray(value, pathLabel, configFilePath) {
|
|
282
|
+
const arrayValue = readOptionalArray(value, pathLabel, configFilePath);
|
|
283
|
+
if (!arrayValue) {
|
|
284
|
+
return undefined;
|
|
285
|
+
}
|
|
286
|
+
return arrayValue.map((entry, index) => readRequiredString(entry, `${pathLabel}[${index}]`, configFilePath));
|
|
287
|
+
}
|
|
288
|
+
function isPlainObject(value) {
|
|
289
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
290
|
+
}
|
|
291
|
+
function getErrorMessage(error) {
|
|
292
|
+
return error instanceof Error ? error.message : String(error);
|
|
293
|
+
}
|
|
59
294
|
export function transformSourceFile(sourceFile, options = {}) {
|
|
60
295
|
const normalizedOptions = normalizeOptions(options);
|
|
61
296
|
const analysis = analyzeSourceFileDependencies(sourceFile, options);
|
|
@@ -79,6 +314,7 @@ export function transformSourceFile(sourceFile, options = {}) {
|
|
|
79
314
|
}
|
|
80
315
|
export function analyzeSourceFileDependencies(sourceFile, options = {}) {
|
|
81
316
|
const normalizedOptions = normalizeOptions(options);
|
|
317
|
+
const angularBrandConfig = resolveAngularBrandConfig(sourceFile, normalizedOptions);
|
|
82
318
|
const result = {
|
|
83
319
|
skipped: false,
|
|
84
320
|
warnings: [],
|
|
@@ -118,22 +354,18 @@ export function analyzeSourceFileDependencies(sourceFile, options = {}) {
|
|
|
118
354
|
? extractProvidedDependencies(sourceFile, classDeclaration, angularKind, normalizedOptions)
|
|
119
355
|
: { entries: [], warnings: [] };
|
|
120
356
|
const constructorDeps = extractConstructorDeps(classDeclaration);
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
357
|
+
const propertyDeps = extractPropertyDependencies(sourceFile, classDeclaration, className);
|
|
358
|
+
const generatedDependencyAugmentation = createGeneratedDependencyGroupAugmentation(sourceFile, metadataDeps.occurrences, angularBrandConfig);
|
|
359
|
+
const syntheticDependencyTexts = mergeDeps(generatedDependencyAugmentation.deps.map((dependency) => dependency.dependencyText), generatedDependencyAugmentation.legacyInjectedDependencies.map((dependency) => dependency.dependencyText));
|
|
360
|
+
result.warnings.push(...metadataDeps.warnings, ...providedDeps.warnings, ...constructorDeps.warnings, ...propertyDeps.warnings);
|
|
361
|
+
result.dependencies = mergeDeps(constructorDeps.dependencies, propertyDeps.dependencies, metadataDeps.imports, metadataDeps.hostDirectives, metadataDeps.providers, metadataDeps.viewProviders, syntheticDependencyTexts);
|
|
124
362
|
result.dependencyGroups = {
|
|
125
|
-
injected: mergeDeps(constructorDeps.dependencies,
|
|
363
|
+
injected: mergeDeps(constructorDeps.dependencies, propertyDeps.dependencies, generatedDependencyAugmentation.legacyInjectedDependencies.map((dependency) => dependency.dependencyText)),
|
|
126
364
|
importDeps: mergeDeps(metadataDeps.imports, metadataDeps.hostDirectives),
|
|
127
365
|
providers: mergeDeps(metadataDeps.providers, metadataDeps.viewProviders),
|
|
128
366
|
};
|
|
129
367
|
result.generatedTypeName = getGeneratedDepsTypeName(className);
|
|
130
|
-
result.generatedDependencyGroups = createGeneratedDependencyGroups(sourceFile, result.dependencyGroups.importDeps,
|
|
131
|
-
...constructorDeps.dependencies.map((dependencyText) => ({
|
|
132
|
-
dependencyText,
|
|
133
|
-
entry: createGeneratedDependencyEntry(sourceFile, dependencyText, 'inject'),
|
|
134
|
-
})),
|
|
135
|
-
...injectCallDeps.generatedDependencies,
|
|
136
|
-
], providedDeps.entries);
|
|
368
|
+
result.generatedDependencyGroups = createGeneratedDependencyGroups(sourceFile, className, result.dependencyGroups.importDeps, constructorDeps.dependencies, propertyDeps, providedDeps.entries, generatedDependencyAugmentation);
|
|
137
369
|
return result;
|
|
138
370
|
}
|
|
139
371
|
export function findAngularDecoratedClass(sourceFile) {
|
|
@@ -268,6 +500,53 @@ export function extractInjectCallDeps(classDeclaration) {
|
|
|
268
500
|
generatedDependencies,
|
|
269
501
|
};
|
|
270
502
|
}
|
|
503
|
+
function extractPropertyDependencies(sourceFile, classDeclaration, className) {
|
|
504
|
+
const warnings = [];
|
|
505
|
+
const dependencies = [];
|
|
506
|
+
const entries = [];
|
|
507
|
+
const missingProvider = [];
|
|
508
|
+
for (const property of classDeclaration.getProperties()) {
|
|
509
|
+
if (property.isStatic()) {
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
const propertyName = getStaticPropertyName(property.getNameNode());
|
|
513
|
+
if (!propertyName) {
|
|
514
|
+
warnings.push(`Skipped property dependency tracking for ${property.getText()} because the property name is not static.`);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const initializer = property.getInitializer();
|
|
518
|
+
if (Node.isCallExpression(initializer)) {
|
|
519
|
+
const expression = initializer.getExpression();
|
|
520
|
+
const injectMethodName = getInjectMethodName(expression);
|
|
521
|
+
if (injectMethodName === null || injectMethodName === void 0 ? void 0 : injectMethodName.startsWith('inject')) {
|
|
522
|
+
const dependencyText = injectMethodName === 'inject'
|
|
523
|
+
? getAngularInjectCallDependency(initializer)
|
|
524
|
+
: getInjectionHelperDependency(expression);
|
|
525
|
+
if (!dependencyText) {
|
|
526
|
+
warnings.push(`Skipped ${injectMethodName}() property dependency tracking for "${propertyName}" because the dependency is not static.`);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
dependencies.push(dependencyText);
|
|
530
|
+
const dependencyEntry = injectMethodName === 'inject'
|
|
531
|
+
? createGeneratedDependencyEntry(sourceFile, dependencyText, 'inject')
|
|
532
|
+
: createGeneratedInjectHelperDependencyEntry(sourceFile, initializer, expression, dependencyText);
|
|
533
|
+
entries.push(createGeneratedPropertyDependencyEntry(propertyName, createSingleDependencyMapTypeText(dependencyEntry)));
|
|
534
|
+
if (shouldGenerateLocalMissingProvider(sourceFile, dependencyText)) {
|
|
535
|
+
missingProvider.push(createGeneratedDependencyEntry(sourceFile, dependencyText, 'inject'));
|
|
536
|
+
}
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
entries.push(createGeneratedPropertyDependencyEntry(propertyName, createExtractDepsTypeText(className, propertyName)));
|
|
542
|
+
}
|
|
543
|
+
return {
|
|
544
|
+
dependencies: mergeDeps(dependencies),
|
|
545
|
+
warnings,
|
|
546
|
+
entries,
|
|
547
|
+
missingProvider: mergeGeneratedDependencyEntries(missingProvider),
|
|
548
|
+
};
|
|
549
|
+
}
|
|
271
550
|
export function mergeDeps(...dependencyGroups) {
|
|
272
551
|
const seen = new Set();
|
|
273
552
|
const dependencies = [];
|
|
@@ -292,44 +571,83 @@ function emptyDependencyGroups() {
|
|
|
292
571
|
function emptyGeneratedDependencyGroups() {
|
|
293
572
|
return {
|
|
294
573
|
deps: [],
|
|
574
|
+
propertiesDeps: [],
|
|
295
575
|
provided: [],
|
|
296
576
|
missingProvider: [],
|
|
297
577
|
};
|
|
298
578
|
}
|
|
579
|
+
function emptyGeneratedDependencyGroupAugmentation() {
|
|
580
|
+
return {
|
|
581
|
+
deps: [],
|
|
582
|
+
missingProvider: [],
|
|
583
|
+
legacyInjectedDependencies: [],
|
|
584
|
+
};
|
|
585
|
+
}
|
|
299
586
|
function getGeneratedDepsTypeName(className) {
|
|
300
587
|
return `GenDeps_${className}`;
|
|
301
588
|
}
|
|
302
|
-
function createGeneratedDependencyGroups(sourceFile, importDependencies,
|
|
303
|
-
const
|
|
589
|
+
function createGeneratedDependencyGroups(sourceFile, className, importDependencies, constructorDependencies, propertyDependencies, providedEntries, augmentation) {
|
|
590
|
+
const constructorEntries = constructorDependencies.map((dependency) => createGeneratedDependencyEntry(sourceFile, dependency, 'inject'));
|
|
591
|
+
const deps = mergeGeneratedDependencyEntries(importDependencies.map((dependency) => createGeneratedDependencyEntry(sourceFile, dependency, 'import')), constructorEntries, augmentation.deps.map((dependency) => dependency.entry));
|
|
592
|
+
const propertiesDeps = mergeGeneratedDependencyEntries(propertyDependencies.entries);
|
|
304
593
|
const provided = mergeGeneratedDependencyEntries(providedEntries);
|
|
305
594
|
const providedKeys = new Set(provided.map((entry) => entry.key));
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
.filter((dependency) => {
|
|
312
|
-
const dependencyKey = dependency.entry.key;
|
|
313
|
-
return (!providedKeys.has(dependencyKey) &&
|
|
314
|
-
shouldGenerateLocalMissingProvider(sourceFile, dependency.dependencyText));
|
|
315
|
-
})
|
|
316
|
-
.map((dependency) => {
|
|
317
|
-
var _a;
|
|
318
|
-
return (_a = injectedEntriesByKey.get(dependency.entry.key)) !== null && _a !== void 0 ? _a : createGeneratedDependencyEntry(sourceFile, dependency.dependencyText, 'inject');
|
|
319
|
-
}));
|
|
595
|
+
const missingProvider = mergeGeneratedDependencyEntries(constructorDependencies
|
|
596
|
+
.filter((dependencyText) => shouldGenerateLocalMissingProvider(sourceFile, dependencyText))
|
|
597
|
+
.map((dependencyText) => createGeneratedDependencyEntry(sourceFile, dependencyText, 'inject')), propertyDependencies.missingProvider, augmentation.missingProvider
|
|
598
|
+
.map((dependency) => dependency.entry)
|
|
599
|
+
.filter((entry) => !providedKeys.has(entry.key)));
|
|
320
600
|
return {
|
|
321
601
|
deps,
|
|
602
|
+
propertiesDeps,
|
|
322
603
|
provided,
|
|
323
604
|
missingProvider,
|
|
324
605
|
};
|
|
325
606
|
}
|
|
607
|
+
function createGeneratedDependencyGroupAugmentation(sourceFile, metadataOccurrences, config) {
|
|
608
|
+
if (metadataOccurrences.length === 0) {
|
|
609
|
+
return emptyGeneratedDependencyGroupAugmentation();
|
|
610
|
+
}
|
|
611
|
+
const deps = [];
|
|
612
|
+
const missingProvider = [];
|
|
613
|
+
const legacyInjectedDependencies = [];
|
|
614
|
+
for (const rule of config.importAugmentations) {
|
|
615
|
+
if (!metadataOccurrences.some((occurrence) => ruleMatchesMetadataOccurrence(rule, occurrence))) {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
const generatedDeps = rule.deps.map((entry) => createConfiguredGeneratedDependencyDescriptor(sourceFile, entry, rule.match.module));
|
|
619
|
+
const generatedMissingProviders = rule.missingProvider.map((entry) => createConfiguredGeneratedDependencyDescriptor(sourceFile, entry, rule.match.module));
|
|
620
|
+
deps.push(...generatedDeps);
|
|
621
|
+
missingProvider.push(...generatedMissingProviders);
|
|
622
|
+
legacyInjectedDependencies.push(...generatedMissingProviders);
|
|
623
|
+
}
|
|
624
|
+
return {
|
|
625
|
+
deps,
|
|
626
|
+
missingProvider,
|
|
627
|
+
legacyInjectedDependencies,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
function ruleMatchesMetadataOccurrence(rule, occurrence) {
|
|
631
|
+
if (occurrence.moduleSpecifier !== rule.match.module) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
if (!rule.match.metadata.includes(occurrence.metadataContext)) {
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
return (!rule.match.symbols || rule.match.symbols.includes(occurrence.symbolName));
|
|
638
|
+
}
|
|
639
|
+
function createConfiguredGeneratedDependencyDescriptor(sourceFile, entry, defaultModuleSpecifier) {
|
|
640
|
+
var _a;
|
|
641
|
+
return {
|
|
642
|
+
dependencyText: entry.symbol,
|
|
643
|
+
entry: createSyntheticGeneratedDependencyEntry(sourceFile, entry.symbol, 'inject', (_a = entry.module) !== null && _a !== void 0 ? _a : defaultModuleSpecifier, entry.key, entry.typeText),
|
|
644
|
+
};
|
|
645
|
+
}
|
|
326
646
|
function mergeGeneratedDependencyEntries(...groups) {
|
|
327
647
|
const entries = new Map();
|
|
328
648
|
for (const group of groups) {
|
|
329
649
|
for (const entry of group) {
|
|
330
|
-
|
|
331
|
-
entries.set(entry.key, entry);
|
|
332
|
-
}
|
|
650
|
+
entries.set(entry.key, entry);
|
|
333
651
|
}
|
|
334
652
|
}
|
|
335
653
|
return [...entries.values()];
|
|
@@ -356,6 +674,12 @@ function createGeneratedDependencyEntry(sourceFile, dependencyText, context) {
|
|
|
356
674
|
typeText: createGeneratedDependencyTypeText(sourceFile, dependencyText),
|
|
357
675
|
};
|
|
358
676
|
}
|
|
677
|
+
function createSyntheticGeneratedDependencyEntry(sourceFile, dependencyText, context, moduleSpecifier, key = createGeneratedDependencyKey(dependencyText), typeText) {
|
|
678
|
+
return Object.assign(Object.assign({}, createGeneratedDependencyEntry(sourceFile, dependencyText, context)), { key, typeText: typeText !== null && typeText !== void 0 ? typeText : createGeneratedDependencyTypeText(sourceFile, dependencyText), typeImport: {
|
|
679
|
+
moduleSpecifier,
|
|
680
|
+
name: dependencyText,
|
|
681
|
+
} });
|
|
682
|
+
}
|
|
359
683
|
function createGeneratedInjectHelperDependencyEntry(sourceFile, callExpression, expression, dependencyText) {
|
|
360
684
|
const trackedHelper = resolveTrackedInjectHelper(expression);
|
|
361
685
|
if (!trackedHelper) {
|
|
@@ -364,11 +688,11 @@ function createGeneratedInjectHelperDependencyEntry(sourceFile, callExpression,
|
|
|
364
688
|
const exposureTracking = extractHelperExposureTracking(callExpression);
|
|
365
689
|
return {
|
|
366
690
|
key: trackedHelper.serviceName,
|
|
367
|
-
typeText: createTrackedInjectHelperTypeText(dependencyText, exposureTracking),
|
|
691
|
+
typeText: createTrackedInjectHelperTypeText(dependencyText, trackedHelper.serviceName, exposureTracking),
|
|
368
692
|
};
|
|
369
693
|
}
|
|
370
|
-
function createTrackedInjectHelperTypeText(dependencyText, exposureTracking) {
|
|
371
|
-
const baseType = `
|
|
694
|
+
function createTrackedInjectHelperTypeText(dependencyText, serviceName, exposureTracking) {
|
|
695
|
+
const baseType = `ExtractDeps<typeof ${dependencyText}>[${JSON.stringify(serviceName)}]`;
|
|
372
696
|
if (!exposureTracking) {
|
|
373
697
|
return baseType;
|
|
374
698
|
}
|
|
@@ -385,6 +709,18 @@ function createTrackedInjectHelperTypeText(dependencyText, exposureTracking) {
|
|
|
385
709
|
'}>',
|
|
386
710
|
].join('\n');
|
|
387
711
|
}
|
|
712
|
+
function createGeneratedPropertyDependencyEntry(propertyName, typeText) {
|
|
713
|
+
return {
|
|
714
|
+
key: propertyName,
|
|
715
|
+
typeText,
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
function createExtractDepsTypeText(className, propertyName) {
|
|
719
|
+
return `ExtractDeps<${className}[${JSON.stringify(propertyName)}]>`;
|
|
720
|
+
}
|
|
721
|
+
function createSingleDependencyMapTypeText(entry) {
|
|
722
|
+
return formatGeneratedDependencyObject([entry]);
|
|
723
|
+
}
|
|
388
724
|
function formatHelperExposurePropertiesType(dependencyText, properties) {
|
|
389
725
|
if (properties.length === 0) {
|
|
390
726
|
return '{}';
|
|
@@ -629,7 +965,10 @@ function resolveAngularDeclarableDependency(sourceFile, dependencyText) {
|
|
|
629
965
|
function ensureGeneratedDependencyTypeImports(sourceFile, generatedDependencyGroups) {
|
|
630
966
|
var _a;
|
|
631
967
|
const importsToAdd = new Map();
|
|
632
|
-
for (const entry of
|
|
968
|
+
for (const entry of [
|
|
969
|
+
...generatedDependencyGroups.deps,
|
|
970
|
+
...generatedDependencyGroups.missingProvider,
|
|
971
|
+
]) {
|
|
633
972
|
if (!entry.typeImport) {
|
|
634
973
|
continue;
|
|
635
974
|
}
|
|
@@ -640,9 +979,18 @@ function ensureGeneratedDependencyTypeImports(sourceFile, generatedDependencyGro
|
|
|
640
979
|
for (const [moduleSpecifier, importNames] of importsToAdd) {
|
|
641
980
|
const existingImport = sourceFile
|
|
642
981
|
.getImportDeclarations()
|
|
643
|
-
.find((importDeclaration) => importDeclaration.getModuleSpecifierValue() === moduleSpecifier
|
|
982
|
+
.find((importDeclaration) => importDeclaration.getModuleSpecifierValue() === moduleSpecifier &&
|
|
983
|
+
!importDeclaration.getNamespaceImport());
|
|
644
984
|
if (existingImport) {
|
|
645
|
-
existingImport.
|
|
985
|
+
const existingImportNames = new Set(existingImport.getNamedImports().map((namedImport) => {
|
|
986
|
+
var _a, _b;
|
|
987
|
+
return ((_b = (_a = namedImport.getAliasNode()) === null || _a === void 0 ? void 0 : _a.getText()) !== null && _b !== void 0 ? _b : namedImport.getNameNode().getText());
|
|
988
|
+
}));
|
|
989
|
+
const namesToAdd = [...importNames].filter((name) => !existingImportNames.has(name));
|
|
990
|
+
if (namesToAdd.length === 0) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
existingImport.addNamedImports(namesToAdd.map((name) => ({ name, isTypeOnly: true })));
|
|
646
994
|
continue;
|
|
647
995
|
}
|
|
648
996
|
sourceFile.addImportDeclaration({
|
|
@@ -658,6 +1006,11 @@ function formatGeneratedDependencyType(angularKind, className, generatedDependen
|
|
|
658
1006
|
return [
|
|
659
1007
|
'{',
|
|
660
1008
|
` deps: ${formatGeneratedDependencyObject(generatedDependencyGroups.deps)};`,
|
|
1009
|
+
...(angularKind === 'component'
|
|
1010
|
+
? [
|
|
1011
|
+
` propertiesDeps: ${formatGeneratedDependencyObject(generatedDependencyGroups.propertiesDeps)};`,
|
|
1012
|
+
]
|
|
1013
|
+
: []),
|
|
661
1014
|
` provided: ${formatGeneratedDependencyObject(generatedDependencyGroups.provided)};`,
|
|
662
1015
|
...(angularKind === 'component'
|
|
663
1016
|
? [` publicProperties: GetPublicComponentProperties<${className}>;`]
|
|
@@ -781,8 +1134,8 @@ function getInjectionHelperDependency(expression) {
|
|
|
781
1134
|
export function ensureHelperImports(sourceFile, helperImportPath) {
|
|
782
1135
|
const missingImports = [
|
|
783
1136
|
'DerivedService',
|
|
1137
|
+
'ExtractDeps',
|
|
784
1138
|
'GetDeps',
|
|
785
|
-
'GetInjectedServiceDependencies',
|
|
786
1139
|
'GetPublicComponentProperties',
|
|
787
1140
|
'GetServiceOutput',
|
|
788
1141
|
].filter((importName) => !hasLocalNamedImport(sourceFile, helperImportPath, importName));
|
|
@@ -884,8 +1237,11 @@ export function formatDependencyGroups(dependencyGroups) {
|
|
|
884
1237
|
}
|
|
885
1238
|
export function runAngularBrandCodemod() {
|
|
886
1239
|
return __awaiter(this, arguments, void 0, function* (options = {}) {
|
|
887
|
-
var _a, _b, _c;
|
|
1240
|
+
var _a, _b, _c, _d;
|
|
888
1241
|
const rootDir = resolve((_a = options.rootDir) !== null && _a !== void 0 ? _a : process.cwd());
|
|
1242
|
+
const config = (_b = options.config) !== null && _b !== void 0 ? _b : (options.configFilePath
|
|
1243
|
+
? loadAngularBrandConfigFromFile(options.configFilePath)
|
|
1244
|
+
: loadDiscoveredAngularBrandConfig(rootDir));
|
|
889
1245
|
const tsConfigFilePath = options.tsConfigFilePath
|
|
890
1246
|
? resolve(options.tsConfigFilePath)
|
|
891
1247
|
: getDefaultTsConfigPath(rootDir);
|
|
@@ -909,7 +1265,7 @@ export function runAngularBrandCodemod() {
|
|
|
909
1265
|
if (!isWithinRoot(sourceFile.getFilePath(), rootDir)) {
|
|
910
1266
|
continue;
|
|
911
1267
|
}
|
|
912
|
-
const result = transformSourceFile(sourceFile, options);
|
|
1268
|
+
const result = transformSourceFile(sourceFile, Object.assign(Object.assign({}, options), { config }));
|
|
913
1269
|
const report = Object.assign(Object.assign({}, result), { filePath: sourceFile.getFilePath() });
|
|
914
1270
|
summary.files.push(report);
|
|
915
1271
|
summary.warnings += result.warnings.length;
|
|
@@ -926,9 +1282,9 @@ export function runAngularBrandCodemod() {
|
|
|
926
1282
|
if (result.skipped) {
|
|
927
1283
|
summary.skippedFiles += 1;
|
|
928
1284
|
}
|
|
929
|
-
logFileResult(report, (
|
|
1285
|
+
logFileResult(report, (_c = options.log) !== null && _c !== void 0 ? _c : console.log);
|
|
930
1286
|
}
|
|
931
|
-
logSummary(summary, (
|
|
1287
|
+
logSummary(summary, (_d = options.log) !== null && _d !== void 0 ? _d : console.log);
|
|
932
1288
|
return summary;
|
|
933
1289
|
});
|
|
934
1290
|
}
|
|
@@ -939,6 +1295,8 @@ function normalizeOptions(options) {
|
|
|
939
1295
|
transformOnlyStandaloneDeclarables: (_b = options.transformOnlyStandaloneDeclarables) !== null && _b !== void 0 ? _b : DEFAULT_OPTIONS.transformOnlyStandaloneDeclarables,
|
|
940
1296
|
includeProviders: (_c = options.includeProviders) !== null && _c !== void 0 ? _c : DEFAULT_OPTIONS.includeProviders,
|
|
941
1297
|
includeViewProviders: (_d = options.includeViewProviders) !== null && _d !== void 0 ? _d : DEFAULT_OPTIONS.includeViewProviders,
|
|
1298
|
+
config: options.config,
|
|
1299
|
+
configFilePath: options.configFilePath,
|
|
942
1300
|
};
|
|
943
1301
|
}
|
|
944
1302
|
function skip(result, warnings) {
|
|
@@ -1008,6 +1366,7 @@ function getObjectPropertyAssignment(objectLiteral, propertyName) {
|
|
|
1008
1366
|
return Node.isPropertyAssignment(property) ? property : undefined;
|
|
1009
1367
|
}
|
|
1010
1368
|
function extractDecoratorMetadataDepGroups(classDeclaration, angularKind, options) {
|
|
1369
|
+
const sourceFile = classDeclaration.getSourceFile();
|
|
1011
1370
|
const metadata = getDecoratorMetadataObject(classDeclaration);
|
|
1012
1371
|
const groups = emptyMetadataDependencyGroups();
|
|
1013
1372
|
if (!metadata) {
|
|
@@ -1021,6 +1380,10 @@ function extractDecoratorMetadataDepGroups(classDeclaration, angularKind, option
|
|
|
1021
1380
|
if (options.includeViewProviders && angularKind === 'component') {
|
|
1022
1381
|
groups.viewProviders = extractMetadataArrayProperty(metadata, 'viewProviders', 'viewProviders', groups.warnings);
|
|
1023
1382
|
}
|
|
1383
|
+
groups.occurrences = [
|
|
1384
|
+
...groups.imports.map((dependencyText) => createMetadataDependencyOccurrence(sourceFile, dependencyText, 'imports')),
|
|
1385
|
+
...groups.hostDirectives.map((dependencyText) => createMetadataDependencyOccurrence(sourceFile, dependencyText, 'hostDirectives')),
|
|
1386
|
+
];
|
|
1024
1387
|
return groups;
|
|
1025
1388
|
}
|
|
1026
1389
|
function emptyMetadataDependencyGroups() {
|
|
@@ -1029,9 +1392,20 @@ function emptyMetadataDependencyGroups() {
|
|
|
1029
1392
|
hostDirectives: [],
|
|
1030
1393
|
providers: [],
|
|
1031
1394
|
viewProviders: [],
|
|
1395
|
+
occurrences: [],
|
|
1032
1396
|
warnings: [],
|
|
1033
1397
|
};
|
|
1034
1398
|
}
|
|
1399
|
+
function createMetadataDependencyOccurrence(sourceFile, dependencyText, metadataContext) {
|
|
1400
|
+
var _a, _b;
|
|
1401
|
+
const resolution = resolveDependencyReference(sourceFile, dependencyText);
|
|
1402
|
+
return {
|
|
1403
|
+
dependencyText,
|
|
1404
|
+
symbolName: (_b = (_a = resolution.importedName) !== null && _a !== void 0 ? _a : dependencyText.split('.').pop()) !== null && _b !== void 0 ? _b : dependencyText,
|
|
1405
|
+
moduleSpecifier: resolution.moduleSpecifier,
|
|
1406
|
+
metadataContext,
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1035
1409
|
function extractProvidedDependencies(sourceFile, classDeclaration, angularKind, options) {
|
|
1036
1410
|
const metadata = getDecoratorMetadataObject(classDeclaration);
|
|
1037
1411
|
const warnings = [];
|
|
@@ -1276,10 +1650,11 @@ function resolveImportedDependencyReference(sourceFile, dependencyText, rootIden
|
|
|
1276
1650
|
return {
|
|
1277
1651
|
kind: 'class',
|
|
1278
1652
|
classDeclaration: declaration,
|
|
1653
|
+
importedName: rootIdentifier,
|
|
1279
1654
|
moduleSpecifier,
|
|
1280
1655
|
};
|
|
1281
1656
|
}
|
|
1282
|
-
return { kind: 'unknown', moduleSpecifier };
|
|
1657
|
+
return { kind: 'unknown', importedName: rootIdentifier, moduleSpecifier };
|
|
1283
1658
|
}
|
|
1284
1659
|
if (((_b = importDeclaration.getNamespaceImport()) === null || _b === void 0 ? void 0 : _b.getText()) === rootIdentifier) {
|
|
1285
1660
|
const declaration = getNamespaceImportClassDeclaration(importDeclaration, dependencyText);
|
|
@@ -1287,10 +1662,15 @@ function resolveImportedDependencyReference(sourceFile, dependencyText, rootIden
|
|
|
1287
1662
|
return {
|
|
1288
1663
|
kind: 'class',
|
|
1289
1664
|
classDeclaration: declaration,
|
|
1665
|
+
importedName: dependencyText.split('.').pop(),
|
|
1290
1666
|
moduleSpecifier,
|
|
1291
1667
|
};
|
|
1292
1668
|
}
|
|
1293
|
-
return {
|
|
1669
|
+
return {
|
|
1670
|
+
kind: 'namespace',
|
|
1671
|
+
importedName: dependencyText.split('.').pop(),
|
|
1672
|
+
moduleSpecifier,
|
|
1673
|
+
};
|
|
1294
1674
|
}
|
|
1295
1675
|
const namedImport = importDeclaration
|
|
1296
1676
|
.getNamedImports()
|
|
@@ -1311,19 +1691,36 @@ function resolveImportedDependencyReference(sourceFile, dependencyText, rootIden
|
|
|
1311
1691
|
return {
|
|
1312
1692
|
kind: 'class',
|
|
1313
1693
|
classDeclaration,
|
|
1694
|
+
importedName: namedImport.getNameNode().getText(),
|
|
1314
1695
|
moduleSpecifier,
|
|
1315
1696
|
};
|
|
1316
1697
|
}
|
|
1317
1698
|
if (declarations.some((declaration) => Node.isEnumDeclaration(declaration))) {
|
|
1318
|
-
return {
|
|
1699
|
+
return {
|
|
1700
|
+
kind: 'enum',
|
|
1701
|
+
importedName: namedImport.getNameNode().getText(),
|
|
1702
|
+
moduleSpecifier,
|
|
1703
|
+
};
|
|
1319
1704
|
}
|
|
1320
1705
|
if (declarations.some((declaration) => Node.isFunctionDeclaration(declaration))) {
|
|
1321
|
-
return {
|
|
1706
|
+
return {
|
|
1707
|
+
kind: 'function',
|
|
1708
|
+
importedName: namedImport.getNameNode().getText(),
|
|
1709
|
+
moduleSpecifier,
|
|
1710
|
+
};
|
|
1322
1711
|
}
|
|
1323
1712
|
if (declarations.some((declaration) => Node.isVariableDeclaration(declaration))) {
|
|
1324
|
-
return {
|
|
1713
|
+
return {
|
|
1714
|
+
kind: 'variable',
|
|
1715
|
+
importedName: namedImport.getNameNode().getText(),
|
|
1716
|
+
moduleSpecifier,
|
|
1717
|
+
};
|
|
1325
1718
|
}
|
|
1326
|
-
return {
|
|
1719
|
+
return {
|
|
1720
|
+
kind: 'unknown',
|
|
1721
|
+
importedName: namedImport.getNameNode().getText(),
|
|
1722
|
+
moduleSpecifier,
|
|
1723
|
+
};
|
|
1327
1724
|
}
|
|
1328
1725
|
return undefined;
|
|
1329
1726
|
}
|
|
@@ -1789,6 +2186,9 @@ function parseCliArgs(argv) {
|
|
|
1789
2186
|
case '--tsconfig':
|
|
1790
2187
|
options.tsConfigFilePath = argv[++index];
|
|
1791
2188
|
break;
|
|
2189
|
+
case '--config':
|
|
2190
|
+
options.configFilePath = argv[++index];
|
|
2191
|
+
break;
|
|
1792
2192
|
case '--helper-import':
|
|
1793
2193
|
options.helperImportPath = argv[++index];
|
|
1794
2194
|
break;
|
|
@@ -1819,6 +2219,7 @@ function printHelpAndExit() {
|
|
|
1819
2219
|
Options:
|
|
1820
2220
|
--root <dir> Project root. Defaults to cwd.
|
|
1821
2221
|
--tsconfig <path> tsconfig path. Defaults to <root>/tsconfig.json.
|
|
2222
|
+
--config <path> Explicit angular brand config file path.
|
|
1822
2223
|
--helper-import <path> Import path for GetDeps.
|
|
1823
2224
|
--transform-only-standalone-declarables Only transform standalone components/directives.
|
|
1824
2225
|
--no-providers Do not include metadata providers in generated types.
|