@invariant-ui/cli 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 (190) hide show
  1. package/LICENSE +105 -0
  2. package/README.md +250 -2
  3. package/dist/agent-kit/apply.js +232 -0
  4. package/dist/agent-kit/guidance.js +236 -0
  5. package/dist/agent-kit/index.js +5 -0
  6. package/dist/agent-kit/integrations.js +121 -0
  7. package/dist/agent-kit/plugin.js +115 -0
  8. package/dist/artifact-generator/index.js +75 -0
  9. package/dist/browser-verify/driver.js +2 -0
  10. package/dist/browser-verify/index.js +4 -0
  11. package/dist/browser-verify/playwright.js +82 -0
  12. package/dist/browser-verify/runner.js +175 -0
  13. package/dist/browser-verify/spec.js +103 -0
  14. package/dist/cli/args.js +77 -0
  15. package/dist/cli/baseline.js +64 -0
  16. package/dist/cli/cli.js +121 -0
  17. package/dist/cli/commands-browser.js +104 -0
  18. package/dist/cli/commands-discover.js +312 -0
  19. package/dist/cli/commands-enforcement.js +35 -0
  20. package/dist/cli/commands-governance.js +179 -0
  21. package/dist/cli/commands-hook.js +269 -0
  22. package/dist/cli/commands-patterns.js +324 -0
  23. package/dist/cli/commands-setup.js +485 -0
  24. package/dist/cli/commands-validate.js +157 -0
  25. package/dist/cli/commands.js +517 -0
  26. package/dist/cli/config.js +197 -0
  27. package/dist/cli/diff.js +66 -0
  28. package/dist/cli/enforcement-log.js +83 -0
  29. package/dist/cli/enforcement-report.js +96 -0
  30. package/dist/cli/errors.js +10 -0
  31. package/dist/cli/format.js +22 -0
  32. package/dist/cli/index.js +5 -0
  33. package/dist/cli/io.js +2 -0
  34. package/dist/cli/main.js +31 -0
  35. package/dist/cli/pipeline.js +262 -0
  36. package/dist/cli/publish.js +77 -0
  37. package/dist/cli/report.js +127 -0
  38. package/dist/cli/starter-rules.js +57 -0
  39. package/dist/cli/store.js +60 -0
  40. package/dist/cli/version.js +5 -0
  41. package/dist/cli/watch.js +68 -0
  42. package/dist/cli/workflow.js +52 -0
  43. package/dist/compiler-angular/adapter.js +115 -0
  44. package/dist/compiler-angular/analyze.js +222 -0
  45. package/dist/compiler-angular/classes.js +446 -0
  46. package/dist/compiler-angular/declared.js +285 -0
  47. package/dist/compiler-angular/emit.js +183 -0
  48. package/dist/compiler-angular/index.js +4 -0
  49. package/dist/compiler-angular/template.js +142 -0
  50. package/dist/compiler-core/adapter.js +2 -0
  51. package/dist/compiler-core/adapters/inventory.js +312 -0
  52. package/dist/compiler-core/compile.js +148 -0
  53. package/dist/compiler-core/component-facts.js +123 -0
  54. package/dist/compiler-core/discovery/docs.js +66 -0
  55. package/dist/compiler-core/discovery/entries.js +270 -0
  56. package/dist/compiler-core/discovery/exports.js +207 -0
  57. package/dist/compiler-core/discovery/graph.js +59 -0
  58. package/dist/compiler-core/discovery/index.js +103 -0
  59. package/dist/compiler-core/discovery/packages.js +148 -0
  60. package/dist/compiler-core/discovery/schema.js +144 -0
  61. package/dist/compiler-core/discovery/storybook.js +232 -0
  62. package/dist/compiler-core/discovery/support.js +82 -0
  63. package/dist/compiler-core/discovery/tokens.js +186 -0
  64. package/dist/compiler-core/discovery/tooling.js +146 -0
  65. package/dist/compiler-core/fs.js +89 -0
  66. package/dist/compiler-core/glob.js +3 -0
  67. package/dist/compiler-core/index.js +16 -0
  68. package/dist/compiler-core/ir-builder.js +68 -0
  69. package/dist/compiler-core/json-schema.js +11 -0
  70. package/dist/compiler-core/testing/index.js +81 -0
  71. package/dist/compiler-core/ts/ast.js +166 -0
  72. package/dist/compiler-core/ts/members.js +163 -0
  73. package/dist/compiler-core/ts/program.js +81 -0
  74. package/dist/compiler-core/ts/static-eval.js +145 -0
  75. package/dist/compiler-core/ts/tsconfig-paths.js +60 -0
  76. package/dist/compiler-core/walk.js +46 -0
  77. package/dist/compiler-ir/index.js +4 -0
  78. package/dist/compiler-ir/ir.js +67 -0
  79. package/dist/compiler-ir/json-schema.js +6 -0
  80. package/dist/compiler-ir/validate.js +116 -0
  81. package/dist/compiler-react/adapter.js +147 -0
  82. package/dist/compiler-react/analyze.js +199 -0
  83. package/dist/compiler-react/behavior.js +75 -0
  84. package/dist/compiler-react/detect.js +558 -0
  85. package/dist/compiler-react/emit.js +188 -0
  86. package/dist/compiler-react/index.js +2 -0
  87. package/dist/compiler-react/props.js +157 -0
  88. package/dist/compiler-react/styling.js +138 -0
  89. package/dist/compiler-react/usage.js +116 -0
  90. package/dist/compiler-react/variants.js +111 -0
  91. package/dist/compiler-storybook/adapter.js +253 -0
  92. package/dist/compiler-storybook/csf.js +521 -0
  93. package/dist/compiler-storybook/emit.js +202 -0
  94. package/dist/compiler-storybook/index-json.js +41 -0
  95. package/dist/compiler-storybook/index.js +5 -0
  96. package/dist/compiler-storybook/mdx.js +120 -0
  97. package/dist/compiler-tokens/adapter.js +158 -0
  98. package/dist/compiler-tokens/css.js +59 -0
  99. package/dist/compiler-tokens/index.js +5 -0
  100. package/dist/compiler-tokens/json-lines.js +106 -0
  101. package/dist/compiler-tokens/json-tokens.js +52 -0
  102. package/dist/compiler-vue/adapter.js +107 -0
  103. package/dist/compiler-vue/analyze.js +344 -0
  104. package/dist/compiler-vue/declared.js +343 -0
  105. package/dist/compiler-vue/emit.js +129 -0
  106. package/dist/compiler-vue/index.js +5 -0
  107. package/dist/compiler-vue/script.js +472 -0
  108. package/dist/compiler-vue/sfc.js +44 -0
  109. package/dist/compiler-vue/template.js +73 -0
  110. package/dist/contract/archetype-checks.js +153 -0
  111. package/dist/contract/components.js +102 -0
  112. package/dist/contract/conflicts.js +39 -0
  113. package/dist/contract/contract.js +46 -0
  114. package/dist/contract/evidence.js +84 -0
  115. package/dist/contract/fact-path.js +39 -0
  116. package/dist/contract/facts.js +62 -0
  117. package/dist/contract/index.js +16 -0
  118. package/dist/contract/integrity.js +21 -0
  119. package/dist/contract/json-schema.js +11 -0
  120. package/dist/contract/knowledge.js +95 -0
  121. package/dist/contract/pattern-checks.js +254 -0
  122. package/dist/contract/patterns.js +225 -0
  123. package/dist/contract/primitives.js +81 -0
  124. package/dist/contract/sources.js +30 -0
  125. package/dist/contract/tokens.js +41 -0
  126. package/dist/contract/validate.js +253 -0
  127. package/dist/contract-query/archetype.js +188 -0
  128. package/dist/contract-query/index.js +6 -0
  129. package/dist/contract-query/patterns.js +298 -0
  130. package/dist/contract-query/search.js +132 -0
  131. package/dist/contract-query/system.js +148 -0
  132. package/dist/contract-query/views.js +288 -0
  133. package/dist/governance/decisions.js +229 -0
  134. package/dist/governance/index.js +5 -0
  135. package/dist/governance/patterns-file.js +156 -0
  136. package/dist/governance/patterns.js +510 -0
  137. package/dist/governance/policies.js +148 -0
  138. package/dist/mcp/index.js +7 -0
  139. package/dist/mcp/loader.js +70 -0
  140. package/dist/mcp/protocol.js +27 -0
  141. package/dist/mcp/resources.js +138 -0
  142. package/dist/mcp/server.js +177 -0
  143. package/dist/mcp/stdio.js +28 -0
  144. package/dist/mcp/tools.js +267 -0
  145. package/dist/reconciliation/code.js +62 -0
  146. package/dist/reconciliation/components.js +401 -0
  147. package/dist/reconciliation/conflicts.js +126 -0
  148. package/dist/reconciliation/facts.js +41 -0
  149. package/dist/reconciliation/index.js +7 -0
  150. package/dist/reconciliation/reconcile.js +134 -0
  151. package/dist/reconciliation/resolve.js +158 -0
  152. package/dist/reconciliation/review.js +81 -0
  153. package/dist/reconciliation/storybook.js +370 -0
  154. package/dist/reconciliation/tokens.js +179 -0
  155. package/dist/reconciliation/util.js +55 -0
  156. package/dist/semantic-engine/additive.js +51 -0
  157. package/dist/semantic-engine/compounds.js +91 -0
  158. package/dist/semantic-engine/documents.js +157 -0
  159. package/dist/semantic-engine/enrich.js +42 -0
  160. package/dist/semantic-engine/index.js +7 -0
  161. package/dist/semantic-engine/infer.js +38 -0
  162. package/dist/semantic-engine/tokens.js +120 -0
  163. package/dist/shared/canonical.js +65 -0
  164. package/dist/shared/diagnostic.js +78 -0
  165. package/dist/shared/glob.js +98 -0
  166. package/dist/shared/index.js +4 -0
  167. package/dist/shared/json.js +2 -0
  168. package/dist/validation/card.js +50 -0
  169. package/dist/validation/discovery/arrangements.js +162 -0
  170. package/dist/validation/discovery/discover.js +70 -0
  171. package/dist/validation/discovery/index.js +8 -0
  172. package/dist/validation/discovery/model.js +127 -0
  173. package/dist/validation/discovery/promote.js +24 -0
  174. package/dist/validation/discovery/reviews.js +63 -0
  175. package/dist/validation/discovery/shapes.js +47 -0
  176. package/dist/validation/discovery/similar-files.js +146 -0
  177. package/dist/validation/discovery/util.js +47 -0
  178. package/dist/validation/index.js +11 -0
  179. package/dist/validation/interaction-facts.js +341 -0
  180. package/dist/validation/interaction-workflows.js +633 -0
  181. package/dist/validation/literals.js +251 -0
  182. package/dist/validation/pattern-rules.js +608 -0
  183. package/dist/validation/policy.js +241 -0
  184. package/dist/validation/report.js +163 -0
  185. package/dist/validation/rules.js +269 -0
  186. package/dist/validation/scan.js +295 -0
  187. package/dist/validation/text.js +34 -0
  188. package/dist/validation/validate-code.js +513 -0
  189. package/dist/validation/validate-usage.js +196 -0
  190. package/package.json +38 -4
