@craft-ng/dev-tools 0.1.4 → 0.1.6
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/package.json +1 -1
- package/src/eslint-rules/brand-angular-deps-match.cjs +33 -7
- package/src/eslint-rules/no-direct-angular-class-export.cjs +35 -6
- package/src/scripts/angular-brand-codemod.d.ts +25 -3
- package/src/scripts/angular-brand-codemod.js +744 -45
- package/src/scripts/angular-brand-codemod.js.map +1 -1
- package/src/scripts/angular-brand-codemod.spec.ts +303 -0
- package/src/scripts/angular-brand-codemod.ts +1260 -77
|
@@ -2,6 +2,7 @@ import { __awaiter } from "tslib";
|
|
|
2
2
|
import { Node, Project, QuoteKind, SyntaxKind, ts, } from 'ts-morph';
|
|
3
3
|
import { existsSync, readdirSync, statSync } from 'node:fs';
|
|
4
4
|
import { basename, extname, isAbsolute, join, resolve } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
5
6
|
const SUPPORTED_DECORATORS = {
|
|
6
7
|
Component: 'component',
|
|
7
8
|
Directive: 'directive',
|
|
@@ -63,18 +64,17 @@ export function transformSourceFile(sourceFile, options = {}) {
|
|
|
63
64
|
if (analysis.skipped || !classDeclaration || !angularKind || !className) {
|
|
64
65
|
return result;
|
|
65
66
|
}
|
|
66
|
-
const exportSafety = getExportRewriteSafety(sourceFile, classDeclaration, className);
|
|
67
|
-
if (!exportSafety.safe) {
|
|
68
|
-
return skip(result, exportSafety.warnings);
|
|
69
|
-
}
|
|
70
67
|
const importSafety = getHelperImportSafety(sourceFile, normalizedOptions.helperImportPath);
|
|
71
68
|
if (!importSafety.safe) {
|
|
72
69
|
return skip(result, importSafety.warnings);
|
|
73
70
|
}
|
|
74
|
-
|
|
71
|
+
const beforeText = sourceFile.getFullText();
|
|
72
|
+
migrateLegacyBrandExport(sourceFile, classDeclaration, className);
|
|
75
73
|
ensureHelperImports(sourceFile, normalizedOptions.helperImportPath);
|
|
76
|
-
|
|
77
|
-
result.
|
|
74
|
+
ensureGeneratedDependencyTypeImports(sourceFile, result.generatedDependencyGroups);
|
|
75
|
+
writeGeneratedDepsTypeAlias(sourceFile, className, result.generatedDependencyGroups);
|
|
76
|
+
sourceFile.organizeImports();
|
|
77
|
+
result.changed = sourceFile.getFullText() !== beforeText;
|
|
78
78
|
return result;
|
|
79
79
|
}
|
|
80
80
|
export function analyzeSourceFileDependencies(sourceFile, options = {}) {
|
|
@@ -84,6 +84,7 @@ export function analyzeSourceFileDependencies(sourceFile, options = {}) {
|
|
|
84
84
|
warnings: [],
|
|
85
85
|
dependencies: [],
|
|
86
86
|
dependencyGroups: emptyDependencyGroups(),
|
|
87
|
+
generatedDependencyGroups: emptyGeneratedDependencyGroups(),
|
|
87
88
|
};
|
|
88
89
|
const angularClass = findAngularDecoratedClass(sourceFile);
|
|
89
90
|
result.warnings.push(...angularClass.warnings);
|
|
@@ -113,15 +114,26 @@ export function analyzeSourceFileDependencies(sourceFile, options = {}) {
|
|
|
113
114
|
const metadataDeps = angularKind === 'component' || angularKind === 'directive'
|
|
114
115
|
? extractDecoratorMetadataDepGroups(classDeclaration, angularKind, normalizedOptions)
|
|
115
116
|
: emptyMetadataDependencyGroups();
|
|
117
|
+
const providedDeps = angularKind === 'component' || angularKind === 'directive'
|
|
118
|
+
? extractProvidedDependencies(sourceFile, classDeclaration, angularKind, normalizedOptions)
|
|
119
|
+
: { entries: [], warnings: [] };
|
|
116
120
|
const constructorDeps = extractConstructorDeps(classDeclaration);
|
|
117
121
|
const injectCallDeps = extractInjectCallDeps(classDeclaration);
|
|
118
|
-
result.warnings.push(...metadataDeps.warnings, ...constructorDeps.warnings, ...injectCallDeps.warnings);
|
|
122
|
+
result.warnings.push(...metadataDeps.warnings, ...providedDeps.warnings, ...constructorDeps.warnings, ...injectCallDeps.warnings);
|
|
119
123
|
result.dependencies = mergeDeps(constructorDeps.dependencies, injectCallDeps.dependencies, metadataDeps.imports, metadataDeps.hostDirectives, metadataDeps.providers, metadataDeps.viewProviders);
|
|
120
124
|
result.dependencyGroups = {
|
|
121
125
|
injected: mergeDeps(constructorDeps.dependencies, injectCallDeps.dependencies),
|
|
122
126
|
importDeps: mergeDeps(metadataDeps.imports, metadataDeps.hostDirectives),
|
|
123
127
|
providers: mergeDeps(metadataDeps.providers, metadataDeps.viewProviders),
|
|
124
128
|
};
|
|
129
|
+
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);
|
|
125
137
|
return result;
|
|
126
138
|
}
|
|
127
139
|
export function findAngularDecoratedClass(sourceFile) {
|
|
@@ -227,6 +239,8 @@ export function extractInjectCallDeps(classDeclaration) {
|
|
|
227
239
|
var _a;
|
|
228
240
|
const warnings = [];
|
|
229
241
|
const dependencies = [];
|
|
242
|
+
const generatedDependencies = [];
|
|
243
|
+
const sourceFile = classDeclaration.getSourceFile();
|
|
230
244
|
for (const callExpression of classDeclaration.getDescendantsOfKind(SyntaxKind.CallExpression)) {
|
|
231
245
|
const expression = callExpression.getExpression();
|
|
232
246
|
const injectMethodName = getInjectMethodName(expression);
|
|
@@ -241,8 +255,18 @@ export function extractInjectCallDeps(classDeclaration) {
|
|
|
241
255
|
continue;
|
|
242
256
|
}
|
|
243
257
|
dependencies.push(dependency);
|
|
258
|
+
generatedDependencies.push({
|
|
259
|
+
dependencyText: dependency,
|
|
260
|
+
entry: injectMethodName === 'inject'
|
|
261
|
+
? createGeneratedDependencyEntry(sourceFile, dependency, 'inject')
|
|
262
|
+
: createGeneratedInjectHelperDependencyEntry(sourceFile, callExpression, expression, dependency),
|
|
263
|
+
});
|
|
244
264
|
}
|
|
245
|
-
return {
|
|
265
|
+
return {
|
|
266
|
+
dependencies: mergeDeps(dependencies),
|
|
267
|
+
warnings,
|
|
268
|
+
generatedDependencies,
|
|
269
|
+
};
|
|
246
270
|
}
|
|
247
271
|
export function mergeDeps(...dependencyGroups) {
|
|
248
272
|
const seen = new Set();
|
|
@@ -265,8 +289,422 @@ function emptyDependencyGroups() {
|
|
|
265
289
|
providers: [],
|
|
266
290
|
};
|
|
267
291
|
}
|
|
268
|
-
function
|
|
269
|
-
return
|
|
292
|
+
function emptyGeneratedDependencyGroups() {
|
|
293
|
+
return {
|
|
294
|
+
deps: [],
|
|
295
|
+
provided: [],
|
|
296
|
+
missingProvider: [],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function getGeneratedDepsTypeName(className) {
|
|
300
|
+
return `GenDeps_${className}`;
|
|
301
|
+
}
|
|
302
|
+
function createGeneratedDependencyGroups(sourceFile, importDependencies, injectedDependencies, providedEntries) {
|
|
303
|
+
const deps = mergeGeneratedDependencyEntries(importDependencies.map((dependency) => createGeneratedDependencyEntry(sourceFile, dependency, 'import')), injectedDependencies.map((dependency) => dependency.entry));
|
|
304
|
+
const provided = mergeGeneratedDependencyEntries(providedEntries);
|
|
305
|
+
const providedKeys = new Set(provided.map((entry) => entry.key));
|
|
306
|
+
const injectedEntriesByKey = new Map(injectedDependencies.map((dependency) => [dependency.entry.key, dependency.entry]));
|
|
307
|
+
const missingProvider = mergeGeneratedDependencyEntries(injectedDependencies
|
|
308
|
+
.filter((dependency) => {
|
|
309
|
+
const dependencyKey = dependency.entry.key;
|
|
310
|
+
return (!providedKeys.has(dependencyKey) &&
|
|
311
|
+
!isDependencyProvidedElsewhere(sourceFile, dependency.dependencyText));
|
|
312
|
+
})
|
|
313
|
+
.map((dependency) => {
|
|
314
|
+
var _a;
|
|
315
|
+
return (_a = injectedEntriesByKey.get(dependency.entry.key)) !== null && _a !== void 0 ? _a : createGeneratedDependencyEntry(sourceFile, dependency.dependencyText, 'inject');
|
|
316
|
+
}));
|
|
317
|
+
return {
|
|
318
|
+
deps,
|
|
319
|
+
provided,
|
|
320
|
+
missingProvider,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function mergeGeneratedDependencyEntries(...groups) {
|
|
324
|
+
const entries = new Map();
|
|
325
|
+
for (const group of groups) {
|
|
326
|
+
for (const entry of group) {
|
|
327
|
+
if (!entries.has(entry.key)) {
|
|
328
|
+
entries.set(entry.key, entry);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return [...entries.values()];
|
|
333
|
+
}
|
|
334
|
+
function createGeneratedDependencyEntry(sourceFile, dependencyText, context) {
|
|
335
|
+
if (context === 'import') {
|
|
336
|
+
const declarableResolution = resolveAngularDeclarableDependency(sourceFile, dependencyText);
|
|
337
|
+
if (declarableResolution) {
|
|
338
|
+
const generatedTypeName = getGeneratedDepsTypeName(declarableResolution.className);
|
|
339
|
+
return {
|
|
340
|
+
key: generatedTypeName,
|
|
341
|
+
typeText: generatedTypeName,
|
|
342
|
+
typeImport: declarableResolution.moduleSpecifier
|
|
343
|
+
? {
|
|
344
|
+
moduleSpecifier: declarableResolution.moduleSpecifier,
|
|
345
|
+
name: generatedTypeName,
|
|
346
|
+
}
|
|
347
|
+
: undefined,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
key: createGeneratedDependencyKey(dependencyText),
|
|
353
|
+
typeText: createGeneratedDependencyTypeText(sourceFile, dependencyText),
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function createGeneratedInjectHelperDependencyEntry(sourceFile, callExpression, expression, dependencyText) {
|
|
357
|
+
const trackedHelper = resolveTrackedInjectHelper(expression);
|
|
358
|
+
if (!trackedHelper) {
|
|
359
|
+
return createGeneratedDependencyEntry(sourceFile, dependencyText, 'inject');
|
|
360
|
+
}
|
|
361
|
+
const exposureTracking = extractHelperExposureTracking(callExpression);
|
|
362
|
+
return {
|
|
363
|
+
key: trackedHelper.serviceName,
|
|
364
|
+
typeText: createTrackedInjectHelperTypeText(dependencyText, exposureTracking),
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function createTrackedInjectHelperTypeText(dependencyText, exposureTracking) {
|
|
368
|
+
const baseType = `GetInjectedServiceDependencies<typeof ${dependencyText}>`;
|
|
369
|
+
if (!exposureTracking) {
|
|
370
|
+
return [baseType + ' & {', ' usesWholeService: true;', '}'].join('\n');
|
|
371
|
+
}
|
|
372
|
+
return [
|
|
373
|
+
`${baseType} & {`,
|
|
374
|
+
` derivedPropertiesUsed: ${formatHelperExposurePropertiesType(dependencyText, exposureTracking.usedProperties.map((sourceKey) => ({
|
|
375
|
+
propertyKey: sourceKey,
|
|
376
|
+
sourceKey,
|
|
377
|
+
})))};`,
|
|
378
|
+
` derivedPropertiesExposed: ${formatHelperExposurePropertiesType(dependencyText, exposureTracking.exposedProperties.map(({ exposedKey, sourceKey }) => ({
|
|
379
|
+
propertyKey: exposedKey,
|
|
380
|
+
sourceKey,
|
|
381
|
+
})))};`,
|
|
382
|
+
'}',
|
|
383
|
+
].join('\n');
|
|
384
|
+
}
|
|
385
|
+
function formatHelperExposurePropertiesType(dependencyText, properties) {
|
|
386
|
+
if (properties.length === 0) {
|
|
387
|
+
return '{}';
|
|
388
|
+
}
|
|
389
|
+
return [
|
|
390
|
+
'{',
|
|
391
|
+
...properties.map(({ propertyKey, sourceKey }) => ` ${formatObjectKey(propertyKey)}: ${createTrackedHelperOutputTypeText(dependencyText, sourceKey)};`),
|
|
392
|
+
' }',
|
|
393
|
+
].join('\n');
|
|
394
|
+
}
|
|
395
|
+
function createTrackedHelperOutputTypeText(dependencyText, sourceKey) {
|
|
396
|
+
if (sourceKey === '$self') {
|
|
397
|
+
return `GetServiceOutput<typeof ${dependencyText}>`;
|
|
398
|
+
}
|
|
399
|
+
return `GetServiceOutput<typeof ${dependencyText}>[${JSON.stringify(sourceKey)}]`;
|
|
400
|
+
}
|
|
401
|
+
function resolveTrackedInjectHelper(expression) {
|
|
402
|
+
var _a, _b, _c, _d;
|
|
403
|
+
const symbol = (_a = expression.getSymbol()) !== null && _a !== void 0 ? _a : expression.getType().getSymbol();
|
|
404
|
+
const declarations = (_d = (_c = (_b = symbol === null || symbol === void 0 ? void 0 : symbol.getAliasedSymbol()) === null || _b === void 0 ? void 0 : _b.getDeclarations()) !== null && _c !== void 0 ? _c : symbol === null || symbol === void 0 ? void 0 : symbol.getDeclarations()) !== null && _d !== void 0 ? _d : [];
|
|
405
|
+
for (const declaration of declarations) {
|
|
406
|
+
const helper = resolveTrackedInjectHelperFromDeclaration(declaration);
|
|
407
|
+
if (helper) {
|
|
408
|
+
return helper;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return undefined;
|
|
412
|
+
}
|
|
413
|
+
function resolveTrackedInjectHelperFromDeclaration(declaration) {
|
|
414
|
+
var _a, _b;
|
|
415
|
+
if (!Node.isBindingElement(declaration)) {
|
|
416
|
+
return undefined;
|
|
417
|
+
}
|
|
418
|
+
const objectBindingPattern = declaration.getFirstAncestorByKind(SyntaxKind.ObjectBindingPattern);
|
|
419
|
+
const variableDeclaration = objectBindingPattern === null || objectBindingPattern === void 0 ? void 0 : objectBindingPattern.getFirstAncestorByKind(SyntaxKind.VariableDeclaration);
|
|
420
|
+
const initializer = variableDeclaration === null || variableDeclaration === void 0 ? void 0 : variableDeclaration.getInitializer();
|
|
421
|
+
if (!Node.isCallExpression(initializer) || !isServiceFactoryCall(initializer)) {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
const [optionsArgument] = initializer.getArguments();
|
|
425
|
+
if (!Node.isObjectLiteralExpression(optionsArgument)) {
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
const nameInitializer = (_a = getObjectPropertyAssignment(optionsArgument, 'name')) === null || _a === void 0 ? void 0 : _a.getInitializer();
|
|
429
|
+
const scopeInitializer = (_b = getObjectPropertyAssignment(optionsArgument, 'scope')) === null || _b === void 0 ? void 0 : _b.getInitializer();
|
|
430
|
+
if (!Node.isStringLiteral(nameInitializer) ||
|
|
431
|
+
!Node.isStringLiteral(scopeInitializer)) {
|
|
432
|
+
return undefined;
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
serviceName: nameInitializer.getLiteralText(),
|
|
436
|
+
scope: scopeInitializer.getLiteralText(),
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function isServiceFactoryCall(callExpression) {
|
|
440
|
+
const expression = callExpression.getExpression();
|
|
441
|
+
if (Node.isIdentifier(expression)) {
|
|
442
|
+
return expression.getText() === 'craftService' || expression.getText() === 'toCraftService';
|
|
443
|
+
}
|
|
444
|
+
if (Node.isPropertyAccessExpression(expression)) {
|
|
445
|
+
const methodName = expression.getName();
|
|
446
|
+
return methodName === 'craftService' || methodName === 'toCraftService';
|
|
447
|
+
}
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
function extractHelperExposureTracking(callExpression) {
|
|
451
|
+
const exposeArgument = [...callExpression.getArguments()]
|
|
452
|
+
.reverse()
|
|
453
|
+
.find((argument) => Node.isArrowFunction(argument) || Node.isFunctionExpression(argument));
|
|
454
|
+
if (!exposeArgument ||
|
|
455
|
+
(!Node.isArrowFunction(exposeArgument) &&
|
|
456
|
+
!Node.isFunctionExpression(exposeArgument))) {
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
459
|
+
const parameter = exposeArgument.getParameters()[0];
|
|
460
|
+
const nameNode = parameter === null || parameter === void 0 ? void 0 : parameter.getNameNode();
|
|
461
|
+
if (!nameNode || !Node.isObjectBindingPattern(nameNode)) {
|
|
462
|
+
return undefined;
|
|
463
|
+
}
|
|
464
|
+
const bindings = extractHelperExposureBindings(nameNode);
|
|
465
|
+
if (bindings.length === 0) {
|
|
466
|
+
return undefined;
|
|
467
|
+
}
|
|
468
|
+
const returnObjectLiteral = getExposureReturnObjectLiteral(exposeArgument);
|
|
469
|
+
if (!returnObjectLiteral) {
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
const exposedProperties = extractHelperExposedProperties(returnObjectLiteral, bindings);
|
|
473
|
+
const usedProperties = mergeDeps(exposedProperties.map(({ sourceKey }) => sourceKey), extractHelperYieldedProperties(exposeArgument, bindings));
|
|
474
|
+
return {
|
|
475
|
+
usedProperties,
|
|
476
|
+
exposedProperties,
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
function extractHelperExposureBindings(bindingPattern) {
|
|
480
|
+
var _a;
|
|
481
|
+
const bindings = [];
|
|
482
|
+
for (const element of bindingPattern.getElements()) {
|
|
483
|
+
const nameNode = element.getNameNode();
|
|
484
|
+
if (!Node.isIdentifier(nameNode)) {
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
const propertyNameNode = element.getPropertyNameNode();
|
|
488
|
+
const sourceKey = (_a = getStaticPropertyName(propertyNameNode !== null && propertyNameNode !== void 0 ? propertyNameNode : nameNode)) !== null && _a !== void 0 ? _a : nameNode.getText();
|
|
489
|
+
bindings.push({
|
|
490
|
+
localName: nameNode.getText(),
|
|
491
|
+
sourceKey,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return bindings;
|
|
495
|
+
}
|
|
496
|
+
function getExposureReturnObjectLiteral(exposeArgument) {
|
|
497
|
+
const body = exposeArgument.getBody();
|
|
498
|
+
if (Node.isObjectLiteralExpression(body)) {
|
|
499
|
+
return body;
|
|
500
|
+
}
|
|
501
|
+
if (Node.isParenthesizedExpression(body)) {
|
|
502
|
+
const expression = body.getExpression();
|
|
503
|
+
return Node.isObjectLiteralExpression(expression) ? expression : undefined;
|
|
504
|
+
}
|
|
505
|
+
if (!Node.isBlock(body)) {
|
|
506
|
+
return undefined;
|
|
507
|
+
}
|
|
508
|
+
const returnStatement = [...body.getDescendantsOfKind(SyntaxKind.ReturnStatement)]
|
|
509
|
+
.reverse()
|
|
510
|
+
.find((statement) => Node.isObjectLiteralExpression(statement.getExpression()));
|
|
511
|
+
const expression = returnStatement === null || returnStatement === void 0 ? void 0 : returnStatement.getExpression();
|
|
512
|
+
return Node.isObjectLiteralExpression(expression) ? expression : undefined;
|
|
513
|
+
}
|
|
514
|
+
function extractHelperExposedProperties(objectLiteral, bindings) {
|
|
515
|
+
const bindingMap = new Map(bindings.map((binding) => [binding.localName, binding.sourceKey]));
|
|
516
|
+
const exposedProperties = [];
|
|
517
|
+
for (const property of objectLiteral.getProperties()) {
|
|
518
|
+
if (Node.isShorthandPropertyAssignment(property)) {
|
|
519
|
+
const sourceKey = bindingMap.get(property.getName());
|
|
520
|
+
if (sourceKey) {
|
|
521
|
+
exposedProperties.push({
|
|
522
|
+
exposedKey: property.getName(),
|
|
523
|
+
sourceKey,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
if (!Node.isPropertyAssignment(property)) {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const exposedKey = getStaticPropertyName(property.getNameNode());
|
|
532
|
+
const initializer = property.getInitializer();
|
|
533
|
+
if (!exposedKey || !Node.isIdentifier(initializer)) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const sourceKey = bindingMap.get(initializer.getText());
|
|
537
|
+
if (!sourceKey) {
|
|
538
|
+
continue;
|
|
539
|
+
}
|
|
540
|
+
exposedProperties.push({
|
|
541
|
+
exposedKey,
|
|
542
|
+
sourceKey,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
return exposedProperties;
|
|
546
|
+
}
|
|
547
|
+
function extractHelperYieldedProperties(exposeArgument, bindings) {
|
|
548
|
+
const bindingMap = new Map(bindings.map((binding) => [binding.localName, binding.sourceKey]));
|
|
549
|
+
const yieldedProperties = [];
|
|
550
|
+
for (const yieldExpression of exposeArgument.getDescendantsOfKind(SyntaxKind.YieldExpression)) {
|
|
551
|
+
const expression = yieldExpression.getExpression();
|
|
552
|
+
if (!Node.isCallExpression(expression)) {
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
const target = expression.getExpression();
|
|
556
|
+
if (!Node.isIdentifier(target)) {
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
const sourceKey = bindingMap.get(target.getText());
|
|
560
|
+
if (sourceKey) {
|
|
561
|
+
yieldedProperties.push(sourceKey);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
return yieldedProperties;
|
|
565
|
+
}
|
|
566
|
+
function createGeneratedDependencyKey(dependencyText) {
|
|
567
|
+
var _a;
|
|
568
|
+
const lastSegment = (_a = dependencyText.split('.').pop()) !== null && _a !== void 0 ? _a : dependencyText;
|
|
569
|
+
const helperMatch = /^(inject|provide)([A-Z].*)$/.exec(lastSegment);
|
|
570
|
+
if (helperMatch) {
|
|
571
|
+
return helperMatch[2];
|
|
572
|
+
}
|
|
573
|
+
const toYieldMatch = /^(.*)ToYield$/.exec(lastSegment);
|
|
574
|
+
if (toYieldMatch === null || toYieldMatch === void 0 ? void 0 : toYieldMatch[1]) {
|
|
575
|
+
return toYieldMatch[1];
|
|
576
|
+
}
|
|
577
|
+
return lastSegment;
|
|
578
|
+
}
|
|
579
|
+
function createGeneratedDependencyTypeText(sourceFile, dependencyText) {
|
|
580
|
+
if (isHelperLikeDependency(dependencyText)) {
|
|
581
|
+
return `ReturnType<typeof ${dependencyText}>`;
|
|
582
|
+
}
|
|
583
|
+
const resolution = resolveDependencyReference(sourceFile, dependencyText);
|
|
584
|
+
if (resolution.kind === 'class' || resolution.kind === 'enum') {
|
|
585
|
+
return dependencyText;
|
|
586
|
+
}
|
|
587
|
+
if (resolution.kind === 'unknown') {
|
|
588
|
+
return dependencyText;
|
|
589
|
+
}
|
|
590
|
+
return `typeof ${dependencyText}`;
|
|
591
|
+
}
|
|
592
|
+
function isHelperLikeDependency(dependencyText) {
|
|
593
|
+
var _a;
|
|
594
|
+
const lastSegment = (_a = dependencyText.split('.').pop()) !== null && _a !== void 0 ? _a : dependencyText;
|
|
595
|
+
return (/^(inject|provide)[A-Z].*/.test(lastSegment) || /ToYield$/.test(lastSegment));
|
|
596
|
+
}
|
|
597
|
+
function resolveAngularDeclarableDependency(sourceFile, dependencyText) {
|
|
598
|
+
const resolution = resolveDependencyReference(sourceFile, dependencyText);
|
|
599
|
+
if (!resolution.classDeclaration) {
|
|
600
|
+
return undefined;
|
|
601
|
+
}
|
|
602
|
+
const angularKind = getAngularKind(resolution.classDeclaration);
|
|
603
|
+
if (angularKind !== 'component' &&
|
|
604
|
+
angularKind !== 'directive' &&
|
|
605
|
+
angularKind !== 'pipe') {
|
|
606
|
+
return undefined;
|
|
607
|
+
}
|
|
608
|
+
const className = resolution.classDeclaration.getName();
|
|
609
|
+
if (!className) {
|
|
610
|
+
return undefined;
|
|
611
|
+
}
|
|
612
|
+
const declarationSourceFile = resolution.classDeclaration.getSourceFile();
|
|
613
|
+
if (declarationSourceFile === sourceFile ||
|
|
614
|
+
declarationSourceFile.isDeclarationFile()) {
|
|
615
|
+
return undefined;
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
className,
|
|
619
|
+
moduleSpecifier: resolution.moduleSpecifier,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function ensureGeneratedDependencyTypeImports(sourceFile, generatedDependencyGroups) {
|
|
623
|
+
var _a;
|
|
624
|
+
const importsToAdd = new Map();
|
|
625
|
+
for (const entry of generatedDependencyGroups.deps) {
|
|
626
|
+
if (!entry.typeImport) {
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
const importNames = (_a = importsToAdd.get(entry.typeImport.moduleSpecifier)) !== null && _a !== void 0 ? _a : new Set();
|
|
630
|
+
importNames.add(entry.typeImport.name);
|
|
631
|
+
importsToAdd.set(entry.typeImport.moduleSpecifier, importNames);
|
|
632
|
+
}
|
|
633
|
+
for (const [moduleSpecifier, importNames] of importsToAdd) {
|
|
634
|
+
const existingImport = sourceFile
|
|
635
|
+
.getImportDeclarations()
|
|
636
|
+
.find((importDeclaration) => importDeclaration.getModuleSpecifierValue() === moduleSpecifier);
|
|
637
|
+
if (existingImport) {
|
|
638
|
+
existingImport.addNamedImports([...importNames].map((name) => ({ name, isTypeOnly: true })));
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
sourceFile.addImportDeclaration({
|
|
642
|
+
moduleSpecifier,
|
|
643
|
+
namedImports: [...importNames].map((name) => ({
|
|
644
|
+
name,
|
|
645
|
+
isTypeOnly: true,
|
|
646
|
+
})),
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
function formatGeneratedDependencyType(generatedDependencyGroups) {
|
|
651
|
+
return [
|
|
652
|
+
'{',
|
|
653
|
+
` deps: ${formatGeneratedDependencyObject(generatedDependencyGroups.deps)};`,
|
|
654
|
+
` provided: ${formatGeneratedDependencyObject(generatedDependencyGroups.provided)};`,
|
|
655
|
+
` missingProvider: ${formatGeneratedDependencyObject(generatedDependencyGroups.missingProvider)};`,
|
|
656
|
+
'}',
|
|
657
|
+
].join('\n');
|
|
658
|
+
}
|
|
659
|
+
function formatGeneratedDependencyObject(entries) {
|
|
660
|
+
if (entries.length === 0) {
|
|
661
|
+
return '{}';
|
|
662
|
+
}
|
|
663
|
+
return [
|
|
664
|
+
'{',
|
|
665
|
+
...entries.map((entry) => formatGeneratedDependencyEntry(entry)),
|
|
666
|
+
' }',
|
|
667
|
+
].join('\n');
|
|
668
|
+
}
|
|
669
|
+
function formatGeneratedDependencyEntry(entry) {
|
|
670
|
+
const typeLines = entry.typeText.split('\n');
|
|
671
|
+
const lines = [
|
|
672
|
+
` ${formatObjectKey(entry.key)}: ${typeLines[0]}`,
|
|
673
|
+
...typeLines.slice(1).map((line) => ` ${line}`),
|
|
674
|
+
];
|
|
675
|
+
lines[lines.length - 1] += ';';
|
|
676
|
+
return lines.join('\n');
|
|
677
|
+
}
|
|
678
|
+
function formatObjectKey(key) {
|
|
679
|
+
return /^[$A-Z_][0-9A-Z_$]*$/i.test(key) ? key : `'${key}'`;
|
|
680
|
+
}
|
|
681
|
+
export function writeGeneratedDepsTypeAlias(sourceFile, className, generatedDependencyGroups) {
|
|
682
|
+
const generatedTypeName = getGeneratedDepsTypeName(className);
|
|
683
|
+
const generatedType = `GetDeps<${formatGeneratedDependencyType(generatedDependencyGroups)}>`;
|
|
684
|
+
const existingTypeAlias = sourceFile.getTypeAlias(generatedTypeName);
|
|
685
|
+
if (existingTypeAlias) {
|
|
686
|
+
existingTypeAlias.setIsExported(true);
|
|
687
|
+
existingTypeAlias.setType(generatedType);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
sourceFile.addTypeAlias({
|
|
691
|
+
isExported: true,
|
|
692
|
+
name: generatedTypeName,
|
|
693
|
+
type: generatedType,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
export function migrateLegacyBrandExport(sourceFile, classDeclaration, className) {
|
|
697
|
+
const existing = readExistingDependencyGroups(sourceFile, className);
|
|
698
|
+
if (!existing.found || !existing.exportAssignmentNode) {
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
const exportAssignment = existing.exportAssignmentNode.asKind(SyntaxKind.ExportAssignment);
|
|
702
|
+
exportAssignment === null || exportAssignment === void 0 ? void 0 : exportAssignment.remove();
|
|
703
|
+
if (!classDeclaration.isDefaultExport() &&
|
|
704
|
+
!classDeclaration.isExported() &&
|
|
705
|
+
exportAssignment) {
|
|
706
|
+
classDeclaration.setIsDefaultExport(true);
|
|
707
|
+
}
|
|
270
708
|
}
|
|
271
709
|
function invalidExistingDependencyGroups(node, warnings) {
|
|
272
710
|
return {
|
|
@@ -327,7 +765,11 @@ function getInjectionHelperDependency(expression) {
|
|
|
327
765
|
return undefined;
|
|
328
766
|
}
|
|
329
767
|
export function ensureHelperImports(sourceFile, helperImportPath) {
|
|
330
|
-
const missingImports = [
|
|
768
|
+
const missingImports = [
|
|
769
|
+
'GetDeps',
|
|
770
|
+
'GetInjectedServiceDependencies',
|
|
771
|
+
'GetServiceOutput',
|
|
772
|
+
].filter((importName) => !hasLocalNamedImport(sourceFile, helperImportPath, importName));
|
|
331
773
|
if (missingImports.length === 0) {
|
|
332
774
|
return;
|
|
333
775
|
}
|
|
@@ -335,35 +777,15 @@ export function ensureHelperImports(sourceFile, helperImportPath) {
|
|
|
335
777
|
.getImportDeclarations()
|
|
336
778
|
.find((importDeclaration) => importDeclaration.getModuleSpecifierValue() === helperImportPath);
|
|
337
779
|
if (existingImport) {
|
|
338
|
-
existingImport.addNamedImports(missingImports);
|
|
780
|
+
existingImport.addNamedImports(missingImports.map((name) => ({ name, isTypeOnly: true })));
|
|
339
781
|
return;
|
|
340
782
|
}
|
|
341
783
|
sourceFile.addImportDeclaration({
|
|
342
784
|
moduleSpecifier: helperImportPath,
|
|
343
|
-
namedImports: missingImports
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if (classDeclaration.isDefaultExport()) {
|
|
348
|
-
classDeclaration.setIsDefaultExport(false);
|
|
349
|
-
}
|
|
350
|
-
if (classDeclaration.isExported()) {
|
|
351
|
-
classDeclaration.setIsExported(false);
|
|
352
|
-
}
|
|
353
|
-
for (const exportAssignment of sourceFile.getExportAssignments()) {
|
|
354
|
-
if (isDefaultIdentifierExport(exportAssignment, className) ||
|
|
355
|
-
isDefaultBrandedExport(exportAssignment, className)) {
|
|
356
|
-
exportAssignment.remove();
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
for (const exportDeclaration of sourceFile.getExportDeclarations()) {
|
|
360
|
-
removeClassFromExportDeclaration(exportDeclaration, className);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
export function writeDefaultBrandExport(sourceFile, className, dependencyGroups) {
|
|
364
|
-
sourceFile.addExportAssignment({
|
|
365
|
-
expression: `brandAngularSymbol(${className}, ${createDepsExpression(dependencyGroups)})`,
|
|
366
|
-
isExportEquals: false,
|
|
785
|
+
namedImports: missingImports.map((name) => ({
|
|
786
|
+
name,
|
|
787
|
+
isTypeOnly: true,
|
|
788
|
+
})),
|
|
367
789
|
});
|
|
368
790
|
}
|
|
369
791
|
export function readExistingDependencyGroups(sourceFile, className) {
|
|
@@ -594,6 +1016,108 @@ function emptyMetadataDependencyGroups() {
|
|
|
594
1016
|
warnings: [],
|
|
595
1017
|
};
|
|
596
1018
|
}
|
|
1019
|
+
function extractProvidedDependencies(sourceFile, classDeclaration, angularKind, options) {
|
|
1020
|
+
const metadata = getDecoratorMetadataObject(classDeclaration);
|
|
1021
|
+
const warnings = [];
|
|
1022
|
+
const entries = [];
|
|
1023
|
+
if (!metadata) {
|
|
1024
|
+
return { entries, warnings };
|
|
1025
|
+
}
|
|
1026
|
+
if (options.includeProviders) {
|
|
1027
|
+
entries.push(...extractProvidedDependencyArrayProperty(sourceFile, metadata, 'providers', warnings));
|
|
1028
|
+
}
|
|
1029
|
+
if (options.includeViewProviders && angularKind === 'component') {
|
|
1030
|
+
entries.push(...extractProvidedDependencyArrayProperty(sourceFile, metadata, 'viewProviders', warnings));
|
|
1031
|
+
}
|
|
1032
|
+
return {
|
|
1033
|
+
entries: mergeGeneratedDependencyEntries(entries),
|
|
1034
|
+
warnings,
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
1037
|
+
function extractProvidedDependencyArrayProperty(sourceFile, metadata, propertyName, warnings) {
|
|
1038
|
+
const property = getObjectPropertyAssignment(metadata, propertyName);
|
|
1039
|
+
if (!property) {
|
|
1040
|
+
return [];
|
|
1041
|
+
}
|
|
1042
|
+
const initializer = property.getInitializer();
|
|
1043
|
+
if (!Node.isArrayLiteralExpression(initializer)) {
|
|
1044
|
+
warnings.push(`Skipped metadata property "${propertyName}" because it is not a static array.`);
|
|
1045
|
+
return [];
|
|
1046
|
+
}
|
|
1047
|
+
return extractProvidedDependencyEntriesFromArray(sourceFile, initializer, propertyName, warnings);
|
|
1048
|
+
}
|
|
1049
|
+
function extractProvidedDependencyEntriesFromArray(sourceFile, arrayLiteral, context, warnings) {
|
|
1050
|
+
const entries = [];
|
|
1051
|
+
for (const element of arrayLiteral.getElements()) {
|
|
1052
|
+
if (Node.isArrayLiteralExpression(element)) {
|
|
1053
|
+
entries.push(...extractProvidedDependencyEntriesFromArray(sourceFile, element, context, warnings));
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
if (Node.isSpreadElement(element)) {
|
|
1057
|
+
warnings.push(`Skipped spread element in "${context}" metadata providers.`);
|
|
1058
|
+
continue;
|
|
1059
|
+
}
|
|
1060
|
+
if (Node.isCallExpression(element)) {
|
|
1061
|
+
const providerFactory = getStaticExpressionText(element.getExpression());
|
|
1062
|
+
if (!providerFactory) {
|
|
1063
|
+
warnings.push(`Skipped complex provider factory "${element.getText()}" in "${context}".`);
|
|
1064
|
+
continue;
|
|
1065
|
+
}
|
|
1066
|
+
entries.push({
|
|
1067
|
+
key: createGeneratedDependencyKey(providerFactory),
|
|
1068
|
+
typeText: `ReturnType<typeof ${providerFactory}>`,
|
|
1069
|
+
});
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
const staticExpression = getStaticExpressionText(element);
|
|
1073
|
+
if (staticExpression) {
|
|
1074
|
+
entries.push({
|
|
1075
|
+
key: createGeneratedDependencyKey(staticExpression),
|
|
1076
|
+
typeText: createGeneratedDependencyTypeText(sourceFile, staticExpression),
|
|
1077
|
+
});
|
|
1078
|
+
continue;
|
|
1079
|
+
}
|
|
1080
|
+
if (Node.isObjectLiteralExpression(element)) {
|
|
1081
|
+
const providerEntry = extractProvidedDependencyEntryFromObjectLiteral(sourceFile, element, context, warnings);
|
|
1082
|
+
if (providerEntry) {
|
|
1083
|
+
entries.push(providerEntry);
|
|
1084
|
+
}
|
|
1085
|
+
continue;
|
|
1086
|
+
}
|
|
1087
|
+
warnings.push(`Skipped complex expression "${element.getText()}" in "${context}" metadata providers.`);
|
|
1088
|
+
}
|
|
1089
|
+
return entries;
|
|
1090
|
+
}
|
|
1091
|
+
function extractProvidedDependencyEntryFromObjectLiteral(sourceFile, objectLiteral, context, warnings) {
|
|
1092
|
+
var _a, _b, _c, _d, _e;
|
|
1093
|
+
const provideProperty = getObjectPropertyAssignment(objectLiteral, 'provide');
|
|
1094
|
+
const provideText = getStaticExpressionText(provideProperty === null || provideProperty === void 0 ? void 0 : provideProperty.getInitializer());
|
|
1095
|
+
if (!provideText) {
|
|
1096
|
+
warnings.push(`Skipped provider object in "${context}" because "provide" is not static.`);
|
|
1097
|
+
return undefined;
|
|
1098
|
+
}
|
|
1099
|
+
const useClass = getStaticExpressionText((_a = getObjectPropertyAssignment(objectLiteral, 'useClass')) === null || _a === void 0 ? void 0 : _a.getInitializer());
|
|
1100
|
+
const useExisting = getStaticExpressionText((_b = getObjectPropertyAssignment(objectLiteral, 'useExisting')) === null || _b === void 0 ? void 0 : _b.getInitializer());
|
|
1101
|
+
const useValue = getStaticExpressionText((_c = getObjectPropertyAssignment(objectLiteral, 'useValue')) === null || _c === void 0 ? void 0 : _c.getInitializer());
|
|
1102
|
+
const useFactory = getStaticExpressionText((_d = getObjectPropertyAssignment(objectLiteral, 'useFactory')) === null || _d === void 0 ? void 0 : _d.getInitializer());
|
|
1103
|
+
if (useFactory) {
|
|
1104
|
+
return {
|
|
1105
|
+
key: createGeneratedDependencyKey(provideText),
|
|
1106
|
+
typeText: `ReturnType<typeof ${useFactory}>`,
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
if (useValue) {
|
|
1110
|
+
return {
|
|
1111
|
+
key: createGeneratedDependencyKey(provideText),
|
|
1112
|
+
typeText: `typeof ${useValue}`,
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
const valueText = (_e = useClass !== null && useClass !== void 0 ? useClass : useExisting) !== null && _e !== void 0 ? _e : provideText;
|
|
1116
|
+
return {
|
|
1117
|
+
key: createGeneratedDependencyKey(provideText),
|
|
1118
|
+
typeText: createGeneratedDependencyTypeText(sourceFile, valueText),
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
597
1121
|
function extractMetadataArrayProperty(metadata, propertyName, context, warnings) {
|
|
598
1122
|
const property = getObjectPropertyAssignment(metadata, propertyName);
|
|
599
1123
|
if (!property) {
|
|
@@ -700,6 +1224,174 @@ function getStaticPropertyName(nameNode) {
|
|
|
700
1224
|
}
|
|
701
1225
|
return undefined;
|
|
702
1226
|
}
|
|
1227
|
+
function resolveDependencyReference(sourceFile, dependencyText) {
|
|
1228
|
+
const [rootIdentifier] = dependencyText.split('.');
|
|
1229
|
+
if (!rootIdentifier) {
|
|
1230
|
+
return { kind: 'unknown' };
|
|
1231
|
+
}
|
|
1232
|
+
const importResolution = resolveImportedDependencyReference(sourceFile, dependencyText, rootIdentifier);
|
|
1233
|
+
if (importResolution) {
|
|
1234
|
+
return importResolution;
|
|
1235
|
+
}
|
|
1236
|
+
const localClass = sourceFile.getClass(rootIdentifier);
|
|
1237
|
+
if (localClass) {
|
|
1238
|
+
return { kind: 'class', classDeclaration: localClass };
|
|
1239
|
+
}
|
|
1240
|
+
if (sourceFile.getEnum(rootIdentifier)) {
|
|
1241
|
+
return { kind: 'enum' };
|
|
1242
|
+
}
|
|
1243
|
+
if (sourceFile.getFunction(rootIdentifier)) {
|
|
1244
|
+
return { kind: 'function' };
|
|
1245
|
+
}
|
|
1246
|
+
if (sourceFile
|
|
1247
|
+
.getVariableDeclarations()
|
|
1248
|
+
.some((declaration) => declaration.getName() === rootIdentifier)) {
|
|
1249
|
+
return { kind: 'variable' };
|
|
1250
|
+
}
|
|
1251
|
+
return { kind: 'unknown' };
|
|
1252
|
+
}
|
|
1253
|
+
function resolveImportedDependencyReference(sourceFile, dependencyText, rootIdentifier) {
|
|
1254
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1255
|
+
for (const importDeclaration of sourceFile.getImportDeclarations()) {
|
|
1256
|
+
const moduleSpecifier = importDeclaration.getModuleSpecifierValue();
|
|
1257
|
+
if (((_a = importDeclaration.getDefaultImport()) === null || _a === void 0 ? void 0 : _a.getText()) === rootIdentifier) {
|
|
1258
|
+
const declaration = getDefaultImportClassDeclaration(importDeclaration);
|
|
1259
|
+
if (declaration) {
|
|
1260
|
+
return {
|
|
1261
|
+
kind: 'class',
|
|
1262
|
+
classDeclaration: declaration,
|
|
1263
|
+
moduleSpecifier,
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
return { kind: 'unknown', moduleSpecifier };
|
|
1267
|
+
}
|
|
1268
|
+
if (((_b = importDeclaration.getNamespaceImport()) === null || _b === void 0 ? void 0 : _b.getText()) === rootIdentifier) {
|
|
1269
|
+
const declaration = getNamespaceImportClassDeclaration(importDeclaration, dependencyText);
|
|
1270
|
+
if (declaration) {
|
|
1271
|
+
return {
|
|
1272
|
+
kind: 'class',
|
|
1273
|
+
classDeclaration: declaration,
|
|
1274
|
+
moduleSpecifier,
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
return { kind: 'namespace', moduleSpecifier };
|
|
1278
|
+
}
|
|
1279
|
+
const namedImport = importDeclaration
|
|
1280
|
+
.getNamedImports()
|
|
1281
|
+
.find((specifier) => {
|
|
1282
|
+
var _a, _b;
|
|
1283
|
+
const localName = (_b = (_a = specifier.getAliasNode()) === null || _a === void 0 ? void 0 : _a.getText()) !== null && _b !== void 0 ? _b : specifier.getNameNode().getText();
|
|
1284
|
+
return localName === rootIdentifier;
|
|
1285
|
+
});
|
|
1286
|
+
if (!namedImport) {
|
|
1287
|
+
continue;
|
|
1288
|
+
}
|
|
1289
|
+
const localIdentifier = (_c = namedImport.getAliasNode()) !== null && _c !== void 0 ? _c : namedImport.getNameNode();
|
|
1290
|
+
const symbol = (_d = localIdentifier.getSymbol()) !== null && _d !== void 0 ? _d : localIdentifier.getType().getSymbol();
|
|
1291
|
+
const aliasedSymbol = (_e = symbol === null || symbol === void 0 ? void 0 : symbol.getAliasedSymbol()) !== null && _e !== void 0 ? _e : symbol;
|
|
1292
|
+
const declarations = (_f = aliasedSymbol === null || aliasedSymbol === void 0 ? void 0 : aliasedSymbol.getDeclarations()) !== null && _f !== void 0 ? _f : [];
|
|
1293
|
+
const classDeclaration = declarations.find((declaration) => Node.isClassDeclaration(declaration));
|
|
1294
|
+
if (classDeclaration && Node.isClassDeclaration(classDeclaration)) {
|
|
1295
|
+
return {
|
|
1296
|
+
kind: 'class',
|
|
1297
|
+
classDeclaration,
|
|
1298
|
+
moduleSpecifier,
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
if (declarations.some((declaration) => Node.isEnumDeclaration(declaration))) {
|
|
1302
|
+
return { kind: 'enum', moduleSpecifier };
|
|
1303
|
+
}
|
|
1304
|
+
if (declarations.some((declaration) => Node.isFunctionDeclaration(declaration))) {
|
|
1305
|
+
return { kind: 'function', moduleSpecifier };
|
|
1306
|
+
}
|
|
1307
|
+
if (declarations.some((declaration) => Node.isVariableDeclaration(declaration))) {
|
|
1308
|
+
return { kind: 'variable', moduleSpecifier };
|
|
1309
|
+
}
|
|
1310
|
+
return { kind: 'unknown', moduleSpecifier };
|
|
1311
|
+
}
|
|
1312
|
+
return undefined;
|
|
1313
|
+
}
|
|
1314
|
+
function getDefaultImportClassDeclaration(importDeclaration) {
|
|
1315
|
+
var _a;
|
|
1316
|
+
const moduleSourceFile = importDeclaration.getModuleSpecifierSourceFile();
|
|
1317
|
+
if (!moduleSourceFile) {
|
|
1318
|
+
return undefined;
|
|
1319
|
+
}
|
|
1320
|
+
const defaultExportSymbol = moduleSourceFile.getDefaultExportSymbol();
|
|
1321
|
+
const declarations = (_a = defaultExportSymbol === null || defaultExportSymbol === void 0 ? void 0 : defaultExportSymbol.getDeclarations()) !== null && _a !== void 0 ? _a : [];
|
|
1322
|
+
return declarations.find((declaration) => Node.isClassDeclaration(declaration));
|
|
1323
|
+
}
|
|
1324
|
+
function getNamespaceImportClassDeclaration(importDeclaration, dependencyText) {
|
|
1325
|
+
var _a;
|
|
1326
|
+
const moduleSourceFile = importDeclaration.getModuleSpecifierSourceFile();
|
|
1327
|
+
if (!moduleSourceFile) {
|
|
1328
|
+
return undefined;
|
|
1329
|
+
}
|
|
1330
|
+
const leafIdentifier = dependencyText.split('.').pop();
|
|
1331
|
+
if (!leafIdentifier) {
|
|
1332
|
+
return undefined;
|
|
1333
|
+
}
|
|
1334
|
+
const exportedDeclarations = (_a = moduleSourceFile.getExportedDeclarations().get(leafIdentifier)) !== null && _a !== void 0 ? _a : [];
|
|
1335
|
+
return exportedDeclarations.find((declaration) => Node.isClassDeclaration(declaration));
|
|
1336
|
+
}
|
|
1337
|
+
function isProvidedInInjectableTree(sourceFile, dependencyText) {
|
|
1338
|
+
const resolution = resolveDependencyReference(sourceFile, dependencyText);
|
|
1339
|
+
const classDeclaration = resolution.classDeclaration;
|
|
1340
|
+
if (!classDeclaration || getAngularKind(classDeclaration) !== 'injectable') {
|
|
1341
|
+
return false;
|
|
1342
|
+
}
|
|
1343
|
+
const metadata = getDecoratorMetadataObject(classDeclaration);
|
|
1344
|
+
const providedInProperty = metadata
|
|
1345
|
+
? getObjectPropertyAssignment(metadata, 'providedIn')
|
|
1346
|
+
: undefined;
|
|
1347
|
+
const initializer = providedInProperty === null || providedInProperty === void 0 ? void 0 : providedInProperty.getInitializer();
|
|
1348
|
+
if (!initializer) {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
return (!Node.isNullLiteral(initializer) &&
|
|
1352
|
+
!Node.isFalseLiteral(initializer) &&
|
|
1353
|
+
!(Node.isIdentifier(initializer) && initializer.getText() === 'undefined'));
|
|
1354
|
+
}
|
|
1355
|
+
function isDependencyProvidedElsewhere(sourceFile, dependencyText) {
|
|
1356
|
+
const trackedHelper = resolveTrackedInjectHelperByName(sourceFile, dependencyText);
|
|
1357
|
+
if (trackedHelper) {
|
|
1358
|
+
return trackedHelper.scope === 'global' || trackedHelper.scope === 'function';
|
|
1359
|
+
}
|
|
1360
|
+
return isProvidedInInjectableTree(sourceFile, dependencyText);
|
|
1361
|
+
}
|
|
1362
|
+
function resolveTrackedInjectHelperByName(sourceFile, dependencyText) {
|
|
1363
|
+
const [rootIdentifier] = dependencyText.split('.');
|
|
1364
|
+
if (!rootIdentifier) {
|
|
1365
|
+
return undefined;
|
|
1366
|
+
}
|
|
1367
|
+
for (const declaration of resolveDependencyIdentifierDeclarations(sourceFile, rootIdentifier)) {
|
|
1368
|
+
const helper = resolveTrackedInjectHelperFromDeclaration(declaration);
|
|
1369
|
+
if (helper) {
|
|
1370
|
+
return helper;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return undefined;
|
|
1374
|
+
}
|
|
1375
|
+
function resolveDependencyIdentifierDeclarations(sourceFile, rootIdentifier) {
|
|
1376
|
+
var _a, _b, _c, _d;
|
|
1377
|
+
for (const importDeclaration of sourceFile.getImportDeclarations()) {
|
|
1378
|
+
const namedImport = importDeclaration.getNamedImports().find((specifier) => {
|
|
1379
|
+
var _a, _b;
|
|
1380
|
+
const localName = (_b = (_a = specifier.getAliasNode()) === null || _a === void 0 ? void 0 : _a.getText()) !== null && _b !== void 0 ? _b : specifier.getNameNode().getText();
|
|
1381
|
+
return localName === rootIdentifier;
|
|
1382
|
+
});
|
|
1383
|
+
if (!namedImport) {
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
const identifier = (_a = namedImport.getAliasNode()) !== null && _a !== void 0 ? _a : namedImport.getNameNode();
|
|
1387
|
+
const symbol = (_b = identifier.getSymbol()) !== null && _b !== void 0 ? _b : identifier.getType().getSymbol();
|
|
1388
|
+
const aliasedSymbol = (_c = symbol === null || symbol === void 0 ? void 0 : symbol.getAliasedSymbol()) !== null && _c !== void 0 ? _c : symbol;
|
|
1389
|
+
return (_d = aliasedSymbol === null || aliasedSymbol === void 0 ? void 0 : aliasedSymbol.getDeclarations()) !== null && _d !== void 0 ? _d : [namedImport];
|
|
1390
|
+
}
|
|
1391
|
+
return sourceFile
|
|
1392
|
+
.getDescendantsOfKind(SyntaxKind.BindingElement)
|
|
1393
|
+
.filter((bindingElement) => bindingElement.getName() === rootIdentifier);
|
|
1394
|
+
}
|
|
703
1395
|
function getDependencyTextFromTypeNode(typeNode) {
|
|
704
1396
|
if (isPrimitiveTypeNode(typeNode)) {
|
|
705
1397
|
return undefined;
|
|
@@ -861,7 +1553,11 @@ function getExportRewriteSafety(sourceFile, classDeclaration, className) {
|
|
|
861
1553
|
: { safe: false, warnings };
|
|
862
1554
|
}
|
|
863
1555
|
function getHelperImportSafety(sourceFile, helperImportPath) {
|
|
864
|
-
const warnings = [
|
|
1556
|
+
const warnings = [
|
|
1557
|
+
'GetDeps',
|
|
1558
|
+
'GetInjectedServiceDependencies',
|
|
1559
|
+
'GetServiceOutput',
|
|
1560
|
+
]
|
|
865
1561
|
.filter((helperName) => hasConflictingTopLevelBinding(sourceFile, helperImportPath, helperName))
|
|
866
1562
|
.map((helperName) => `Skipped file because "${helperName}" is already bound to a different top-level symbol.`);
|
|
867
1563
|
return warnings.length === 0
|
|
@@ -1044,9 +1740,9 @@ function logFileResult(report, log) {
|
|
|
1044
1740
|
`file=${report.filePath}`,
|
|
1045
1741
|
report.angularKind ? `kind=${report.angularKind}` : undefined,
|
|
1046
1742
|
report.className ? `class=${report.className}` : undefined,
|
|
1047
|
-
`
|
|
1048
|
-
`
|
|
1049
|
-
`
|
|
1743
|
+
`deps=[${report.generatedDependencyGroups.deps.map((entry) => entry.key).join(', ')}]`,
|
|
1744
|
+
`provided=[${report.generatedDependencyGroups.provided.map((entry) => entry.key).join(', ')}]`,
|
|
1745
|
+
`missingProvider=[${report.generatedDependencyGroups.missingProvider.map((entry) => entry.key).join(', ')}]`,
|
|
1050
1746
|
`status=${status}`,
|
|
1051
1747
|
].filter(Boolean);
|
|
1052
1748
|
log(details.join(' '));
|
|
@@ -1106,16 +1802,19 @@ function printHelpAndExit() {
|
|
|
1106
1802
|
Options:
|
|
1107
1803
|
--root <dir> Project root. Defaults to cwd.
|
|
1108
1804
|
--tsconfig <path> tsconfig path. Defaults to <root>/tsconfig.json.
|
|
1109
|
-
--helper-import <path> Import path for
|
|
1805
|
+
--helper-import <path> Import path for GetDeps.
|
|
1110
1806
|
--transform-only-standalone-declarables Only transform standalone components/directives.
|
|
1111
|
-
--no-providers Do not include metadata providers in
|
|
1112
|
-
--no-view-providers Do not include component viewProviders in
|
|
1807
|
+
--no-providers Do not include metadata providers in generated types.
|
|
1808
|
+
--no-view-providers Do not include component viewProviders in generated types.
|
|
1113
1809
|
--dry-run Print results without writing files.
|
|
1114
1810
|
--help Show this help.
|
|
1115
1811
|
`);
|
|
1116
1812
|
process.exit(0);
|
|
1117
1813
|
}
|
|
1118
|
-
if (require.main === module)
|
|
1814
|
+
// Check if this module is being run directly (ESM equivalent of require.main === module)
|
|
1815
|
+
if (import.meta.url === `file://${process.argv[1]}` ||
|
|
1816
|
+
(import.meta.url.startsWith('file:') &&
|
|
1817
|
+
process.argv[1] === fileURLToPath(import.meta.url))) {
|
|
1119
1818
|
runAngularBrandCodemod(parseCliArgs(process.argv.slice(2))).catch((error) => {
|
|
1120
1819
|
console.error(error);
|
|
1121
1820
|
process.exitCode = 1;
|