@estiva-app/ui 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/AppShell.d.ts.map +1 -1
- package/dist/AttachmentCard.d.ts.map +1 -1
- package/dist/Banner.d.ts +20 -2
- package/dist/Banner.d.ts.map +1 -1
- package/dist/ContainerHeader.d.ts +25 -0
- package/dist/ContainerHeader.d.ts.map +1 -0
- package/dist/EmptyState.d.ts +10 -1
- package/dist/EmptyState.d.ts.map +1 -1
- package/dist/Form.d.ts.map +1 -1
- package/dist/IconButton.d.ts +9 -1
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/PreviewCard.d.ts +9 -2
- package/dist/PreviewCard.d.ts.map +1 -1
- package/dist/SectionHeader.d.ts +7 -1
- package/dist/SectionHeader.d.ts.map +1 -1
- package/dist/Select.d.ts +11 -3
- package/dist/Select.d.ts.map +1 -1
- package/dist/Tooltip.d.ts +13 -1
- package/dist/Tooltip.d.ts.map +1 -1
- package/dist/eslint/index.js +2 -1
- package/dist/eslint/index.js.map +2 -2
- package/dist/eslint/no-restyled-part.d.ts.map +1 -1
- package/dist/gates/app-checks.d.ts.map +1 -1
- package/dist/gates/{chunk-ZGJ2J5NU.js → chunk-EA33NP5B.js} +275 -11
- package/dist/gates/chunk-EA33NP5B.js.map +7 -0
- package/dist/gates/{chunk-AUXD4GCY.js → chunk-GTQZEHPC.js} +15 -1
- package/dist/gates/chunk-GTQZEHPC.js.map +7 -0
- package/dist/gates/cli.js +1 -1
- package/dist/gates/create-app.d.ts +2 -0
- package/dist/gates/create-app.d.ts.map +1 -1
- package/dist/gates/create-app.js +1 -1
- package/dist/gates/index.js +25 -3
- package/dist/gates/index.js.map +2 -2
- package/dist/gates/status.d.ts +2 -0
- package/dist/gates/status.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +196 -156
- package/dist/index.js.map +4 -4
- package/dist/registry/app-DQI6WLHR.js +10 -0
- package/dist/registry/app.d.ts +21 -0
- package/dist/registry/app.d.ts.map +1 -0
- package/dist/registry/build-LGFCCOLR.js +27 -0
- package/dist/registry/build-LGFCCOLR.js.map +7 -0
- package/dist/registry/build.d.ts +68 -2
- package/dist/registry/build.d.ts.map +1 -1
- package/dist/registry/{chunk-MRSBS5OP.js → chunk-E4JNV7PC.js} +68 -12
- package/dist/registry/chunk-E4JNV7PC.js.map +7 -0
- package/dist/registry/{chunk-QDYGB3QN.js → chunk-NJN4MQAM.js} +60 -15
- package/dist/registry/chunk-NJN4MQAM.js.map +7 -0
- package/dist/registry/{chunk-IJNCYVH4.js → chunk-W2B2G7OE.js} +34 -9
- package/dist/registry/chunk-W2B2G7OE.js.map +7 -0
- package/dist/registry/chunk-WMFF3MPP.js +648 -0
- package/dist/registry/chunk-WMFF3MPP.js.map +7 -0
- package/dist/registry/cli.js +81 -26
- package/dist/registry/cli.js.map +3 -3
- package/dist/registry/find.d.ts +12 -1
- package/dist/registry/find.d.ts.map +1 -1
- package/dist/registry/index.d.ts +5 -2
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +11 -3
- package/dist/registry/schema.d.ts +83 -6
- package/dist/registry/schema.d.ts.map +1 -1
- package/package.json +2 -2
- package/registry.json +283 -95
- package/src/AppShell.mdx +10 -0
- package/src/AppShell.test.tsx +16 -0
- package/src/AppShell.tsx +4 -1
- package/src/AttachmentCard.mdx +9 -0
- package/src/AttachmentCard.test.tsx +10 -0
- package/src/AttachmentCard.tsx +8 -5
- package/src/Avatar.mdx +13 -3
- package/src/AvatarGroup.mdx +4 -0
- package/src/Banner.mdx +30 -7
- package/src/Banner.stories.tsx +22 -0
- package/src/Banner.test.tsx +35 -0
- package/src/Banner.tsx +34 -9
- package/src/Breadcrumb.mdx +10 -0
- package/src/Button.mdx +14 -3
- package/src/Card.mdx +9 -0
- package/src/Checkbox.mdx +10 -0
- package/src/Chip.mdx +4 -0
- package/src/ChipInput.mdx +12 -0
- package/src/CollapsibleSection.mdx +9 -0
- package/src/CommandPalette.mdx +14 -2
- package/src/ConfirmDialog.mdx +11 -0
- package/src/ContainerHeader.mdx +60 -0
- package/src/ContainerHeader.stories.tsx +62 -0
- package/src/ContainerHeader.test.tsx +47 -0
- package/src/ContainerHeader.tsx +45 -0
- package/src/DialogShell.mdx +14 -0
- package/src/Divider.mdx +9 -1
- package/src/EditableText.mdx +11 -0
- package/src/EmptyState.mdx +27 -4
- package/src/EmptyState.stories.tsx +6 -1
- package/src/EmptyState.test.tsx +18 -1
- package/src/EmptyState.tsx +14 -1
- package/src/Field.mdx +10 -1
- package/src/FieldLine.mdx +9 -1
- package/src/FilePicker.mdx +8 -0
- package/src/Form.mdx +10 -0
- package/src/Form.test.tsx +26 -0
- package/src/Form.tsx +7 -0
- package/src/IconButton.mdx +16 -2
- package/src/IconButton.stories.tsx +3 -0
- package/src/IconButton.test.tsx +25 -0
- package/src/IconButton.tsx +61 -46
- package/src/IdentityMenu.mdx +9 -0
- package/src/InlineChip.mdx +8 -0
- package/src/Kbd.mdx +4 -0
- package/src/Link.mdx +10 -0
- package/src/Menu.mdx +16 -1
- package/src/MenuItem.mdx +12 -2
- package/src/NavItem.mdx +8 -0
- package/src/Person.mdx +4 -0
- package/src/PersonTrigger.mdx +9 -0
- package/src/Popover.mdx +21 -0
- package/src/PreviewCard.mdx +19 -4
- package/src/PreviewCard.tsx +11 -4
- package/src/ProgressBar.mdx +8 -0
- package/src/Property.mdx +4 -0
- package/src/Rail.mdx +9 -1
- package/src/RailItem.mdx +8 -0
- package/src/Reaction.mdx +9 -0
- package/src/ReactionPicker.mdx +8 -0
- package/src/ScrollArea.mdx +13 -2
- package/src/SearchInput.mdx +9 -0
- package/src/SectionHeader.mdx +13 -0
- package/src/SectionHeader.stories.tsx +9 -0
- package/src/SectionHeader.test.tsx +9 -0
- package/src/SectionHeader.tsx +8 -2
- package/src/SectionLabel.mdx +4 -0
- package/src/Select.mdx +21 -2
- package/src/Select.stories.tsx +4 -1
- package/src/Select.test.tsx +17 -0
- package/src/Select.tsx +34 -13
- package/src/Sidebar.mdx +8 -0
- package/src/Skeleton.mdx +4 -0
- package/src/Tabs.mdx +12 -1
- package/src/TextInput.mdx +8 -0
- package/src/Textarea.mdx +8 -0
- package/src/Toast.mdx +12 -1
- package/src/Toolbar.mdx +11 -0
- package/src/Tooltip.mdx +26 -2
- package/src/Tooltip.stories.tsx +26 -0
- package/src/Tooltip.test.tsx +29 -0
- package/src/Tooltip.tsx +17 -4
- package/src/TopBar.mdx +4 -0
- package/src/eslint/no-rebuilt-behaviour.ts +1 -1
- package/src/eslint/no-restyled-part.ts +1 -0
- package/src/gates/app-checks.ts +23 -1
- package/src/gates/create-app.test.ts +77 -6
- package/src/gates/create-app.ts +288 -15
- package/src/gates/status.ts +16 -0
- package/src/index.ts +1 -0
- package/src/pages.test.ts +142 -0
- package/src/registry/app.test.ts +562 -0
- package/src/registry/app.ts +854 -0
- package/src/registry/build.ts +114 -25
- package/src/registry/cli.ts +105 -42
- package/src/registry/find.ts +45 -8
- package/src/registry/index.ts +8 -1
- package/src/registry/registry.test.ts +5 -5
- package/src/registry/schema.ts +163 -12
- package/tailwind-preset.js +22 -1
- package/dist/gates/chunk-AUXD4GCY.js.map +0 -7
- package/dist/gates/chunk-ZGJ2J5NU.js.map +0 -7
- package/dist/registry/build-GOVLABI6.js +0 -13
- package/dist/registry/chunk-IJNCYVH4.js.map +0 -7
- package/dist/registry/chunk-MRSBS5OP.js.map +0 -7
- package/dist/registry/chunk-QDYGB3QN.js.map +0 -7
- /package/dist/registry/{build-GOVLABI6.js.map → app-DQI6WLHR.js.map} +0 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PACKAGE_IMPORT,
|
|
4
|
+
firstSentence,
|
|
5
|
+
pageOpening,
|
|
6
|
+
readModule,
|
|
7
|
+
sanitize,
|
|
8
|
+
toId
|
|
9
|
+
} from "./chunk-NJN4MQAM.js";
|
|
10
|
+
import {
|
|
11
|
+
SCHEMA_VERSION
|
|
12
|
+
} from "./chunk-E4JNV7PC.js";
|
|
13
|
+
|
|
14
|
+
// src/registry/app.ts
|
|
15
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
16
|
+
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
17
|
+
import ts from "typescript";
|
|
18
|
+
var WRITABLE = ["reusable", "one-off", "promote-candidate"];
|
|
19
|
+
var WRITTEN = /^@registry\s+([a-z-]+)\s*:\s*(.+)$/m;
|
|
20
|
+
var isStory = (file) => /\.stories\.[cm]?[jt]sx?$/.test(file);
|
|
21
|
+
var isTest = (file) => /\.(test|spec)\.[cm]?[jt]sx?$/.test(file) || /(^|\/)__(tests|mocks)__\//.test(file);
|
|
22
|
+
var isPascal = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name) && !/^[A-Z0-9_]+$/.test(name);
|
|
23
|
+
function pickedFrom(call) {
|
|
24
|
+
const then = call.parent;
|
|
25
|
+
const invoked = then?.parent;
|
|
26
|
+
if (then && ts.isPropertyAccessExpression(then) && then.name.text === "then" && invoked && ts.isCallExpression(invoked)) {
|
|
27
|
+
const callback = invoked.arguments[0];
|
|
28
|
+
const param = callback && (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback)) ? callback.parameters[0]?.name : void 0;
|
|
29
|
+
if (param && ts.isIdentifier(param)) {
|
|
30
|
+
const names = /* @__PURE__ */ new Set();
|
|
31
|
+
const visit = (n) => {
|
|
32
|
+
if (ts.isPropertyAccessExpression(n) && ts.isIdentifier(n.expression) && n.expression.text === param.text) names.add(n.name.text);
|
|
33
|
+
ts.forEachChild(n, visit);
|
|
34
|
+
};
|
|
35
|
+
visit(callback);
|
|
36
|
+
if (names.size) return [...names].map((imported) => ({ imported, local: "(dynamic)" }));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return [{ imported: "*", local: "(dynamic)" }];
|
|
40
|
+
}
|
|
41
|
+
function unwrapDefault(ex) {
|
|
42
|
+
if (!ex.isDefault || ex.local || !ex.node || !ts.isExpression(ex.node)) return ex;
|
|
43
|
+
const name = handedOut(ex.node);
|
|
44
|
+
return name ? { ...ex, local: name, node: null } : ex;
|
|
45
|
+
}
|
|
46
|
+
function handedOut(expression) {
|
|
47
|
+
let e = expression;
|
|
48
|
+
for (; ; ) {
|
|
49
|
+
if (ts.isIdentifier(e)) return e.text;
|
|
50
|
+
if (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isSatisfiesExpression(e) || ts.isNonNullExpression(e) || ts.isTypeAssertionExpression(e)) e = e.expression;
|
|
51
|
+
else if (ts.isTaggedTemplateExpression(e)) e = e.tag;
|
|
52
|
+
else if (ts.isCallExpression(e) && e.arguments[0] && !e.arguments.some((a) => ts.isArrowFunction(a) || ts.isFunctionExpression(a))) e = e.arguments[0];
|
|
53
|
+
else return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
var pascalOf = (stem) => stem.split(/[^A-Za-z0-9]+/).filter(Boolean).map((word) => word[0].toUpperCase() + word.slice(1)).join("");
|
|
57
|
+
var defaultNameOf = (file) => {
|
|
58
|
+
const stem = basename(file, extname(file));
|
|
59
|
+
return pascalOf(stem === "index" ? basename(dirname(file)) : stem);
|
|
60
|
+
};
|
|
61
|
+
var CODE = [".tsx", ".ts", ".jsx", ".js", ".mts", ".cts"];
|
|
62
|
+
function packageOf(specifier) {
|
|
63
|
+
const parts = specifier.split("/");
|
|
64
|
+
return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0];
|
|
65
|
+
}
|
|
66
|
+
function packageSelf() {
|
|
67
|
+
const at = (rel) => new URL(rel, import.meta.url);
|
|
68
|
+
const manifest = JSON.parse(readFileSync(at("../../package.json"), "utf8"));
|
|
69
|
+
const registryUrl = at("../../registry.json");
|
|
70
|
+
const registry = existsSync(registryUrl) ? JSON.parse(readFileSync(registryUrl, "utf8")) : null;
|
|
71
|
+
return { dependencies: [manifest.name, ...Object.keys(manifest.dependencies ?? {}), ...Object.keys(manifest.peerDependencies ?? {})], registry };
|
|
72
|
+
}
|
|
73
|
+
function readAliases(root) {
|
|
74
|
+
const aliases = [];
|
|
75
|
+
const bases = [];
|
|
76
|
+
for (const name of readdirSync(root).filter((file) => /^tsconfig.*\.json$/.test(file)).sort()) {
|
|
77
|
+
const read = ts.readConfigFile(join(root, name), ts.sys.readFile);
|
|
78
|
+
const options = read.config?.compilerOptions ?? {};
|
|
79
|
+
const base = resolve(root, options.baseUrl ?? ".");
|
|
80
|
+
if (options.baseUrl !== void 0 && !bases.includes(base)) bases.push(base);
|
|
81
|
+
for (const [pattern, targets] of Object.entries(options.paths ?? {})) {
|
|
82
|
+
if (!pattern.endsWith("/*") || !targets[0]?.endsWith("/*")) continue;
|
|
83
|
+
const prefix = pattern.slice(0, -1);
|
|
84
|
+
if (!aliases.some((alias) => alias.prefix === prefix)) aliases.push({ prefix, target: resolve(base, targets[0].slice(0, -2)) });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { aliases, bases };
|
|
88
|
+
}
|
|
89
|
+
function walk(dir) {
|
|
90
|
+
return readdirSync(dir).flatMap((name) => {
|
|
91
|
+
if (name === "node_modules" || name.startsWith(".")) return [];
|
|
92
|
+
const path = join(dir, name);
|
|
93
|
+
return statSync(path).isDirectory() ? walk(path) : [path];
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function draws(node) {
|
|
97
|
+
let found = false;
|
|
98
|
+
const visit = (n) => {
|
|
99
|
+
if (found) return;
|
|
100
|
+
if (ts.isJsxElement(n) || ts.isJsxSelfClosingElement(n) || ts.isJsxFragment(n)) {
|
|
101
|
+
found = true;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (ts.isCallExpression(n)) {
|
|
105
|
+
const callee = ts.isPropertyAccessExpression(n.expression) ? n.expression.name.text : ts.isIdentifier(n.expression) ? n.expression.text : "";
|
|
106
|
+
if (callee === "createElement" || callee === "createPortal") {
|
|
107
|
+
found = true;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
ts.forEachChild(n, visit);
|
|
112
|
+
};
|
|
113
|
+
visit(node);
|
|
114
|
+
return found;
|
|
115
|
+
}
|
|
116
|
+
function mentions(sf, local, home) {
|
|
117
|
+
let named = false;
|
|
118
|
+
const visit = (n) => {
|
|
119
|
+
if (named) return;
|
|
120
|
+
if (ts.isIdentifier(n) && n.text === local) {
|
|
121
|
+
const parent = n.parent;
|
|
122
|
+
const declares = (ts.isPropertySignature(parent) || ts.isPropertyDeclaration(parent) || ts.isMethodDeclaration(parent) || ts.isMethodSignature(parent) || ts.isGetAccessorDeclaration(parent) || ts.isSetAccessorDeclaration(parent) || ts.isEnumMember(parent) || ts.isVariableDeclaration(parent) || ts.isFunctionDeclaration(parent) || ts.isClassDeclaration(parent) || ts.isParameter(parent) || ts.isBindingElement(parent)) && parent.name === n;
|
|
123
|
+
const bindingKey = ts.isBindingElement(parent) && parent.propertyName === n;
|
|
124
|
+
const isName = declares || bindingKey || ts.isPropertyAccessExpression(parent) && parent.name === n || ts.isPropertyAssignment(parent) && parent.name === n || ts.isJsxAttribute(parent) || ts.isExportSpecifier(parent) || ts.isImportSpecifier(parent) || ts.isJsxClosingElement(parent);
|
|
125
|
+
const configures = ts.isPropertyAccessExpression(parent) && parent.expression === n && ts.isBinaryExpression(parent.parent) && parent.parent.left === parent && parent.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken;
|
|
126
|
+
if (configures) {
|
|
127
|
+
ts.forEachChild(n, visit);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let inType = false;
|
|
131
|
+
for (let a = parent; a && a !== sf; a = a.parent) if (ts.isTypeNode(a)) inType = true;
|
|
132
|
+
if (!isName && !inType && !shadowed(n, local, sf)) named = true;
|
|
133
|
+
}
|
|
134
|
+
ts.forEachChild(n, visit);
|
|
135
|
+
};
|
|
136
|
+
for (const s of sf.statements) {
|
|
137
|
+
if (s === home || ts.isExportDeclaration(s) || ts.isImportDeclaration(s)) continue;
|
|
138
|
+
if (ts.isExportAssignment(s) && handedOut(s.expression)) continue;
|
|
139
|
+
visit(s);
|
|
140
|
+
}
|
|
141
|
+
return named;
|
|
142
|
+
}
|
|
143
|
+
function binds(name, local) {
|
|
144
|
+
if (!name) return false;
|
|
145
|
+
if (ts.isIdentifier(name)) return name.text === local;
|
|
146
|
+
return name.elements.some((element) => !ts.isOmittedExpression(element) && binds(element.name, local));
|
|
147
|
+
}
|
|
148
|
+
function shadowed(n, local, sf) {
|
|
149
|
+
for (let a = n.parent; a && a !== sf; a = a.parent) {
|
|
150
|
+
if (ts.isFunctionLike(a)) {
|
|
151
|
+
if (a.parameters.some((p) => binds(p.name, local))) return true;
|
|
152
|
+
if ((ts.isFunctionExpression(a) || ts.isClassExpression(a)) && a.name?.text === local) return true;
|
|
153
|
+
}
|
|
154
|
+
if (ts.isCatchClause(a) && binds(a.variableDeclaration?.name, local)) return true;
|
|
155
|
+
if (ts.isBlock(a) || ts.isModuleBlock(a) || ts.isCaseClause(a) || ts.isDefaultClause(a)) {
|
|
156
|
+
for (const s of a.statements) {
|
|
157
|
+
if (ts.isVariableStatement(s) && s.declarationList.declarations.some((d) => binds(d.name, local))) return true;
|
|
158
|
+
if ((ts.isFunctionDeclaration(s) || ts.isClassDeclaration(s)) && s.name?.text === local) return true;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if ((ts.isForStatement(a) || ts.isForOfStatement(a) || ts.isForInStatement(a)) && a.initializer && ts.isVariableDeclarationList(a.initializer) && a.initializer.declarations.some((d) => binds(d.name, local))) return true;
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
function drawingBody(node) {
|
|
166
|
+
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) return node;
|
|
167
|
+
const init = ts.isVariableDeclaration(node) ? node.initializer : ts.isExpression(node) ? node : void 0;
|
|
168
|
+
if (!init) return null;
|
|
169
|
+
if (ts.isArrowFunction(init) || ts.isFunctionExpression(init) || ts.isClassExpression(init)) return init;
|
|
170
|
+
if (ts.isCallExpression(init)) {
|
|
171
|
+
const callee = init.expression.getText();
|
|
172
|
+
if (/(^|\.)createContext$/.test(callee)) return null;
|
|
173
|
+
if (init.arguments.some((a) => ts.isArrowFunction(a) || ts.isFunctionExpression(a))) return init;
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
function buildAppRegistry({ root = process.cwd(), repo, packageRegistry, packageDependencies } = {}) {
|
|
178
|
+
const app = resolve(root);
|
|
179
|
+
const src = join(app, "src");
|
|
180
|
+
if (!existsSync(src)) throw new Error(`${app} has no src/ folder: estiva-ui reads an app's parts from src/`);
|
|
181
|
+
const manifest = JSON.parse(readFileSync(join(app, "package.json"), "utf8"));
|
|
182
|
+
const self = packageRegistry === void 0 || packageDependencies === void 0 ? packageSelf() : null;
|
|
183
|
+
const theRegistry = packageRegistry === void 0 ? self?.registry ?? null : packageRegistry;
|
|
184
|
+
const allowed = new Set(packageDependencies ?? self?.dependencies ?? []);
|
|
185
|
+
const repoName = repo ?? manifest.name ?? basename(app);
|
|
186
|
+
const { aliases, bases } = readAliases(app);
|
|
187
|
+
const rel = (abs) => relative(app, abs).split(sep).join("/");
|
|
188
|
+
const files = walk(src).filter((path) => CODE.includes(extname(path)) && !path.endsWith(".d.ts")).map(rel).sort();
|
|
189
|
+
const known = new Set(files);
|
|
190
|
+
const resolveSpecifier = (from, specifier) => {
|
|
191
|
+
let base = null;
|
|
192
|
+
if (specifier.startsWith(".")) base = resolve(app, dirname(from), specifier);
|
|
193
|
+
else {
|
|
194
|
+
const alias = aliases.find((a) => specifier.startsWith(a.prefix));
|
|
195
|
+
if (alias) base = join(alias.target, specifier.slice(alias.prefix.length));
|
|
196
|
+
}
|
|
197
|
+
const lookUp = (at) => {
|
|
198
|
+
const stem = at.replace(/\.(js|jsx)$/, "");
|
|
199
|
+
for (const candidate of [at, ...CODE.map((e) => stem + e), ...CODE.map((e) => join(at, `index${e}`))]) {
|
|
200
|
+
const r = rel(candidate);
|
|
201
|
+
if (known.has(r)) return r;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
};
|
|
205
|
+
if (base === null) {
|
|
206
|
+
for (const folder of bases) {
|
|
207
|
+
const hit = lookUp(join(folder, specifier));
|
|
208
|
+
if (hit) return hit;
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
return lookUp(base) ?? "?";
|
|
213
|
+
};
|
|
214
|
+
const facts = /* @__PURE__ */ new Map();
|
|
215
|
+
for (const file of files) {
|
|
216
|
+
const source = readFileSync(join(app, file), "utf8");
|
|
217
|
+
const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, /x$/.test(file) ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
|
|
218
|
+
const links = [];
|
|
219
|
+
const exports = [];
|
|
220
|
+
const reexports = [];
|
|
221
|
+
const starFrom = [];
|
|
222
|
+
const namespaces = [];
|
|
223
|
+
for (const statement of sf.statements) {
|
|
224
|
+
if (ts.isImportDeclaration(statement)) {
|
|
225
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
226
|
+
const specifier = statement.moduleSpecifier.text;
|
|
227
|
+
const clause = statement.importClause;
|
|
228
|
+
const names = [];
|
|
229
|
+
if (clause && !clause.isTypeOnly) {
|
|
230
|
+
if (clause.name) names.push({ imported: "default", local: clause.name.text });
|
|
231
|
+
const bindings2 = clause.namedBindings;
|
|
232
|
+
if (bindings2 && ts.isNamedImports(bindings2)) {
|
|
233
|
+
for (const e of bindings2.elements) if (!e.isTypeOnly) names.push({ imported: (e.propertyName ?? e.name).text, local: e.name.text });
|
|
234
|
+
}
|
|
235
|
+
if (bindings2 && ts.isNamespaceImport(bindings2)) names.push({ imported: "*", local: bindings2.name.text });
|
|
236
|
+
}
|
|
237
|
+
links.push({ specifier, target: resolveSpecifier(file, specifier), names, typeOnly: !!clause?.isTypeOnly || clause !== void 0 && names.length === 0 && !!clause.namedBindings, kind: "import" });
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (ts.isExportDeclaration(statement)) {
|
|
241
|
+
const specifier = statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : null;
|
|
242
|
+
if (specifier === null) {
|
|
243
|
+
if (!statement.isTypeOnly && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
244
|
+
for (const e of statement.exportClause.elements) if (!e.isTypeOnly) exports.push({ name: e.name.text, local: (e.propertyName ?? e.name).text, isDefault: e.name.text === "default", node: null });
|
|
245
|
+
}
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
const target = resolveSpecifier(file, specifier);
|
|
249
|
+
links.push({ specifier, target, names: [], typeOnly: statement.isTypeOnly, kind: "re-export" });
|
|
250
|
+
if (statement.isTypeOnly) continue;
|
|
251
|
+
if (!statement.exportClause) starFrom.push({ specifier, target });
|
|
252
|
+
else if (ts.isNamedExports(statement.exportClause)) {
|
|
253
|
+
for (const e of statement.exportClause.elements) if (!e.isTypeOnly) reexports.push({ name: e.name.text, source: (e.propertyName ?? e.name).text, specifier, target });
|
|
254
|
+
} else if (ts.isNamespaceExport(statement.exportClause)) {
|
|
255
|
+
namespaces.push({ name: statement.exportClause.name.text, target });
|
|
256
|
+
}
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
|
|
260
|
+
const e = statement.expression;
|
|
261
|
+
exports.push({ name: "default", local: ts.isIdentifier(e) ? e.text : null, isDefault: true, node: ts.isIdentifier(e) ? null : e });
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const mods = ts.canHaveModifiers(statement) ? ts.getModifiers(statement) ?? [] : [];
|
|
265
|
+
if (!mods.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) continue;
|
|
266
|
+
const isDefault = mods.some((m) => m.kind === ts.SyntaxKind.DefaultKeyword);
|
|
267
|
+
if (ts.isFunctionDeclaration(statement) && !statement.body) continue;
|
|
268
|
+
if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) {
|
|
269
|
+
exports.push({ name: isDefault ? "default" : statement.name?.text ?? "default", local: statement.name?.text ?? null, isDefault, node: statement });
|
|
270
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
271
|
+
for (const d of statement.declarationList.declarations) if (ts.isIdentifier(d.name)) exports.push({ name: d.name.text, local: d.name.text, isDefault: false, node: d });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const tags = /* @__PURE__ */ new Set();
|
|
275
|
+
const visit = (n) => {
|
|
276
|
+
if (ts.isCallExpression(n) && n.expression.kind === ts.SyntaxKind.ImportKeyword && n.arguments[0] && ts.isStringLiteralLike(n.arguments[0])) {
|
|
277
|
+
const specifier = n.arguments[0].text;
|
|
278
|
+
links.push({ specifier, target: resolveSpecifier(file, specifier), names: pickedFrom(n), typeOnly: false, kind: "dynamic" });
|
|
279
|
+
}
|
|
280
|
+
if ((ts.isJsxOpeningElement(n) || ts.isJsxSelfClosingElement(n)) && ts.isIdentifier(n.tagName)) tags.add(n.tagName.text);
|
|
281
|
+
ts.forEachChild(n, visit);
|
|
282
|
+
};
|
|
283
|
+
visit(sf);
|
|
284
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
285
|
+
for (const link of links) if (link.kind === "import") {
|
|
286
|
+
for (const n of link.names) if (n.imported !== "*") bindings.set(n.local, { specifier: link.specifier, imported: n.imported, target: link.target });
|
|
287
|
+
}
|
|
288
|
+
facts.set(file, { file, source, sf, links, exports, reexports, starFrom, namespaces, tags, bindings });
|
|
289
|
+
}
|
|
290
|
+
const drawnAnywhere = /* @__PURE__ */ new Set();
|
|
291
|
+
for (const f of facts.values()) for (const tag of f.tags) drawnAnywhere.add(tag);
|
|
292
|
+
const declarationOf = (f, local) => {
|
|
293
|
+
for (const s of f.sf.statements) {
|
|
294
|
+
if (ts.isFunctionDeclaration(s) && s.name?.text === local && !s.body) continue;
|
|
295
|
+
if ((ts.isFunctionDeclaration(s) || ts.isClassDeclaration(s)) && s.name?.text === local) return s;
|
|
296
|
+
if (ts.isVariableStatement(s)) {
|
|
297
|
+
for (const d of s.declarationList.declarations) if (ts.isIdentifier(d.name) && d.name.text === local) return d;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
};
|
|
302
|
+
const problems = [];
|
|
303
|
+
const found = [];
|
|
304
|
+
const targets = files.filter((file) => file.endsWith(".tsx") && !isStory(file) && !isTest(file));
|
|
305
|
+
for (const file of targets) {
|
|
306
|
+
const f = facts.get(file);
|
|
307
|
+
for (const written of f.exports) {
|
|
308
|
+
const ex = unwrapDefault(written);
|
|
309
|
+
if (ex !== written && ex.local && isPascal(ex.local) && !declarationOf(f, ex.local) && f.bindings.has(ex.local)) {
|
|
310
|
+
found.push({ file, name: defaultNameOf(file), local: null, defaultExport: true, from: null });
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (ex.isDefault && ex.local && f.exports.some((other) => !other.isDefault && other.local === ex.local)) continue;
|
|
314
|
+
const node = ex.node ?? (ex.local ? declarationOf(f, ex.local) : null);
|
|
315
|
+
const own = ex.local ?? (ex.isDefault ? defaultNameOf(file) : ex.name);
|
|
316
|
+
const name = ex.isDefault ? own : ex.name;
|
|
317
|
+
if (!isPascal(name)) continue;
|
|
318
|
+
const bound = node === null && ex.local ? f.bindings.get(ex.local) : void 0;
|
|
319
|
+
if (bound) {
|
|
320
|
+
if (bound.target === null) found.push({ file, name, local: null, defaultExport: ex.isDefault, from: { specifier: bound.specifier, name: bound.imported } });
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const alias = node && ts.isVariableDeclaration(node) && node.initializer && ts.isIdentifier(node.initializer) ? f.bindings.get(node.initializer.text) : void 0;
|
|
324
|
+
if (alias) {
|
|
325
|
+
if (alias.target === null) found.push({ file, name, local: null, defaultExport: ex.isDefault, from: { specifier: alias.specifier, name: alias.imported } });
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
const body = node ? drawingBody(node) : null;
|
|
329
|
+
const isPart = body !== null && draws(body) || drawnAnywhere.has(ex.local ?? name);
|
|
330
|
+
if (isPart) found.push({ file, name, local: ex.local, defaultExport: ex.isDefault, from: null });
|
|
331
|
+
}
|
|
332
|
+
for (const re of f.reexports) {
|
|
333
|
+
if (re.target !== null || !isPascal(re.name)) continue;
|
|
334
|
+
found.push({ file, name: re.name, local: null, defaultExport: false, from: { specifier: re.specifier, name: re.source } });
|
|
335
|
+
}
|
|
336
|
+
for (const star of f.starFrom) {
|
|
337
|
+
if (star.target === null) problems.push(`${file} hands on everything from '${star.specifier}' with export *: name the parts it hands on, so the catalogue can list them`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const key = (file, name) => `${file}#${name}`;
|
|
341
|
+
const byKey = new Map(found.map((p) => [key(p.file, p.name), p]));
|
|
342
|
+
const partsIn = (file) => found.filter((p) => p.file === file);
|
|
343
|
+
const defaultPartOf = (file) => {
|
|
344
|
+
const written = facts.get(file)?.exports.find((e) => e.isDefault);
|
|
345
|
+
if (!written) return null;
|
|
346
|
+
const d = unwrapDefault(written);
|
|
347
|
+
return partsIn(file).find((p) => p.defaultExport || d.local !== null && p.local === d.local) ?? null;
|
|
348
|
+
};
|
|
349
|
+
const origin = (file, name, seen = /* @__PURE__ */ new Set()) => {
|
|
350
|
+
if (seen.has(key(file, name))) return null;
|
|
351
|
+
seen.add(key(file, name));
|
|
352
|
+
const direct = byKey.get(key(file, name));
|
|
353
|
+
if (direct) return direct;
|
|
354
|
+
const f = facts.get(file);
|
|
355
|
+
if (!f) return null;
|
|
356
|
+
if (name === "default") {
|
|
357
|
+
const d = defaultPartOf(file);
|
|
358
|
+
if (d) return d;
|
|
359
|
+
}
|
|
360
|
+
const re = f.reexports.find((r) => r.name === name);
|
|
361
|
+
if (re && re.target && re.target !== "?") return origin(re.target, re.source, seen);
|
|
362
|
+
const ex = f.exports.find((e) => name === "default" ? e.isDefault : e.name === name && !e.isDefault);
|
|
363
|
+
const renamed = ex?.node && ts.isVariableDeclaration(ex.node) && ex.node.initializer && ts.isIdentifier(ex.node.initializer) ? f.bindings.get(ex.node.initializer.text) : void 0;
|
|
364
|
+
const bound = (ex?.local && !ex.node && !declarationOf(f, ex.local) ? f.bindings.get(ex.local) : void 0) ?? renamed;
|
|
365
|
+
if (bound?.target && bound.target !== "?") return origin(bound.target, bound.imported, seen);
|
|
366
|
+
for (const star of f.starFrom) if (star.target && star.target !== "?") {
|
|
367
|
+
const hit = origin(star.target, name, seen);
|
|
368
|
+
if (hit) return hit;
|
|
369
|
+
}
|
|
370
|
+
return null;
|
|
371
|
+
};
|
|
372
|
+
const everyPartOf = (file, seen = /* @__PURE__ */ new Set()) => {
|
|
373
|
+
if (seen.has(file)) return [];
|
|
374
|
+
seen.add(file);
|
|
375
|
+
const f = facts.get(file);
|
|
376
|
+
if (!f) return [];
|
|
377
|
+
const out = [...partsIn(file)];
|
|
378
|
+
for (const re of f.reexports) if (re.target && re.target !== "?") {
|
|
379
|
+
const o = origin(re.target, re.source);
|
|
380
|
+
if (o) out.push(o);
|
|
381
|
+
}
|
|
382
|
+
for (const star of f.starFrom) if (star.target && star.target !== "?") out.push(...everyPartOf(star.target, seen));
|
|
383
|
+
for (const ns of f.namespaces) if (ns.target && ns.target !== "?") out.push(...everyPartOf(ns.target, seen));
|
|
384
|
+
return out;
|
|
385
|
+
};
|
|
386
|
+
const namespaceParts = (file, name, seen = /* @__PURE__ */ new Set()) => {
|
|
387
|
+
if (seen.has(`${file}#${name}`)) return [];
|
|
388
|
+
seen.add(`${file}#${name}`);
|
|
389
|
+
const f = facts.get(file);
|
|
390
|
+
if (!f) return [];
|
|
391
|
+
const ns = f.namespaces.find((x) => x.name === name);
|
|
392
|
+
if (ns) return ns.target && ns.target !== "?" ? everyPartOf(ns.target) : [];
|
|
393
|
+
const re = f.reexports.find((r) => r.name === name);
|
|
394
|
+
if (re?.target && re.target !== "?") return namespaceParts(re.target, re.source, seen);
|
|
395
|
+
return f.starFrom.flatMap((star) => star.target && star.target !== "?" ? namespaceParts(star.target, name, seen) : []);
|
|
396
|
+
};
|
|
397
|
+
const users = /* @__PURE__ */ new Map();
|
|
398
|
+
for (const p of found) users.set(key(p.file, p.name), { app: /* @__PURE__ */ new Set(), stories: /* @__PURE__ */ new Set(), tests: /* @__PURE__ */ new Set() });
|
|
399
|
+
for (const f of facts.values()) {
|
|
400
|
+
const bucket = (p) => {
|
|
401
|
+
const u = users.get(key(p.file, p.name));
|
|
402
|
+
return isStory(f.file) ? u.stories : isTest(f.file) ? u.tests : u.app;
|
|
403
|
+
};
|
|
404
|
+
for (const link of f.links) {
|
|
405
|
+
if (link.kind === "re-export" || link.typeOnly || !link.target || link.target === "?") continue;
|
|
406
|
+
for (const n of link.names) {
|
|
407
|
+
if (n.imported === "*") {
|
|
408
|
+
const theDefault = link.kind === "dynamic" ? defaultPartOf(link.target) : null;
|
|
409
|
+
const chosen = theDefault ? [theDefault] : everyPartOf(link.target);
|
|
410
|
+
for (const p2 of chosen) if (p2.file !== f.file) bucket(p2).add(f.file);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const p = origin(link.target, n.imported);
|
|
414
|
+
const handsOn = f.exports.some((e) => e.local === n.local && e.node === null) && !mentions(f.sf, n.local, null);
|
|
415
|
+
if (handsOn) continue;
|
|
416
|
+
if (p) {
|
|
417
|
+
if (p.file !== f.file) bucket(p).add(f.file);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
for (const part of namespaceParts(link.target, n.imported)) if (part.file !== f.file) bucket(part).add(f.file);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
for (const p of found) {
|
|
425
|
+
if (p.from || !p.local) continue;
|
|
426
|
+
const f = facts.get(p.file);
|
|
427
|
+
const decl = declarationOf(f, p.local);
|
|
428
|
+
const home = decl ? ts.isVariableDeclaration(decl) ? decl.parent.parent : decl : null;
|
|
429
|
+
if (mentions(f.sf, p.local, home)) users.get(key(p.file, p.name)).app.add(p.file);
|
|
430
|
+
}
|
|
431
|
+
const directTies = /* @__PURE__ */ new Map();
|
|
432
|
+
const appDeps = /* @__PURE__ */ new Map();
|
|
433
|
+
for (const f of facts.values()) {
|
|
434
|
+
const ties = [];
|
|
435
|
+
const deps = [];
|
|
436
|
+
for (const link of f.links) {
|
|
437
|
+
if (link.target === null) {
|
|
438
|
+
const tie = link.specifier.startsWith("node:") ? link.specifier : allowed.has(packageOf(link.specifier)) ? null : packageOf(link.specifier);
|
|
439
|
+
if (tie && !ties.includes(tie)) ties.push(tie);
|
|
440
|
+
} else if (link.target === "?") {
|
|
441
|
+
if (!ties.includes(link.specifier)) ties.push(link.specifier);
|
|
442
|
+
} else if (link.target !== f.file && !deps.includes(link.target)) deps.push(link.target);
|
|
443
|
+
}
|
|
444
|
+
directTies.set(f.file, ties);
|
|
445
|
+
appDeps.set(f.file, deps);
|
|
446
|
+
}
|
|
447
|
+
const tied = new Set([...directTies].filter(([, t]) => t.length > 0).map(([file]) => file));
|
|
448
|
+
for (let changed = true; changed; ) {
|
|
449
|
+
changed = false;
|
|
450
|
+
for (const [file, deps] of appDeps) if (!tied.has(file) && deps.some((d) => tied.has(d))) tied.add(file), changed = true;
|
|
451
|
+
}
|
|
452
|
+
const tiesOf = (file) => [...directTies.get(file), ...appDeps.get(file).filter((d) => tied.has(d))].sort();
|
|
453
|
+
const stories = files.filter(isStory).map((file) => {
|
|
454
|
+
const f = facts.get(file);
|
|
455
|
+
let title = null;
|
|
456
|
+
let component = null;
|
|
457
|
+
let noDocs = false;
|
|
458
|
+
const names = [];
|
|
459
|
+
for (const s of f.sf.statements) {
|
|
460
|
+
if (!ts.isVariableStatement(s)) continue;
|
|
461
|
+
const exported = (ts.getModifiers(s) ?? []).some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
|
|
462
|
+
for (const d of s.declarationList.declarations) {
|
|
463
|
+
if (!ts.isIdentifier(d.name)) continue;
|
|
464
|
+
if (d.name.text === "meta") {
|
|
465
|
+
let init = d.initializer;
|
|
466
|
+
while (init && (ts.isSatisfiesExpression(init) || ts.isAsExpression(init) || ts.isParenthesizedExpression(init))) init = init.expression;
|
|
467
|
+
if (init && ts.isObjectLiteralExpression(init)) {
|
|
468
|
+
for (const prop of init.properties) {
|
|
469
|
+
if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;
|
|
470
|
+
if (prop.name.text === "title" && ts.isStringLiteralLike(prop.initializer)) title = prop.initializer.text;
|
|
471
|
+
if (prop.name.text === "component" && ts.isIdentifier(prop.initializer)) component = prop.initializer.text;
|
|
472
|
+
if (prop.name.text === "tags" && ts.isArrayLiteralExpression(prop.initializer)) noDocs = prop.initializer.elements.some((e) => ts.isStringLiteralLike(e) && e.text === "!autodocs");
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} else if (exported) names.push(d.name.text);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const imported = /* @__PURE__ */ new Map();
|
|
479
|
+
for (const link of f.links) {
|
|
480
|
+
if (!link.target || link.target === "?") continue;
|
|
481
|
+
for (const n of link.names) {
|
|
482
|
+
if (n.imported === "*") continue;
|
|
483
|
+
const p = origin(link.target, n.imported);
|
|
484
|
+
if (p) imported.set(n.local, p);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return { file, title, component: component ? imported.get(component) ?? null : null, noDocs, names, imports: [...imported.values()] };
|
|
488
|
+
});
|
|
489
|
+
const storyOf = (p) => {
|
|
490
|
+
const stem = (file) => basename(file).replace(/\.stories\.[cm]?[jt]sx?$/, "");
|
|
491
|
+
const own = basename(p.file, extname(p.file));
|
|
492
|
+
const candidates = stories.filter((s2) => s2.title && s2.names.length && (s2.component === p || s2.imports.includes(p) && (stem(s2.file) === p.name || stem(s2.file) === own)));
|
|
493
|
+
candidates.sort((a, b) => Number(b.component === p) - Number(a.component === p) || a.file.localeCompare(b.file));
|
|
494
|
+
const s = candidates[0];
|
|
495
|
+
if (!s || !s.title) return { docsId: null, storyId: null };
|
|
496
|
+
return { docsId: s.noDocs ? null : `${sanitize(s.title)}--docs`, storyId: toId(s.title, s.names.includes(p.name) ? p.name : s.names[0]) };
|
|
497
|
+
};
|
|
498
|
+
const modules = /* @__PURE__ */ new Map();
|
|
499
|
+
const moduleAt = (file) => {
|
|
500
|
+
const held = modules.get(file);
|
|
501
|
+
if (held) return held;
|
|
502
|
+
const read = readModule(facts.get(file).source, (specifier, typeName) => {
|
|
503
|
+
if (specifier === PACKAGE_IMPORT) {
|
|
504
|
+
const part = typeName.endsWith("Props") ? theRegistry?.entries.find((entry) => entry.name === typeName.slice(0, -"Props".length)) : void 0;
|
|
505
|
+
return part ? { props: part.props, variants: part.variants } : void 0;
|
|
506
|
+
}
|
|
507
|
+
const target = resolveSpecifier(file, specifier);
|
|
508
|
+
return target && target !== "?" ? moduleAt(target).resolveName(typeName) : void 0;
|
|
509
|
+
}, { lendFirstComment: false });
|
|
510
|
+
modules.set(file, read);
|
|
511
|
+
return read;
|
|
512
|
+
};
|
|
513
|
+
const namesakes = new Set((theRegistry?.entries ?? []).map((e) => e.name));
|
|
514
|
+
const importPathOf = (file) => {
|
|
515
|
+
const abs = join(app, file);
|
|
516
|
+
const alias = aliases.find((a) => abs.startsWith(a.target + sep));
|
|
517
|
+
const stem = file.replace(/\.[cm]?[jt]sx?$/, "").replace(/\/index$/, "");
|
|
518
|
+
return alias ? `${alias.prefix}${relative(alias.target, join(app, stem)).split(sep).join("/")}` : stem;
|
|
519
|
+
};
|
|
520
|
+
const port = /(?:-p|--port)[\s=]+(\d+)/.exec(manifest.scripts?.storybook ?? "")?.[1] ?? "6006";
|
|
521
|
+
const entries = [];
|
|
522
|
+
for (const p of found) {
|
|
523
|
+
const u = users.get(key(p.file, p.name));
|
|
524
|
+
const usedIn = [...u.app].sort();
|
|
525
|
+
const pass = p.from;
|
|
526
|
+
const onePart = partsIn(p.file).filter((q) => !q.from).length === 1;
|
|
527
|
+
const module = pass ? null : moduleAt(p.file);
|
|
528
|
+
const declared = pass ? void 0 : module.declarations.get(p.local ?? "default");
|
|
529
|
+
const header = module?.headerDoc ?? "";
|
|
530
|
+
const doc = declared?.doc || (defaultPartOf(p.file) === p ? module?.declarations.get("default")?.doc ?? "" : "");
|
|
531
|
+
const page = pass ? null : join(dirname(p.file), `${p.name}.mdx`).split(sep).join("/");
|
|
532
|
+
const pageText = page && existsSync(join(app, page)) ? pageOpening(readFileSync(join(app, page), "utf8")) : "";
|
|
533
|
+
let purpose = "";
|
|
534
|
+
let purposeFrom = "comment";
|
|
535
|
+
if (pass) {
|
|
536
|
+
const as = pass.name === p.name ? "" : ` as ${p.name}`;
|
|
537
|
+
purpose = pass.specifier === PACKAGE_IMPORT ? `The package's ${pass.name}, handed on${as} so the app can import it from ${importPathOf(p.file)}.` : `${pass.name} from ${pass.specifier}, handed on${as} so the app can import it from ${importPathOf(p.file)}.`;
|
|
538
|
+
purposeFrom = "package";
|
|
539
|
+
} else if (firstSentence(pageText)) {
|
|
540
|
+
purpose = firstSentence(pageText);
|
|
541
|
+
purposeFrom = "page";
|
|
542
|
+
} else if (firstSentence(doc)) {
|
|
543
|
+
purpose = firstSentence(doc);
|
|
544
|
+
} else if (onePart && firstSentence(header)) {
|
|
545
|
+
purpose = firstSentence(header);
|
|
546
|
+
purposeFrom = "file";
|
|
547
|
+
}
|
|
548
|
+
if (!purpose) {
|
|
549
|
+
problems.push(`${p.name} in ${p.file} has no one-line description. Write one as a /** \u2026 */ comment directly above it${onePart ? ", or at the top of the file" : ""}.`);
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
const writtenLine = WRITTEN.exec(doc) ?? (onePart ? WRITTEN.exec(header) : null);
|
|
553
|
+
const ties = pass ? [] : tiesOf(p.file);
|
|
554
|
+
let cls;
|
|
555
|
+
let reason;
|
|
556
|
+
let written = false;
|
|
557
|
+
if (pass) {
|
|
558
|
+
cls = "re-export";
|
|
559
|
+
reason = `Its file only hands on ${pass.specifier === PACKAGE_IMPORT ? `the package's ${pass.name}` : `${pass.name} from ${pass.specifier}`}.`;
|
|
560
|
+
if (writtenLine) problems.push(`${p.name} in ${p.file} is a pass-on, so its kind is read from the file: remove "@registry ${writtenLine[1]}"`);
|
|
561
|
+
} else if (writtenLine) {
|
|
562
|
+
const said = writtenLine[1];
|
|
563
|
+
if (!WRITABLE.includes(said)) {
|
|
564
|
+
problems.push(`${p.name} in ${p.file} says "@registry ${writtenLine[1]}": the kinds a person may write are ${WRITABLE.join(", ")}`);
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
cls = said;
|
|
568
|
+
reason = writtenLine[2].trim();
|
|
569
|
+
written = true;
|
|
570
|
+
} else if (usedIn.length === 0) {
|
|
571
|
+
cls = "unused";
|
|
572
|
+
reason = u.stories.size ? "No file of the app uses it; only its stories do." : u.tests.size ? "No file of the app uses it; only its tests do." : "Nothing uses it.";
|
|
573
|
+
} else if (usedIn.length === 1) {
|
|
574
|
+
cls = "one-off";
|
|
575
|
+
reason = `Used in one place: ${usedIn[0]}.`;
|
|
576
|
+
} else if (ties.length) {
|
|
577
|
+
cls = "reusable";
|
|
578
|
+
reason = `Used in ${usedIn.length} places, and tied to the app by ${ties[0]}${ties.length > 1 ? ` and ${ties.length - 1} more` : ""}.`;
|
|
579
|
+
} else {
|
|
580
|
+
cls = "promote-candidate";
|
|
581
|
+
reason = `Used in ${usedIn.length} places, and everything it uses is already in the package.`;
|
|
582
|
+
}
|
|
583
|
+
const shape = declared ? module.resolve(declared.propsType) : { props: [], variants: [] };
|
|
584
|
+
const facts_ = {
|
|
585
|
+
class: cls,
|
|
586
|
+
reason,
|
|
587
|
+
written,
|
|
588
|
+
handsOn: pass ? pass.specifier === PACKAGE_IMPORT ? pass.name : `${pass.name} from ${pass.specifier}` : null,
|
|
589
|
+
usedIn,
|
|
590
|
+
tiedTo: ties,
|
|
591
|
+
packageNamesake: namesakes.has(p.name) && !(pass && pass.specifier === PACKAGE_IMPORT && pass.name === p.name) ? p.name : null,
|
|
592
|
+
defaultExport: p.defaultExport
|
|
593
|
+
};
|
|
594
|
+
const { docsId, storyId } = pass ? { docsId: null, storyId: null } : storyOf(p);
|
|
595
|
+
entries.push({
|
|
596
|
+
name: p.name,
|
|
597
|
+
repo: repoName,
|
|
598
|
+
kind: "component",
|
|
599
|
+
importPath: importPathOf(p.file),
|
|
600
|
+
sourceFile: p.file,
|
|
601
|
+
purpose,
|
|
602
|
+
purposeFrom,
|
|
603
|
+
props: shape.props,
|
|
604
|
+
variants: shape.variants,
|
|
605
|
+
ownsBehaviours: [],
|
|
606
|
+
status: declared?.deprecated ? "deprecated" : "stable",
|
|
607
|
+
migrationStage: null,
|
|
608
|
+
docsId,
|
|
609
|
+
storyId,
|
|
610
|
+
docPage: pageText ? page : null,
|
|
611
|
+
app: facts_
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
if (problems.length) throw new Error(`the catalogue of ${repoName} cannot be built:
|
|
615
|
+
${problems.join("\n ")}`);
|
|
616
|
+
entries.sort((a, b) => a.name.localeCompare(b.name) || a.sourceFile.localeCompare(b.sourceFile));
|
|
617
|
+
const withParts = new Set(found.map((p) => p.file));
|
|
618
|
+
const filesWithoutParts = targets.filter((file) => !withParts.has(file)).map((file) => {
|
|
619
|
+
const f = facts.get(file);
|
|
620
|
+
const names = [...f.exports.map((e) => e.isDefault ? e.local ?? "a default" : e.name), ...f.reexports.map((r) => r.name)];
|
|
621
|
+
return { file, reason: names.length ? `It exports no part, only ${names.join(", ")}.` : "It exports nothing." };
|
|
622
|
+
});
|
|
623
|
+
return {
|
|
624
|
+
schemaVersion: SCHEMA_VERSION,
|
|
625
|
+
builtFrom: {
|
|
626
|
+
kind: "app",
|
|
627
|
+
repo: repoName,
|
|
628
|
+
package: manifest.name ?? repoName,
|
|
629
|
+
packageVersion: manifest.version ?? "0.0.0",
|
|
630
|
+
exports: found.length,
|
|
631
|
+
typeExports: 0,
|
|
632
|
+
files: targets.length
|
|
633
|
+
},
|
|
634
|
+
storybook: {
|
|
635
|
+
docsPath: "/?path=/docs/{docsId}",
|
|
636
|
+
storyPath: "/?path=/story/{storyId}",
|
|
637
|
+
devUrl: `http://localhost:${port}`
|
|
638
|
+
},
|
|
639
|
+
entries,
|
|
640
|
+
excluded: [],
|
|
641
|
+
filesWithoutParts
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export {
|
|
646
|
+
buildAppRegistry
|
|
647
|
+
};
|
|
648
|
+
//# sourceMappingURL=chunk-WMFF3MPP.js.map
|