@layoutdesign/context 0.4.0 → 0.6.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 (51) hide show
  1. package/dist/bin/cli.js +37 -0
  2. package/dist/bin/cli.js.map +1 -1
  3. package/dist/src/cli/diff.d.ts +4 -0
  4. package/dist/src/cli/diff.d.ts.map +1 -0
  5. package/dist/src/cli/diff.js +53 -0
  6. package/dist/src/cli/diff.js.map +1 -0
  7. package/dist/src/cli/import-tokens-json.d.ts +5 -0
  8. package/dist/src/cli/import-tokens-json.d.ts.map +1 -0
  9. package/dist/src/cli/import-tokens-json.js +174 -0
  10. package/dist/src/cli/import-tokens-json.js.map +1 -0
  11. package/dist/src/cli/lint.d.ts +7 -0
  12. package/dist/src/cli/lint.d.ts.map +1 -0
  13. package/dist/src/cli/lint.js +80 -0
  14. package/dist/src/cli/lint.js.map +1 -0
  15. package/dist/src/cli/scan.d.ts +8 -0
  16. package/dist/src/cli/scan.d.ts.map +1 -0
  17. package/dist/src/cli/scan.js +143 -0
  18. package/dist/src/cli/scan.js.map +1 -0
  19. package/dist/src/integrations/codebase-scan.d.ts +46 -0
  20. package/dist/src/integrations/codebase-scan.d.ts.map +1 -0
  21. package/dist/src/integrations/codebase-scan.js +231 -0
  22. package/dist/src/integrations/codebase-scan.js.map +1 -0
  23. package/dist/src/integrations/storybook.d.ts +36 -0
  24. package/dist/src/integrations/storybook.d.ts.map +1 -0
  25. package/dist/src/integrations/storybook.js +124 -0
  26. package/dist/src/integrations/storybook.js.map +1 -0
  27. package/dist/src/kit/stage.d.ts +19 -0
  28. package/dist/src/kit/stage.d.ts.map +1 -0
  29. package/dist/src/kit/stage.js +30 -0
  30. package/dist/src/kit/stage.js.map +1 -0
  31. package/dist/src/lint/diff.d.ts +23 -0
  32. package/dist/src/lint/diff.d.ts.map +1 -0
  33. package/dist/src/lint/diff.js +62 -0
  34. package/dist/src/lint/diff.js.map +1 -0
  35. package/dist/src/lint/layout-md.d.ts +21 -0
  36. package/dist/src/lint/layout-md.d.ts.map +1 -0
  37. package/dist/src/lint/layout-md.js +376 -0
  38. package/dist/src/lint/layout-md.js.map +1 -0
  39. package/dist/src/mcp/server.d.ts.map +1 -1
  40. package/dist/src/mcp/server.js +17 -2
  41. package/dist/src/mcp/server.js.map +1 -1
  42. package/dist/src/mcp/tools/list-components.d.ts +2 -1
  43. package/dist/src/mcp/tools/list-components.d.ts.map +1 -1
  44. package/dist/src/mcp/tools/list-components.js +50 -24
  45. package/dist/src/mcp/tools/list-components.js.map +1 -1
  46. package/dist/src/mcp/tools/scan-project.d.ts +30 -0
  47. package/dist/src/mcp/tools/scan-project.d.ts.map +1 -0
  48. package/dist/src/mcp/tools/scan-project.js +97 -0
  49. package/dist/src/mcp/tools/scan-project.js.map +1 -0
  50. package/package.json +2 -1
  51. package/skills/layout-md/SKILL.md +135 -0
