@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.
- package/LICENSE +105 -0
- package/README.md +250 -2
- package/dist/agent-kit/apply.js +232 -0
- package/dist/agent-kit/guidance.js +236 -0
- package/dist/agent-kit/index.js +5 -0
- package/dist/agent-kit/integrations.js +121 -0
- package/dist/agent-kit/plugin.js +115 -0
- package/dist/artifact-generator/index.js +75 -0
- package/dist/browser-verify/driver.js +2 -0
- package/dist/browser-verify/index.js +4 -0
- package/dist/browser-verify/playwright.js +82 -0
- package/dist/browser-verify/runner.js +175 -0
- package/dist/browser-verify/spec.js +103 -0
- package/dist/cli/args.js +77 -0
- package/dist/cli/baseline.js +64 -0
- package/dist/cli/cli.js +121 -0
- package/dist/cli/commands-browser.js +104 -0
- package/dist/cli/commands-discover.js +312 -0
- package/dist/cli/commands-enforcement.js +35 -0
- package/dist/cli/commands-governance.js +179 -0
- package/dist/cli/commands-hook.js +269 -0
- package/dist/cli/commands-patterns.js +324 -0
- package/dist/cli/commands-setup.js +485 -0
- package/dist/cli/commands-validate.js +157 -0
- package/dist/cli/commands.js +517 -0
- package/dist/cli/config.js +197 -0
- package/dist/cli/diff.js +66 -0
- package/dist/cli/enforcement-log.js +83 -0
- package/dist/cli/enforcement-report.js +96 -0
- package/dist/cli/errors.js +10 -0
- package/dist/cli/format.js +22 -0
- package/dist/cli/index.js +5 -0
- package/dist/cli/io.js +2 -0
- package/dist/cli/main.js +31 -0
- package/dist/cli/pipeline.js +262 -0
- package/dist/cli/publish.js +77 -0
- package/dist/cli/report.js +127 -0
- package/dist/cli/starter-rules.js +57 -0
- package/dist/cli/store.js +60 -0
- package/dist/cli/version.js +5 -0
- package/dist/cli/watch.js +68 -0
- package/dist/cli/workflow.js +52 -0
- package/dist/compiler-angular/adapter.js +115 -0
- package/dist/compiler-angular/analyze.js +222 -0
- package/dist/compiler-angular/classes.js +446 -0
- package/dist/compiler-angular/declared.js +285 -0
- package/dist/compiler-angular/emit.js +183 -0
- package/dist/compiler-angular/index.js +4 -0
- package/dist/compiler-angular/template.js +142 -0
- package/dist/compiler-core/adapter.js +2 -0
- package/dist/compiler-core/adapters/inventory.js +312 -0
- package/dist/compiler-core/compile.js +148 -0
- package/dist/compiler-core/component-facts.js +123 -0
- package/dist/compiler-core/discovery/docs.js +66 -0
- package/dist/compiler-core/discovery/entries.js +270 -0
- package/dist/compiler-core/discovery/exports.js +207 -0
- package/dist/compiler-core/discovery/graph.js +59 -0
- package/dist/compiler-core/discovery/index.js +103 -0
- package/dist/compiler-core/discovery/packages.js +148 -0
- package/dist/compiler-core/discovery/schema.js +144 -0
- package/dist/compiler-core/discovery/storybook.js +232 -0
- package/dist/compiler-core/discovery/support.js +82 -0
- package/dist/compiler-core/discovery/tokens.js +186 -0
- package/dist/compiler-core/discovery/tooling.js +146 -0
- package/dist/compiler-core/fs.js +89 -0
- package/dist/compiler-core/glob.js +3 -0
- package/dist/compiler-core/index.js +16 -0
- package/dist/compiler-core/ir-builder.js +68 -0
- package/dist/compiler-core/json-schema.js +11 -0
- package/dist/compiler-core/testing/index.js +81 -0
- package/dist/compiler-core/ts/ast.js +166 -0
- package/dist/compiler-core/ts/members.js +163 -0
- package/dist/compiler-core/ts/program.js +81 -0
- package/dist/compiler-core/ts/static-eval.js +145 -0
- package/dist/compiler-core/ts/tsconfig-paths.js +60 -0
- package/dist/compiler-core/walk.js +46 -0
- package/dist/compiler-ir/index.js +4 -0
- package/dist/compiler-ir/ir.js +67 -0
- package/dist/compiler-ir/json-schema.js +6 -0
- package/dist/compiler-ir/validate.js +116 -0
- package/dist/compiler-react/adapter.js +147 -0
- package/dist/compiler-react/analyze.js +199 -0
- package/dist/compiler-react/behavior.js +75 -0
- package/dist/compiler-react/detect.js +558 -0
- package/dist/compiler-react/emit.js +188 -0
- package/dist/compiler-react/index.js +2 -0
- package/dist/compiler-react/props.js +157 -0
- package/dist/compiler-react/styling.js +138 -0
- package/dist/compiler-react/usage.js +116 -0
- package/dist/compiler-react/variants.js +111 -0
- package/dist/compiler-storybook/adapter.js +253 -0
- package/dist/compiler-storybook/csf.js +521 -0
- package/dist/compiler-storybook/emit.js +202 -0
- package/dist/compiler-storybook/index-json.js +41 -0
- package/dist/compiler-storybook/index.js +5 -0
- package/dist/compiler-storybook/mdx.js +120 -0
- package/dist/compiler-tokens/adapter.js +158 -0
- package/dist/compiler-tokens/css.js +59 -0
- package/dist/compiler-tokens/index.js +5 -0
- package/dist/compiler-tokens/json-lines.js +106 -0
- package/dist/compiler-tokens/json-tokens.js +52 -0
- package/dist/compiler-vue/adapter.js +107 -0
- package/dist/compiler-vue/analyze.js +344 -0
- package/dist/compiler-vue/declared.js +343 -0
- package/dist/compiler-vue/emit.js +129 -0
- package/dist/compiler-vue/index.js +5 -0
- package/dist/compiler-vue/script.js +472 -0
- package/dist/compiler-vue/sfc.js +44 -0
- package/dist/compiler-vue/template.js +73 -0
- package/dist/contract/archetype-checks.js +153 -0
- package/dist/contract/components.js +102 -0
- package/dist/contract/conflicts.js +39 -0
- package/dist/contract/contract.js +46 -0
- package/dist/contract/evidence.js +84 -0
- package/dist/contract/fact-path.js +39 -0
- package/dist/contract/facts.js +62 -0
- package/dist/contract/index.js +16 -0
- package/dist/contract/integrity.js +21 -0
- package/dist/contract/json-schema.js +11 -0
- package/dist/contract/knowledge.js +95 -0
- package/dist/contract/pattern-checks.js +254 -0
- package/dist/contract/patterns.js +225 -0
- package/dist/contract/primitives.js +81 -0
- package/dist/contract/sources.js +30 -0
- package/dist/contract/tokens.js +41 -0
- package/dist/contract/validate.js +253 -0
- package/dist/contract-query/archetype.js +188 -0
- package/dist/contract-query/index.js +6 -0
- package/dist/contract-query/patterns.js +298 -0
- package/dist/contract-query/search.js +132 -0
- package/dist/contract-query/system.js +148 -0
- package/dist/contract-query/views.js +288 -0
- package/dist/governance/decisions.js +229 -0
- package/dist/governance/index.js +5 -0
- package/dist/governance/patterns-file.js +156 -0
- package/dist/governance/patterns.js +510 -0
- package/dist/governance/policies.js +148 -0
- package/dist/mcp/index.js +7 -0
- package/dist/mcp/loader.js +70 -0
- package/dist/mcp/protocol.js +27 -0
- package/dist/mcp/resources.js +138 -0
- package/dist/mcp/server.js +177 -0
- package/dist/mcp/stdio.js +28 -0
- package/dist/mcp/tools.js +267 -0
- package/dist/reconciliation/code.js +62 -0
- package/dist/reconciliation/components.js +401 -0
- package/dist/reconciliation/conflicts.js +126 -0
- package/dist/reconciliation/facts.js +41 -0
- package/dist/reconciliation/index.js +7 -0
- package/dist/reconciliation/reconcile.js +134 -0
- package/dist/reconciliation/resolve.js +158 -0
- package/dist/reconciliation/review.js +81 -0
- package/dist/reconciliation/storybook.js +370 -0
- package/dist/reconciliation/tokens.js +179 -0
- package/dist/reconciliation/util.js +55 -0
- package/dist/semantic-engine/additive.js +51 -0
- package/dist/semantic-engine/compounds.js +91 -0
- package/dist/semantic-engine/documents.js +157 -0
- package/dist/semantic-engine/enrich.js +42 -0
- package/dist/semantic-engine/index.js +7 -0
- package/dist/semantic-engine/infer.js +38 -0
- package/dist/semantic-engine/tokens.js +120 -0
- package/dist/shared/canonical.js +65 -0
- package/dist/shared/diagnostic.js +78 -0
- package/dist/shared/glob.js +98 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/json.js +2 -0
- package/dist/validation/card.js +50 -0
- package/dist/validation/discovery/arrangements.js +162 -0
- package/dist/validation/discovery/discover.js +70 -0
- package/dist/validation/discovery/index.js +8 -0
- package/dist/validation/discovery/model.js +127 -0
- package/dist/validation/discovery/promote.js +24 -0
- package/dist/validation/discovery/reviews.js +63 -0
- package/dist/validation/discovery/shapes.js +47 -0
- package/dist/validation/discovery/similar-files.js +146 -0
- package/dist/validation/discovery/util.js +47 -0
- package/dist/validation/index.js +11 -0
- package/dist/validation/interaction-facts.js +341 -0
- package/dist/validation/interaction-workflows.js +633 -0
- package/dist/validation/literals.js +251 -0
- package/dist/validation/pattern-rules.js +608 -0
- package/dist/validation/policy.js +241 -0
- package/dist/validation/report.js +163 -0
- package/dist/validation/rules.js +269 -0
- package/dist/validation/scan.js +295 -0
- package/dist/validation/text.js +34 -0
- package/dist/validation/validate-code.js +513 -0
- package/dist/validation/validate-usage.js +196 -0
- package/package.json +38 -4
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { declarationOf, literalValue, resolveSymbol, unwrap, walkSameFunction } from "../compiler-core/index.js";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
/**
|
|
4
|
+
* Variants come from two deterministic sources: props typed as a union of two or more string
|
|
5
|
+
* literals, and `cva(...)` configs (`variants` + `defaultVariants`) whose function the component calls.
|
|
6
|
+
*/
|
|
7
|
+
export function variantsOf(analysis, candidate, props) {
|
|
8
|
+
const out = new Map();
|
|
9
|
+
for (const p of props) {
|
|
10
|
+
const values = p.allowedValues;
|
|
11
|
+
if (p.kind !== "enum" || !values || values.length < 2 || !values.every((v) => typeof v === "string"))
|
|
12
|
+
continue;
|
|
13
|
+
const fallback = typeof p.default === "string" && values.includes(p.default) ? p.default : undefined;
|
|
14
|
+
out.set(p.name, {
|
|
15
|
+
name: p.name,
|
|
16
|
+
values: values,
|
|
17
|
+
...(fallback ? { default: fallback } : {}),
|
|
18
|
+
source: "prop-union",
|
|
19
|
+
node: p.declaration.node
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
for (const cva of cvaCallsUsedBy(analysis, candidate)) {
|
|
23
|
+
for (const [name, info] of cva.variants) {
|
|
24
|
+
const existing = out.get(name);
|
|
25
|
+
if (existing?.source !== "cva")
|
|
26
|
+
out.set(name, { ...info, via: cva.via, node: cva.node });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return [...out.values()].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
30
|
+
}
|
|
31
|
+
function cvaCallsUsedBy(analysis, candidate) {
|
|
32
|
+
const impl = candidate.impl;
|
|
33
|
+
if (!impl)
|
|
34
|
+
return [];
|
|
35
|
+
const { checker } = analysis;
|
|
36
|
+
const found = new Map();
|
|
37
|
+
const consider = (identifier) => {
|
|
38
|
+
const decl = declarationOf(resolveSymbol(checker, checker.getSymbolAtLocation(identifier)));
|
|
39
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer && isCva(decl.initializer))
|
|
40
|
+
found.set(decl, identifier.text);
|
|
41
|
+
};
|
|
42
|
+
if (ts.isFunctionLike(impl)) {
|
|
43
|
+
walkSameFunction(impl, (n) => {
|
|
44
|
+
if (ts.isCallExpression(n) && ts.isIdentifier(n.expression))
|
|
45
|
+
consider(n.expression);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const walk = (n) => {
|
|
50
|
+
if (ts.isCallExpression(n) && ts.isIdentifier(n.expression))
|
|
51
|
+
consider(n.expression);
|
|
52
|
+
ts.forEachChild(n, walk);
|
|
53
|
+
};
|
|
54
|
+
walk(impl);
|
|
55
|
+
}
|
|
56
|
+
return [...found].map(([decl, via]) => {
|
|
57
|
+
const init = unwrap(decl.initializer);
|
|
58
|
+
return { via, node: decl, variants: parseCva(init, via) };
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function isCva(expression) {
|
|
62
|
+
const node = unwrap(expression);
|
|
63
|
+
return ts.isCallExpression(node) && node.expression.getText() === "cva";
|
|
64
|
+
}
|
|
65
|
+
function parseCva(call, via) {
|
|
66
|
+
const result = new Map();
|
|
67
|
+
const config = call.arguments[1] ? unwrap(call.arguments[1]) : undefined;
|
|
68
|
+
if (!config || !ts.isObjectLiteralExpression(config))
|
|
69
|
+
return result;
|
|
70
|
+
const member = (name) => {
|
|
71
|
+
const p = config.properties.find((x) => ts.isPropertyAssignment(x) && x.name.getText() === name);
|
|
72
|
+
return p && ts.isPropertyAssignment(p) ? unwrap(p.initializer) : undefined;
|
|
73
|
+
};
|
|
74
|
+
const variants = member("variants");
|
|
75
|
+
const defaults = member("defaultVariants");
|
|
76
|
+
const defaultMap = new Map();
|
|
77
|
+
if (defaults && ts.isObjectLiteralExpression(defaults)) {
|
|
78
|
+
for (const p of defaults.properties) {
|
|
79
|
+
if (ts.isPropertyAssignment(p)) {
|
|
80
|
+
const v = literalValue(p.initializer);
|
|
81
|
+
if (v !== undefined)
|
|
82
|
+
defaultMap.set(p.name.getText().replace(/^["']|["']$/g, ""), v);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (variants && ts.isObjectLiteralExpression(variants)) {
|
|
87
|
+
for (const p of variants.properties) {
|
|
88
|
+
if (!ts.isPropertyAssignment(p))
|
|
89
|
+
continue;
|
|
90
|
+
const inner = unwrap(p.initializer);
|
|
91
|
+
if (!ts.isObjectLiteralExpression(inner))
|
|
92
|
+
continue;
|
|
93
|
+
const name = p.name.getText().replace(/^["']|["']$/g, "");
|
|
94
|
+
const values = inner.properties.flatMap((v) => ts.isPropertyAssignment(v) || ts.isShorthandPropertyAssignment(v)
|
|
95
|
+
? [v.name.getText().replace(/^["']|["']$/g, "")]
|
|
96
|
+
: []);
|
|
97
|
+
const fallback = defaultMap.get(name);
|
|
98
|
+
result.set(name, {
|
|
99
|
+
name,
|
|
100
|
+
values,
|
|
101
|
+
...(typeof fallback === "string" || typeof fallback === "boolean" || typeof fallback === "number"
|
|
102
|
+
? { default: String(fallback) }
|
|
103
|
+
: {}),
|
|
104
|
+
source: "cva",
|
|
105
|
+
via
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=variants.js.map
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { createAnalysis, DEFAULT_IGNORED_DIRS, hashText, IrBuilder, posix, tsconfigPaths, walk } from "../compiler-core/index.js";
|
|
2
|
+
import { hashJson } from "../shared/index.js";
|
|
3
|
+
import { extractCsf } from "./csf.js";
|
|
4
|
+
import { CAPABILITIES, emitCsf, emitMdx } from "./emit.js";
|
|
5
|
+
import { parseBuiltIndex } from "./index-json.js";
|
|
6
|
+
import { parseMdx } from "./mdx.js";
|
|
7
|
+
export const ADAPTER_ID = "storybook";
|
|
8
|
+
export const ADAPTER_VERSION = "0.1.0";
|
|
9
|
+
const CODE_FILE = /\.(?:[cm]?[jt]sx?)$/;
|
|
10
|
+
// `.vue` files are loaded as well, so stories that import single-file components can be linked to them.
|
|
11
|
+
const PROGRAM_FILE = /\.(?:[cm]?[jt]sx?|vue)$|(?:^|\/)tsconfig[^/]*\.json$/;
|
|
12
|
+
const MAX_FILE_BYTES = 1_000_000;
|
|
13
|
+
/**
|
|
14
|
+
* Storybook adapter. Reads story files (CSF 2 and 3) and MDX pages statically: titles, the component each
|
|
15
|
+
* meta points at (resolved through the type checker to a file and declaration), args, argTypes and
|
|
16
|
+
* controls, parameters, tags, play-function structure, and components composed in story renders. A built
|
|
17
|
+
* `storybook-static/index.json`, when present, is recorded as optional evidence. Nothing is executed and
|
|
18
|
+
* no story identity is synthesized: a story is identified by its export.
|
|
19
|
+
*/
|
|
20
|
+
export const storybookAdapter = {
|
|
21
|
+
id: ADAPTER_ID,
|
|
22
|
+
version: ADAPTER_VERSION,
|
|
23
|
+
type: "storybook",
|
|
24
|
+
async discover({ fs, project }) {
|
|
25
|
+
const sources = [];
|
|
26
|
+
const used = new Set();
|
|
27
|
+
for (const sb of project.storybooks) {
|
|
28
|
+
if (sb.storyFiles.length === 0)
|
|
29
|
+
continue;
|
|
30
|
+
const { files, hashes, paths } = await loadProgramFiles(fs, project, sb);
|
|
31
|
+
const slug = (sb.directory === "." ? "root" : sb.directory)
|
|
32
|
+
.toLowerCase()
|
|
33
|
+
.replace(/[^a-z0-9._-]+/g, "-")
|
|
34
|
+
.replace(/^[^a-z0-9]+|[-.]+$/g, "") || "root";
|
|
35
|
+
let id = `stories-${slug}`;
|
|
36
|
+
for (let n = 2; used.has(id); n++)
|
|
37
|
+
id = `stories-${slug}-${n}`;
|
|
38
|
+
used.add(id);
|
|
39
|
+
const index = sb.builtOutput?.hasIndexJson
|
|
40
|
+
? await readText(fs, posix.join(sb.builtOutput.path, "index.json"))
|
|
41
|
+
: undefined;
|
|
42
|
+
sources.push({
|
|
43
|
+
id,
|
|
44
|
+
type: "storybook",
|
|
45
|
+
location: sb.directory,
|
|
46
|
+
config: { storybookId: sb.id, files: [...files.keys()], paths },
|
|
47
|
+
...(sb.version?.installedVersion
|
|
48
|
+
? { version: { kind: "tool-version", value: sb.version.installedVersion } }
|
|
49
|
+
: {}),
|
|
50
|
+
inputHash: hashJson({
|
|
51
|
+
files: hashes,
|
|
52
|
+
index: index === undefined ? null : hashText(index),
|
|
53
|
+
config: sb.configHash
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return { sources, diagnostics: [] };
|
|
58
|
+
},
|
|
59
|
+
async extract({ fs, project, source, clock }, config) {
|
|
60
|
+
const sb = project.storybooks.find((s) => s.id === config.storybookId);
|
|
61
|
+
if (!sb)
|
|
62
|
+
throw new Error(`Storybook ${config.storybookId} is not in the project discovery`);
|
|
63
|
+
const files = new Map();
|
|
64
|
+
for (const path of config.files)
|
|
65
|
+
files.set(path, await fs.readFile(path));
|
|
66
|
+
const analysis = createAnalysis(files, { paths: config.paths });
|
|
67
|
+
const builder = new IrBuilder({
|
|
68
|
+
source: {
|
|
69
|
+
id: source.id,
|
|
70
|
+
type: source.type,
|
|
71
|
+
location: source.location,
|
|
72
|
+
...(source.version ? { version: source.version } : {}),
|
|
73
|
+
inputHash: source.inputHash,
|
|
74
|
+
adapter: { name: ADAPTER_ID, version: ADAPTER_VERSION }
|
|
75
|
+
},
|
|
76
|
+
extractor: { name: "storybook-csf", version: ADAPTER_VERSION },
|
|
77
|
+
capabilities: CAPABILITIES,
|
|
78
|
+
clock
|
|
79
|
+
});
|
|
80
|
+
let index;
|
|
81
|
+
if (sb.builtOutput?.hasIndexJson) {
|
|
82
|
+
const text = await readText(fs, posix.join(sb.builtOutput.path, "index.json"));
|
|
83
|
+
index = text === undefined ? undefined : parseBuiltIndex(text);
|
|
84
|
+
if (!index)
|
|
85
|
+
builder.diagnostic({
|
|
86
|
+
code: "storybook.index-unreadable",
|
|
87
|
+
severity: "info",
|
|
88
|
+
message: `${sb.builtOutput.path}/index.json could not be read as a story index and was ignored`
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const storyFiles = sb.storyFiles.filter((f) => CODE_FILE.test(f));
|
|
92
|
+
const mdxFiles = sb.storyFiles.filter((f) => f.endsWith(".mdx"));
|
|
93
|
+
const projectFiles = new Set(files.keys());
|
|
94
|
+
let partial = sb.dynamicProperties.length > 0 || sb.storyFilesTruncated;
|
|
95
|
+
const note = (code, severity, message, location) => {
|
|
96
|
+
builder.diagnostic({ code, severity, message, location });
|
|
97
|
+
};
|
|
98
|
+
// One unusual story file must not fail the whole source: isolate it, report it, and mark the result partial.
|
|
99
|
+
const readStoryFile = (file) => {
|
|
100
|
+
const sf = analysis.sourceFile(file);
|
|
101
|
+
const csf = sf ? extractCsf(analysis, sf) : undefined;
|
|
102
|
+
if (!csf || (!csf.group && csf.stories.length === 0)) {
|
|
103
|
+
note("storybook.no-meta", "warning", `${file} matches the story globs but has no default-exported meta and no stories`, { path: file });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
emitCsf(builder, csf, index?.entries, index ? posix.relative(sb.directory, file) : undefined);
|
|
107
|
+
const group = csf.group;
|
|
108
|
+
if (!group) {
|
|
109
|
+
note("storybook.no-meta", "warning", `${file} exports stories but no default-exported meta`, {
|
|
110
|
+
path: file
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (!group.title)
|
|
115
|
+
note("storybook.title-auto", "info", `${file} has no explicit title; Storybook infers it from the path, which is not reproduced here`, { path: file, line: group.line });
|
|
116
|
+
if (!group.component)
|
|
117
|
+
note("storybook.component-missing", "info", `${file} meta has no resolvable component`, {
|
|
118
|
+
path: file,
|
|
119
|
+
line: group.line
|
|
120
|
+
});
|
|
121
|
+
else if (!group.component.file) {
|
|
122
|
+
const origin = group.component.external
|
|
123
|
+
? ` (from package ${group.component.external})`
|
|
124
|
+
: group.component.unresolvedModule
|
|
125
|
+
? ` (module ${group.component.unresolvedModule} not found)`
|
|
126
|
+
: "";
|
|
127
|
+
note("storybook.component-unresolved", "info", `${file} meta component ${group.component.text} could not be resolved to a project file${origin}`, { path: file, line: group.line });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (csf.selectionUncertain)
|
|
131
|
+
partial = true;
|
|
132
|
+
if ([csf.group, ...csf.stories].some((x) => x && x.args.unresolved.length > 0)) {
|
|
133
|
+
note("storybook.dynamic-args", "info", `${file} has args that are not statically resolvable; they are listed as unresolved, not guessed`, { path: file });
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
for (const file of storyFiles) {
|
|
137
|
+
try {
|
|
138
|
+
readStoryFile(file);
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
partial = true;
|
|
142
|
+
note("storybook.file-failed", "warning", `${file} could not be analyzed: ${error.message}`, { path: file });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
for (const file of mdxFiles) {
|
|
146
|
+
const text = files.has(file) ? files.get(file) : await fs.readFile(file);
|
|
147
|
+
emitMdx(builder, parseMdx(file, text, projectFiles));
|
|
148
|
+
}
|
|
149
|
+
if (index) {
|
|
150
|
+
const known = new Set(sb.storyFiles.map((f) => posix.relative(sb.directory, f)));
|
|
151
|
+
for (const entry of index.entries) {
|
|
152
|
+
const path = entry.importPath.replace(/^\.\//, "");
|
|
153
|
+
if (!known.has(path))
|
|
154
|
+
note("storybook.index-stale", "warning", `The built index lists ${entry.importPath}, which no longer matches the story globs`, { path: posix.join(sb.directory, path) });
|
|
155
|
+
}
|
|
156
|
+
const indexed = new Set(index.entries.map((e) => e.importPath.replace(/^\.\//, "")));
|
|
157
|
+
for (const file of sb.storyFiles) {
|
|
158
|
+
if (!indexed.has(posix.relative(sb.directory, file)))
|
|
159
|
+
note("storybook.not-in-built-index", "info", `${file} is not in the built index (the build may predate it)`, { path: file });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return { ir: builder.build(partial ? "partial" : "complete") };
|
|
163
|
+
},
|
|
164
|
+
async validate({ ir }) {
|
|
165
|
+
return ir.entities.length === 0
|
|
166
|
+
? [
|
|
167
|
+
{
|
|
168
|
+
code: "storybook.no-stories",
|
|
169
|
+
severity: "warning",
|
|
170
|
+
message: `No stories were extracted for ${ir.source.id}`,
|
|
171
|
+
sourceId: ir.source.id
|
|
172
|
+
}
|
|
173
|
+
]
|
|
174
|
+
: [];
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Files for the type-checking program: every package that owns a story file, plus the workspace packages
|
|
179
|
+
* those packages depend on (so `import { X } from "@scope/ui"` resolves to the real declaration).
|
|
180
|
+
*/
|
|
181
|
+
async function loadProgramFiles(fs, project, sb) {
|
|
182
|
+
const owners = new Map();
|
|
183
|
+
const owner = (file) => project.packages
|
|
184
|
+
.filter((p) => p.dir === "." || file === p.dir || file.startsWith(`${p.dir}/`))
|
|
185
|
+
.sort((a, b) => b.dir.length - a.dir.length)[0];
|
|
186
|
+
for (const file of sb.storyFiles) {
|
|
187
|
+
const pkg = owner(file);
|
|
188
|
+
if (pkg)
|
|
189
|
+
owners.set(pkg.id, pkg);
|
|
190
|
+
}
|
|
191
|
+
const byName = new Map(project.packages.flatMap((p) => (p.name ? [[p.name, p]] : [])));
|
|
192
|
+
const included = new Map(owners);
|
|
193
|
+
for (const pkg of owners.values()) {
|
|
194
|
+
for (const dep of pkg.dependencies) {
|
|
195
|
+
const target = byName.get(dep.name);
|
|
196
|
+
if (target)
|
|
197
|
+
included.set(target.id, target);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const paths = {};
|
|
201
|
+
const named = {};
|
|
202
|
+
for (const pkg of included.values()) {
|
|
203
|
+
if (!pkg.name)
|
|
204
|
+
continue;
|
|
205
|
+
for (const entry of pkg.entryPoints) {
|
|
206
|
+
if (!entry.file)
|
|
207
|
+
continue;
|
|
208
|
+
const specifier = entry.subpath === "." ? pkg.name : `${pkg.name}/${entry.subpath.replace(/^\.\//, "")}`;
|
|
209
|
+
named[specifier] = [entry.file];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const files = new Map();
|
|
213
|
+
const hashes = [];
|
|
214
|
+
for (const pkg of [...included.values()].sort((a, b) => (a.dir < b.dir ? -1 : 1))) {
|
|
215
|
+
const nested = project.packages.filter((p) => p.id !== pkg.id && p.dir !== "." && (pkg.dir === "." || p.dir.startsWith(`${pkg.dir}/`)));
|
|
216
|
+
const walked = await walk(fs, {
|
|
217
|
+
ignoreDirs: new Set(DEFAULT_IGNORED_DIRS),
|
|
218
|
+
maxFiles: 20_000,
|
|
219
|
+
start: pkg.dir
|
|
220
|
+
});
|
|
221
|
+
for (const path of walked.files) {
|
|
222
|
+
if (!PROGRAM_FILE.test(path) ||
|
|
223
|
+
files.has(path) ||
|
|
224
|
+
nested.some((n) => path === n.dir || path.startsWith(`${n.dir}/`)))
|
|
225
|
+
continue;
|
|
226
|
+
const text = await fs.readFile(path);
|
|
227
|
+
if (text.length > MAX_FILE_BYTES)
|
|
228
|
+
continue;
|
|
229
|
+
files.set(path, text);
|
|
230
|
+
hashes.push([path, hashText(text)]);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// MDX files are read as documents, so their content also determines the input hash.
|
|
234
|
+
for (const file of sb.storyFiles.filter((f) => f.endsWith(".mdx"))) {
|
|
235
|
+
const text = await fs.readFile(file);
|
|
236
|
+
hashes.push([file, hashText(text)]);
|
|
237
|
+
}
|
|
238
|
+
// Each package's own tsconfig `paths` apply first; workspace package names then take precedence.
|
|
239
|
+
for (const pkg of [...included.values()].sort((a, b) => (a.dir < b.dir ? -1 : 1)))
|
|
240
|
+
Object.assign(paths, tsconfigPaths(files, pkg.dir));
|
|
241
|
+
Object.assign(paths, named);
|
|
242
|
+
return { files, hashes, paths };
|
|
243
|
+
}
|
|
244
|
+
async function readText(fs, path) {
|
|
245
|
+
try {
|
|
246
|
+
const text = await fs.readFile(path);
|
|
247
|
+
return text.length > MAX_FILE_BYTES * 5 ? undefined : text;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=adapter.js.map
|