@estiva-app/ui 0.21.1 → 0.23.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 (108) hide show
  1. package/README.md +21 -0
  2. package/dist/Avatar.d.ts +3 -0
  3. package/dist/Avatar.d.ts.map +1 -1
  4. package/dist/Banner.d.ts +20 -2
  5. package/dist/Banner.d.ts.map +1 -1
  6. package/dist/ChipInput.d.ts +3 -0
  7. package/dist/ChipInput.d.ts.map +1 -1
  8. package/dist/CommandPalette.d.ts +6 -0
  9. package/dist/CommandPalette.d.ts.map +1 -1
  10. package/dist/ContainerHeader.d.ts +25 -0
  11. package/dist/ContainerHeader.d.ts.map +1 -0
  12. package/dist/EmptyState.d.ts +10 -1
  13. package/dist/EmptyState.d.ts.map +1 -1
  14. package/dist/IdentityMenu.d.ts +3 -0
  15. package/dist/IdentityMenu.d.ts.map +1 -1
  16. package/dist/Menu.d.ts +7 -0
  17. package/dist/Menu.d.ts.map +1 -1
  18. package/dist/Skeleton.d.ts +2 -0
  19. package/dist/Skeleton.d.ts.map +1 -1
  20. package/dist/Toast.d.ts +5 -0
  21. package/dist/Toast.d.ts.map +1 -1
  22. package/dist/Toolbar.d.ts +4 -0
  23. package/dist/Toolbar.d.ts.map +1 -1
  24. package/dist/Tooltip.d.ts +4 -0
  25. package/dist/Tooltip.d.ts.map +1 -1
  26. package/dist/gates/app-checks.d.ts.map +1 -1
  27. package/dist/gates/{chunk-ZGJ2J5NU.js → chunk-EA33NP5B.js} +275 -11
  28. package/dist/gates/chunk-EA33NP5B.js.map +7 -0
  29. package/dist/gates/{chunk-AUXD4GCY.js → chunk-GTQZEHPC.js} +15 -1
  30. package/dist/gates/chunk-GTQZEHPC.js.map +7 -0
  31. package/dist/gates/cli.js +1 -1
  32. package/dist/gates/create-app.d.ts +2 -0
  33. package/dist/gates/create-app.d.ts.map +1 -1
  34. package/dist/gates/create-app.js +1 -1
  35. package/dist/gates/index.js +25 -3
  36. package/dist/gates/index.js.map +2 -2
  37. package/dist/gates/status.d.ts +2 -0
  38. package/dist/gates/status.d.ts.map +1 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +69 -48
  42. package/dist/index.js.map +4 -4
  43. package/dist/registry/app-DQI6WLHR.js +10 -0
  44. package/dist/registry/app-DQI6WLHR.js.map +7 -0
  45. package/dist/registry/app.d.ts +21 -0
  46. package/dist/registry/app.d.ts.map +1 -0
  47. package/dist/registry/build-LGFCCOLR.js +27 -0
  48. package/dist/registry/build-LGFCCOLR.js.map +7 -0
  49. package/dist/registry/build.d.ts +95 -0
  50. package/dist/registry/build.d.ts.map +1 -0
  51. package/dist/registry/chunk-E4JNV7PC.js +155 -0
  52. package/dist/registry/chunk-E4JNV7PC.js.map +7 -0
  53. package/dist/registry/chunk-NJN4MQAM.js +397 -0
  54. package/dist/registry/chunk-NJN4MQAM.js.map +7 -0
  55. package/dist/registry/chunk-W2B2G7OE.js +188 -0
  56. package/dist/registry/chunk-W2B2G7OE.js.map +7 -0
  57. package/dist/registry/chunk-WMFF3MPP.js +648 -0
  58. package/dist/registry/chunk-WMFF3MPP.js.map +7 -0
  59. package/dist/registry/cli.d.ts +2 -0
  60. package/dist/registry/cli.d.ts.map +1 -0
  61. package/dist/registry/cli.js +176 -0
  62. package/dist/registry/cli.js.map +7 -0
  63. package/dist/registry/find.d.ts +54 -0
  64. package/dist/registry/find.d.ts.map +1 -0
  65. package/dist/registry/index.d.ts +17 -0
  66. package/dist/registry/index.d.ts.map +1 -0
  67. package/dist/registry/index.js +34 -0
  68. package/dist/registry/index.js.map +7 -0
  69. package/dist/registry/schema.d.ts +224 -0
  70. package/dist/registry/schema.d.ts.map +1 -0
  71. package/package.json +15 -2
  72. package/registry.json +4615 -0
  73. package/src/Avatar.tsx +3 -0
  74. package/src/Banner.mdx +17 -4
  75. package/src/Banner.stories.tsx +22 -0
  76. package/src/Banner.test.tsx +35 -0
  77. package/src/Banner.tsx +34 -9
  78. package/src/ChipInput.tsx +3 -0
  79. package/src/CommandPalette.tsx +6 -0
  80. package/src/ContainerHeader.mdx +56 -0
  81. package/src/ContainerHeader.stories.tsx +62 -0
  82. package/src/ContainerHeader.test.tsx +47 -0
  83. package/src/ContainerHeader.tsx +45 -0
  84. package/src/EmptyState.mdx +12 -0
  85. package/src/EmptyState.stories.tsx +6 -1
  86. package/src/EmptyState.test.tsx +18 -1
  87. package/src/EmptyState.tsx +14 -1
  88. package/src/IdentityMenu.tsx +3 -0
  89. package/src/Menu.tsx +7 -0
  90. package/src/Skeleton.tsx +2 -0
  91. package/src/Toast.tsx +5 -0
  92. package/src/Toolbar.tsx +4 -0
  93. package/src/Tooltip.tsx +4 -0
  94. package/src/gates/app-checks.ts +23 -1
  95. package/src/gates/create-app.test.ts +77 -6
  96. package/src/gates/create-app.ts +288 -15
  97. package/src/gates/status.ts +16 -0
  98. package/src/index.ts +1 -0
  99. package/src/registry/app.test.ts +562 -0
  100. package/src/registry/app.ts +854 -0
  101. package/src/registry/build.ts +679 -0
  102. package/src/registry/cli.ts +204 -0
  103. package/src/registry/find.ts +232 -0
  104. package/src/registry/index.ts +31 -0
  105. package/src/registry/registry.test.ts +448 -0
  106. package/src/registry/schema.ts +419 -0
  107. package/dist/gates/chunk-AUXD4GCY.js.map +0 -7
  108. package/dist/gates/chunk-ZGJ2J5NU.js.map +0 -7
