@nanisoft/prism-llms 0.4.0 → 0.5.1

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 (175) hide show
  1. package/README.md +88 -0
  2. package/THIRD-PARTY-NOTICES.md +48 -0
  3. package/dist/data.json +4037 -386
  4. package/dist/demo-graph.d.ts +21 -12
  5. package/dist/demo-graph.js +37 -21
  6. package/dist/extractor.d.ts +24 -17
  7. package/dist/extractor.js +299 -156
  8. package/dist/index.d.ts +12 -7
  9. package/dist/index.js +9 -7
  10. package/dist/llms-full.txt +8248 -2013
  11. package/dist/llms.txt +98 -93
  12. package/dist/markdown.d.ts +69 -23
  13. package/dist/markdown.js +131 -72
  14. package/dist/md/blocks/app-shell-01.md +135 -0
  15. package/dist/md/blocks/auth-form-01.md +135 -0
  16. package/dist/md/blocks/cta-01.md +88 -0
  17. package/dist/md/blocks/data-table-01.md +196 -0
  18. package/dist/md/blocks/feature-grid-01.md +92 -0
  19. package/dist/md/blocks/hero-01.md +90 -0
  20. package/dist/md/blocks/instrument-panel-01.md +109 -0
  21. package/dist/md/blocks/logo-strip-01.md +97 -0
  22. package/dist/md/blocks/note-grid-01.md +98 -0
  23. package/dist/md/blocks/page-header-01.md +97 -0
  24. package/dist/md/blocks/pricing-01.md +91 -0
  25. package/dist/md/blocks/process-rail-01.md +106 -0
  26. package/dist/md/blocks/product-grid-01.md +107 -0
  27. package/dist/md/blocks/settings-panel-01.md +146 -0
  28. package/dist/md/blocks/site-footer.md +103 -11
  29. package/dist/md/blocks/site-header.md +107 -11
  30. package/dist/md/blocks/stack-grid-01.md +108 -0
  31. package/dist/md/blocks/stats-01.md +89 -0
  32. package/dist/md/blocks/status-ledger-01.md +121 -0
  33. package/dist/md/changelogs/prism-llms.md +244 -0
  34. package/dist/md/changelogs/prism-mcp-server.md +95 -0
  35. package/dist/md/changelogs/prism-tokens.md +126 -0
  36. package/dist/md/changelogs/prism-ui.md +467 -0
  37. package/dist/md/components/accordion.md +108 -0
  38. package/dist/md/components/alert.md +90 -7
  39. package/dist/md/components/avatar.md +89 -7
  40. package/dist/md/components/badge.md +74 -7
  41. package/dist/md/components/breadcrumb.md +84 -7
  42. package/dist/md/components/button.md +90 -7
  43. package/dist/md/components/card.md +90 -7
  44. package/dist/md/components/checkbox.md +101 -7
  45. package/dist/md/components/cta-link.md +98 -0
  46. package/dist/md/components/diagram.md +124 -0
  47. package/dist/md/components/dialog.md +128 -0
  48. package/dist/md/components/dropdown-menu.md +125 -0
  49. package/dist/md/components/fact-list.md +85 -0
  50. package/dist/md/components/field.md +116 -0
  51. package/dist/md/components/input.md +86 -7
  52. package/dist/md/components/kbd.md +77 -0
  53. package/dist/md/components/pagination.md +95 -7
  54. package/dist/md/components/popover.md +95 -7
  55. package/dist/md/components/product-mark.md +114 -0
  56. package/dist/md/components/product-switcher.md +88 -0
  57. package/dist/md/components/progress.md +88 -7
  58. package/dist/md/components/prose.md +91 -0
  59. package/dist/md/components/radio-group.md +111 -0
  60. package/dist/md/components/section.md +91 -0
  61. package/dist/md/components/select.md +143 -7
  62. package/dist/md/components/separator.md +77 -0
  63. package/dist/md/components/skeleton.md +71 -7
  64. package/dist/md/components/slider.md +90 -7
  65. package/dist/md/components/switch.md +104 -7
  66. package/dist/md/components/table.md +104 -7
  67. package/dist/md/components/tabs.md +105 -7
  68. package/dist/md/components/textarea.md +101 -0
  69. package/dist/md/components/tooltip.md +95 -7
  70. package/dist/md/components/typography.md +82 -7
  71. package/dist/md/content/about-content.md +36 -0
  72. package/dist/md/content/audience.md +43 -0
  73. package/dist/md/content/glossary.md +69 -0
  74. package/dist/md/content/product-vocabulary.md +53 -0
  75. package/dist/md/content/voice.md +52 -0
  76. package/dist/md/content/writing-mechanics.md +58 -0
  77. package/dist/md/foundation/colors.md +10 -0
  78. package/dist/md/foundation/iconography.md +14 -0
  79. package/dist/md/foundation/motion.md +10 -0
  80. package/dist/md/foundation/radii.md +9 -0
  81. package/dist/md/foundation/shadows.md +9 -0
  82. package/dist/md/foundation/spacings.md +8 -0
  83. package/dist/md/foundation/typography.md +9 -0
  84. package/dist/md/foundation/variables.md +9 -0
  85. package/dist/md/overview/architecture.md +76 -0
  86. package/dist/md/overview/brand.md +41 -0
  87. package/dist/md/overview/composition.md +77 -0
  88. package/dist/md/overview/quickstart.md +97 -0
  89. package/dist/md/overview/theming.md +89 -0
  90. package/dist/md/overview/using-llms.md +83 -0
  91. package/dist/md/pages/auth-page.md +149 -0
  92. package/dist/md/pages/blog-post-page.md +136 -0
  93. package/dist/md/pages/dashboard-page.md +241 -0
  94. package/dist/md/pages/docs-shell.md +210 -15
  95. package/dist/md/pages/marketing-page.md +199 -0
  96. package/dist/md/pages/not-found-page.md +105 -0
  97. package/dist/md/pages/settings-page.md +206 -0
  98. package/dist/prism-skill.md +50 -0
  99. package/dist/store.d.ts +203 -0
  100. package/dist/store.js +317 -0
  101. package/package.json +29 -26
  102. package/dist/demo-graph.d.ts.map +0 -1
  103. package/dist/demo-graph.js.map +0 -1
  104. package/dist/extractor.d.ts.map +0 -1
  105. package/dist/extractor.js.map +0 -1
  106. package/dist/index.d.ts.map +0 -1
  107. package/dist/index.js.map +0 -1
  108. package/dist/markdown.d.ts.map +0 -1
  109. package/dist/markdown.js.map +0 -1
  110. package/dist/md/blocks/component-demo.md +0 -19
  111. package/dist/md/blocks/page-header.md +0 -19
  112. package/dist/md/components/affix.md +0 -14
  113. package/dist/md/components/anchor.md +0 -14
  114. package/dist/md/components/auto-complete.md +0 -14
  115. package/dist/md/components/back-top.md +0 -14
  116. package/dist/md/components/border-beam.md +0 -14
  117. package/dist/md/components/calendar.md +0 -14
  118. package/dist/md/components/carousel.md +0 -14
  119. package/dist/md/components/cascader.md +0 -14
  120. package/dist/md/components/col.md +0 -14
  121. package/dist/md/components/collapse.md +0 -14
  122. package/dist/md/components/color-picker.md +0 -14
  123. package/dist/md/components/date-picker.md +0 -14
  124. package/dist/md/components/descriptions.md +0 -14
  125. package/dist/md/components/display-title.md +0 -20
  126. package/dist/md/components/divider.md +0 -14
  127. package/dist/md/components/drawer.md +0 -14
  128. package/dist/md/components/dropdown.md +0 -14
  129. package/dist/md/components/empty.md +0 -14
  130. package/dist/md/components/flex.md +0 -14
  131. package/dist/md/components/float-button.md +0 -14
  132. package/dist/md/components/form.md +0 -14
  133. package/dist/md/components/grid.md +0 -14
  134. package/dist/md/components/image.md +0 -14
  135. package/dist/md/components/input-number.md +0 -14
  136. package/dist/md/components/layout.md +0 -14
  137. package/dist/md/components/list.md +0 -14
  138. package/dist/md/components/listy.md +0 -14
  139. package/dist/md/components/masonry.md +0 -14
  140. package/dist/md/components/mentions.md +0 -14
  141. package/dist/md/components/menu.md +0 -14
  142. package/dist/md/components/modal.md +0 -14
  143. package/dist/md/components/popconfirm.md +0 -14
  144. package/dist/md/components/qrcode.md +0 -14
  145. package/dist/md/components/radio.md +0 -14
  146. package/dist/md/components/rate.md +0 -14
  147. package/dist/md/components/result.md +0 -14
  148. package/dist/md/components/row.md +0 -14
  149. package/dist/md/components/segmented.md +0 -14
  150. package/dist/md/components/space.md +0 -14
  151. package/dist/md/components/spin.md +0 -14
  152. package/dist/md/components/splitter.md +0 -14
  153. package/dist/md/components/statistic.md +0 -14
  154. package/dist/md/components/steps.md +0 -14
  155. package/dist/md/components/tag.md +0 -14
  156. package/dist/md/components/time-picker.md +0 -14
  157. package/dist/md/components/timeline.md +0 -14
  158. package/dist/md/components/tour.md +0 -14
  159. package/dist/md/components/transfer.md +0 -14
  160. package/dist/md/components/tree-select.md +0 -14
  161. package/dist/md/components/tree.md +0 -14
  162. package/dist/md/components/upload.md +0 -14
  163. package/dist/md/components/watermark.md +0 -14
  164. package/dist/md/docs/brand.md +0 -41
  165. package/dist/md/pages/blog-layout.md +0 -19
  166. package/dist/md/theme/blue-dark.md +0 -127
  167. package/dist/md/theme/blue-light.md +0 -129
  168. package/dist/md/theme/green-dark.md +0 -127
  169. package/dist/md/theme/green-light.md +0 -129
  170. package/dist/md/theme/lavender-dark.md +0 -127
  171. package/dist/md/theme/lavender-light.md +0 -129
  172. package/dist/md/theme/peach-dark.md +0 -127
  173. package/dist/md/theme/peach-light.md +0 -129
  174. package/dist/md/theme/rose-dark.md +0 -127
  175. package/dist/md/theme/rose-light.md +0 -129
