ng-checkup 0.0.0-stage → 0.2.0

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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +273 -2
  3. package/dist/checks/change-detection.d.ts +22 -0
  4. package/dist/checks/change-detection.js +99 -0
  5. package/dist/checks/change-detection.js.map +1 -0
  6. package/dist/checks/circular-deps.d.ts +13 -0
  7. package/dist/checks/circular-deps.js +43 -0
  8. package/dist/checks/circular-deps.js.map +1 -0
  9. package/dist/checks/components.d.ts +19 -0
  10. package/dist/checks/components.js +97 -0
  11. package/dist/checks/components.js.map +1 -0
  12. package/dist/checks/context.d.ts +51 -0
  13. package/dist/checks/context.js +53 -0
  14. package/dist/checks/context.js.map +1 -0
  15. package/dist/checks/deprecated-apis.d.ts +14 -0
  16. package/dist/checks/deprecated-apis.js +141 -0
  17. package/dist/checks/deprecated-apis.js.map +1 -0
  18. package/dist/checks/state.d.ts +13 -0
  19. package/dist/checks/state.js +72 -0
  20. package/dist/checks/state.js.map +1 -0
  21. package/dist/checks/testing.d.ts +13 -0
  22. package/dist/checks/testing.js +98 -0
  23. package/dist/checks/testing.js.map +1 -0
  24. package/dist/checks/type-safety.d.ts +14 -0
  25. package/dist/checks/type-safety.js +117 -0
  26. package/dist/checks/type-safety.js.map +1 -0
  27. package/dist/checks/version.d.ts +12 -0
  28. package/dist/checks/version.js +107 -0
  29. package/dist/checks/version.js.map +1 -0
  30. package/dist/cli.d.ts +65 -0
  31. package/dist/cli.js +285 -0
  32. package/dist/cli.js.map +1 -0
  33. package/dist/config.d.ts +47 -0
  34. package/dist/config.js +93 -0
  35. package/dist/config.js.map +1 -0
  36. package/dist/deprecations.d.ts +30 -0
  37. package/dist/deprecations.js +279 -0
  38. package/dist/deprecations.js.map +1 -0
  39. package/dist/files.d.ts +33 -0
  40. package/dist/files.js +98 -0
  41. package/dist/files.js.map +1 -0
  42. package/dist/graph.d.ts +44 -0
  43. package/dist/graph.js +151 -0
  44. package/dist/graph.js.map +1 -0
  45. package/dist/index.d.ts +44 -0
  46. package/dist/index.js +135 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/init.d.ts +78 -0
  49. package/dist/init.js +220 -0
  50. package/dist/init.js.map +1 -0
  51. package/dist/report/html.d.ts +14 -0
  52. package/dist/report/html.js +210 -0
  53. package/dist/report/html.js.map +1 -0
  54. package/dist/report/markdown.d.ts +8 -0
  55. package/dist/report/markdown.js +55 -0
  56. package/dist/report/markdown.js.map +1 -0
  57. package/dist/report/summary.d.ts +45 -0
  58. package/dist/report/summary.js +65 -0
  59. package/dist/report/summary.js.map +1 -0
  60. package/dist/report/terminal.d.ts +17 -0
  61. package/dist/report/terminal.js +70 -0
  62. package/dist/report/terminal.js.map +1 -0
  63. package/dist/scan.d.ts +119 -0
  64. package/dist/scan.js +270 -0
  65. package/dist/scan.js.map +1 -0
  66. package/dist/types.d.ts +97 -0
  67. package/dist/types.js +9 -0
  68. package/dist/types.js.map +1 -0
  69. package/dist/workspace.d.ts +76 -0
  70. package/dist/workspace.js +156 -0
  71. package/dist/workspace.js.map +1 -0
  72. package/package.json +67 -4
  73. package/schematics/collection.json +10 -0
  74. package/schematics/ng-add/index.cjs +60 -0
  75. package/schematics/ng-add/schema.json +29 -0