@@ -0,0 +1,52 @@
1
+ import { CLI_VERSION, NPM_PACKAGE } from "./version.js";
2
+ export const WORKFLOW_PATH = ".github/workflows/invariant.yml";
3
+ /**
4
+ * Steps that install a project's dependencies, for a project that gets its contract from a package. The package manager
5
+ * is the one the lockfile says. Returns steps already indented for the workflow.
6
+ */
7
+ export function installStepsFor(has) {
8
+ if (has("pnpm-lock.yaml"))
9
+ return [" - uses: pnpm/action-setup@v4", " - run: pnpm install --frozen-lockfile"];
10
+ if (has("yarn.lock"))
11
+ return [" - run: yarn install --frozen-lockfile"];
12
+ if (has("package-lock.json"))
13
+ return [" - run: npm ci"];
14
+ return [" - run: npm install"];
15
+ }
16
+ /**
17
+ * The GitHub Actions job `setup` offers to add. It runs on every pull request commit, pins the exact version it was
18
+ * written for so a later release cannot change what CI does, and needs only Node: npx fetches the package. Paths are
19
+ * quoted, since they come from the project's folder names.
20
+ */
21
+ export function workflowYaml(paths, installSteps = []) {
22
+ const targets = (paths.length > 0 ? paths : ["src"]).map((p) => `'${p.replace(/'/g, "''")}'`).join(" ");
23
+ const run = `npx ${NPM_PACKAGE}@${CLI_VERSION}`;
24
+ return `# Added by \`invariant setup\`. Checks every commit on a pull request against your design system contract.
25
+ name: Invariant
26
+ on:
27
+ pull_request:
28
+ types: [opened, synchronize, reopened]
29
+ push:
30
+ branches: [main]
31
+ permissions:
32
+ contents: read
33
+ concurrency:
34
+ group: invariant-\${{ github.ref }}
35
+ cancel-in-progress: true
36
+ jobs:
37
+ invariant:
38
+ runs-on: ubuntu-latest
39
+ steps:
40
+ - uses: actions/checkout@v4
41
+ - uses: actions/setup-node@v4
42
+ with:
43
+ node-version: 22
44
+ ${installSteps.length > 0 ? `${installSteps.join("\n")}\n` : ""} # Fails if the committed contract (the invariant/ folder) is stale or was edited by hand.
45
+ - name: Verify the contract is current
46
+ run: ${run} verify --fresh
47
+ # Annotates the pull request. Violations listed in invariant.baseline.json are hidden; new ones fail the check.
48
+ - name: Validate code against the contract
49
+ run: ${run} validate ${targets} --format github
50
+ `;
51
+ }
52
+ //# sourceMappingURL=workflow.js.map
@@ -0,0 +1,115 @@
1
+ import { DEFAULT_IGNORED_DIRS, hashText, IrBuilder, walk } from "../compiler-core/index.js";
2
+ import { hashJson } from "../shared/index.js";
3
+ import { analyzePackage } from "./analyze.js";
4
+ import { CAPABILITIES, emitComponent, emitModule } from "./emit.js";
5
+ export const ADAPTER_ID = "angular";
6
+ export const ADAPTER_VERSION = "0.1.0";
7
+ const SOURCE_FILE = /\.(?:[cm]?[jt]sx?|html|css|scss|sass|less)$|(?:^|\/)tsconfig[^/]*\.json$/;
8
+ const MAX_FILE_BYTES = 1_000_000;
9
+ /**
10
+ * Angular adapter. For every workspace package that declares `@angular/core` it reads decorated classes
11
+ * with the TypeScript API (what the Angular compiler reads from decorators, evaluated statically):
12
+ * components and directives, decorator and signal inputs and outputs, `model()`, selectors, standalone
13
+ * metadata and imports, content projection, host bindings, templates and styles, and NgModules.
14
+ * Nothing is executed. `node_modules` is read only for a package opted in as a declaration root, from its `.d.ts` files.
15
+ */
16
+ export const angularAdapter = {
17
+ id: ADAPTER_ID,
18
+ version: ADAPTER_VERSION,
19
+ type: "angular",
20
+ async discover({ fs, project }) {
21
+ const sources = [];
22
+ const used = new Set();
23
+ for (const pkg of project.packages.filter((p) => p.frameworks.some((f) => f.name === "angular"))) {
24
+ const others = project.packages.filter((p) => p.id !== pkg.id && p.dir !== "." && (pkg.dir === "." || p.dir.startsWith(`${pkg.dir}/`)));
25
+ const { files, hashes } = await readPackageFiles(fs, pkg, others);
26
+ const slug = (pkg.name ?? pkg.dir)
27
+ .toLowerCase()
28
+ .replace(/[^a-z0-9._-]+/g, "-")
29
+ .replace(/^[^a-z0-9]+|[-.]+$/g, "") || "root";
30
+ let id = `angular-${slug}`;
31
+ for (let n = 2; used.has(id); n++)
32
+ id = `angular-${slug}-${n}`;
33
+ used.add(id);
34
+ sources.push({
35
+ id,
36
+ type: "angular",
37
+ location: pkg.dir,
38
+ config: { packageId: pkg.id, files: [...files.keys()] },
39
+ ...(pkg.version ? { version: { kind: "package-version", value: pkg.version } } : {}),
40
+ inputHash: hashJson(hashes)
41
+ });
42
+ }
43
+ return { sources, diagnostics: [] };
44
+ },
45
+ async extract({ fs, project, source, clock }, config) {
46
+ const pkg = project.packages.find((p) => p.id === config.packageId);
47
+ if (!pkg)
48
+ throw new Error(`Package ${config.packageId} is not in the project discovery`);
49
+ const files = new Map();
50
+ for (const path of config.files)
51
+ files.set(path, await fs.readFile(path));
52
+ const analysis = analyzePackage({
53
+ ...(pkg.name ? { packageName: pkg.name } : {}),
54
+ packageDir: pkg.dir,
55
+ entryPoints: pkg.entryPoints,
56
+ files
57
+ });
58
+ const builder = new IrBuilder({
59
+ source: {
60
+ id: source.id,
61
+ type: source.type,
62
+ location: source.location,
63
+ ...(source.version ? { version: source.version } : {}),
64
+ inputHash: source.inputHash,
65
+ adapter: { name: ADAPTER_ID, version: ADAPTER_VERSION }
66
+ },
67
+ extractor: { name: "angular-ts", version: ADAPTER_VERSION },
68
+ capabilities: CAPABILITIES,
69
+ clock
70
+ });
71
+ for (const component of analysis.components)
72
+ emitComponent(builder, component, pkg);
73
+ for (const module of analysis.modules)
74
+ emitModule(builder, module);
75
+ for (const d of analysis.diagnostics)
76
+ builder.diagnostic(d);
77
+ return { ir: builder.build(analysis.components.some((c) => !c.propsComplete) ? "partial" : "complete") };
78
+ },
79
+ async validate({ ir }) {
80
+ return !ir.entities.some((e) => e.kind === "component")
81
+ ? [
82
+ {
83
+ code: "angular.no-components",
84
+ severity: "info",
85
+ message: `No Angular components or directives were found in the entry points of ${ir.source.id}`,
86
+ sourceId: ir.source.id
87
+ }
88
+ ]
89
+ : [];
90
+ }
91
+ };
92
+ async function readPackageFiles(fs, pkg, nested) {
93
+ // An installed package (opted in through a declaration root) keeps its declaration files in build output.
94
+ const installed = pkg.dir.split("/").includes("node_modules");
95
+ const walked = await walk(fs, {
96
+ ignoreDirs: new Set(installed
97
+ ? DEFAULT_IGNORED_DIRS.filter((d) => !["dist", "build", "out"].includes(d))
98
+ : DEFAULT_IGNORED_DIRS),
99
+ maxFiles: 20_000,
100
+ start: pkg.dir
101
+ });
102
+ const files = new Map();
103
+ const hashes = [];
104
+ for (const path of walked.files) {
105
+ if (!SOURCE_FILE.test(path) || nested.some((n) => path === n.dir || path.startsWith(`${n.dir}/`)))
106
+ continue;
107
+ const text = await fs.readFile(path);
108
+ if (text.length > MAX_FILE_BYTES)
109
+ continue;
110
+ files.set(path, text);
111
+ hashes.push([path, hashText(text)]);
112
+ }
113
+ return { files, hashes };
114
+ }
115
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1,222 @@
1
+ import { createAnalysis, cssVariableReferences, declarationOf, isProjectNode, posix, resolveSymbol, tsconfigPaths } from "../compiler-core/index.js";
2
+ import ts from "typescript";
3
+ import { readClass } from "./classes.js";
4
+ import { readDeclaredClass } from "./declared.js";
5
+ import { matchesSelector, parseSelector, scanTemplate } from "./template.js";
6
+ const NON_SOURCE = /\.(?:test|spec|stories)\.[cm]?[jt]sx?$|(?:^|\/)__(?:tests|mocks)__\//;
7
+ /** Public components and directives (class exports of the entry points) plus every NgModule, read statically. */
8
+ export function analyzePackage(input) {
9
+ const diagnostics = [];
10
+ const note = (severity, code, message, location) => {
11
+ diagnostics.push({ code, severity, message, ...(location ? { location } : {}) });
12
+ };
13
+ const codeFiles = new Map([...input.files].filter(([path]) => /\.[cm]?[jt]sx?$/.test(path) && !NON_SOURCE.test(path)));
14
+ // A library imports its own entry points by package name (`@scope/lib/accordion`): map those to files.
15
+ const paths = { ...tsconfigPaths(input.files, input.packageDir) };
16
+ if (input.packageName) {
17
+ for (const entry of input.entryPoints) {
18
+ if (entry.file)
19
+ paths[entry.subpath === "."
20
+ ? input.packageName
21
+ : `${input.packageName}/${entry.subpath.replace(/^\.\//, "")}`] = [entry.file];
22
+ }
23
+ }
24
+ const analysis = createAnalysis(codeFiles, { paths });
25
+ const publicClasses = new Map();
26
+ for (const entry of input.entryPoints) {
27
+ const sf = entry.file ? analysis.sourceFile(entry.file) : undefined;
28
+ const moduleSymbol = sf ? analysis.checker.getSymbolAtLocation(sf) : undefined;
29
+ if (!sf || !moduleSymbol)
30
+ continue;
31
+ for (const exported of analysis.checker.getExportsOfModule(moduleSymbol)) {
32
+ const decl = declarationOf(resolveSymbol(analysis.checker, exported));
33
+ if (decl && ts.isClassDeclaration(decl) && isProjectNode(analysis, decl))
34
+ publicClasses.set(decl, [
35
+ ...(publicClasses.get(decl) ?? []),
36
+ { subpath: entry.subpath, name: exported.name }
37
+ ]);
38
+ }
39
+ }
40
+ const metas = new Map();
41
+ const modules = [];
42
+ for (const sf of analysis.program.getSourceFiles()) {
43
+ if (!analysis.relativePath(sf.fileName))
44
+ continue;
45
+ for (const statement of sf.statements) {
46
+ if (!ts.isClassDeclaration(statement))
47
+ continue;
48
+ const meta = readClass(analysis, statement) ?? readDeclaredClass(analysis, statement);
49
+ if (!meta)
50
+ continue;
51
+ metas.set(statement, meta);
52
+ if (meta.kind === "module")
53
+ modules.push({ ref: `angular:${meta.file}#${meta.name}`, meta, public: publicClasses.has(statement) });
54
+ }
55
+ }
56
+ const publicComponents = [...publicClasses.keys()].flatMap((decl) => {
57
+ const meta = metas.get(decl);
58
+ return meta && meta.kind !== "module" ? [{ decl, meta }] : [];
59
+ });
60
+ const selectors = new Map();
61
+ const refs = new Map();
62
+ for (const { decl, meta } of publicComponents) {
63
+ refs.set(decl, `angular:${meta.file}#${meta.name}`);
64
+ if (meta.selector)
65
+ selectors.set(refs.get(decl), parseSelector(meta.selector));
66
+ }
67
+ const components = publicComponents.map(({ decl, meta }) => {
68
+ const ref = refs.get(decl);
69
+ const template = readTemplate(meta, input.files, note);
70
+ const styling = readStyling(meta, input.files, note);
71
+ const renders = new Map();
72
+ for (const element of template?.info.elements ?? []) {
73
+ for (const [targetRef, parsed] of selectors) {
74
+ if (targetRef !== ref && matchesSelector(element, parsed))
75
+ renders.set(targetRef, (renders.get(targetRef) ?? 0) + 1);
76
+ }
77
+ }
78
+ const { inputs, outputs, complete } = withMetadataMembers(meta);
79
+ if (!meta.selector && meta.kind === "component")
80
+ note("info", "angular.no-selector", `${meta.name} has no static selector`, {
81
+ path: meta.file,
82
+ line: meta.line
83
+ });
84
+ for (const message of meta.notes)
85
+ note("info", "angular.unsupported", `${meta.name}: ${message}`, { path: meta.file, line: meta.line });
86
+ if (meta.inheritsFrom.length > 0)
87
+ note("info", "angular.base-class-external", `${meta.name} extends ${meta.inheritsFrom.join(", ")}, whose inputs and outputs are not enumerated`, { path: meta.file, line: meta.line });
88
+ const a11y = accessibilityOf(template?.info);
89
+ return {
90
+ ref,
91
+ meta,
92
+ exports: (publicClasses.get(decl) ?? []).sort((a, b) => a.subpath < b.subpath ? -1 : a.subpath > b.subpath ? 1 : a.name < b.name ? -1 : 1),
93
+ inputs,
94
+ outputs,
95
+ ...(template ? { template } : {}),
96
+ accessibility: a11y,
97
+ styling,
98
+ renders: [...renders]
99
+ .map(([target, count]) => ({ target, count }))
100
+ .sort((a, b) => (a.target < b.target ? -1 : 1)),
101
+ modules: modulesOf(meta, modules),
102
+ propsComplete: complete && meta.inheritsFrom.length === 0 && meta.hostDirectives.length === 0
103
+ };
104
+ });
105
+ components.sort((a, b) => (a.ref < b.ref ? -1 : a.ref > b.ref ? 1 : 0));
106
+ modules.sort((a, b) => (a.ref < b.ref ? -1 : 1));
107
+ return { components, modules, diagnostics };
108
+ }
109
+ function readTemplate(meta, files, note) {
110
+ const template = meta.template;
111
+ if (!template)
112
+ return undefined;
113
+ if ("inline" in template)
114
+ return {
115
+ source: "inline",
116
+ file: meta.file,
117
+ line: template.line,
118
+ info: scanTemplate(template.inline, template.line)
119
+ };
120
+ const file = posix.normalize(posix.join(posix.dirname(meta.file), template.url));
121
+ const text = files.get(file);
122
+ if (text === undefined) {
123
+ note("warning", "angular.templateurl-missing", `${meta.name}: template file ${file} was not found`, {
124
+ path: meta.file,
125
+ line: meta.line
126
+ });
127
+ return undefined;
128
+ }
129
+ return { source: "file", file, line: 1, info: scanTemplate(text, 1) };
130
+ }
131
+ function readStyling(meta, files, note) {
132
+ const variables = new Map();
133
+ const styleFiles = [];
134
+ for (const s of meta.styles) {
135
+ for (const ref of cssVariableReferences(s.text))
136
+ if (!variables.has(ref.name))
137
+ variables.set(ref.name, { file: meta.file, line: s.line + ref.line - 1 });
138
+ }
139
+ for (const url of meta.styleUrls) {
140
+ const file = posix.normalize(posix.join(posix.dirname(meta.file), url));
141
+ const text = files.get(file);
142
+ if (text === undefined) {
143
+ note("warning", "angular.styleurl-missing", `${meta.name}: stylesheet ${file} was not found`, {
144
+ path: meta.file,
145
+ line: meta.line
146
+ });
147
+ continue;
148
+ }
149
+ styleFiles.push(file);
150
+ for (const ref of cssVariableReferences(text))
151
+ if (!variables.has(ref.name))
152
+ variables.set(ref.name, { file, line: ref.line });
153
+ }
154
+ return {
155
+ files: styleFiles.sort(),
156
+ variables: [...variables].map(([name, v]) => ({ name, ...v })).sort((a, b) => (a.name < b.name ? -1 : 1)),
157
+ preprocessors: [
158
+ ...new Set(styleFiles.flatMap((f) => /\.(scss|sass|less)$/.exec(f)?.[1] ? [/\.(scss|sass|less)$/.exec(f)?.[1]] : []))
159
+ ].sort()
160
+ };
161
+ }
162
+ function accessibilityOf(info) {
163
+ const roles = new Set();
164
+ const attributes = new Set();
165
+ for (const element of info?.elements ?? []) {
166
+ // Native elements only: custom elements (with a dash) are Angular components.
167
+ if (element.tag.includes("-") || /^[A-Z]/.test(element.tag) || element.tag === "ng-content")
168
+ continue;
169
+ for (const a of element.attributes) {
170
+ if (a.name === "role" && !a.bound && a.value)
171
+ roles.add(a.value);
172
+ if (a.name.startsWith("aria-"))
173
+ attributes.add(a.name);
174
+ }
175
+ }
176
+ return { roles: [...roles].sort(), attributes: [...attributes].sort() };
177
+ }
178
+ /** `inputs: ['a', 'b: alias']` and `outputs: [...]` in the decorator, for names with no declared member. */
179
+ function withMetadataMembers(meta) {
180
+ const inputs = [...meta.inputs];
181
+ const outputs = [...meta.outputs];
182
+ for (const spec of meta.metadataInputs) {
183
+ const [property = "", alias] = spec.split(":").map((s) => s.trim());
184
+ const name = alias || property;
185
+ if (!property || inputs.some((i) => i.name === name))
186
+ continue;
187
+ inputs.push({
188
+ name,
189
+ property,
190
+ kind: "input",
191
+ typeText: "unknown",
192
+ typeKind: "unknown",
193
+ required: false,
194
+ ...(alias ? { alias } : {}),
195
+ node: meta.node
196
+ });
197
+ }
198
+ for (const spec of meta.metadataOutputs) {
199
+ const [property = "", alias] = spec.split(":").map((s) => s.trim());
200
+ const name = alias || property;
201
+ if (!property || outputs.some((o) => o.name === name))
202
+ continue;
203
+ outputs.push({ name, property, kind: "output", ...(alias ? { alias } : {}), node: meta.node });
204
+ }
205
+ inputs.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
206
+ outputs.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
207
+ return { inputs, outputs, complete: true };
208
+ }
209
+ function modulesOf(meta, modules) {
210
+ const matches = (refs) => refs.some((r) => r.file === meta.file && r.localName === meta.name);
211
+ return {
212
+ declaredIn: modules
213
+ .filter((m) => matches(m.meta.declarations))
214
+ .map((m) => m.meta.name)
215
+ .sort(),
216
+ exportedBy: modules
217
+ .filter((m) => matches(m.meta.exports))
218
+ .map((m) => m.meta.name)
219
+ .sort()
220
+ };
221
+ }
222
+ //# sourceMappingURL=analyze.js.map