@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,521 @@
1
+ import { collapse, componentNameFromFile, declarationOf, evaluate, isProjectNode, jsxTargetDeclaration, lineOf, posix, relativeFileOf, resolveSymbol, topLevelAssignments, unwrap } from "../compiler-core/index.js";
2
+ import ts from "typescript";
3
+ const MAX_CALLS = 50;
4
+ /** Statically reads a Component Story Format file (CSF 2 and 3). Nothing is executed. */
5
+ export function extractCsf(analysis, sf) {
6
+ const { checker } = analysis;
7
+ const file = relativeFileOf(analysis, sf);
8
+ const moduleSymbol = checker.getSymbolAtLocation(sf);
9
+ if (!file || !moduleSymbol)
10
+ return undefined;
11
+ const exports = checker.getExportsOfModule(moduleSymbol);
12
+ const defaultExport = exports.find((e) => e.name === "default");
13
+ const meta = defaultExport ? findMeta(analysis, defaultExport) : undefined;
14
+ const group = meta ? readGroup(analysis, file, meta) : undefined;
15
+ const selection = meta ? readStorySelection(meta.object) : { uncertain: false };
16
+ const assignments = topLevelAssignments(sf);
17
+ const stories = [];
18
+ const excluded = [];
19
+ for (const exported of exports) {
20
+ if (exported.name === "default" || exported.name === "__namedExportsOrder")
21
+ continue;
22
+ if (!(exported.flags & ts.SymbolFlags.Value) && !(exported.flags & ts.SymbolFlags.Alias))
23
+ continue;
24
+ const resolved = resolveSymbol(checker, exported);
25
+ const decl = declarationOf(resolved);
26
+ if (!decl || !isProjectNode(analysis, decl))
27
+ continue;
28
+ if (!isSelected(exported.name, selection)) {
29
+ excluded.push(exported.name);
30
+ continue;
31
+ }
32
+ const story = readStory(analysis, exported.name, decl, assignments);
33
+ if (story)
34
+ stories.push(story);
35
+ }
36
+ stories.sort((a, b) => a.line - b.line || (a.exportName < b.exportName ? -1 : 1));
37
+ return {
38
+ file,
39
+ ...(group ? { group } : {}),
40
+ stories,
41
+ excluded: excluded.sort(),
42
+ selectionUncertain: selection.uncertain
43
+ };
44
+ }
45
+ function findMeta(analysis, symbol) {
46
+ const { checker } = analysis;
47
+ const decl = declarationOf(symbol);
48
+ if (!decl)
49
+ return undefined;
50
+ let expression;
51
+ if (ts.isExportAssignment(decl))
52
+ expression = decl.expression;
53
+ else if (ts.isVariableDeclaration(decl))
54
+ expression = decl.initializer;
55
+ let typeArgument;
56
+ let current = expression;
57
+ for (let hops = 0; current && hops < 8; hops++) {
58
+ if (ts.isParenthesizedExpression(current) || ts.isNonNullExpression(current))
59
+ current = current.expression;
60
+ else if (ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
61
+ typeArgument ??= metaTypeArgument(current.type);
62
+ current = current.expression;
63
+ }
64
+ else if (ts.isIdentifier(current)) {
65
+ const target = declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(current)));
66
+ if (!target || !ts.isVariableDeclaration(target) || !target.initializer)
67
+ return undefined;
68
+ typeArgument ??= target.type ? metaTypeArgument(target.type) : undefined;
69
+ current = target.initializer;
70
+ }
71
+ else
72
+ break;
73
+ }
74
+ if (!current || !ts.isObjectLiteralExpression(current))
75
+ return undefined;
76
+ return { object: current, ...(typeArgument ? { typeArgument } : {}), node: current };
77
+ }
78
+ /** `typeof Button` from `Meta<typeof Button>`. */
79
+ function metaTypeArgument(type) {
80
+ if (ts.isTypeReferenceNode(type) && type.typeArguments?.[0] && ts.isTypeQueryNode(type.typeArguments[0]))
81
+ return type.typeArguments[0];
82
+ return undefined;
83
+ }
84
+ function readGroup(analysis, file, meta) {
85
+ const { checker } = analysis;
86
+ const props = objectProperties(meta.object);
87
+ const title = props.get("title");
88
+ const component = props.get("component");
89
+ let target;
90
+ let componentNode;
91
+ if (component && ts.isPropertyAssignment(component)) {
92
+ componentNode = component;
93
+ target = resolveTarget(analysis, component.initializer, "component");
94
+ }
95
+ else if (meta.typeArgument && ts.isTypeQueryNode(meta.typeArgument)) {
96
+ componentNode = meta.typeArgument;
97
+ target = resolveTarget(analysis, meta.typeArgument.exprName, "type-argument");
98
+ }
99
+ return {
100
+ file,
101
+ line: lineOf(meta.node),
102
+ node: meta.node,
103
+ ...(title && ts.isPropertyAssignment(title) && ts.isStringLiteralLike(unwrap(title.initializer))
104
+ ? { title: unwrap(title.initializer).text }
105
+ : {}),
106
+ ...(target ? { component: target } : {}),
107
+ ...(componentNode ? { componentNode } : {}),
108
+ ...annotations(checker, props)
109
+ };
110
+ }
111
+ function readStory(analysis, exportName, decl, assignments) {
112
+ const { checker } = analysis;
113
+ let shape;
114
+ let object;
115
+ let localName;
116
+ let renderNode;
117
+ if (ts.isVariableDeclaration(decl) && ts.isIdentifier(decl.name) && decl.initializer) {
118
+ localName = decl.name.text;
119
+ const init = unwrap(decl.initializer);
120
+ if (ts.isObjectLiteralExpression(init)) {
121
+ shape = "object";
122
+ object = init;
123
+ }
124
+ else if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) {
125
+ shape = "function";
126
+ renderNode = init;
127
+ }
128
+ else if (ts.isCallExpression(init) &&
129
+ ts.isPropertyAccessExpression(init.expression) &&
130
+ init.expression.name.text === "bind") {
131
+ shape = "template";
132
+ renderNode = init;
133
+ }
134
+ }
135
+ else if (ts.isFunctionDeclaration(decl) && decl.name) {
136
+ localName = decl.name.text;
137
+ shape = "function";
138
+ renderNode = decl;
139
+ }
140
+ if (!shape)
141
+ return undefined;
142
+ const props = object ? objectProperties(object) : new Map();
143
+ // CSF 2 style annotations: `Story.args = {…}`, `Story.storyName = "…"`, `Story.play = …`.
144
+ const assigned = (key) => localName ? assignments.get(`${localName}.${key}`) : undefined;
145
+ const synthetic = new Map(props);
146
+ for (const key of [
147
+ "args",
148
+ "argTypes",
149
+ "parameters",
150
+ "tags",
151
+ "decorators",
152
+ "loaders",
153
+ "play",
154
+ "render",
155
+ "name",
156
+ "storyName"
157
+ ]) {
158
+ const expr = assigned(key);
159
+ if (expr && !synthetic.has(key))
160
+ synthetic.set(key, fakeAssignment(key, expr));
161
+ }
162
+ const nameProp = synthetic.get("name") ?? synthetic.get("storyName");
163
+ const nameExpr = nameProp && ts.isPropertyAssignment(nameProp) ? unwrap(nameProp.initializer) : undefined;
164
+ const play = synthetic.get("play");
165
+ const playExpr = play && ts.isPropertyAssignment(play)
166
+ ? unwrap(play.initializer)
167
+ : play && ts.isMethodDeclaration(play)
168
+ ? play
169
+ : undefined;
170
+ const annotated = annotations(checker, synthetic);
171
+ const symbol = ts.isVariableDeclaration(decl) || ts.isFunctionDeclaration(decl)
172
+ ? checker.getSymbolAtLocation(decl.name)
173
+ : undefined;
174
+ const doc = symbol ? ts.displayPartsToString(symbol.getDocumentationComment(checker)).trim() : "";
175
+ const description = annotated.parameters.docsDescription?.story ?? (doc || undefined);
176
+ return {
177
+ exportName,
178
+ line: lineOf(decl),
179
+ node: decl,
180
+ shape,
181
+ ...(nameExpr && ts.isStringLiteralLike(nameExpr) ? { name: nameExpr.text } : {}),
182
+ ...(description ? { description } : {}),
183
+ ...(playExpr ? { play: inspectPlay(playExpr) } : {}),
184
+ hasRender: synthetic.has("render") || shape !== "object",
185
+ composes: composedComponents(analysis, object ?? renderNode ?? decl),
186
+ ...annotated
187
+ };
188
+ }
189
+ /** Collects Annotations from a property map (object literal members, or CSF 2 assignments). */
190
+ function annotations(checker, props) {
191
+ const expressionOf = (key) => {
192
+ const p = props.get(key);
193
+ return p && ts.isPropertyAssignment(p) ? p.initializer : undefined;
194
+ };
195
+ const argsExpr = expressionOf("args");
196
+ const args = argsExpr ? evaluate(checker, argsExpr) : { unresolved: [], spies: [] };
197
+ const argNodes = new Map();
198
+ const argsObject = argsExpr ? unwrap(argsExpr) : undefined;
199
+ if (argsObject && ts.isObjectLiteralExpression(argsObject)) {
200
+ for (const [k, p] of objectProperties(argsObject))
201
+ argNodes.set(k, p);
202
+ }
203
+ const argTypesExpr = expressionOf("argTypes");
204
+ const argTypesEval = argTypesExpr ? evaluate(checker, argTypesExpr) : { unresolved: [], spies: [] };
205
+ const argTypeNodes = new Map();
206
+ const argTypesObject = argTypesExpr ? unwrap(argTypesExpr) : undefined;
207
+ if (argTypesObject && ts.isObjectLiteralExpression(argTypesObject)) {
208
+ for (const [k, p] of objectProperties(argTypesObject))
209
+ argTypeNodes.set(k, p);
210
+ }
211
+ const parametersExpr = expressionOf("parameters");
212
+ const parametersEval = parametersExpr ? evaluate(checker, parametersExpr) : { unresolved: [], spies: [] };
213
+ const tagsExpr = expressionOf("tags");
214
+ const tagsEval = tagsExpr ? evaluate(checker, tagsExpr) : undefined;
215
+ return {
216
+ args,
217
+ argNodes,
218
+ ...(argsExpr ? { argsNode: argsExpr } : {}),
219
+ argTypes: readArgTypes(argTypesEval, syntacticMappingKeys(argTypeNodes)),
220
+ argTypeNodes,
221
+ argTypesUnresolved: argTypesEval.unresolved,
222
+ parameters: readParameters(parametersEval),
223
+ parametersUnresolved: parametersEval.unresolved,
224
+ ...(Array.isArray(tagsEval?.value) && tagsEval.value.every((t) => typeof t === "string")
225
+ ? { tags: tagsEval.value }
226
+ : {}),
227
+ hasDecorators: props.has("decorators"),
228
+ hasLoaders: props.has("loaders"),
229
+ nodes: {
230
+ ...(evidenceNode(props.get("parameters"))
231
+ ? { parameters: evidenceNode(props.get("parameters")) }
232
+ : {}),
233
+ ...(evidenceNode(props.get("tags")) ? { tags: evidenceNode(props.get("tags")) } : {}),
234
+ ...(evidenceNode(props.get("decorators"))
235
+ ? { decorators: evidenceNode(props.get("decorators")) }
236
+ : {}),
237
+ ...(evidenceNode(props.get("loaders"))
238
+ ? { loaders: evidenceNode(props.get("loaders")) }
239
+ : {})
240
+ }
241
+ };
242
+ }
243
+ function readArgTypes(evaluated, mappingKeys) {
244
+ const out = {};
245
+ const root = evaluated.value;
246
+ if (root === null || typeof root !== "object" || Array.isArray(root))
247
+ return out;
248
+ for (const [prop, raw] of Object.entries(root)) {
249
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
250
+ out[prop] = {};
251
+ continue;
252
+ }
253
+ const info = {};
254
+ const control = raw.control;
255
+ if (typeof control === "string" || control === false)
256
+ info.control = control;
257
+ else if (control &&
258
+ typeof control === "object" &&
259
+ !Array.isArray(control) &&
260
+ typeof control.type === "string")
261
+ info.control = control.type;
262
+ if (Array.isArray(raw.options) &&
263
+ raw.options.every((o) => ["string", "number", "boolean"].includes(typeof o)))
264
+ info.options = raw.options;
265
+ if (evaluated.unresolved.some((p) => p === `${prop}.options` || p.startsWith(`${prop}.options.`)) ||
266
+ (control &&
267
+ typeof control === "object" &&
268
+ evaluated.unresolved.some((p) => p.startsWith(`${prop}.control.options`))))
269
+ info.optionsUnresolved = true;
270
+ if (typeof raw.description === "string")
271
+ info.description = raw.description;
272
+ const table = raw.table;
273
+ if (table && typeof table === "object" && !Array.isArray(table)) {
274
+ const dv = table.defaultValue;
275
+ if (dv && typeof dv === "object" && !Array.isArray(dv) && typeof dv.summary === "string")
276
+ info.defaultSummary = dv.summary;
277
+ if (table.disable === true)
278
+ info.hidden = true;
279
+ if (typeof table.category === "string")
280
+ info.category = table.category;
281
+ }
282
+ // Mapping keys come from the syntax: a key whose value is JSX or `undefined` is still a key.
283
+ const syntactic = mappingKeys.get(prop);
284
+ if (syntactic)
285
+ info.mappingKeys = syntactic;
286
+ else if (raw.mapping && typeof raw.mapping === "object" && !Array.isArray(raw.mapping))
287
+ info.mappingKeys = Object.keys(raw.mapping).sort();
288
+ else if (evaluated.unresolved.some((p) => p === `${prop}.mapping`))
289
+ info.mappingKeys = [];
290
+ if (typeof raw.action === "string")
291
+ info.action = raw.action;
292
+ out[prop] = info;
293
+ }
294
+ return out;
295
+ }
296
+ function syntacticMappingKeys(argTypeNodes) {
297
+ const out = new Map();
298
+ for (const [prop, node] of argTypeNodes) {
299
+ if (!ts.isPropertyAssignment(node))
300
+ continue;
301
+ const argType = unwrap(node.initializer);
302
+ if (!ts.isObjectLiteralExpression(argType))
303
+ continue;
304
+ const mapping = objectProperties(argType).get("mapping");
305
+ const object = mapping && ts.isPropertyAssignment(mapping) ? unwrap(mapping.initializer) : undefined;
306
+ if (object && ts.isObjectLiteralExpression(object))
307
+ out.set(prop, [...objectProperties(object).keys()].sort());
308
+ }
309
+ return out;
310
+ }
311
+ function readParameters(evaluated) {
312
+ const root = evaluated.value;
313
+ if (root === null || typeof root !== "object" || Array.isArray(root))
314
+ return { keys: [] };
315
+ const info = { keys: Object.keys(root).sort() };
316
+ if (root.a11y !== undefined)
317
+ info.a11y = root.a11y;
318
+ if (typeof root.layout === "string")
319
+ info.layout = root.layout;
320
+ if (root.controls !== undefined)
321
+ info.controls = root.controls;
322
+ const docs = root.docs;
323
+ if (docs && typeof docs === "object" && !Array.isArray(docs)) {
324
+ const d = docs.description;
325
+ if (d && typeof d === "object" && !Array.isArray(d)) {
326
+ info.docsDescription = {
327
+ ...(typeof d.component === "string" ? { component: d.component } : {}),
328
+ ...(typeof d.story === "string" ? { story: d.story } : {})
329
+ };
330
+ }
331
+ }
332
+ return info;
333
+ }
334
+ function readStorySelection(object) {
335
+ const props = objectProperties(object);
336
+ const read = (key) => {
337
+ const p = props.get(key);
338
+ if (!p || !ts.isPropertyAssignment(p))
339
+ return { uncertain: false };
340
+ const matcher = toMatcher(unwrap(p.initializer));
341
+ return matcher ? { matcher, uncertain: false } : { uncertain: true };
342
+ };
343
+ const include = read("includeStories");
344
+ const exclude = read("excludeStories");
345
+ return {
346
+ ...(include.matcher ? { include: include.matcher } : {}),
347
+ ...(exclude.matcher ? { exclude: exclude.matcher } : {}),
348
+ uncertain: include.uncertain || exclude.uncertain
349
+ };
350
+ }
351
+ function toMatcher(node) {
352
+ if (ts.isRegularExpressionLiteral(node)) {
353
+ const body = node.text.slice(1, node.text.lastIndexOf("/"));
354
+ const flags = node.text.slice(node.text.lastIndexOf("/") + 1);
355
+ try {
356
+ const re = new RegExp(body, flags);
357
+ return (name) => re.test(name);
358
+ }
359
+ catch {
360
+ return undefined;
361
+ }
362
+ }
363
+ if (ts.isStringLiteralLike(node))
364
+ return (name) => name === node.text;
365
+ if (ts.isArrayLiteralExpression(node)) {
366
+ const parts = node.elements.map((e) => toMatcher(unwrap(e)));
367
+ return parts.every((p) => p !== undefined) ? (name) => parts.some((p) => p(name)) : undefined;
368
+ }
369
+ return undefined;
370
+ }
371
+ function isSelected(name, selection) {
372
+ if (selection.include && !selection.include(name))
373
+ return false;
374
+ if (selection.exclude?.(name))
375
+ return false;
376
+ return true;
377
+ }
378
+ function resolveTarget(analysis, node, via) {
379
+ const { checker } = analysis;
380
+ const text = collapse(node.getText());
381
+ const symbolNode = ts.isIdentifier(node) || ts.isPropertyAccessExpression(node) || ts.isQualifiedName(node)
382
+ ? node
383
+ : undefined;
384
+ const decl = symbolNode && !ts.isQualifiedName(symbolNode)
385
+ ? jsxTargetDeclaration(checker, symbolNode)
386
+ : undefinedDeclaration(checker, node);
387
+ if (decl && isProjectNode(analysis, decl)) {
388
+ const name = declarationName(decl);
389
+ const file = relativeFileOf(analysis, decl);
390
+ if (file && name)
391
+ return { file, name, text, via };
392
+ }
393
+ const importSpecifier = importOf(checker, node);
394
+ if (importSpecifier?.startsWith(".")) {
395
+ // Single-file components (`./Button.vue`) are not TypeScript modules, so they are linked by file
396
+ // and the PascalCase component name, the same key the Vue adapter publishes.
397
+ const from = relativeFileOf(analysis, node);
398
+ const resolved = from ? posix.normalize(posix.join(posix.dirname(from), importSpecifier)) : undefined;
399
+ if (resolved?.endsWith(".vue") && analysis.hasFile(resolved))
400
+ return { file: resolved, name: componentNameFromFile(resolved), text, via };
401
+ }
402
+ if (importSpecifier) {
403
+ return importSpecifier.startsWith(".")
404
+ ? { text, via, unresolvedModule: importSpecifier }
405
+ : { text, via, external: importSpecifier };
406
+ }
407
+ return { text, via };
408
+ }
409
+ function undefinedDeclaration(checker, node) {
410
+ const symbol = checker.getSymbolAtLocation(node);
411
+ return declarationOf(resolveSymbol(checker, symbol));
412
+ }
413
+ /** Module specifier of the import that brought the leftmost identifier of `node` into scope. */
414
+ function importOf(checker, node) {
415
+ let root = node;
416
+ while (ts.isPropertyAccessExpression(root))
417
+ root = root.expression;
418
+ while (ts.isQualifiedName(root))
419
+ root = root.left;
420
+ const symbol = checker.getSymbolAtLocation(root);
421
+ const decl = symbol?.declarations?.[0];
422
+ let cursor = decl;
423
+ while (cursor && !ts.isImportDeclaration(cursor))
424
+ cursor = cursor.parent;
425
+ return cursor && ts.isImportDeclaration(cursor) && ts.isStringLiteral(cursor.moduleSpecifier)
426
+ ? cursor.moduleSpecifier.text
427
+ : undefined;
428
+ }
429
+ function declarationName(decl) {
430
+ const named = decl;
431
+ if (named.name && ts.isIdentifier(named.name))
432
+ return named.name.text;
433
+ if (ts.isExportAssignment(decl)) {
434
+ const base = posix.basename(decl.getSourceFile().fileName).replace(/\.[^.]+$/, "");
435
+ return base.charAt(0).toUpperCase() + base.slice(1);
436
+ }
437
+ return undefined;
438
+ }
439
+ function composedComponents(analysis, root) {
440
+ const { checker } = analysis;
441
+ const counts = new Map();
442
+ const visit = (n) => {
443
+ if (ts.isJsxSelfClosingElement(n) || ts.isJsxOpeningElement(n)) {
444
+ const tag = n.tagName;
445
+ if (!(ts.isIdentifier(tag) && /^[a-z]/.test(tag.text))) {
446
+ const decl = jsxTargetDeclaration(checker, tag);
447
+ if (decl && isProjectNode(analysis, decl)) {
448
+ const file = relativeFileOf(analysis, decl);
449
+ const name = declarationName(decl);
450
+ if (file && name) {
451
+ const key = `${file}#${name}`;
452
+ const entry = counts.get(key) ?? { file, name, count: 0 };
453
+ entry.count++;
454
+ counts.set(key, entry);
455
+ }
456
+ }
457
+ }
458
+ }
459
+ ts.forEachChild(n, visit);
460
+ };
461
+ visit(root);
462
+ return [...counts.values()].sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : a.name < b.name ? -1 : 1);
463
+ }
464
+ function inspectPlay(node) {
465
+ const calls = new Set();
466
+ const steps = [];
467
+ const visit = (n) => {
468
+ if (ts.isCallExpression(n)) {
469
+ const callee = calleeName(n.expression);
470
+ if (calls.size < MAX_CALLS)
471
+ calls.add(callee);
472
+ const first = n.arguments[0];
473
+ if (callee === "step" && first && ts.isStringLiteralLike(first))
474
+ steps.push(first.text);
475
+ }
476
+ ts.forEachChild(n, visit);
477
+ };
478
+ visit(node);
479
+ return { calls: [...calls].sort(), steps };
480
+ }
481
+ /** `expect(x).toBe(y)` becomes `expect().toBe`, so call arguments never leak into the call list. */
482
+ function calleeName(expression) {
483
+ if (ts.isIdentifier(expression))
484
+ return expression.text;
485
+ if (ts.isPropertyAccessExpression(expression))
486
+ return `${calleeName(expression.expression)}.${expression.name.text}`;
487
+ if (ts.isCallExpression(expression))
488
+ return `${calleeName(expression.expression)}()`;
489
+ if (ts.isAwaitExpression(expression) ||
490
+ ts.isParenthesizedExpression(expression) ||
491
+ ts.isNonNullExpression(expression))
492
+ return calleeName(expression.expression);
493
+ return "<expression>";
494
+ }
495
+ function objectProperties(object) {
496
+ const out = new Map();
497
+ for (const p of object.properties) {
498
+ const name = p.name;
499
+ if (name && (ts.isIdentifier(name) || ts.isStringLiteralLike(name)))
500
+ out.set(name.text, p);
501
+ }
502
+ return out;
503
+ }
504
+ /** A real syntax node to cite as evidence: synthetic assignment wrappers are replaced by their initializer. */
505
+ function evidenceNode(property) {
506
+ if (!property)
507
+ return undefined;
508
+ return property.synthetic && ts.isPropertyAssignment(property)
509
+ ? property.initializer
510
+ : property;
511
+ }
512
+ /** Adapts a `Story.key = value` assignment to the property-assignment shape the readers expect. */
513
+ function fakeAssignment(key, expression) {
514
+ return {
515
+ kind: ts.SyntaxKind.PropertyAssignment,
516
+ name: { kind: ts.SyntaxKind.Identifier, text: key },
517
+ initializer: expression,
518
+ synthetic: true
519
+ };
520
+ }
521
+ //# sourceMappingURL=csf.js.map