@@ -0,0 +1,65 @@
1
+ /** Points per grade for the overall score. `info` is absent: it never counts. */
2
+ const GRADE_POINTS = { good: 100, fair: 60, poor: 20 };
3
+ /** Severity order, most urgent first. */
4
+ const SEVERITY_RANK = { high: 0, medium: 1, low: 2, info: 3 };
5
+ /**
6
+ * The overall score, 0 to 100: the average of the graded areas at 100 for
7
+ * good, 60 for fair and 20 for poor. Areas graded `info` are left out, so a
8
+ * repository is not marked down for what the tool could not measure.
9
+ * Undefined when nothing was graded at all.
10
+ *
11
+ * A deliberately simple formula. Every report prints it next to the score,
12
+ * because a number whose derivation is hidden invites arguing with it instead
13
+ * of with the findings.
14
+ */
15
+ export function overallScore(report) {
16
+ const graded = report.checks.filter((check) => check.grade !== 'info');
17
+ if (graded.length === 0)
18
+ return undefined;
19
+ return Math.round(graded.reduce((sum, check) => sum + GRADE_POINTS[check.grade], 0) / graded.length);
20
+ }
21
+ /** The sentence every format prints under the score. */
22
+ export const SCORE_EXPLANATION = 'Average of the graded areas: good counts 100, fair 60, poor 20. Areas marked info are not counted.';
23
+ /**
24
+ * The findings to act on first, across all checks: every `high` finding,
25
+ * then `medium` ones if fewer than `limit` are high, in report order within a
26
+ * severity. Low and info findings never make the list.
27
+ */
28
+ export function topPriorities(report, limit = 5) {
29
+ return report.checks
30
+ .flatMap((check) => check.findings.map((finding) => ({ check, finding })))
31
+ .filter(({ finding }) => finding.severity === 'high' || finding.severity === 'medium')
32
+ .sort((left, right) => SEVERITY_RANK[left.finding.severity] - SEVERITY_RANK[right.finding.severity])
33
+ .slice(0, limit);
34
+ }
35
+ /** Display label of a grade. */
36
+ export function gradeLabel(grade) {
37
+ return { good: 'Good', fair: 'Fair', poor: 'Poor', info: 'Info' }[grade];
38
+ }
39
+ /** Display label of a severity. */
40
+ export function severityLabel(severity) {
41
+ return { high: 'High', medium: 'Medium', low: 'Low', info: 'Note' }[severity];
42
+ }
43
+ /** `path:line`, or just `path` when the location has no line. */
44
+ export function formatLocation(ref) {
45
+ return ref.line === undefined ? ref.path : `${ref.path}:${ref.line}`;
46
+ }
47
+ /** "1.5 s" or "820 ms". */
48
+ export function formatDuration(milliseconds) {
49
+ return milliseconds >= 1000 ? `${(milliseconds / 1000).toFixed(1)} s` : `${milliseconds} ms`;
50
+ }
51
+ /** The workspace kind as a reader would name it. */
52
+ export function kindLabel(kind) {
53
+ return { 'angular-cli': 'Angular CLI', nx: 'Nx', unknown: 'unknown workspace' }[kind];
54
+ }
55
+ /**
56
+ * How many more files a finding covers than it lists. 0 when it lists them
57
+ * all, and 0 when it lists none: then `count` is a number of occurrences in
58
+ * the message, not of files, and "and 12 more" under an empty list would
59
+ * read as a rendering bug.
60
+ */
61
+ export function remainingCount(finding) {
62
+ const listed = finding.files?.length ?? 0;
63
+ return listed === 0 ? 0 : Math.max(0, (finding.count ?? 0) - listed);
64
+ }
65
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/report/summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Report } from '../types.js';
2
+ /** Options for the terminal renderer. */
3
+ export interface TerminalOptions {
4
+ /** ANSI colours. The CLI turns them off for a non-TTY, `NO_COLOR` or `--no-color`. */
5
+ color: boolean;
6
+ /** Every finding of every check instead of the summary and the top priorities. */
7
+ verbose: boolean;
8
+ }
9
+ /**
10
+ * Renders the report for a terminal.
11
+ *
12
+ * By default it shows one line per check and the top priorities, which fits a
13
+ * screen and is what someone running the tool for the first time wants;
14
+ * `verbose` adds every finding with its example files. The file reports
15
+ * (`--report x.html`) always carry everything, so the terminal never has to.
16
+ */
17
+ export declare function renderTerminal(report: Report, options: TerminalOptions): string;
@@ -0,0 +1,70 @@
1
+ import { formatCount, plural } from '../checks/context.js';
2
+ import { formatDuration, formatLocation, gradeLabel, kindLabel, overallScore, remainingCount, SCORE_EXPLANATION, severityLabel, topPriorities } from './summary.js';
3
+ /** A tiny ANSI palette; every function is the identity when colour is off. */
4
+ function palette(enabled) {
5
+ const wrap = (open, close) => (text) => (enabled ? `\u001b[${open}m${text}\u001b[${close}m` : text);
6
+ return { bold: wrap(1, 22), dim: wrap(2, 22), red: wrap(31, 39), green: wrap(32, 39), yellow: wrap(33, 39), cyan: wrap(36, 39), gray: wrap(90, 39) };
7
+ }
8
+ /**
9
+ * Renders the report for a terminal.
10
+ *
11
+ * By default it shows one line per check and the top priorities, which fits a
12
+ * screen and is what someone running the tool for the first time wants;
13
+ * `verbose` adds every finding with its example files. The file reports
14
+ * (`--report x.html`) always carry everything, so the terminal never has to.
15
+ */
16
+ export function renderTerminal(report, options) {
17
+ const c = palette(options.color);
18
+ /** Backtick spans become cyan text without the backticks; without colour the backticks stay as the only marker. */
19
+ const code = (text) => (options.color ? text.replace(/`([^`]+)`/g, (_, inner) => c.cyan(inner)) : text);
20
+ const gradeBadge = (grade) => {
21
+ const label = ` ${gradeLabel(grade).toUpperCase().padEnd(4)} `;
22
+ return { good: c.green, fair: c.yellow, poor: c.red, info: c.gray }[grade](options.color ? c.bold(label) : `[${gradeLabel(grade).toUpperCase()}]`.padEnd(7));
23
+ };
24
+ const severityTag = (severity) => ({ high: c.red, medium: c.yellow, low: c.gray, info: c.gray })[severity](severityLabel(severity).toLowerCase().padEnd(6));
25
+ const lines = [];
26
+ const { project } = report;
27
+ lines.push(`${c.bold(report.tool.name)} ${c.dim(report.tool.version)} ${c.bold(project.name)} ${c.dim(`· ${kindLabel(project.kind)}${project.angularVersion ? ` · Angular ${project.angularVersion}` : ''}`)}`);
28
+ lines.push(c.dim(`${plural(project.sourceFiles, 'TypeScript file')}, ${plural(project.templateFiles, 'template')}, ${plural(project.linesOfCode, 'line')} of application code, analysed in ${formatDuration(report.durationMs)}`));
29
+ lines.push('');
30
+ const titleWidth = Math.max(...report.checks.map((check) => check.title.length));
31
+ for (const check of report.checks) {
32
+ lines.push(`${gradeBadge(check.grade)} ${c.bold(check.title.padEnd(titleWidth))} ${code(check.summary)}`);
33
+ if (!options.verbose)
34
+ continue;
35
+ for (const finding of check.findings) {
36
+ lines.push(` ${severityTag(finding.severity)} ${code(finding.message)}`);
37
+ if (finding.detail)
38
+ lines.push(` ${c.dim(code(finding.detail))}`);
39
+ for (const file of finding.files ?? [])
40
+ lines.push(` ${c.gray(formatLocation(file))}`);
41
+ const more = remainingCount(finding);
42
+ if (more > 0)
43
+ lines.push(` ${c.gray(`and ${formatCount(more)} more`)}`);
44
+ }
45
+ }
46
+ const score = overallScore(report);
47
+ if (score !== undefined) {
48
+ lines.push('');
49
+ const color = score >= 80 ? c.green : score >= 50 ? c.yellow : c.red;
50
+ lines.push(`${c.bold('Score')} ${color(c.bold(`${score}/100`))} ${c.dim(SCORE_EXPLANATION)}`);
51
+ }
52
+ const priorities = topPriorities(report);
53
+ if (!options.verbose && priorities.length > 0) {
54
+ lines.push('');
55
+ lines.push(c.bold('Top priorities'));
56
+ priorities.forEach(({ check, finding }, index) => {
57
+ lines.push(` ${index + 1}. ${severityTag(finding.severity)} ${code(finding.message)} ${c.dim(`(${check.title})`)}`);
58
+ const [first] = finding.files ?? [];
59
+ const total = finding.count ?? finding.files?.length ?? 0;
60
+ if (first)
61
+ lines.push(` ${c.gray(`${formatLocation(first)}${total > 1 ? ` and ${formatCount(total - 1)} more` : ''}`)}`);
62
+ });
63
+ }
64
+ if (!options.verbose) {
65
+ lines.push('');
66
+ lines.push(c.dim('Every finding with its files: --verbose, or write a report with --report checkup.html (also .md, .json).'));
67
+ }
68
+ return lines.join('\n');
69
+ }
70
+ //# sourceMappingURL=terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal.js","sourceRoot":"","sources":["../../src/report/terminal.ts"],"names":[],"mappings":"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"}
package/dist/scan.d.ts ADDED
@@ -0,0 +1,119 @@
1
+ /** One name brought in by an import or re-export. */
2
+ export interface ImportBinding {
3
+ /** The name the module exports. `default` for a default import, `*` for a namespace import. */
4
+ imported: string;
5
+ /** The name it is bound to in this file. */
6
+ local: string;
7
+ typeOnly: boolean;
8
+ }
9
+ /** One `import`, `export … from` or dynamic `import()` in a source file. */
10
+ export interface ImportFact {
11
+ specifier: string;
12
+ line: number;
13
+ /**
14
+ * True for `import type`, and for a named import whose every binding is
15
+ * `type`. Such an import is erased at compile time, so it cannot take part in
16
+ * a runtime cycle and the dependency graph ignores it.
17
+ */
18
+ typeOnly: boolean;
19
+ /** `import()` loads lazily and does not form an eager cycle either. */
20
+ dynamic: boolean;
21
+ /** Empty for a side-effect import (`import 'zone.js'`) and for `export * from`. */
22
+ bindings: ImportBinding[];
23
+ }
24
+ /** One `@Component` class. */
25
+ export interface ComponentFact {
26
+ name: string;
27
+ line: number;
28
+ /**
29
+ * The literal value of `standalone` in the decorator, undefined when absent.
30
+ * What an absent flag means depends on the Angular version (standalone is the
31
+ * default from v19), which is why the scanner records only what is written
32
+ * and the components check interprets it.
33
+ */
34
+ standalone?: boolean;
35
+ /**
36
+ * The strategy named in `changeDetection`, undefined when absent. Like
37
+ * `standalone`, the default changed (OnPush from v22), so an absent value is
38
+ * interpreted by the check that knows the version.
39
+ */
40
+ changeDetection?: string;
41
+ }
42
+ /** Control-flow and escape-hatch counts for one template, inline or external. */
43
+ export interface TemplateStats {
44
+ ngIf: number;
45
+ ngFor: number;
46
+ ngSwitch: number;
47
+ ifBlocks: number;
48
+ forBlocks: number;
49
+ switchBlocks: number;
50
+ deferBlocks: number;
51
+ /** `$any(...)`, the template's way of switching type checking off for one expression. */
52
+ anyCasts: number;
53
+ }
54
+ /** A template and where its first legacy structural directive sits, for report examples. */
55
+ export interface TemplateFact {
56
+ path: string;
57
+ /** True for a `template:` string inside a component file. */
58
+ inline: boolean;
59
+ stats: TemplateStats;
60
+ /** 1-based line of the first `*ngIf`/`*ngFor`/`[ngSwitch]`, undefined when there is none. */
61
+ firstLegacyLine?: number;
62
+ }
63
+ /** Everything the checks need from one TypeScript file, gathered in a single AST pass. */
64
+ export interface SourceFileFacts {
65
+ /** Report path: relative to the root, `/`-separated. */
66
+ path: string;
67
+ absolutePath: string;
68
+ isSpec: boolean;
69
+ /** Non-blank lines. */
70
+ linesOfCode: number;
71
+ imports: ImportFact[];
72
+ components: ComponentFact[];
73
+ ngModules: number;
74
+ injectables: number;
75
+ /** `@Input()` decorators on properties and setters. */
76
+ decoratorInputs: number;
77
+ /** `@Output()` decorators. */
78
+ decoratorOutputs: number;
79
+ /**
80
+ * Calls of imported functions, keyed `module#name` (`@angular/core#signal`)
81
+ * or `module#name.member` for calls such as `input.required()`. Values are the
82
+ * 1-based lines of each call. Resolving through the imports is what keeps a
83
+ * local helper that happens to be called `signal` out of the signal count.
84
+ */
85
+ calls: Map<string, number[]>;
86
+ /** `new X()` of an imported class, keyed like `calls`. */
87
+ constructions: Map<string, number[]>;
88
+ /** `X.member` on an imported binding, keyed `module#X.member`. Used for deprecated enum members. */
89
+ memberAccesses: Map<string, number[]>;
90
+ /**
91
+ * Calls of test-framework globals that are never imported: `spyOn` and
92
+ * `jasmine.*` for Jasmine. Each one is a line to rewrite when moving to Vitest
93
+ * or Jest, which is what the testing check reports them for.
94
+ */
95
+ jasmineCalls: number;
96
+ /** Lines of every `any` type annotation or `as any`. */
97
+ anyLines: number[];
98
+ /** Lines of every `x!` non-null assertion. */
99
+ nonNullLines: number[];
100
+ /** `x!: T` property declarations, which skip definite-assignment checking. */
101
+ definiteAssignments: number;
102
+ /** `@ts-ignore`, `@ts-expect-error` and `@ts-nocheck` comments. */
103
+ typeSuppressions: number;
104
+ /** `templateUrl`/`template` is resolved by the template scan; inline templates are collected here. */
105
+ inlineTemplates: TemplateFact[];
106
+ }
107
+ /**
108
+ * Parses one file and extracts its facts. Parsing is syntax-only (no type
109
+ * checker, no program), which is what lets a 3 000-file repository finish in
110
+ * seconds and lets the tool run without the project's dependencies installed.
111
+ * The cost is that identifiers are matched by their import, never by type.
112
+ */
113
+ export declare function scanSourceFile(root: string, absolutePath: string): SourceFileFacts;
114
+ /** Counts control flow in one template's text. */
115
+ export declare function scanTemplate(text: string): TemplateStats;
116
+ /** Character offset of the first legacy structural directive in a template, or undefined. */
117
+ export declare function firstLegacyOffset(text: string): number | undefined;
118
+ /** Scans an external template file. */
119
+ export declare function scanTemplateFile(root: string, absolutePath: string): TemplateFact;
package/dist/scan.js ADDED
@@ -0,0 +1,270 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import ts from 'typescript';
3
+ import { isSpecFile, toReportPath } from './files.js';
4
+ /**
5
+ * Parses one file and extracts its facts. Parsing is syntax-only (no type
6
+ * checker, no program), which is what lets a 3 000-file repository finish in
7
+ * seconds and lets the tool run without the project's dependencies installed.
8
+ * The cost is that identifiers are matched by their import, never by type.
9
+ */
10
+ export function scanSourceFile(root, absolutePath) {
11
+ const text = readFileSync(absolutePath, 'utf8');
12
+ const source = ts.createSourceFile(absolutePath, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
13
+ const path = toReportPath(root, absolutePath);
14
+ const facts = {
15
+ path,
16
+ absolutePath,
17
+ isSpec: isSpecFile(absolutePath),
18
+ linesOfCode: countLinesOfCode(text),
19
+ imports: [],
20
+ components: [],
21
+ ngModules: 0,
22
+ injectables: 0,
23
+ decoratorInputs: 0,
24
+ decoratorOutputs: 0,
25
+ calls: new Map(),
26
+ constructions: new Map(),
27
+ memberAccesses: new Map(),
28
+ jasmineCalls: 0,
29
+ anyLines: [],
30
+ nonNullLines: [],
31
+ definiteAssignments: 0,
32
+ typeSuppressions: (text.match(/@ts-(ignore|expect-error|nocheck)\b/g) ?? []).length,
33
+ inlineTemplates: [],
34
+ };
35
+ /** Imported bindings by local name: what `signal` in this file actually refers to. */
36
+ const locals = new Map();
37
+ for (const statement of source.statements) {
38
+ const fact = importFactOf(statement, source);
39
+ if (!fact)
40
+ continue;
41
+ facts.imports.push(fact);
42
+ for (const binding of fact.bindings)
43
+ locals.set(binding.local, { module: fact.specifier, imported: binding.imported });
44
+ }
45
+ const lineOf = (node) => source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
46
+ /** `module#name` for an identifier bound by an import, undefined for anything local or global. */
47
+ const keyOf = (expression) => {
48
+ if (ts.isIdentifier(expression)) {
49
+ const binding = locals.get(expression.text);
50
+ return binding && binding.imported !== '*' ? `${binding.module}#${binding.imported}` : undefined;
51
+ }
52
+ if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression)) {
53
+ const binding = locals.get(expression.expression.text);
54
+ if (!binding)
55
+ return undefined;
56
+ // `core.signal()` on a namespace import is `signal`; `input.required()` on a named import is `input.required`.
57
+ return binding.imported === '*' ? `${binding.module}#${expression.name.text}` : `${binding.module}#${binding.imported}.${expression.name.text}`;
58
+ }
59
+ return undefined;
60
+ };
61
+ const record = (map, key, line) => {
62
+ const lines = map.get(key);
63
+ if (lines)
64
+ lines.push(line);
65
+ else
66
+ map.set(key, [line]);
67
+ };
68
+ const visit = (node) => {
69
+ if (ts.isCallExpression(node)) {
70
+ const key = keyOf(node.expression);
71
+ if (key)
72
+ record(facts.calls, key, lineOf(node));
73
+ else if (isJasmineGlobalCall(node.expression, locals))
74
+ facts.jasmineCalls++;
75
+ if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {
76
+ const [argument] = node.arguments;
77
+ if (argument && ts.isStringLiteralLike(argument)) {
78
+ facts.imports.push({ specifier: argument.text, line: lineOf(node), typeOnly: false, dynamic: true, bindings: [] });
79
+ }
80
+ }
81
+ }
82
+ else if (ts.isNewExpression(node)) {
83
+ const key = keyOf(node.expression);
84
+ if (key)
85
+ record(facts.constructions, key, lineOf(node));
86
+ }
87
+ else if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
88
+ const binding = locals.get(node.expression.text);
89
+ if (binding && binding.imported !== '*')
90
+ record(facts.memberAccesses, `${binding.module}#${binding.imported}.${node.name.text}`, lineOf(node));
91
+ }
92
+ else if (node.kind === ts.SyntaxKind.AnyKeyword) {
93
+ facts.anyLines.push(lineOf(node));
94
+ }
95
+ else if (ts.isNonNullExpression(node)) {
96
+ facts.nonNullLines.push(lineOf(node));
97
+ }
98
+ else if (ts.isPropertyDeclaration(node) && node.exclamationToken) {
99
+ facts.definiteAssignments++;
100
+ }
101
+ if (ts.isClassDeclaration(node))
102
+ visitClassDecorators(node);
103
+ if ((ts.isPropertyDeclaration(node) || ts.isSetAccessorDeclaration(node) || ts.isGetAccessorDeclaration(node)) && ts.canHaveDecorators(node)) {
104
+ for (const decorator of ts.getDecorators(node) ?? []) {
105
+ const key = decoratorKey(decorator);
106
+ if (key === '@angular/core#Input')
107
+ facts.decoratorInputs++;
108
+ else if (key === '@angular/core#Output')
109
+ facts.decoratorOutputs++;
110
+ }
111
+ }
112
+ ts.forEachChild(node, visit);
113
+ };
114
+ /** `module#Name` of a decorator such as `@Component({...})`, resolved through the imports. */
115
+ const decoratorKey = (decorator) => {
116
+ const expression = ts.isCallExpression(decorator.expression) ? decorator.expression.expression : decorator.expression;
117
+ return keyOf(expression);
118
+ };
119
+ const visitClassDecorators = (node) => {
120
+ for (const decorator of ts.getDecorators(node) ?? []) {
121
+ const key = decoratorKey(decorator);
122
+ if (key === '@angular/core#NgModule')
123
+ facts.ngModules++;
124
+ else if (key === '@angular/core#Injectable')
125
+ facts.injectables++;
126
+ else if (key === '@angular/core#Component') {
127
+ const metadata = ts.isCallExpression(decorator.expression) ? decorator.expression.arguments[0] : undefined;
128
+ const component = { name: node.name?.text ?? '(anonymous)', line: lineOf(node) };
129
+ if (metadata && ts.isObjectLiteralExpression(metadata)) {
130
+ for (const property of metadata.properties) {
131
+ if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name))
132
+ continue;
133
+ const value = property.initializer;
134
+ if (property.name.text === 'standalone') {
135
+ if (value.kind === ts.SyntaxKind.TrueKeyword)
136
+ component.standalone = true;
137
+ else if (value.kind === ts.SyntaxKind.FalseKeyword)
138
+ component.standalone = false;
139
+ }
140
+ else if (property.name.text === 'changeDetection' && ts.isPropertyAccessExpression(value)) {
141
+ component.changeDetection = value.name.text;
142
+ }
143
+ else if (property.name.text === 'template') {
144
+ const template = templateTextOf(value);
145
+ if (template !== undefined) {
146
+ const stats = scanTemplate(template.text);
147
+ const legacyOffset = firstLegacyOffset(template.text);
148
+ facts.inlineTemplates.push({
149
+ path,
150
+ inline: true,
151
+ stats,
152
+ firstLegacyLine: legacyOffset === undefined ? undefined : source.getLineAndCharacterOfPosition(template.start + legacyOffset).line + 1,
153
+ });
154
+ }
155
+ }
156
+ }
157
+ }
158
+ facts.components.push(component);
159
+ }
160
+ }
161
+ };
162
+ visit(source);
163
+ return facts;
164
+ }
165
+ /** Turns an import or re-export statement into an `ImportFact`; undefined for any other statement. */
166
+ function importFactOf(statement, source) {
167
+ const line = source.getLineAndCharacterOfPosition(statement.getStart(source)).line + 1;
168
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteralLike(statement.moduleSpecifier)) {
169
+ const clause = statement.importClause;
170
+ const bindings = [];
171
+ const clauseTypeOnly = clause?.isTypeOnly ?? false;
172
+ if (clause?.name)
173
+ bindings.push({ imported: 'default', local: clause.name.text, typeOnly: clauseTypeOnly });
174
+ const named = clause?.namedBindings;
175
+ if (named && ts.isNamespaceImport(named))
176
+ bindings.push({ imported: '*', local: named.name.text, typeOnly: clauseTypeOnly });
177
+ if (named && ts.isNamedImports(named)) {
178
+ for (const element of named.elements) {
179
+ bindings.push({ imported: (element.propertyName ?? element.name).text, local: element.name.text, typeOnly: clauseTypeOnly || element.isTypeOnly });
180
+ }
181
+ }
182
+ return {
183
+ specifier: statement.moduleSpecifier.text,
184
+ line,
185
+ typeOnly: clauseTypeOnly || (bindings.length > 0 && bindings.every((binding) => binding.typeOnly)),
186
+ dynamic: false,
187
+ bindings,
188
+ };
189
+ }
190
+ if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteralLike(statement.moduleSpecifier)) {
191
+ const clause = statement.exportClause;
192
+ const bindings = clause && ts.isNamedExports(clause)
193
+ ? clause.elements.map((element) => ({
194
+ imported: (element.propertyName ?? element.name).text,
195
+ // A re-export binds nothing locally; the empty name keeps it out of the local lookup.
196
+ local: '',
197
+ typeOnly: statement.isTypeOnly || element.isTypeOnly,
198
+ }))
199
+ : [];
200
+ return {
201
+ specifier: statement.moduleSpecifier.text,
202
+ line,
203
+ typeOnly: statement.isTypeOnly || (bindings.length > 0 && bindings.every((binding) => binding.typeOnly)),
204
+ dynamic: false,
205
+ bindings,
206
+ };
207
+ }
208
+ return undefined;
209
+ }
210
+ /**
211
+ * True for `spyOn(...)` and `jasmine.x(...)` when neither name is imported. An
212
+ * imported `spyOn` (some Vitest setups re-export one) is not Jasmine.
213
+ */
214
+ function isJasmineGlobalCall(expression, locals) {
215
+ if (ts.isIdentifier(expression))
216
+ return (expression.text === 'spyOn' || expression.text === 'spyOnProperty') && !locals.has(expression.text);
217
+ return ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === 'jasmine' && !locals.has('jasmine');
218
+ }
219
+ /**
220
+ * The text of an inline template and the offset of its first character in the
221
+ * file. For a template literal with `${}` substitutions only the literal parts
222
+ * are kept, which is enough for counting control flow and rare in practice.
223
+ */
224
+ function templateTextOf(value) {
225
+ if (ts.isStringLiteral(value) || ts.isNoSubstitutionTemplateLiteral(value))
226
+ return { text: value.text, start: value.getStart() + 1 };
227
+ if (ts.isTemplateExpression(value)) {
228
+ return { text: [value.head.text, ...value.templateSpans.map((span) => span.literal.text)].join(' '), start: value.getStart() + 1 };
229
+ }
230
+ return undefined;
231
+ }
232
+ /** Counts control flow in one template's text. */
233
+ export function scanTemplate(text) {
234
+ const count = (pattern) => (text.match(pattern) ?? []).length;
235
+ return {
236
+ ngIf: count(/\*ngIf\s*=|\[ngIf\]\s*=/g),
237
+ ngFor: count(/\*ngFor\s*=|\[ngForOf\]\s*=/g),
238
+ ngSwitch: count(/\[ngSwitch\]\s*=/g),
239
+ ifBlocks: count(/@if\s*\(/g),
240
+ forBlocks: count(/@for\s*\(/g),
241
+ switchBlocks: count(/@switch\s*\(/g),
242
+ deferBlocks: count(/@defer\b/g),
243
+ anyCasts: count(/\$any\s*\(/g),
244
+ };
245
+ }
246
+ /** Character offset of the first legacy structural directive in a template, or undefined. */
247
+ export function firstLegacyOffset(text) {
248
+ const match = /\*ngIf\s*=|\[ngIf\]\s*=|\*ngFor\s*=|\[ngForOf\]\s*=|\[ngSwitch\]\s*=/.exec(text);
249
+ return match?.index;
250
+ }
251
+ /** Scans an external template file. */
252
+ export function scanTemplateFile(root, absolutePath) {
253
+ const text = readFileSync(absolutePath, 'utf8');
254
+ const offset = firstLegacyOffset(text);
255
+ return {
256
+ path: toReportPath(root, absolutePath),
257
+ inline: false,
258
+ stats: scanTemplate(text),
259
+ firstLegacyLine: offset === undefined ? undefined : text.slice(0, offset).split('\n').length,
260
+ };
261
+ }
262
+ /** Non-blank lines, the figure a reader expects behind "lines of code". */
263
+ function countLinesOfCode(text) {
264
+ let count = 0;
265
+ for (const line of text.split('\n'))
266
+ if (line.trim() !== '')
267
+ count++;
268
+ return count;
269
+ }
270
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}