package/dist/extractor.js CHANGED
@@ -1,42 +1,78 @@
1
1
  /**
2
- * The one props extractor (tickets 12/16): reads prism-ui's built `.d.ts`
3
- * surface — TSDoc preserved — and returns the Prism-added props. Homed here
4
- * and exported (`@nanisoft/prism-llms/extractor`) for the site's API tables;
5
- * one extractor, two consumers. Runs after `^build`, so it reads declarations,
6
- * never TS source.
2
+ * The one props extractor.
7
3
  *
8
- * Deliberately compiler-API-free: TypeScript 7 (this repo's compiler) no
9
- * longer ships the JS compiler API, and ADR-0003 already accepts cosmetic
10
- * fidelity risk on gnarly unions. This is a small structural scanner for the
11
- * declaration shape prism-ui emits — `export interface XProps [extends Y]`
12
- * with JSDoc-carried descriptions. Pass-through re-exports never match, and
13
- * that absence IS the Extends seam (ADR-0004): no extracted props means the
14
- * item is "antd X, unchanged".
15
- */
16
- /**
17
- * Extract every exported `*Props` interface from a `.d.ts` source, in source
18
- * order. Returns an empty array for re-export-only files (pass-throughs).
4
+ * It reads `@nanisoft/prism-ui`'s emitted declarations, never its TypeScript
5
+ * source, and it is deliberately compiler-API-free: a small structural scanner
6
+ * for the declaration shapes this repository emits. Ticket 12 section 2 fixes
7
+ * the seam at the emitted `.d.ts`, so a compiler bump cannot break the corpus.
8
+ *
9
+ * The shapes it understands:
10
+ * - a named props type (`export type XProps = { ... }` or
11
+ * `export interface XProps extends Y { ... }`), referenced by a function;
12
+ * - an inline props object on the function parameter;
13
+ * - `ComponentProps<'tag'>`, recorded as an inherited base rather than
14
+ * expanded, so a native-backed component reports its element;
15
+ * - `VariantProps<typeof recipe>`, expanded from the emitted `cva` declaration
16
+ * into the recipe's `variant` and `size` rows.
17
+ *
18
+ * One extractor, two renderers: the corpus's `## Props` definition list and the
19
+ * site's API reference table. There is no second extraction.
19
20
  */