@@ -0,0 +1,46 @@
1
+ import { type StoryComponentMeta } from "./storybook.js";
2
+ export interface ScannedProp {
3
+ name: string;
4
+ type?: string;
5
+ optional?: boolean;
6
+ }
7
+ export interface ScannedComponent {
8
+ /** PascalCase component name */
9
+ name: string;
10
+ /** File path relative to the scan root */
11
+ filePath: string;
12
+ /** How the component is exported */
13
+ exportType: "named" | "default";
14
+ /** Props interface/type name if detected */
15
+ propsInterfaceName?: string;
16
+ /** Individual prop keys extracted from the interface */
17
+ props: ScannedProp[];
18
+ /** Whether the component uses forwardRef */
19
+ usesForwardRef: boolean;
20
+ /** Storybook metadata if a matching .stories file was found */
21
+ storybook?: StoryComponentMeta;
22
+ }
23
+ export interface ScanResult {
24
+ /** Root directory that was scanned */
25
+ rootPath: string;
26
+ /** All detected React components */
27
+ components: ScannedComponent[];
28
+ /** Storybook stories that matched a component */
29
+ storybookStories: StoryComponentMeta[];
30
+ /** Stories that did not match any scanned component */
31
+ unmatchedStories: StoryComponentMeta[];
32
+ /** Total files scanned */
33
+ filesScanned: number;
34
+ /** Scan duration in milliseconds */
35
+ durationMs: number;
36
+ }
37
+ /**
38
+ * Scan a directory for React components and Storybook stories.
39
+ * Returns structured results with component metadata and story associations.
40
+ */
41
+ export declare function scanCodebase(rootPath: string): Promise<ScanResult>;
42
+ /**
43
+ * Scan for Storybook stories only.
44
+ */
45
+ export declare function scanStorybook(rootPath: string): Promise<StoryComponentMeta[]>;
46
+ //# sourceMappingURL=codebase-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codebase-scan.d.ts","sourceRoot":"","sources":["../../../src/integrations/codebase-scan.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wDAAwD;IACxD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,4CAA4C;IAC5C,cAAc,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAED,MAAM,WAAW,UAAU;IACzB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,iDAAiD;IACjD,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,uDAAuD;IACvD,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;IACvC,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAqLD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAuExE;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAkB/B"}
@@ -0,0 +1,231 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join, relative, extname } from "node:path";
3
+ import { parseStoryFromPath, } from "./storybook.js";
4
+ // ── Constants ──────────────────────────────────────────────────────────────
5
+ const SKIP_DIRS = new Set([
6
+ "node_modules",
7
+ ".next",
8
+ ".nuxt",
9
+ "dist",
10
+ "build",
11
+ "out",
12
+ ".git",
13
+ ".layout",
14
+ ".superduper",
15
+ "coverage",
16
+ "__tests__",
17
+ "__mocks__",
18
+ ".turbo",
19
+ ".cache",
20
+ ".vercel",
21
+ ".output",
22
+ ]);
23
+ const COMPONENT_EXTENSIONS = new Set([".tsx", ".jsx"]);
24
+ const STORY_SUFFIXES = [".stories.ts", ".stories.tsx", ".stories.js", ".stories.jsx"];
25
+ // ── Regex patterns ─────────────────────────────────────────────────────────
26
+ // Named export: `export function Button(` or `export const Button =` or `export const Button: FC`
27
+ const NAMED_FUNCTION_RE = /export\s+function\s+([A-Z]\w+)\s*(?:<[^>]*>)?\s*\(/g;
28
+ const NAMED_CONST_RE = /export\s+const\s+([A-Z]\w+)\s*(?::\s*(?:React\.)?(?:FC|FunctionComponent|ComponentType)(?:<[^>]*>)?\s*)?=\s*/g;
29
+ // Default export: `export default function Button(`
30
+ const DEFAULT_FUNCTION_RE = /export\s+default\s+function\s+([A-Z]\w+)\s*(?:<[^>]*>)?\s*\(/g;
31
+ // forwardRef: `export const Button = forwardRef<` or `React.forwardRef<`
32
+ const FORWARD_REF_RE = /export\s+const\s+([A-Z]\w+)\s*=\s*(?:React\.)?forwardRef/g;
33
+ // Grouped export: `export { Button, Card, buttonVariants }` — capture PascalCase names only
34
+ const GROUPED_EXPORT_RE = /export\s*\{([^}]+)\}/g;
35
+ // Props interface: `interface ButtonProps {` or `type ButtonProps = {`
36
+ const PROPS_INTERFACE_RE = /(?:interface|type)\s+(\w+Props)\s*(?:=\s*)?\{([\s\S]*?)\n\}/g;
37
+ // Individual prop from interface body: ` label: string;` or ` disabled?: boolean;`
38
+ const PROP_LINE_RE = /^\s+(\w+)(\?)?\s*:\s*([^;]+)/gm;
39
+ // ── File discovery ─────────────────────────────────────────────────────────
40
+ function isStoryFile(filePath) {
41
+ return STORY_SUFFIXES.some((suffix) => filePath.endsWith(suffix));
42
+ }
43
+ /**
44
+ * Recursively walk a directory, yielding file paths.
45
+ * Skips directories in the SKIP_DIRS set.
46
+ */
47
+ async function* walkDir(dir) {
48
+ let entries;
49
+ try {
50
+ entries = await readdir(dir, { withFileTypes: true });
51
+ }
52
+ catch {
53
+ return;
54
+ }
55
+ for (const entry of entries) {
56
+ const fullPath = join(dir, entry.name);
57
+ if (entry.isDirectory()) {
58
+ if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith(".")) {
59
+ yield* walkDir(fullPath);
60
+ }
61
+ }
62
+ else if (entry.isFile()) {
63
+ yield fullPath;
64
+ }
65
+ }
66
+ }
67
+ // ── Component extraction ───────────────────────────────────────────────────
68
+ function extractComponents(content, filePath) {
69
+ const components = [];
70
+ const seen = new Set();
71
+ // Extract all props interfaces/types from the file
72
+ const propsMap = new Map();
73
+ let propsMatch;
74
+ PROPS_INTERFACE_RE.lastIndex = 0;
75
+ while ((propsMatch = PROPS_INTERFACE_RE.exec(content)) !== null) {
76
+ const interfaceName = propsMatch[1];
77
+ const body = propsMatch[2] ?? "";
78
+ const props = [];
79
+ let propLineMatch;
80
+ PROP_LINE_RE.lastIndex = 0;
81
+ while ((propLineMatch = PROP_LINE_RE.exec(body)) !== null) {
82
+ props.push({
83
+ name: propLineMatch[1],
84
+ optional: propLineMatch[2] === "?",
85
+ type: propLineMatch[3]?.trim(),
86
+ });
87
+ }
88
+ propsMap.set(interfaceName, props);
89
+ }
90
+ function addComponent(name, exportType, usesForwardRef) {
91
+ if (seen.has(name))
92
+ return;
93
+ seen.add(name);
94
+ // Try to find a matching props interface
95
+ const propsInterfaceName = `${name}Props`;
96
+ const props = propsMap.get(propsInterfaceName) ?? [];
97
+ components.push({
98
+ name,
99
+ filePath,
100
+ exportType,
101
+ propsInterfaceName: propsMap.has(propsInterfaceName)
102
+ ? propsInterfaceName
103
+ : undefined,
104
+ props,
105
+ usesForwardRef,
106
+ });
107
+ }
108
+ // Named function exports
109
+ let match;
110
+ NAMED_FUNCTION_RE.lastIndex = 0;
111
+ while ((match = NAMED_FUNCTION_RE.exec(content)) !== null) {
112
+ addComponent(match[1], "named", false);
113
+ }
114
+ // Named const exports (FC, arrow functions)
115
+ NAMED_CONST_RE.lastIndex = 0;
116
+ while ((match = NAMED_CONST_RE.exec(content)) !== null) {
117
+ addComponent(match[1], "named", false);
118
+ }
119
+ // Default function exports
120
+ DEFAULT_FUNCTION_RE.lastIndex = 0;
121
+ while ((match = DEFAULT_FUNCTION_RE.exec(content)) !== null) {
122
+ addComponent(match[1], "default", false);
123
+ }
124
+ // forwardRef exports
125
+ FORWARD_REF_RE.lastIndex = 0;
126
+ while ((match = FORWARD_REF_RE.exec(content)) !== null) {
127
+ addComponent(match[1], "named", true);
128
+ }
129
+ // Grouped exports: `export { Button, Card, buttonVariants }`
130
+ // Only pick PascalCase names (components), skip camelCase (utilities)
131
+ GROUPED_EXPORT_RE.lastIndex = 0;
132
+ while ((match = GROUPED_EXPORT_RE.exec(content)) !== null) {
133
+ const names = match[1].split(",").map((n) => n.trim().split(/\s+as\s+/).pop().trim());
134
+ for (const name of names) {
135
+ if (/^[A-Z][a-zA-Z0-9]+$/.test(name)) {
136
+ addComponent(name, "named", false);
137
+ }
138
+ }
139
+ }
140
+ return components;
141
+ }
142
+ // ── Main scanner ───────────────────────────────────────────────────────────
143
+ /**
144
+ * Scan a directory for React components and Storybook stories.
145
+ * Returns structured results with component metadata and story associations.
146
+ */
147
+ export async function scanCodebase(rootPath) {
148
+ const startTime = Date.now();
149
+ const componentFiles = [];
150
+ const storyFiles = [];
151
+ let filesScanned = 0;
152
+ // Collect all relevant files
153
+ for await (const filePath of walkDir(rootPath)) {
154
+ filesScanned++;
155
+ const ext = extname(filePath);
156
+ if (isStoryFile(filePath)) {
157
+ storyFiles.push(filePath);
158
+ }
159
+ else if (COMPONENT_EXTENSIONS.has(ext)) {
160
+ componentFiles.push(filePath);
161
+ }
162
+ }
163
+ // Parse all component files
164
+ const allComponents = [];
165
+ for (const filePath of componentFiles) {
166
+ try {
167
+ const content = await readFile(filePath, "utf-8");
168
+ const relPath = relative(rootPath, filePath);
169
+ const found = extractComponents(content, relPath);
170
+ allComponents.push(...found);
171
+ }
172
+ catch {
173
+ // Skip unreadable files
174
+ }
175
+ }
176
+ // Parse all story files
177
+ const allStories = [];
178
+ for (const filePath of storyFiles) {
179
+ try {
180
+ const relPath = relative(rootPath, filePath);
181
+ const story = await parseStoryFromPath(filePath);
182
+ if (story) {
183
+ // Use relative path in the result
184
+ allStories.push({ ...story, filePath: relPath });
185
+ }
186
+ }
187
+ catch {
188
+ // Skip unreadable files
189
+ }
190
+ }
191
+ // Match stories to components
192
+ const matchedStoryNames = new Set();
193
+ for (const component of allComponents) {
194
+ const matchingStory = allStories.find((s) => s.componentName === component.name);
195
+ if (matchingStory) {
196
+ component.storybook = matchingStory;
197
+ matchedStoryNames.add(matchingStory.componentName);
198
+ }
199
+ }
200
+ const unmatchedStories = allStories.filter((s) => !matchedStoryNames.has(s.componentName));
201
+ return {
202
+ rootPath,
203
+ components: allComponents,
204
+ storybookStories: allStories,
205
+ unmatchedStories,
206
+ filesScanned,
207
+ durationMs: Date.now() - startTime,
208
+ };
209
+ }
210
+ /**
211
+ * Scan for Storybook stories only.
212
+ */
213
+ export async function scanStorybook(rootPath) {
214
+ const stories = [];
215
+ for await (const filePath of walkDir(rootPath)) {
216
+ if (isStoryFile(filePath)) {
217
+ try {
218
+ const relPath = relative(rootPath, filePath);
219
+ const story = await parseStoryFromPath(filePath);
220
+ if (story) {
221
+ stories.push({ ...story, filePath: relPath });
222
+ }
223
+ }
224
+ catch {
225
+ // Skip unreadable files
226
+ }
227
+ }
228
+ }
229
+ return stories;
230
+ }
231
+ //# sourceMappingURL=codebase-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codebase-scan.js","sourceRoot":"","sources":["../../../src/integrations/codebase-scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ export interface StoryArg {
2
+ name: string;
3
+ type?: string;
4
+ defaultValue?: string;
5
+ description?: string;
6
+ control?: string;
7
+ options?: string[];
8
+ }
9
+ export interface StoryEntry {
10
+ name: string;
11
+ tags?: string[];
12
+ }
13
+ export interface StoryComponentMeta {
14
+ /** Component name derived from the story title (e.g. "Button" from "Components/Button") */
15
+ componentName: string;
16
+ /** Full title as declared in the story meta */
17
+ title: string;
18
+ /** File path relative to the scan root */
19
+ filePath: string;
20
+ /** Args and argTypes extracted from the default export */
21
+ args: StoryArg[];
22
+ /** Individual stories (named exports) */
23
+ stories: StoryEntry[];
24
+ /** Tags declared on the meta object */
25
+ tags?: string[];
26
+ }
27
+ /**
28
+ * Parse a single Storybook story file and extract component metadata.
29
+ * Uses regex-based extraction (no AST required).
30
+ */
31
+ export declare function parseStoryFile(content: string, filePath: string): StoryComponentMeta | null;
32
+ /**
33
+ * Parse a story file from disk.
34
+ */
35
+ export declare function parseStoryFromPath(filePath: string): Promise<StoryComponentMeta | null>;
36
+ //# sourceMappingURL=storybook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storybook.d.ts","sourceRoot":"","sources":["../../../src/integrations/storybook.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,2FAA2F;IAC3F,aAAa,EAAE,MAAM,CAAC;IACtB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,yCAAyC;IACzC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAmCD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAkG3B;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAGpC"}
@@ -0,0 +1,124 @@
1
+ import { readFile } from "node:fs/promises";
2
+ // ── Regex patterns ─────────────────────────────────────────────────────────
3
+ // Match `title: "Components/Button"` or `title: 'Components/Button'`
4
+ const TITLE_RE = /title\s*:\s*["'`]([^"'`]+)["'`]/;
5
+ // Match `component: Button` or `component: "Button"`
6
+ const COMPONENT_RE = /component\s*:\s*["'`]?(\w+)["'`]?/;
7
+ // Match individual argTypes entries like: size: { control: "select", options: ["sm", "md", "lg"] }
8
+ const ARG_TYPE_RE = /(\w+)\s*:\s*\{([^}]*)\}/g;
9
+ // Match `control:` value inside an argType block
10
+ const CONTROL_RE = /control\s*:\s*["'`](\w+)["'`]/;
11
+ // Match `options:` array inside an argType block
12
+ const OPTIONS_RE = /options\s*:\s*\[([^\]]*)\]/;
13
+ // Match `type:` value inside an argType block
14
+ const TYPE_RE = /type\s*:\s*["'`](\w+)["'`]/;
15
+ // Match named exports like `export const Primary: Story = ...`
16
+ const STORY_EXPORT_RE = /export\s+const\s+(\w+)\s*(?::\s*\w+(?:<[^>]*>)?\s*)?=/g;
17
+ // Match `tags: ["autodocs", ...]` on the meta object
18
+ const TAGS_RE = /tags\s*:\s*\[([^\]]*)\]/;
19
+ // Match `args: { ... }` on the meta object (top-level default args)
20
+ const DEFAULT_ARGS_RE = /args\s*:\s*\{([^}]*)\}/;
21
+ // ── Parser ─────────────────────────────────────────────────────────────────
22
+ /**
23
+ * Parse a single Storybook story file and extract component metadata.
24
+ * Uses regex-based extraction (no AST required).
25
+ */
26
+ export function parseStoryFile(content, filePath) {
27
+ // Must have a default export (the meta object)
28
+ if (!content.includes("export default") &&
29
+ !content.includes("satisfies Meta")) {
30
+ return null;
31
+ }
32
+ // Extract title — required
33
+ const titleMatch = TITLE_RE.exec(content);
34
+ const componentMatch = COMPONENT_RE.exec(content);
35
+ // Derive component name from title or component field
36
+ let componentName;
37
+ if (titleMatch?.[1]) {
38
+ const parts = titleMatch[1].split("/");
39
+ componentName = parts[parts.length - 1];
40
+ }
41
+ else if (componentMatch?.[1]) {
42
+ componentName = componentMatch[1];
43
+ }
44
+ if (!componentName)
45
+ return null;
46
+ const title = titleMatch?.[1] ?? componentName;
47
+ // Extract args from argTypes
48
+ const args = [];
49
+ const argTypesSection = content.match(/argTypes\s*:\s*\{([\s\S]*?)\n\s*\}/);
50
+ if (argTypesSection?.[1]) {
51
+ let match;
52
+ ARG_TYPE_RE.lastIndex = 0;
53
+ while ((match = ARG_TYPE_RE.exec(argTypesSection[1])) !== null) {
54
+ const name = match[1];
55
+ const block = match[2] ?? "";
56
+ const controlMatch = CONTROL_RE.exec(block);
57
+ const optionsMatch = OPTIONS_RE.exec(block);
58
+ const typeMatch = TYPE_RE.exec(block);
59
+ const arg = { name };
60
+ if (typeMatch?.[1])
61
+ arg.type = typeMatch[1];
62
+ if (controlMatch?.[1])
63
+ arg.control = controlMatch[1];
64
+ if (optionsMatch?.[1]) {
65
+ arg.options = optionsMatch[1]
66
+ .split(",")
67
+ .map((s) => s.trim().replace(/["'`]/g, ""))
68
+ .filter(Boolean);
69
+ }
70
+ args.push(arg);
71
+ }
72
+ }
73
+ // Also extract from top-level `args: { ... }` if argTypes is empty
74
+ if (args.length === 0) {
75
+ const defaultArgsMatch = DEFAULT_ARGS_RE.exec(content);
76
+ if (defaultArgsMatch?.[1]) {
77
+ const entries = defaultArgsMatch[1].split(",");
78
+ for (const entry of entries) {
79
+ const [key, value] = entry.split(":").map((s) => s.trim());
80
+ if (key) {
81
+ args.push({
82
+ name: key,
83
+ defaultValue: value?.replace(/["'`]/g, ""),
84
+ });
85
+ }
86
+ }
87
+ }
88
+ }
89
+ // Extract story names from named exports
90
+ const stories = [];
91
+ let storyMatch;
92
+ STORY_EXPORT_RE.lastIndex = 0;
93
+ while ((storyMatch = STORY_EXPORT_RE.exec(content)) !== null) {
94
+ const name = storyMatch[1];
95
+ // Skip common non-story exports
96
+ if (name === "default" || name === "meta" || name === "Meta")
97
+ continue;
98
+ stories.push({ name });
99
+ }
100
+ // Extract tags
101
+ const tagsMatch = TAGS_RE.exec(content);
102
+ const tags = tagsMatch?.[1]
103
+ ? tagsMatch[1]
104
+ .split(",")
105
+ .map((s) => s.trim().replace(/["'`]/g, ""))
106
+ .filter(Boolean)
107
+ : undefined;
108
+ return {
109
+ componentName,
110
+ title,
111
+ filePath,
112
+ args,
113
+ stories,
114
+ tags,
115
+ };
116
+ }
117
+ /**
118
+ * Parse a story file from disk.
119
+ */
120
+ export async function parseStoryFromPath(filePath) {
121
+ const content = await readFile(filePath, "utf-8");
122
+ return parseStoryFile(content, filePath);
123
+ }
124
+ //# sourceMappingURL=storybook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storybook.js","sourceRoot":"","sources":["../../../src/integrations/storybook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Resolve a user-supplied kit reference into a directory that the loader can
3
+ * read. Accepts:
4
+ * 1. A path to a directory containing a .layout/ subfolder (default for
5
+ * consumer projects).
6
+ * 2. A path to a directory with layout.md at its root (a bundled kit or
7
+ * an unzipped export). Staged into a temp dir that wraps it in .layout/.
8
+ * 3. A bundled kit name (linear-lite, stripe-lite, notion-lite). Likewise
9
+ * staged.
10
+ *
11
+ * The caller MUST invoke the returned cleanup() when done to remove any temp
12
+ * directory the function created.
13
+ */
14
+ export interface StagedKit {
15
+ path: string;
16
+ cleanup: () => void;
17
+ }
18
+ export declare function stageKitReference(input: string | undefined): StagedKit;
19
+ //# sourceMappingURL=stage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.d.ts","sourceRoot":"","sources":["../../../src/kit/stage.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAUtE"}
@@ -0,0 +1,30 @@
1
+ import { existsSync, mkdtempSync, writeFileSync, mkdirSync, readFileSync, rmSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join, resolve } from "node:path";
4
+ import { LAYOUT_DIR, LAYOUT_MD_FILE, TOKENS_CSS_FILE, TOKENS_JSON_FILE, KIT_MANIFEST_FILE, } from "./types.js";
5
+ import { getBundledKitPath } from "./loader.js";
6
+ export function stageKitReference(input) {
7
+ if (!input)
8
+ return { path: process.cwd(), cleanup: () => { } };
9
+ const abs = resolve(input);
10
+ if (existsSync(join(abs, LAYOUT_DIR)))
11
+ return { path: abs, cleanup: () => { } };
12
+ if (existsSync(join(abs, LAYOUT_MD_FILE)))
13
+ return stageDirAsKit(abs);
14
+ const bundled = getBundledKitPath(input);
15
+ if (bundled)
16
+ return stageDirAsKit(bundled);
17
+ return { path: abs, cleanup: () => { } };
18
+ }
19
+ function stageDirAsKit(kitDir) {
20
+ const tmp = mkdtempSync(join(tmpdir(), "layout-stage-"));
21
+ const layoutDir = join(tmp, LAYOUT_DIR);
22
+ mkdirSync(layoutDir, { recursive: true });
23
+ for (const f of [LAYOUT_MD_FILE, TOKENS_CSS_FILE, TOKENS_JSON_FILE, KIT_MANIFEST_FILE]) {
24
+ const src = join(kitDir, f);
25
+ if (existsSync(src))
26
+ writeFileSync(join(layoutDir, f), readFileSync(src));
27
+ }
28
+ return { path: tmp, cleanup: () => rmSync(tmp, { recursive: true, force: true }) };
29
+ }
30
+ //# sourceMappingURL=stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stage.js","sourceRoot":"","sources":["../../../src/kit/stage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,UAAU,EACV,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAoBhD,MAAM,UAAU,iBAAiB,CAAC,KAAyB;IACzD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IAC9D,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3B,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IAC/E,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAAE,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;IAErE,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,OAAO;QAAE,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;IAE3C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,aAAa,CAAC,MAAc;IACnC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACxC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,KAAK,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,EAAE,CAAC;QACvF,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5B,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AACrF,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { Kit } from "../kit/types.js";
2
+ export interface TokenChange {
3
+ name: string;
4
+ before?: string;
5
+ after?: string;
6
+ }
7
+ export interface KitDiff {
8
+ tokens: {
9
+ added: TokenChange[];
10
+ removed: TokenChange[];
11
+ modified: TokenChange[];
12
+ };
13
+ sections: {
14
+ added: string[];
15
+ removed: string[];
16
+ };
17
+ summary: {
18
+ totalChanges: number;
19
+ breakingChanges: number;
20
+ };
21
+ }
22
+ export declare function diffKits(base: Kit, head: Kit): KitDiff;
23
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/lint/diff.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE;QACN,KAAK,EAAE,WAAW,EAAE,CAAC;QACrB,OAAO,EAAE,WAAW,EAAE,CAAC;QACvB,QAAQ,EAAE,WAAW,EAAE,CAAC;KACzB,CAAC;IACF,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,OAAO,EAAE;QACP,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAqBD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,OAAO,CAoCtD"}
@@ -0,0 +1,62 @@
1
+ // Token-level diff engine for two layout kits. Mirrors the shape of the
2
+ // extraction-diff UI in Studio so outputs are recognisable to anyone who
3
+ // has used re-extract.
4
+ function parseCssTokens(css) {
5
+ const map = new Map();
6
+ if (!css)
7
+ return map;
8
+ for (const match of css.matchAll(/^\s*(--[a-zA-Z0-9_-]+)\s*:\s*([^;\n]+);/gm)) {
9
+ const name = match[1];
10
+ const value = match[2];
11
+ if (name && value)
12
+ map.set(name, value.trim());
13
+ }
14
+ return map;
15
+ }
16
+ function parseSections(layoutMd) {
17
+ const out = new Set();
18
+ for (const match of layoutMd.matchAll(/^##\s+(.+)$/gm)) {
19
+ if (match[1])
20
+ out.add(match[1].trim());
21
+ }
22
+ return out;
23
+ }
24
+ export function diffKits(base, head) {
25
+ const baseTokens = parseCssTokens(base.tokensCss);
26
+ const headTokens = parseCssTokens(head.tokensCss);
27
+ const added = [];
28
+ const removed = [];
29
+ const modified = [];
30
+ for (const [name, value] of headTokens) {
31
+ if (!baseTokens.has(name)) {
32
+ added.push({ name, after: value });
33
+ }
34
+ else if (baseTokens.get(name) !== value) {
35
+ modified.push({ name, before: baseTokens.get(name), after: value });
36
+ }
37
+ }
38
+ for (const [name, value] of baseTokens) {
39
+ if (!headTokens.has(name))
40
+ removed.push({ name, before: value });
41
+ }
42
+ const baseSections = parseSections(base.layoutMd);
43
+ const headSections = parseSections(head.layoutMd);
44
+ const sectionsAdded = [];
45
+ const sectionsRemoved = [];
46
+ for (const s of headSections)
47
+ if (!baseSections.has(s))
48
+ sectionsAdded.push(s);
49
+ for (const s of baseSections)
50
+ if (!headSections.has(s))
51
+ sectionsRemoved.push(s);
52
+ const totalChanges = added.length + removed.length + modified.length + sectionsAdded.length + sectionsRemoved.length;
53
+ // Breaking: removed tokens + removed sections (references in downstream code
54
+ // may now fail).
55
+ const breakingChanges = removed.length + sectionsRemoved.length;
56
+ return {
57
+ tokens: { added, removed, modified },
58
+ sections: { added: sectionsAdded, removed: sectionsRemoved },
59
+ summary: { totalChanges, breakingChanges },
60
+ };
61
+ }
62
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/lint/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Kit } from "../kit/types.js";
2
+ export type LintSeverity = "error" | "warning" | "info";
3
+ export interface LintIssue {
4
+ ruleId: string;
5
+ severity: LintSeverity;
6
+ message: string;
7
+ file?: "layout.md" | "tokens.css" | "tokens.json";
8
+ line?: number;
9
+ detail?: Record<string, unknown>;
10
+ }
11
+ export interface LintResult {
12
+ issues: LintIssue[];
13
+ summary: {
14
+ errors: number;
15
+ warnings: number;
16
+ info: number;
17
+ passed: boolean;
18
+ };
19
+ }
20
+ export declare function lintKit(kit: Kit): LintResult;
21
+ //# sourceMappingURL=layout-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-md.d.ts","sourceRoot":"","sources":["../../../src/lint/layout-md.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAExD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,OAAO,CAAC;KACjB,CAAC;CACH;AAqWD,wBAAgB,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU,CAkB5C"}