@@ -0,0 +1,397 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SCHEMA_VERSION
4
+ } from "./chunk-E4JNV7PC.js";
5
+
6
+ // src/registry/build.ts
7
+ import { readFileSync, readdirSync } from "node:fs";
8
+ import { join } from "node:path";
9
+ import ts from "typescript";
10
+ import { OWNED_BEHAVIOURS } from "../eslint/index.js";
11
+ var PACKAGE_IMPORT = "@estiva-app/ui";
12
+ function sanitize(name) {
13
+ return name.toLowerCase().replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>{}[\]\\/]/g, "-").replace(/-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
14
+ }
15
+ function storyNameFromExport(key) {
16
+ return key.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").replace(/([a-zA-Z])([0-9])/g, "$1 $2").replace(/([0-9])([a-zA-Z])/g, "$1 $2").replace(/[_-]+/g, " ").trim();
17
+ }
18
+ var toId = (title, name) => `${sanitize(title)}--${sanitize(storyNameFromExport(name))}`;
19
+ function readIndexExports(source) {
20
+ const file = ts.createSourceFile("index.ts", source, ts.ScriptTarget.Latest, true);
21
+ const found = [];
22
+ for (const statement of file.statements) {
23
+ if (!ts.isExportDeclaration(statement)) continue;
24
+ const from = statement.moduleSpecifier;
25
+ const clause = statement.exportClause;
26
+ if (!from || !ts.isStringLiteral(from) || !clause || !ts.isNamedExports(clause)) continue;
27
+ for (const element of clause.elements) {
28
+ found.push({ name: element.name.text, module: from.text.replace(/^\.\//, ""), isType: statement.isTypeOnly || element.isTypeOnly });
29
+ }
30
+ }
31
+ return found;
32
+ }
33
+ function docAbove(source, node, headerPos = null) {
34
+ const ranges = ts.getLeadingCommentRanges(source, node.getFullStart()) ?? [];
35
+ const jsdoc = ranges.filter((range) => source.slice(range.pos, range.pos + 3) === "/**").pop();
36
+ if (!jsdoc) return "";
37
+ if (headerPos !== null && jsdoc.pos === headerPos) return "";
38
+ const between = source.slice(jsdoc.end, node.getStart());
39
+ if (between.replace(/\/\/[^\n]*/g, "").trim() !== "") return "";
40
+ return source.slice(jsdoc.pos, jsdoc.end).split(/\r?\n/).map((line) => line.trim().replace(/^\/\*\*/, "").replace(/\*\/$/, "").replace(/^\*/, "").trim()).join("\n").trim();
41
+ }
42
+ function firstSentence(prose) {
43
+ const flat = prose.split(/\n\s*\n/)[0].split("\n").filter((line2) => !line2.trim().startsWith("@")).join(" ").replace(/\*\*/g, "").replace(/\s+/g, " ").trim();
44
+ const parts = flat.split(/(?<=[.!?])\s+(?=[A-Z`'"‘“])/);
45
+ let line = parts[0] ?? "";
46
+ if (line.length < 40 && parts[1]) line = `${line} ${parts[1]}`;
47
+ return line.trim();
48
+ }
49
+ function pageOpening(mdx) {
50
+ const lines = mdx.split(/\r?\n/);
51
+ const heading = lines.findIndex((line) => /^#\s+\S/.test(line));
52
+ if (heading < 0) return "";
53
+ const paragraph = [];
54
+ for (const line of lines.slice(heading + 1)) {
55
+ const text = line.trim();
56
+ if (text === "") {
57
+ if (paragraph.length) break;
58
+ continue;
59
+ }
60
+ if (text.startsWith("<") || text.startsWith("#")) break;
61
+ paragraph.push(text);
62
+ }
63
+ return paragraph.join(" ");
64
+ }
65
+ function propName(member) {
66
+ if (!member.name) return null;
67
+ if (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)) return member.name.text;
68
+ return null;
69
+ }
70
+ function literalUnion(type, aliases, seen = /* @__PURE__ */ new Set()) {
71
+ if (!type) return null;
72
+ if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {
73
+ const name = type.typeName.text;
74
+ if (seen.has(name)) return null;
75
+ seen.add(name);
76
+ const alias = aliases.get(name);
77
+ return alias ? literalUnion(alias, aliases, seen) : null;
78
+ }
79
+ if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text];
80
+ if (!ts.isUnionTypeNode(type)) return null;
81
+ const values = [];
82
+ for (const member of type.types) {
83
+ if (member.kind === ts.SyntaxKind.UndefinedKeyword || member.kind === ts.SyntaxKind.NullKeyword) continue;
84
+ const inner = literalUnion(member, aliases, seen);
85
+ if (!inner) return null;
86
+ values.push(...inner);
87
+ }
88
+ return values.length > 1 ? values : null;
89
+ }
90
+ function readModule(source, sibling = () => void 0, { lendFirstComment = true } = {}) {
91
+ const file = ts.createSourceFile("module.tsx", source, ts.ScriptTarget.Latest, true);
92
+ const declarations = /* @__PURE__ */ new Map();
93
+ const aliases = /* @__PURE__ */ new Map();
94
+ const shapes = /* @__PURE__ */ new Map();
95
+ const bases = /* @__PURE__ */ new Map();
96
+ const importedFrom = /* @__PURE__ */ new Map();
97
+ const propsTypeOf = (parameters) => parameters[0]?.type;
98
+ const propsOfInitializer = (initializer) => {
99
+ if (!initializer) return void 0;
100
+ if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return propsTypeOf(initializer.parameters);
101
+ if (ts.isCallExpression(initializer)) {
102
+ const callee = ts.isPropertyAccessExpression(initializer.expression) ? initializer.expression.name.text : ts.isIdentifier(initializer.expression) ? initializer.expression.text : "";
103
+ if (callee === "forwardRef" && initializer.typeArguments?.[1]) return initializer.typeArguments[1];
104
+ const wrapped = initializer.arguments.find((argument) => ts.isArrowFunction(argument) || ts.isFunctionExpression(argument));
105
+ if (wrapped) return propsTypeOf(wrapped.parameters);
106
+ }
107
+ return void 0;
108
+ };
109
+ const propsOfAnnotation = (type) => {
110
+ if (!type || !ts.isTypeReferenceNode(type)) return void 0;
111
+ const named = ts.isIdentifier(type.typeName) ? type.typeName.text : type.typeName.right.text;
112
+ return named === "FC" || named === "FunctionComponent" ? type.typeArguments?.[0] : void 0;
113
+ };
114
+ const opening = file.statements.find((statement) => !ts.isImportDeclaration(statement));
115
+ const headerPos = opening ? (ts.getLeadingCommentRanges(source, opening.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === "/**")?.pos ?? null : null;
116
+ const topPos = file.statements[0] ? (ts.getLeadingCommentRanges(source, file.statements[0].getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === "/**")?.pos ?? null : null;
117
+ const aboveImports = !!file.statements[0] && ts.isImportDeclaration(file.statements[0]);
118
+ const refused = lendFirstComment ? topPos ?? headerPos : aboveImports ? topPos : null;
119
+ for (const statement of file.statements) {
120
+ if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
121
+ const bindings = statement.importClause?.namedBindings;
122
+ if (bindings && ts.isNamedImports(bindings)) {
123
+ for (const element of bindings.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text });
124
+ }
125
+ }
126
+ if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
127
+ for (const element of statement.exportClause.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text });
128
+ }
129
+ if (ts.isTypeAliasDeclaration(statement)) aliases.set(statement.name.text, statement.type);
130
+ if (ts.isInterfaceDeclaration(statement)) {
131
+ shapes.set(statement.name.text, [...statement.members]);
132
+ const extended = (statement.heritageClauses ?? []).flatMap((clause) => [...clause.types]);
133
+ if (extended.length) bases.set(statement.name.text, extended);
134
+ }
135
+ if (ts.isTypeAliasDeclaration(statement) && ts.isTypeLiteralNode(statement.type)) shapes.set(statement.name.text, [...statement.type.members]);
136
+ if (ts.isClassDeclaration(statement)) {
137
+ const base = (statement.heritageClauses ?? []).find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0];
138
+ const name = statement.name?.text ?? (ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword) ? "default" : null);
139
+ if (name) declarations.set(name, { doc: docAbove(source, statement, refused), deprecated: false, propsType: base?.typeArguments?.[0] });
140
+ continue;
141
+ }
142
+ if (ts.isExportAssignment(statement) && !statement.isExportEquals && !ts.isIdentifier(statement.expression)) {
143
+ declarations.set("default", { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsOfInitializer(statement.expression) });
144
+ continue;
145
+ }
146
+ if (ts.isFunctionDeclaration(statement) && !statement.name && ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword)) {
147
+ declarations.set("default", { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsTypeOf(statement.parameters) });
148
+ continue;
149
+ }
150
+ if (!ts.isFunctionDeclaration(statement) && !ts.isVariableStatement(statement)) continue;
151
+ const doc = docAbove(source, statement, refused);
152
+ const deprecated = /(^|\n)@deprecated\b/.test(doc) || /\*\s*@deprecated\b/.test(source.slice(Math.max(0, statement.getFullStart()), statement.getStart()));
153
+ if (ts.isFunctionDeclaration(statement) && statement.name) {
154
+ const held = declarations.get(statement.name.text);
155
+ if (held) {
156
+ if (!held.doc && doc) held.doc = doc;
157
+ continue;
158
+ }
159
+ declarations.set(statement.name.text, { doc, deprecated, propsType: propsTypeOf(statement.parameters) });
160
+ continue;
161
+ }
162
+ if (ts.isVariableStatement(statement)) {
163
+ for (const declaration of statement.declarationList.declarations) {
164
+ if (!ts.isIdentifier(declaration.name)) continue;
165
+ declarations.set(declaration.name.text, { doc, deprecated, propsType: propsOfInitializer(declaration.initializer) ?? propsOfAnnotation(declaration.type) });
166
+ }
167
+ }
168
+ }
169
+ const EMPTY = { props: [], variants: [] };
170
+ const keysOf = (type) => {
171
+ if (!type) return null;
172
+ if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text];
173
+ if (!ts.isUnionTypeNode(type)) return null;
174
+ const keys = [];
175
+ for (const member of type.types) {
176
+ if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return null;
177
+ keys.push(member.literal.text);
178
+ }
179
+ return keys;
180
+ };
181
+ const narrow = (resolved, how, keys) => {
182
+ if (!keys) return resolved;
183
+ const named = new Set(keys);
184
+ const keep = (name) => how === "Omit" ? !named.has(name) : named.has(name);
185
+ return { props: resolved.props.filter((prop) => keep(prop.name)), variants: resolved.variants.filter((variant) => keep(variant.prop)) };
186
+ };
187
+ const merge = (parts) => {
188
+ const props = [];
189
+ const variants = [];
190
+ const seenProp = /* @__PURE__ */ new Set();
191
+ const seenVariant = /* @__PURE__ */ new Set();
192
+ for (const part of parts) {
193
+ for (const prop of part.props) if (!seenProp.has(prop.name)) seenProp.add(prop.name), props.push(prop);
194
+ for (const variant of part.variants) if (!seenVariant.has(variant.prop)) seenVariant.add(variant.prop), variants.push(variant);
195
+ }
196
+ return { props, variants };
197
+ };
198
+ const takes = (type, values) => {
199
+ if (values) return values.join(" | ");
200
+ if (!type) return "anything";
201
+ const written = type.getText(file).replace(/\s+/g, " ").trim();
202
+ if (written === "boolean") return "true/false";
203
+ if (written === "number") return "number";
204
+ if (written === "string") return "text";
205
+ if (/^React(Node|Element)\b/.test(written)) return "anything";
206
+ if (written.includes("=>")) return "a handler";
207
+ return written.length > 60 ? `${written.slice(0, 57)}\u2026` : written;
208
+ };
209
+ const fromMembers = (members) => {
210
+ const props = [];
211
+ const variants = [];
212
+ for (const member of members) {
213
+ const name = propName(member);
214
+ if (name === null || !ts.isPropertySignature(member)) continue;
215
+ const values = literalUnion(member.type, aliases);
216
+ const note = firstSentence(docAbove(source, member));
217
+ props.push({ name, takes: takes(member.type, values), required: !member.questionToken, note: note || null });
218
+ if (values) variants.push({ prop: name, values });
219
+ }
220
+ return { props, variants };
221
+ };
222
+ const resolveNode = (type, seen) => {
223
+ if (!type || seen.size > 12) return EMPTY;
224
+ if (ts.isTypeLiteralNode(type)) return fromMembers(type.members);
225
+ if (ts.isIntersectionTypeNode(type)) return merge(type.types.map((side) => resolveNode(side, seen)));
226
+ if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {
227
+ const named = type.typeName.text;
228
+ if (named === "Omit" || named === "Pick") {
229
+ return narrow(resolveNode(type.typeArguments?.[0], seen), named, keysOf(type.typeArguments?.[1]));
230
+ }
231
+ return resolveName(named, seen);
232
+ }
233
+ return EMPTY;
234
+ };
235
+ const resolveBase = (base, seen) => {
236
+ if (!ts.isIdentifier(base.expression)) return EMPTY;
237
+ const named = base.expression.text;
238
+ if (named === "Omit" || named === "Pick") {
239
+ return narrow(resolveNode(base.typeArguments?.[0], seen), named, keysOf(base.typeArguments?.[1]));
240
+ }
241
+ return resolveName(named, seen);
242
+ };
243
+ function resolveName(name, seen) {
244
+ if (seen.has(name) || seen.size > 12) return EMPTY;
245
+ seen.add(name);
246
+ const own = shapes.get(name);
247
+ if (own) {
248
+ const inherited = (bases.get(name) ?? []).map((base) => resolveBase(base, seen));
249
+ return merge([fromMembers(own), ...inherited]);
250
+ }
251
+ const alias = aliases.get(name);
252
+ if (alias) return resolveNode(alias, seen);
253
+ const from = importedFrom.get(name);
254
+ return (from ? sibling(from.specifier, from.imported) : void 0) ?? EMPTY;
255
+ }
256
+ const resolve = (propsType) => resolveNode(propsType, /* @__PURE__ */ new Set());
257
+ const jsdocAt = (node) => node ? (ts.getLeadingCommentRanges(source, node.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === "/**") : void 0;
258
+ const headerRange = jsdocAt(file.statements[0]) ?? jsdocAt(opening);
259
+ return { declarations, headerDoc: headerRange ? headerComment(source, headerRange) : "", resolve, resolveName: (name) => resolveName(name, /* @__PURE__ */ new Set()) };
260
+ }
261
+ function headerComment(source, range) {
262
+ return source.slice(range.pos, range.end).split(/\r?\n/).map((line) => line.trim().replace(/^\/\*\*/, "").replace(/\*\/$/, "").replace(/^\*/, "").trim()).join("\n").trim();
263
+ }
264
+ function readStories(source) {
265
+ const file = ts.createSourceFile("x.stories.tsx", source, ts.ScriptTarget.Latest, true);
266
+ let title = null;
267
+ const stories = [];
268
+ for (const statement of file.statements) {
269
+ if (ts.isVariableStatement(statement)) {
270
+ for (const declaration of statement.declarationList.declarations) {
271
+ if (!ts.isIdentifier(declaration.name)) continue;
272
+ const initializer = declaration.initializer;
273
+ const object = initializer && ts.isSatisfiesExpression(initializer) ? initializer.expression : initializer;
274
+ if (declaration.name.text === "meta" && object && ts.isObjectLiteralExpression(object)) {
275
+ for (const property of object.properties) {
276
+ if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === "title" && ts.isStringLiteral(property.initializer)) {
277
+ title = property.initializer.text;
278
+ }
279
+ }
280
+ }
281
+ const exported = ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
282
+ if (exported && declaration.name.text !== "meta") stories.push(declaration.name.text);
283
+ }
284
+ }
285
+ }
286
+ return { title, stories };
287
+ }
288
+ var isAllCaps = (name) => /^[A-Z0-9_]+$/.test(name);
289
+ function kindOf(name) {
290
+ if (/^use[A-Z]/.test(name)) return "hook";
291
+ return /^[A-Z]/.test(name) && !isAllCaps(name) ? "component" : "helper";
292
+ }
293
+ function behavioursOf(name) {
294
+ return OWNED_BEHAVIOURS.filter((owned) => owned.owners.includes(name)).map((owned) => ({ id: owned.id, behaviour: owned.behaviour }));
295
+ }
296
+ function buildRegistry({ root = process.cwd(), repo = "estiva-ui" } = {}) {
297
+ const src = join(root, "src");
298
+ const manifest = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
299
+ const files = new Set(readdirSync(src));
300
+ const exported = readIndexExports(readFileSync(join(src, "index.ts"), "utf8"));
301
+ const values = exported.filter((entry) => !entry.isType);
302
+ const modules = /* @__PURE__ */ new Map();
303
+ const moduleOf = (name) => {
304
+ const held = modules.get(name);
305
+ if (held) return held;
306
+ const file = [".tsx", ".ts"].map((extension) => `${name}${extension}`).find((candidate) => files.has(candidate));
307
+ if (!file) throw new Error(`src/index.ts exports from './${name}', which is not a file in src/`);
308
+ const read = { ...readModule(readFileSync(join(src, file), "utf8"), (specifier, typeName) => specifier.startsWith("./") ? moduleOf(specifier.slice(2)).resolveName(typeName) : void 0), file: `src/${file}` };
309
+ modules.set(name, read);
310
+ return read;
311
+ };
312
+ const problems = [];
313
+ const entries = [];
314
+ for (const value of values) {
315
+ const module = moduleOf(value.module);
316
+ const declared = module.declarations.get(value.name);
317
+ if (!declared) {
318
+ problems.push(`${value.name} is exported from './${value.module}' but is not declared there`);
319
+ continue;
320
+ }
321
+ const pageFile = files.has(`${value.name}.mdx`) ? `src/${value.name}.mdx` : null;
322
+ const fromPage = pageFile ? firstSentence(pageOpening(readFileSync(join(root, pageFile), "utf8"))) : "";
323
+ const fromComment = firstSentence(declared.doc);
324
+ const purpose = fromPage || fromComment;
325
+ if (!purpose) {
326
+ problems.push(`${value.name} has no purpose: no opening paragraph on its page, and no doc comment above it in ${module.file}`);
327
+ continue;
328
+ }
329
+ const storiesFile = files.has(`${value.name}.stories.tsx`) ? `${value.name}.stories.tsx` : files.has(`${value.module}.stories.tsx`) ? `${value.module}.stories.tsx` : null;
330
+ const stories = storiesFile ? readStories(readFileSync(join(src, storiesFile), "utf8")) : { title: null, stories: [] };
331
+ const title = stories.title;
332
+ const story = stories.stories.includes(value.name) ? value.name : stories.stories[0];
333
+ const shape = module.resolve(declared.propsType);
334
+ entries.push({
335
+ name: value.name,
336
+ repo,
337
+ kind: kindOf(value.name),
338
+ importPath: PACKAGE_IMPORT,
339
+ sourceFile: module.file,
340
+ purpose,
341
+ purposeFrom: fromPage ? "page" : "comment",
342
+ props: shape.props,
343
+ variants: shape.variants,
344
+ ownsBehaviours: behavioursOf(value.name),
345
+ status: declared.deprecated ? "deprecated" : "stable",
346
+ migrationStage: null,
347
+ docsId: title ? `${sanitize(title)}--docs` : null,
348
+ storyId: title && story ? toId(title, story) : null,
349
+ docPage: pageFile,
350
+ app: null
351
+ });
352
+ }
353
+ if (problems.length) throw new Error(`the registry cannot be built:
354
+ ${problems.join("\n ")}`);
355
+ entries.sort((a, b) => a.name.localeCompare(b.name));
356
+ return {
357
+ schemaVersion: SCHEMA_VERSION,
358
+ builtFrom: {
359
+ kind: "package",
360
+ repo,
361
+ package: manifest.name,
362
+ packageVersion: manifest.version,
363
+ exports: values.length,
364
+ typeExports: exported.length - values.length,
365
+ files: null
366
+ },
367
+ storybook: {
368
+ docsPath: "/?path=/docs/{docsId}",
369
+ storyPath: "/?path=/story/{storyId}",
370
+ devUrl: "http://localhost:6008"
371
+ },
372
+ entries,
373
+ // Nothing is excluded: every value export is an entry, helpers and the one
374
+ // hook included, each marked by `kind`. The field stays because the count
375
+ // has to reconcile out loud — see validateRegistry.
376
+ excluded: [],
377
+ filesWithoutParts: []
378
+ };
379
+ }
380
+ function serializeRegistry(registry) {
381
+ return `${JSON.stringify(registry, null, 2)}
382
+ `;
383
+ }
384
+
385
+ export {
386
+ PACKAGE_IMPORT,
387
+ sanitize,
388
+ toId,
389
+ readIndexExports,
390
+ firstSentence,
391
+ pageOpening,
392
+ readModule,
393
+ readStories,
394
+ buildRegistry,
395
+ serializeRegistry
396
+ };
397
+ //# sourceMappingURL=chunk-NJN4MQAM.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/registry/build.ts"],
4
+ "sourcesContent": ["/// <reference types=\"node\" />\n/**\n * The catalogue's builder (UIG-12): it reads the code and writes\n * `registry.json`. Nothing here is kept by hand, and CI rebuilds it and fails\n * on a difference, so the file cannot drift from what it describes.\n *\n * **Why a parser and not a regex.** This package's components are flat in\n * `src/`, with `.tsx`, `.mdx`, `.stories.tsx` and sometimes `.test.tsx` side by\n * side, and **a file is not a component**: eleven files export more than one\n * name \u2014 `Menu.tsx` alone exports seven \u2014 and `Skeleton.tsx` exports no\n * `Skeleton` at all. Pairing by filename gets `FieldLine`, `MenuItem` and every\n * one of those wrong. The target set is what `src/index.ts` exports, read with\n * TypeScript's own parser, and everything else is looked up from there.\n *\n * TypeScript is the app's own install, as it is for the gate pieces\n * (`build.mjs`): every package this names stays external.\n */\nimport { existsSync, readFileSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport ts from 'typescript'\nimport { OWNED_BEHAVIOURS } from '../eslint/index'\nimport { SCHEMA_VERSION, type EntryBehaviour, type EntryKind, type EntryProp, type EntryVariant, type Registry, type RegistryEntry } from './schema'\n\nexport interface BuildOptions {\n /** The repository's top folder. */\n root?: string\n /** The name this registry's entries are recorded under. */\n repo?: string\n}\n\n/** One name as `index.ts` exports it. */\ninterface RawExport {\n name: string\n /** The sibling it comes from, without `./`. */\n module: string\n isType: boolean\n}\n\n/** What the parser found above and about one top-level declaration. */\ninterface Declared {\n /** The doc comment, cleaned, or `''`. */\n doc: string\n deprecated: boolean\n /**\n * Its first parameter's type, as written. Kept as the node and resolved after\n * the whole file is walked: a props interface is often declared *below* the\n * component that takes it.\n */\n propsType?: ts.TypeNode\n}\n\nexport const PACKAGE_IMPORT = '@estiva-app/ui'\n\n/**\n * Storybook's own `sanitize`, which is what turns a title and a story's export\n * name into the id in the URL. Copied rather than imported: `storybook` is a\n * dev dependency of this repo and must not become a runtime dependency of the\n * builder, which apps run. A test holds this to the ids a real Storybook build\n * produces.\n */\nexport function sanitize(name: string): string {\n return name\n .toLowerCase()\n .replace(/[ \u2019\u2013\u2014\u2015\u2032\u00BF'`~!@#$%^&*()_|+\\-=?;:'\",.<>{}[\\]\\\\/]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+/, '')\n .replace(/-+$/, '')\n}\n\n/**\n * Storybook's `storyNameFromExport`, which is lodash's `startCase`: an export\n * called `WithCounts` is the story \"With Counts\", and its id is\n * `navigation-tabs--with-counts`, not `--withcounts`.\n *\n * Measured against a real `storybook build` (2026-09-18): without this, 11 of\n * the 81 ids resolved nowhere \u2014 every export whose name is more than one word.\n * Written out rather than pulled from lodash or `@storybook/csf`, neither of\n * which may become a runtime dependency of a builder that apps run.\n */\nfunction storyNameFromExport(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/([a-zA-Z])([0-9])/g, '$1 $2')\n .replace(/([0-9])([a-zA-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim()\n}\n\nexport const toId = (title: string, name: string) => `${sanitize(title)}--${sanitize(storyNameFromExport(name))}`\n\n/** Read `src/index.ts`. Its `export { \u2026 } from './Sibling'` statements are the target set. */\nexport function readIndexExports(source: string): RawExport[] {\n const file = ts.createSourceFile('index.ts', source, ts.ScriptTarget.Latest, true)\n const found: RawExport[] = []\n for (const statement of file.statements) {\n if (!ts.isExportDeclaration(statement)) continue\n const from = statement.moduleSpecifier\n const clause = statement.exportClause\n if (!from || !ts.isStringLiteral(from) || !clause || !ts.isNamedExports(clause)) continue\n for (const element of clause.elements) {\n found.push({ name: element.name.text, module: from.text.replace(/^\\.\\//, ''), isType: statement.isTypeOnly || element.isTypeOnly })\n }\n }\n return found\n}\n\n/**\n * The doc comment immediately above a declaration, cleaned of its markers.\n * `''` when there is none.\n *\n * `headerPos` is where the **file's** own header comment starts, and a\n * declaration never gets to claim it. Measured: `Skeleton.tsx` opens with a\n * paragraph about the whole family and `export function SkeletonBar` follows it\n * directly, so the bar was given the family's description \u2014 right-looking, and\n * wrong. Refusing it turns that into a build failure with the export's name in\n * it, which is a line somebody then writes.\n */\nfunction docAbove(source: string, node: ts.Node, headerPos: number | null = null): string {\n const ranges = ts.getLeadingCommentRanges(source, node.getFullStart()) ?? []\n const jsdoc = ranges.filter((range) => source.slice(range.pos, range.pos + 3) === '/**').pop()\n if (!jsdoc) return ''\n if (headerPos !== null && jsdoc.pos === headerPos) return ''\n // Only a comment that sits against the declaration describes it: anything\n // with another statement between them is about something else. A `//` line\n // between is still its own \u2014 the written note an escape needs sits there, and\n // TypeScript attaches the doc comment through it too.\n const between = source.slice(jsdoc.end, node.getStart())\n if (between.replace(/\\/\\/[^\\n]*/g, '').trim() !== '') return ''\n return source\n .slice(jsdoc.pos, jsdoc.end)\n .split(/\\r?\\n/)\n .map((line) => line.trim().replace(/^\\/\\*\\*/, '').replace(/\\*\\/$/, '').replace(/^\\*/, '').trim())\n .join('\\n')\n .trim()\n}\n\n/**\n * The first sentence of a block of prose, which is the purpose.\n *\n * A sentence ends at `.`, `!` or `?` followed by a space and something that\n * starts a new one. A very short first sentence takes the next as well \u2014\n * \"A list of actions from a trigger.\" is a purpose; \"One row, two parts.\" is\n * not, on its own.\n */\nexport function firstSentence(prose: string): string {\n const flat = prose\n .split(/\\n\\s*\\n/)[0]\n .split('\\n')\n .filter((line) => !line.trim().startsWith('@'))\n .join(' ')\n .replace(/\\*\\*/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n const parts = flat.split(/(?<=[.!?])\\s+(?=[A-Z`'\"\u2018\u201C])/)\n let line = parts[0] ?? ''\n if (line.length < 40 && parts[1]) line = `${line} ${parts[1]}`\n return line.trim()\n}\n\n/** A page's opening paragraph: everything between its `# Heading` and the first blank line. */\nexport function pageOpening(mdx: string): string {\n const lines = mdx.split(/\\r?\\n/)\n const heading = lines.findIndex((line) => /^#\\s+\\S/.test(line))\n if (heading < 0) return ''\n const paragraph: string[] = []\n for (const line of lines.slice(heading + 1)) {\n const text = line.trim()\n if (text === '') {\n if (paragraph.length) break\n continue\n }\n // A canvas, an import or the next heading: the opening paragraph is over,\n // or there never was one.\n if (text.startsWith('<') || text.startsWith('#')) break\n paragraph.push(text)\n }\n return paragraph.join(' ')\n}\n\n/**\n * A property's name, however it is written.\n *\n * **A quoted name is a name.** `'aria-label'?: string` cannot be written as an\n * identifier, so a reader that takes identifiers only drops it \u2014 and with it\n * every accessible name this package declares. Found by comparing against\n * `react-docgen`, a parser with none of this one's assumptions: 13 props over\n * 10 files, two of them required (`Reaction`, `Toolbar`).\n */\nfunction propName(member: ts.TypeElement): string | null {\n if (!member.name) return null\n if (ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)) return member.name.text\n return null\n}\n\n/** A union of string literals, following one local type alias if the property points at one. */\nfunction literalUnion(type: ts.TypeNode | undefined, aliases: Map<string, ts.TypeNode>, seen = new Set<string>()): string[] | null {\n if (!type) return null\n if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {\n const name = type.typeName.text\n if (seen.has(name)) return null\n seen.add(name)\n const alias = aliases.get(name)\n return alias ? literalUnion(alias, aliases, seen) : null\n }\n if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text]\n if (!ts.isUnionTypeNode(type)) return null\n const values: string[] = []\n for (const member of type.types) {\n // `'small' | 'default' | undefined` is still a set of two words.\n if (member.kind === ts.SyntaxKind.UndefinedKeyword || member.kind === ts.SyntaxKind.NullKeyword) continue\n const inner = literalUnion(member, aliases, seen)\n if (!inner) return null\n values.push(...inner)\n }\n return values.length > 1 ? values : null\n}\n\n/** A type\u2019s finished props and word-choices, read by the module that declares them. */\nexport interface Resolved {\n props: EntryProp[]\n variants: EntryVariant[]\n}\n\n/**\n * Ask another file for a type it declares, already resolved. `specifier` is the\n * import as written (`./IconButton`, `@/lib/types`); the caller decides what it\n * points at, and answers `undefined` for anything outside the library it reads.\n */\nexport type Sibling = (specifier: string, typeName: string) => Resolved | undefined\n\nexport interface ReadOptions {\n /**\n * Whether a file with no comment of its own at the top lends the comment on\n * its first declaration to the file. The package: yes \u2014 `Skeleton.tsx`'s\n * family paragraph sits there, and taking it as `SkeletonBar`'s was wrong. An\n * app: no \u2014 a comment directly above a part is that part's, which is what a\n * person writing one expects; a file's own goes at the very top.\n */\n lendFirstComment?: boolean\n}\n\nexport function readModule(source: string, sibling: Sibling = () => undefined, { lendFirstComment = true }: ReadOptions = {}) {\n const file = ts.createSourceFile('module.tsx', source, ts.ScriptTarget.Latest, true)\n const declarations = new Map<string, Declared>()\n const aliases = new Map<string, ts.TypeNode>()\n const shapes = new Map<string, ts.TypeElement[]>()\n /** What each interface extends, as written \u2014 `Omit<IdentityMenuProps, 'compact'>` and all. */\n const bases = new Map<string, ts.ExpressionWithTypeArguments[]>()\n /** Which module each imported name came from. */\n const importedFrom = new Map<string, { specifier: string; imported: string }>()\n\n const propsTypeOf = (parameters: readonly ts.ParameterDeclaration[]): ts.TypeNode | undefined => parameters[0]?.type\n\n /**\n * The props type of `const X = \u2026`.\n *\n * A plain function expression carries it on its first parameter. `forwardRef`\n * carries it as its **second type argument** and leaves the inner function's\n * parameter bare \u2014 `TextInput`, whose `size` was missed until this read it.\n */\n const propsOfInitializer = (initializer: ts.Expression | undefined): ts.TypeNode | undefined => {\n if (!initializer) return undefined\n if (ts.isArrowFunction(initializer) || ts.isFunctionExpression(initializer)) return propsTypeOf(initializer.parameters)\n if (ts.isCallExpression(initializer)) {\n const callee = ts.isPropertyAccessExpression(initializer.expression) ? initializer.expression.name.text : ts.isIdentifier(initializer.expression) ? initializer.expression.text : ''\n if (callee === 'forwardRef' && initializer.typeArguments?.[1]) return initializer.typeArguments[1]\n // `memo(function X({ \u2026 }: Props) { \u2026 })` and anything else that wraps a\n // function written out at the call.\n const wrapped = initializer.arguments.find((argument) => ts.isArrowFunction(argument) || ts.isFunctionExpression(argument))\n if (wrapped) return propsTypeOf((wrapped as ts.ArrowFunction | ts.FunctionExpression).parameters)\n }\n return undefined\n }\n\n /**\n * `const Row: FC<RowProps> = ({ \u2026 }) => \u2026` leaves the parameter bare: the\n * props are the annotation's type argument \u2014 `FC`, `FunctionComponent`,\n * `React.FC`, `React.FunctionComponent`.\n */\n const propsOfAnnotation = (type: ts.TypeNode | undefined): ts.TypeNode | undefined => {\n if (!type || !ts.isTypeReferenceNode(type)) return undefined\n const named = ts.isIdentifier(type.typeName) ? type.typeName.text : type.typeName.right.text\n return named === 'FC' || named === 'FunctionComponent' ? type.typeArguments?.[0] : undefined\n }\n\n // The file's header comment: the first `/**` above the first thing that is\n // not an import. It belongs to the file, whatever export happens to follow it.\n const opening = file.statements.find((statement) => !ts.isImportDeclaration(statement))\n const headerPos = opening ? ((ts.getLeadingCommentRanges(source, opening.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**')?.pos ?? null) : null\n // A file that opens with its own comment, above its imports \u2014 Peek's and Ship's\n // way \u2014 has its header there, so the comment on its first declaration is that\n // declaration's own. Only a file with no such comment lends the first one it has.\n const topPos = file.statements[0] ? ((ts.getLeadingCommentRanges(source, file.statements[0].getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**')?.pos ?? null) : null\n // An app lends no comment to the file but one above its imports: in a file\n // with no imports the first comment sits on the first part, and is the part's.\n const aboveImports = !!file.statements[0] && ts.isImportDeclaration(file.statements[0])\n const refused = lendFirstComment ? (topPos ?? headerPos) : aboveImports ? topPos : null\n\n for (const statement of file.statements) {\n if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {\n const bindings = statement.importClause?.namedBindings\n if (bindings && ts.isNamedImports(bindings)) {\n for (const element of bindings.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text })\n }\n }\n // `export type { TopicRowProps } from './TopicRow'` hands a type on without\n // declaring it: a file that asks this one for it is sent on to the next.\n if (ts.isExportDeclaration(statement) && statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {\n for (const element of statement.exportClause.elements) importedFrom.set(element.name.text, { specifier: statement.moduleSpecifier.text, imported: (element.propertyName ?? element.name).text })\n }\n if (ts.isTypeAliasDeclaration(statement)) aliases.set(statement.name.text, statement.type)\n if (ts.isInterfaceDeclaration(statement)) {\n shapes.set(statement.name.text, [...statement.members])\n // The whole clause, not its name: `extends Omit<IdentityMenuProps,\n // 'compact'>` reads as the name `Omit` and loses both the type it wraps\n // and the key it drops.\n const extended = (statement.heritageClauses ?? []).flatMap((clause) => [...clause.types])\n if (extended.length) bases.set(statement.name.text, extended)\n }\n if (ts.isTypeAliasDeclaration(statement) && ts.isTypeLiteralNode(statement.type)) shapes.set(statement.name.text, [...statement.type.members])\n\n // Every top-level function, class and constant, exported or not. The package\n // exports at the declaration, so for it the two are the same; an app also\n // writes `function Row() {\u2026}` and `export { Row }` or `export default Row`\n // further down, and the name is still read here, with its comment and props.\n if (ts.isClassDeclaration(statement)) {\n // `class ErrorBoundary extends Component<Props, State>`: its props are the\n // first type argument of what it extends. `export default class extends \u2026`\n // has no name of its own, and is kept under `default`.\n const base = (statement.heritageClauses ?? []).find((clause) => clause.token === ts.SyntaxKind.ExtendsKeyword)?.types[0]\n const name = statement.name?.text ?? (ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword) ? 'default' : null)\n if (name) declarations.set(name, { doc: docAbove(source, statement, refused), deprecated: false, propsType: base?.typeArguments?.[0] })\n continue\n }\n // `export default memo(() => \u2026)` and `export default function () {\u2026}`: a part\n // an app writes as its file's default, with no name of its own. Kept under\n // `default`, with its comment and its props.\n if (ts.isExportAssignment(statement) && !statement.isExportEquals && !ts.isIdentifier(statement.expression)) {\n declarations.set('default', { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsOfInitializer(statement.expression) })\n continue\n }\n if (ts.isFunctionDeclaration(statement) && !statement.name && ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword)) {\n declarations.set('default', { doc: docAbove(source, statement, refused), deprecated: false, propsType: propsTypeOf(statement.parameters) })\n continue\n }\n if (!ts.isFunctionDeclaration(statement) && !ts.isVariableStatement(statement)) continue\n const doc = docAbove(source, statement, refused)\n const deprecated = /(^|\\n)@deprecated\\b/.test(doc) || /\\*\\s*@deprecated\\b/.test(source.slice(Math.max(0, statement.getFullStart()), statement.getStart()))\n\n if (ts.isFunctionDeclaration(statement) && statement.name) {\n // Overloads: the first signature carries the comment and the props a caller\n // sees; a later one, or the body, only fills in a comment the first lacks.\n const held = declarations.get(statement.name.text)\n if (held) {\n if (!held.doc && doc) held.doc = doc\n continue\n }\n declarations.set(statement.name.text, { doc, deprecated, propsType: propsTypeOf(statement.parameters) })\n continue\n }\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n declarations.set(declaration.name.text, { doc, deprecated, propsType: propsOfInitializer(declaration.initializer) ?? propsOfAnnotation(declaration.type) })\n }\n }\n }\n /**\n * A type's props and its word-choices, **resolved in the file that declares\n * them**.\n *\n * This is the whole shape of the thing, and the reason for it is a bug that\n * looked like nothing: a `ts.TypeElement` carries positions into *its own*\n * source text, so handing a sibling's node to this file's `getText`, `aliases`\n * and `docAbove` reads the wrong file at those offsets. `ToolbarButton` came\n * out with `variant: \"ats over what it a\"` and `children: \"omeAndEndK\"` \u2014\n * real prop names, and slices of another file for their types. Nothing caught\n * it: the names were right, and the cross-check against `react-docgen`\n * compared names.\n *\n * So a sibling never returns nodes. It returns finished props, read by the\n * module that owns them, and this file only merges them.\n */\n const EMPTY: Resolved = { props: [], variants: [] }\n\n /** The keys named by an `Omit`/`Pick` argument: `'a'` or `'a' | 'b'`. */\n const keysOf = (type: ts.TypeNode | undefined): string[] | null => {\n if (!type) return null\n if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) return [type.literal.text]\n if (!ts.isUnionTypeNode(type)) return null\n const keys: string[] = []\n for (const member of type.types) {\n if (!ts.isLiteralTypeNode(member) || !ts.isStringLiteral(member.literal)) return null\n keys.push(member.literal.text)\n }\n return keys\n }\n\n /** `Omit` drops the keys it names, `Pick` keeps only them. Unreadable keys change nothing. */\n const narrow = (resolved: Resolved, how: 'Omit' | 'Pick', keys: string[] | null): Resolved => {\n if (!keys) return resolved\n const named = new Set(keys)\n const keep = (name: string) => (how === 'Omit' ? !named.has(name) : named.has(name))\n return { props: resolved.props.filter((prop) => keep(prop.name)), variants: resolved.variants.filter((variant) => keep(variant.prop)) }\n }\n\n /** The first of each name wins, so what a type declares itself beats what it inherits. */\n const merge = (parts: Resolved[]): Resolved => {\n const props: EntryProp[] = []\n const variants: EntryVariant[] = []\n const seenProp = new Set<string>()\n const seenVariant = new Set<string>()\n for (const part of parts) {\n for (const prop of part.props) if (!seenProp.has(prop.name)) (seenProp.add(prop.name), props.push(prop))\n for (const variant of part.variants) if (!seenVariant.has(variant.prop)) (seenVariant.add(variant.prop), variants.push(variant))\n }\n return { props, variants }\n }\n\n /**\n * What a prop takes, in a word a person reads. The type as written is the\n * fallback, not the answer: `(next: string) => void` tells a reader nothing\n * they cannot guess, and \"a handler\" tells them what to pass.\n */\n const takes = (type: ts.TypeNode | undefined, values: string[] | null): string => {\n if (values) return values.join(' | ')\n if (!type) return 'anything'\n const written = type.getText(file).replace(/\\s+/g, ' ').trim()\n if (written === 'boolean') return 'true/false'\n if (written === 'number') return 'number'\n if (written === 'string') return 'text'\n if (/^React(Node|Element)\\b/.test(written)) return 'anything'\n if (written.includes('=>')) return 'a handler'\n return written.length > 60 ? `${written.slice(0, 57)}\u2026` : written\n }\n\n /** Members of this file, read with this file's text and aliases. */\n const fromMembers = (members: readonly ts.TypeElement[]): Resolved => {\n const props: EntryProp[] = []\n const variants: EntryVariant[] = []\n for (const member of members) {\n const name = propName(member)\n if (name === null || !ts.isPropertySignature(member)) continue\n const values = literalUnion(member.type, aliases)\n const note = firstSentence(docAbove(source, member))\n props.push({ name, takes: takes(member.type, values), required: !member.questionToken, note: note || null })\n if (values) variants.push({ prop: name, values })\n }\n return { props, variants }\n }\n\n const resolveNode = (type: ts.TypeNode | undefined, seen: Set<string>): Resolved => {\n if (!type || seen.size > 12) return EMPTY\n // `{ tone?: 'primary' | 'secondary' }` written out at the parameter.\n if (ts.isTypeLiteralNode(type)) return fromMembers(type.members)\n if (ts.isIntersectionTypeNode(type)) return merge(type.types.map((side) => resolveNode(side, seen)))\n if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) {\n const named = type.typeName.text\n if (named === 'Omit' || named === 'Pick') {\n return narrow(resolveNode(type.typeArguments?.[0], seen), named, keysOf(type.typeArguments?.[1]))\n }\n return resolveName(named, seen)\n }\n return EMPTY\n }\n\n /** A heritage clause is not a `TypeNode`, and carries the same `Omit<\u2026>` shapes. */\n const resolveBase = (base: ts.ExpressionWithTypeArguments, seen: Set<string>): Resolved => {\n if (!ts.isIdentifier(base.expression)) return EMPTY\n const named = base.expression.text\n if (named === 'Omit' || named === 'Pick') {\n return narrow(resolveNode(base.typeArguments?.[0], seen), named, keysOf(base.typeArguments?.[1]))\n }\n return resolveName(named, seen)\n }\n\n /**\n * A named type: its own props, plus everything it extends **within this\n * package**.\n *\n * It stops at React and Base UI on purpose. `ToolbarButtonProps extends\n * IconButtonProps` is ours, and `variant`, `pressed` and `tooltip` are things\n * `ToolbarButton` genuinely takes; `ButtonProps extends\n * ComponentPropsWithRef<'button'>` is the DOM, and listing `onCopy` and\n * `spellCheck` would bury the answer. The rule is where the type is declared,\n * not what it is called.\n */\n function resolveName(name: string, seen: Set<string>): Resolved {\n if (seen.has(name) || seen.size > 12) return EMPTY\n seen.add(name)\n const own = shapes.get(name)\n if (own) {\n const inherited = (bases.get(name) ?? []).map((base) => resolveBase(base, seen))\n return merge([fromMembers(own), ...inherited])\n }\n // `type ToolbarInputProps = TextInputProps` \u2014 an alias, not an interface.\n const alias = aliases.get(name)\n if (alias) return resolveNode(alias, seen)\n // Not declared here at all. Follow the import; the caller says where it may go.\n const from = importedFrom.get(name)\n return (from ? sibling(from.specifier, from.imported) : undefined) ?? EMPTY\n }\n\n /** What one declaration's first parameter takes. */\n const resolve = (propsType: ts.TypeNode | undefined): Resolved => resolveNode(propsType, new Set())\n\n // The file's own description, for an app's file of one part: the first `/**`\n // at the very top, above the imports \u2014 where Peek and Ship write it \u2014 or else\n // the one directly above the first thing that is not an import.\n const jsdocAt = (node: ts.Node | undefined) => (node ? (ts.getLeadingCommentRanges(source, node.getFullStart()) ?? []).find((range) => source.slice(range.pos, range.pos + 3) === '/**') : undefined)\n const headerRange = jsdocAt(file.statements[0]) ?? jsdocAt(opening)\n return { declarations, headerDoc: headerRange ? headerComment(source, headerRange) : '', resolve, resolveName: (name: string) => resolveName(name, new Set()) }\n}\n\n/** The file's own header comment, cleaned the way `docAbove` cleans a declaration's. */\nfunction headerComment(source: string, range: ts.CommentRange): string {\n return source\n .slice(range.pos, range.end)\n .split(/\\r?\\n/)\n .map((line) => line.trim().replace(/^\\/\\*\\*/, '').replace(/\\*\\/$/, '').replace(/^\\*/, '').trim())\n .join('\\n')\n .trim()\n}\n\n/** The `title` a stories file gives Storybook, and the stories it exports. */\nexport function readStories(source: string): { title: string | null; stories: string[] } {\n const file = ts.createSourceFile('x.stories.tsx', source, ts.ScriptTarget.Latest, true)\n let title: string | null = null\n const stories: string[] = []\n for (const statement of file.statements) {\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n const initializer = declaration.initializer\n const object = initializer && ts.isSatisfiesExpression(initializer) ? initializer.expression : initializer\n if (declaration.name.text === 'meta' && object && ts.isObjectLiteralExpression(object)) {\n for (const property of object.properties) {\n if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.text === 'title' && ts.isStringLiteral(property.initializer)) {\n title = property.initializer.text\n }\n }\n }\n const exported = ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)\n if (exported && declaration.name.text !== 'meta') stories.push(declaration.name.text)\n }\n }\n }\n return { title, stories }\n}\n\nconst isAllCaps = (name: string) => /^[A-Z0-9_]+$/.test(name)\n\n/** What a name is. A constant and a function are both helpers; only a `use\u2026` is a hook. */\nfunction kindOf(name: string): EntryKind {\n if (/^use[A-Z]/.test(name)) return 'hook'\n return /^[A-Z]/.test(name) && !isAllCaps(name) ? 'component' : 'helper'\n}\n\n/** What UIG-8's enumeration says this component owns. */\nfunction behavioursOf(name: string): EntryBehaviour[] {\n return OWNED_BEHAVIOURS.filter((owned) => owned.owners.includes(name)).map((owned) => ({ id: owned.id, behaviour: owned.behaviour }))\n}\n\n/**\n * Read the repository and return the catalogue.\n *\n * Throws on anything it cannot explain \u2014 a missing sibling, a name with no\n * purpose anywhere. A registry that quietly drops what it could not read is\n * worse than no registry, because a reader cannot tell the difference between\n * \"we have nothing for that\" and \"the builder gave up\".\n */\nexport function buildRegistry({ root = process.cwd(), repo = 'estiva-ui' }: BuildOptions = {}): Registry {\n const src = join(root, 'src')\n const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as { name: string; version: string }\n const files = new Set(readdirSync(src))\n const exported = readIndexExports(readFileSync(join(src, 'index.ts'), 'utf8'))\n const values = exported.filter((entry) => !entry.isType)\n\n type Module = ReturnType<typeof readModule> & { file: string }\n const modules = new Map<string, Module>()\n const moduleOf = (name: string): Module => {\n const held = modules.get(name)\n if (held) return held\n const file = ['.tsx', '.ts'].map((extension) => `${name}${extension}`).find((candidate) => files.has(candidate))\n if (!file) throw new Error(`src/index.ts exports from './${name}', which is not a file in src/`)\n // The callback lets one file's props type reach a type declared in another\n // \u2014 `ToolbarButtonProps extends IconButtonProps`. It is only called later,\n // by which time this module is in the cache, so the recursion terminates.\n const read = { ...readModule(readFileSync(join(src, file), 'utf8'), (specifier, typeName) => (specifier.startsWith('./') ? moduleOf(specifier.slice(2)).resolveName(typeName) : undefined)), file: `src/${file}` }\n modules.set(name, read)\n return read\n }\n\n const problems: string[] = []\n const entries: RegistryEntry[] = []\n\n for (const value of values) {\n const module = moduleOf(value.module)\n const declared = module.declarations.get(value.name)\n if (!declared) {\n problems.push(`${value.name} is exported from './${value.module}' but is not declared there`)\n continue\n }\n\n // A name with a page of its own takes its purpose from the page; the rest\n // are documented on a sibling's page, and take it from the comment above\n // the export. Every one of them has one \u2014 the build fails below if not.\n const pageFile = files.has(`${value.name}.mdx`) ? `src/${value.name}.mdx` : null\n const fromPage = pageFile ? firstSentence(pageOpening(readFileSync(join(root, pageFile), 'utf8'))) : ''\n const fromComment = firstSentence(declared.doc)\n const purpose = fromPage || fromComment\n if (!purpose) {\n problems.push(`${value.name} has no purpose: no opening paragraph on its page, and no doc comment above it in ${module.file}`)\n continue\n }\n\n // A name with stories of its own uses them; otherwise the sibling's, which\n // is the page that documents it.\n const storiesFile = files.has(`${value.name}.stories.tsx`) ? `${value.name}.stories.tsx` : files.has(`${value.module}.stories.tsx`) ? `${value.module}.stories.tsx` : null\n const stories = storiesFile ? readStories(readFileSync(join(src, storiesFile), 'utf8')) : { title: null, stories: [] }\n const title = stories.title\n const story = stories.stories.includes(value.name) ? value.name : stories.stories[0]\n\n const shape = module.resolve(declared.propsType)\n\n entries.push({\n name: value.name,\n repo,\n kind: kindOf(value.name),\n importPath: PACKAGE_IMPORT,\n sourceFile: module.file,\n purpose,\n purposeFrom: fromPage ? 'page' : 'comment',\n props: shape.props,\n variants: shape.variants,\n ownsBehaviours: behavioursOf(value.name),\n status: declared.deprecated ? 'deprecated' : 'stable',\n migrationStage: null,\n docsId: title ? `${sanitize(title)}--docs` : null,\n storyId: title && story ? toId(title, story) : null,\n docPage: pageFile,\n app: null,\n })\n }\n\n if (problems.length) throw new Error(`the registry cannot be built:\\n ${problems.join('\\n ')}`)\n\n entries.sort((a, b) => a.name.localeCompare(b.name))\n\n return {\n schemaVersion: SCHEMA_VERSION,\n builtFrom: {\n kind: 'package',\n repo,\n package: manifest.name,\n packageVersion: manifest.version,\n exports: values.length,\n typeExports: exported.length - values.length,\n files: null,\n },\n storybook: {\n docsPath: '/?path=/docs/{docsId}',\n storyPath: '/?path=/story/{storyId}',\n devUrl: 'http://localhost:6008',\n },\n entries,\n // Nothing is excluded: every value export is an entry, helpers and the one\n // hook included, each marked by `kind`. The field stays because the count\n // has to reconcile out loud \u2014 see validateRegistry.\n excluded: [],\n filesWithoutParts: [],\n }\n}\n\n/** The committed file's text, so a check and a write produce the same bytes. */\nexport function serializeRegistry(registry: Registry): string {\n return `${JSON.stringify(registry, null, 2)}\\n`\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["line"]
7
+ }