21
+ function toProp(row) {
22
+ return {
23
+ name: row.name,
24
+ typeText: row.type.replace(/\s+/g, ' ').trim(),
25
+ required: row.required,
26
+ ...(row.description ? { description: row.description } : {}),
27
+ ...(row.default && row.default !== '-' ? { defaultValue: row.default } : {}),
28
+ };
29
+ }
30
+ /** Extract every exported `*Props` interface from a declaration, in source order. */
20
31
  export function extractProps(source) {
21
32
  const results = [];
22
- const interfacePattern = /export\s+interface\s+(\w+)(?:\s+extends\s+([\w.]+))?\s*\{/g;
33
+ const pattern = /export\s+interface\s+(\w+)(?:\s+extends\s+([^{}]+?))?\s*\{/g;
23
34
  let match;
24
- while ((match = interfacePattern.exec(source)) !== null) {
35
+ while ((match = pattern.exec(source)) !== null) {
25
36
  if (!(match[1] ?? '').endsWith('Props'))
26
- continue; // supporting types (DocsNavEntry, BlogFrontmatter) are not props
27
- const openBrace = interfacePattern.lastIndex - 1;
28
- const body = readBalancedBody(source, openBrace);
29
- if (body === undefined)
30
- continue; // unbalanced — skip rather than guess
37
+ continue;
38
+ const openBrace = pattern.lastIndex - 1;
39
+ const found = readBalancedBody(source, openBrace);
40
+ if (found === undefined)
41
+ continue;
31
42
  results.push({
32
43
  typeName: match[1] ?? '',
33
- extendsType: match[2],
34
- props: parseProps(body),
44
+ ...(match[2] ? { extendsType: match[2].trim() } : {}),
45
+ props: parseMembers(found.body).map(toProp),
35
46
  });
36
47
  }
37
48
  return results;
38
49
  }
39
- /** The `{…}` body of the declaration whose brace sits at `openBrace`, or undefined when unbalanced. */
50
+ /**
51
+ * Extract the props of the named exports from one declaration file's text.
52
+ * Exports with no declaration are reported with an empty prop list.
53
+ */
54
+ export function extractExports(source, exportNames) {
55
+ return exportNames.map((name) => {
56
+ const params = findFunctionParams(source, name);
57
+ if (params === null)
58
+ return { typeName: name, props: [] };
59
+ const { props, inherited } = resolveAnnotation(annotationOf(params), source);
60
+ return {
61
+ typeName: name,
62
+ ...(inherited.length > 0 ? { extendsType: inherited.join(' & ') } : {}),
63
+ props,
64
+ };
65
+ });
66
+ }
67
+ /**
68
+ * The `{...}` body of the declaration whose brace sits at `openBrace`, and the
69
+ * index of the brace that closed it.
70
+ *
71
+ * The index is returned as well as the text because `findTypeBodies` has to
72
+ * resume scanning after the body, and re-walking it with a second depth counter
73
+ * is how the two came to disagree. `undefined` for the text means the body never
74
+ * closed, and the caller stops rather than guessing where it ended.
75
+ */
40
76
  function readBalancedBody(source, openBrace) {
41
77
  let depth = 0;
42
78
  let i = openBrace;
@@ -66,7 +102,7 @@ function readBalancedBody(source, openBrace) {
66
102
  if (ch === '}') {
67
103
  depth -= 1;
68
104
  if (depth === 0)
69
- return source.slice(openBrace + 1, i);
105
+ return { body: source.slice(openBrace + 1, i), end: i };
70
106
  }
71
107
  i += 1;
72
108
  }
@@ -86,158 +122,265 @@ function skipString(source, start, quote) {
86
122
  }
87
123
  return -1;
88
124
  }
89
- /** Parse property signatures out of an interface body. Non-signature members (methods, indexers) are skipped. */
90
- function parseProps(body) {
91
- const props = [];
92
- let i = 0;
93
- let pendingDocs;
94
- while (i < body.length) {
95
- const trivia = skipTrivia(body, i);
96
- i = trivia.next;
97
- pendingDocs = trivia.jsDoc ?? pendingDocs;
98
- if (i >= body.length)
99
- break;
100
- const nameMatch = /^([\w$]+)(\?)?\s*:/.exec(body.slice(i));
101
- if (!nameMatch) {
102
- // Not a property signature (call/construct/index signature, stray token) —
103
- // skip to the next statement boundary at depth 0.
104
- const boundary = nextTopLevelBoundary(body, i);
105
- if (boundary === -1)
106
- break;
107
- pendingDocs = undefined;
108
- i = boundary;
109
- continue;
110
- }
111
- const typeStart = i + nameMatch[0].length;
112
- const typeEnd = nextTopLevelBoundary(body, typeStart);
113
- const rawType = typeEnd === -1 ? body.slice(typeStart) : body.slice(typeStart, typeEnd);
114
- props.push({
115
- name: nameMatch[1] ?? '',
116
- typeText: normalizeType(rawType),
117
- description: pendingDocs?.description,
118
- defaultValue: pendingDocs?.defaultValue,
119
- required: !nameMatch[2],
120
- });
121
- pendingDocs = undefined;
122
- if (typeEnd === -1)
123
- break;
124
- i = typeEnd + 1;
125
- }
126
- return props;
127
- }
128
125
  /**
129
- * Advance past whitespace/comments. `/**` comments are captured as JSDoc
130
- * (description + `@defaultValue`), merged across consecutive blocks.
126
+ * Every object body a named type's declaration holds, in source order.
127
+ *
128
+ * A union is published whole or not at all. The single-body form this replaces
129
+ * took the FIRST match and the first balanced body, so it published one body and
130
+ * dropped every other by declaration order. For an emitted declaration shaped
131
+ * `Common & ({ A } | { B })` it published neither arm at all, only the shared
132
+ * part, so the API table described a type the declaration does not describe: the
133
+ * `bare` arm of a union was invisible to every reader and every agent. A
134
+ * type-level truth the extractor drops becomes a documentation-level lie, so the
135
+ * scan walks every balanced body inside the declaration's own extent instead.
136
+ *
137
+ * The depth and angle tracking is load-bearing rather than defensive. A member
138
+ * semicolon sits at depth 1, so a scan that stopped on the first `;` would end
139
+ * the declaration at `variant?: 'icon';` and never reach the second arm, which
140
+ * is the defect this function exists to remove. Angle brackets are tracked
141
+ * because a generic argument can carry its own braces.
142
+ *
143
+ * **A body is consumed once and skipped, not re-walked.** `readBalancedBody`
144
+ * returns a body's text, and the scan used to leave `i` on the opening brace and
145
+ * walk the body a second time with its own depth counter. The second walk counts
146
+ * every `{` the balanced read had already accounted for, so the two disagreed and
147
+ * `depth` could not be trusted to reach 0 at the brace that closed the body. The
148
+ * scan therefore depended on finding a terminator it was no longer counting
149
+ * correctly, and the caller concatenates the emitted JavaScript of the same
150
+ * module beside the declaration, so a scan that ran long published every object
151
+ * literal in that implementation as another arm of the type. Advancing `i` to the
152
+ * brace `readBalancedBody` reported removes the second walk rather than trying to
153
+ * correct for it, and one walk cannot disagree with itself.
154
+ *
155
+ * The honest limit on that claim: a declaration whose body closes and is followed
156
+ * immediately by a terminator terminated the scan correctly even before this
157
+ * change, which is why every Page in the package was published correctly and only
158
+ * the first Page with a two-line barrel was not. The defect was a miscount, not a
159
+ * missing terminator, and a miscount is only visible where a miscount is.
131
160
  */
132
- function skipTrivia(source, start) {
133
- let i = start;
134
- let jsDoc;
135
- while (i < source.length) {
136
- const ch = source[i] ?? '';
137
- if (/\s/.test(ch)) {
138
- i += 1;
139
- continue;
140
- }
141
- if (ch === '/' && source[i + 1] === '*' && source[i + 2] === '*') {
142
- const close = source.indexOf('*/', i + 3);
143
- if (close === -1)
144
- return { next: source.length };
145
- // Consecutive JSDoc blocks merge — a description and a @defaultValue may
146
- // live in separate blocks (tsc emits one, hand-written d.ts may not).
147
- const parsed = readJsDoc(source.slice(i + 3, close));
148
- if (parsed) {
149
- jsDoc = {
150
- description: jsDoc?.description ?? parsed.description,
151
- defaultValue: jsDoc?.defaultValue ?? parsed.defaultValue,
152
- };
153
- }
154
- i = close + 2;
161
+ function findTypeBodies(source, name) {
162
+ const pattern = new RegExp(`(?:export\\s+)?(?:type|interface)\\s+${name}\\b`);
163
+ const match = pattern.exec(source);
164
+ if (!match)
165
+ return [];
166
+ const bodies = [];
167
+ let depth = 0;
168
+ let angle = 0;
169
+ let quote = null;
170
+ let i = match.index + match[0].length;
171
+ for (; i < source.length; i += 1) {
172
+ const ch = source[i];
173
+ if (quote !== null) {
174
+ if (ch === quote && source[i - 1] !== '\\')
175
+ quote = null;
155
176
  continue;
156
177
  }
157
- if (ch === '/' && source[i + 1] === '*') {
158
- const close = source.indexOf('*/', i + 2);
159
- if (close === -1)
160
- return { next: source.length };
161
- i = close + 2;
178
+ if (ch === '"' || ch === "'" || ch === '`') {
179
+ quote = ch;
162
180
  continue;
163
181
  }
164
- if (ch === '/' && source[i + 1] === '/') {
165
- const close = source.indexOf('\n', i);
166
- if (close === -1)
167
- return { next: source.length };
168
- i = close;
182
+ if (ch === '{') {
183
+ const found = readBalancedBody(source, i);
184
+ if (found === undefined)
185
+ return bodies;
186
+ bodies.push(found.body);
187
+ // Resume AFTER the brace that closed the body. The re-walk this replaces
188
+ // counted every `{` in the body a second time and only the closing `}`
189
+ // once, so `depth` never returned to 0 and the scan never terminated.
190
+ i = found.end;
169
191
  continue;
170
192
  }
171
- return { next: i, jsDoc };
193
+ if (ch === '(')
194
+ depth += 1;
195
+ else if (ch === ')')
196
+ depth -= 1;
197
+ else if (ch === '<')
198
+ angle += 1;
199
+ else if (ch === '>')
200
+ angle = Math.max(0, angle - 1);
201
+ // The declaration ends at the first terminator that closes nothing it
202
+ // opened, so the next declaration's braces cannot be collected as arms.
203
+ else if ((ch === ';' || ch === '\n') && depth <= 0 && angle === 0)
204
+ return bodies;
172
205
  }
173
- return { next: i, jsDoc };
206
+ return bodies;
174
207
  }
175
- function readJsDoc(text) {
176
- const lines = text
177
- .split('\n')
178
- .map((line) => line.replace(/^\s*\*/, '').trim());
179
- const description = [];
180
- let defaultValue;
181
- for (const line of lines) {
182
- if (!line) {
183
- if (description.length > 0)
184
- description.push('');
185
- continue;
186
- }
187
- const tag = /^@(\w+)\s*(.*)$/.exec(line);
188
- if (tag) {
189
- if (tag[1] === 'defaultValue')
190
- defaultValue = tag[2] || undefined;
191
- continue; // other tags (@example, @internal, …) stay out of the docs
192
- }
193
- description.push(line);
208
+ function findFunctionParams(source, name) {
209
+ const pattern = new RegExp(`declare\\s+function\\s+${name}\\s*\\(`);
210
+ const match = pattern.exec(source);
211
+ if (!match)
212
+ return null;
213
+ const start = match.index + match[0].length;
214
+ let depth = 1;
215
+ let quote = null;
216
+ let i = start;
217
+ for (; i < source.length; i += 1) {
218
+ const ch = source[i];
219
+ if (quote) {
220
+ if (ch === quote && source[i - 1] !== '\\')
221
+ quote = null;
222
+ continue;
223
+ }
224
+ if (ch === '"' || ch === "'" || ch === '`')
225
+ quote = ch;
226
+ else if (ch === '(')
227
+ depth += 1;
228
+ else if (ch === ')') {
229
+ depth -= 1;
230
+ if (depth === 0)
231
+ break;
232
+ }
194
233
  }
195
- const joined = description.join(' ').trim();
196
- if (!joined && !defaultValue)
197
- return undefined;
198
- return { description: joined || undefined, defaultValue };
234
+ return source.slice(start, i);
199
235
  }
200
- /** Index of the next `;` or `,` at bracket depth 0 (starting at `from`), or -1. */
201
- function nextTopLevelBoundary(source, from) {
236
+ function annotationOf(params) {
202
237
  let depth = 0;
203
- let i = from;
204
- while (i < source.length) {
205
- const ch = source[i];
206
- if (ch === '/' && source[i + 1] === '*') {
207
- const close = source.indexOf('*/', i + 2);
208
- if (close === -1)
209
- return -1;
210
- i = close + 2;
238
+ let angle = 0;
239
+ let quote = null;
240
+ for (let i = 0; i < params.length; i += 1) {
241
+ const ch = params[i];
242
+ if (quote) {
243
+ if (ch === quote && params[i - 1] !== '\\')
244
+ quote = null;
211
245
  continue;
212
246
  }
213
- if (ch === '/' && source[i + 1] === '/') {
214
- const close = source.indexOf('\n', i);
215
- if (close === -1)
216
- return -1;
217
- i = close;
247
+ if (ch === '"' || ch === "'" || ch === '`')
248
+ quote = ch;
249
+ else if (ch === '(' || ch === '{' || ch === '[')
250
+ depth += 1;
251
+ else if (ch === ')' || ch === '}' || ch === ']')
252
+ depth -= 1;
253
+ else if (ch === '<')
254
+ angle += 1;
255
+ else if (ch === '>')
256
+ angle = Math.max(0, angle - 1);
257
+ else if (ch === ':' && depth === 0 && angle === 0)
258
+ return params.slice(i + 1).trim();
259
+ }
260
+ return null;
261
+ }
262
+ function variantRows(source, recipeName) {
263
+ const pattern = new RegExp(`declare const ${recipeName}\\s*:\\s*\\(props\\?:\\s*\\(\\{([\\s\\S]*?)\\}\\s*&`);
264
+ const match = pattern.exec(source);
265
+ return match ? parseMembers(match[1] ?? '') : [];
266
+ }
267
+ function resolveAnnotation(annotation, source) {
268
+ if (!annotation)
269
+ return { props: [], inherited: [] };
270
+ const named = /^[A-Za-z_$][\w$]*$/.test(annotation) ? findTypeBodies(source, annotation) : [];
271
+ if (named.length > 0) {
272
+ // Every arm, in declaration order, so a union reaches the table whole
273
+ // rather than as whichever arm happened to be written first.
274
+ return { props: named.flatMap((body) => parseMembers(body)).map(toProp), inherited: [] };
275
+ }
276
+ if (annotation.startsWith('{')) {
277
+ const found = readBalancedBody(annotation, 0);
278
+ if (found !== undefined)
279
+ return { props: parseMembers(found.body).map(toProp), inherited: [] };
280
+ }
281
+ const props = [];
282
+ const inherited = [];
283
+ const recipe = /VariantProps<typeof (\w+)>/.exec(annotation);
284
+ if (recipe)
285
+ props.push(...variantRows(source, recipe[1] ?? '').map(toProp));
286
+ const componentProps = /ComponentProps<'([^']+)'>/.exec(annotation);
287
+ if (componentProps)
288
+ inherited.push(`React.ComponentProps<'${componentProps[1]}'>`);
289
+ if (props.length === 0 && inherited.length === 0) {
290
+ inherited.push(annotation.replace(/\s+/g, ' ').slice(0, 200));
291
+ }
292
+ return { props, inherited };
293
+ }
294
+ function splitTopLevel(body) {
295
+ const parts = [];
296
+ let depth = 0;
297
+ let angle = 0;
298
+ let quote = null;
299
+ let current = '';
300
+ for (let i = 0; i < body.length; i += 1) {
301
+ const ch = body[i];
302
+ if (!quote && ch === '/' && body[i + 1] === '*') {
303
+ const end = body.indexOf('*/', i + 2);
304
+ const stop = end < 0 ? body.length : end + 2;
305
+ current += body.slice(i, stop);
306
+ i = stop - 1;
307
+ continue;
308
+ }
309
+ if (!quote && ch === '/' && body[i + 1] === '/') {
310
+ const end = body.indexOf('\n', i + 2);
311
+ const stop = end < 0 ? body.length : end;
312
+ current += body.slice(i, stop);
313
+ i = stop - 1;
314
+ continue;
315
+ }
316
+ if (quote) {
317
+ current += ch;
318
+ if (ch === quote && body[i - 1] !== '\\')
319
+ quote = null;
218
320
  continue;
219
321
  }
220
322
  if (ch === '"' || ch === "'" || ch === '`') {
221
- i = skipString(source, i, ch);
222
- if (i === -1)
223
- return -1;
323
+ quote = ch;
324
+ current += ch;
224
325
  continue;
225
326
  }
226
- if (ch === '(' || ch === '[' || ch === '{' || ch === '<')
327
+ if (ch === '(' || ch === '{' || ch === '[')
227
328
  depth += 1;
228
- if (ch === ')' || ch === ']' || ch === '}' || ch === '>')
329
+ else if (ch === ')' || ch === '}' || ch === ']')
229
330
  depth -= 1;
230
- if (depth === 0 && (ch === ';' || ch === ','))
231
- return i;
232
- i += 1;
331
+ else if (ch === '<')
332
+ angle += 1;
333
+ else if (ch === '>')
334
+ angle = Math.max(0, angle - 1);
335
+ if (ch === ';' && depth <= 0 && angle === 0) {
336
+ parts.push(current);
337
+ current = '';
338
+ continue;
339
+ }
340
+ current += ch;
233
341
  }
234
- return -1;
342
+ if (current.trim())
343
+ parts.push(current);
344
+ return parts;
235
345
  }
236
- /** Collapse comments and newlines to single spaces — readable, verbatim type text. */
237
- function normalizeType(raw) {
238
- return raw
239
- .replace(/\/\*[\s\S]*?\*\//g, ' ')
240
- .replace(/\s+/g, ' ')
346
+ function parseJsdoc(text) {
347
+ const match = /\/\*\*([\s\S]*?)\*\//.exec(text);
348
+ if (!match)
349
+ return { description: '', defaultValue: '' };
350
+ let content = match[1] ?? '';
351
+ let defaultValue = '';
352
+ const tag = /@defaultValue\s+([^\s*]+)/.exec(content);
353
+ if (tag) {
354
+ defaultValue = tag[1] ?? '';
355
+ content = content.replace(tag[0], ' ');
356
+ }
357
+ const description = content
358
+ .split('\n')
359
+ .map((line) => line.replace(/^\s*\*?\s?/, '').trim())
360
+ .filter((line) => line && !line.startsWith('@'))
361
+ .join(' ')
241
362
  .trim();
363
+ return { description, defaultValue };
364
+ }
365
+ function parseMembers(body) {
366
+ const rows = [];
367
+ for (const part of splitTopLevel(body)) {
368
+ const trimmed = part.trim();
369
+ if (!trimmed)
370
+ continue;
371
+ const comment = /\/\*\*([\s\S]*?)\*\//.exec(trimmed);
372
+ const rest = comment ? trimmed.slice(comment.index + comment[0].length) : trimmed;
373
+ const { description, defaultValue } = parseJsdoc(trimmed);
374
+ const member = /^([A-Za-z_$][\w$]*)\s*(\?)?\s*:\s*([\s\S]+)$/.exec(rest.trim());
375
+ if (!member)
376
+ continue;
377
+ rows.push({
378
+ name: member[1] ?? '',
379
+ type: (member[3] ?? '').replace(/;\s*$/, '').trim(),
380
+ required: !member[2],
381
+ default: defaultValue || '-',
382
+ description,
383
+ });
384
+ }
385
+ return rows;
242
386
  }
243
- //# sourceMappingURL=extractor.js.map
package/dist/index.d.ts CHANGED
@@ -1,10 +1,15 @@
1
1
  /**
2
- * prism-llms public surface. The root stays compiler-free (the extractor sits
3
- * behind `./extractor`); what ships here is the Markdown lane every consumer
4
- * of the corpus shares — the site's stub/API tooling imports these helpers so
5
- * it renders exactly what the generator emits.
2
+ * prism-llms public surface.
3
+ *
4
+ * The store contract is exported from the root; the extractor sits behind the
5
+ * `./extractor` subpath and is shared with the site's API reference table. The
6
+ * Markdown lane and the demo contract ship so a consumer renders exactly what
7
+ * the generator emits.
6
8
  */
7
- export { parseMdx, fence, renderComponentDemos, stripMdxMechanics, renderTable, renderPropsSection, type DocMeta, type ParsedMdx, } from './markdown.js';
9
+ export { parsePrismDocsStore, STORE_CATEGORIES, STORE_KINDS, STORE_MODES, STORE_PACKS, STORE_SCALE_GROUPS, STORE_SECTIONS, STORE_SECTION_TITLES, STORE_STATUSES, } from './store.js';
10
+ export type { Mode, PackId, PrismChangelog, PrismChangelogRelease, PrismDocsExample, PrismDocsPage, PrismDocsStore, PrismDocsStoreEntry, PrismScaleGroup, PrismScaleToken, PrismSemanticToken, PrismThemeTokens, PrismTokensProjection, StoreKind, StoreSection, StoreStatus, TokenGroup, } from './store.js';
11
+ export { assembleDoc, demoTitle, fence, parseMdx, parsePropLine, renderCompositionSection, renderCrossReferences, renderDemoSection, renderPropLine, renderPropsBody, renderPropsSection, stripMdxMechanics, stripSection, } from './markdown.js';
12
+ export type { CompositionField, CrossReference, DocMeta, ParsedMdx, ParsedPropLine, } from './markdown.js';
8
13
  export type { ExtractedInterface, ExtractedProp } from './extractor.js';
9
- export { scanPrismImports, validateDemoSource, type DemoViolation } from './demo-graph.js';
10
- //# sourceMappingURL=index.d.ts.map
14
+ export { scanPrismImports, scanPrismImportsWithSource, validateDemoSource, } from './demo-graph.js';
15
+ export type { DemoViolation, PrismImport } from './demo-graph.js';
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  /**
2
- * prism-llms public surface. The root stays compiler-free (the extractor sits
3
- * behind `./extractor`); what ships here is the Markdown lane every consumer
4
- * of the corpus shares — the site's stub/API tooling imports these helpers so
5
- * it renders exactly what the generator emits.
2
+ * prism-llms public surface.
3
+ *
4
+ * The store contract is exported from the root; the extractor sits behind the
5
+ * `./extractor` subpath and is shared with the site's API reference table. The
6
+ * Markdown lane and the demo contract ship so a consumer renders exactly what
7
+ * the generator emits.
6
8
  */
7
- export { parseMdx, fence, renderComponentDemos, stripMdxMechanics, renderTable, renderPropsSection, } from './markdown.js';
8
- export { scanPrismImports, validateDemoSource } from './demo-graph.js';
9
- //# sourceMappingURL=index.js.map
9
+ export { parsePrismDocsStore, STORE_CATEGORIES, STORE_KINDS, STORE_MODES, STORE_PACKS, STORE_SCALE_GROUPS, STORE_SECTIONS, STORE_SECTION_TITLES, STORE_STATUSES, } from './store.js';
10
+ export { assembleDoc, demoTitle, fence, parseMdx, parsePropLine, renderCompositionSection, renderCrossReferences, renderDemoSection, renderPropLine, renderPropsBody, renderPropsSection, stripMdxMechanics, stripSection, } from './markdown.js';
11
+ export { scanPrismImports, scanPrismImportsWithSource, validateDemoSource, } from './demo-graph.js';