uidex 0.4.0 → 0.5.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/dist/cli/cli.cjs +996 -73
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/cloud/index.cjs +375 -72
- package/dist/cloud/index.cjs.map +1 -1
- package/dist/cloud/index.d.cts +82 -0
- package/dist/cloud/index.d.ts +82 -0
- package/dist/cloud/index.js +376 -71
- package/dist/cloud/index.js.map +1 -1
- package/dist/headless/index.cjs +620 -469
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +77 -75
- package/dist/headless/index.d.ts +77 -75
- package/dist/headless/index.js +624 -469
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +4255 -2884
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +275 -234
- package/dist/index.d.ts +275 -234
- package/dist/index.js +4277 -2890
- package/dist/index.js.map +1 -1
- package/dist/playwright/index.cjs +4 -4
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.js +3 -3
- package/dist/playwright/index.js.map +1 -1
- package/dist/playwright/reporter.cjs +3 -3
- package/dist/playwright/reporter.cjs.map +1 -1
- package/dist/playwright/reporter.js +3 -3
- package/dist/playwright/reporter.js.map +1 -1
- package/dist/react/index.cjs +4298 -2908
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +206 -200
- package/dist/react/index.d.ts +206 -200
- package/dist/react/index.js +4334 -2924
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +91 -40
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +26 -0
- package/dist/scan/index.d.ts +26 -0
- package/dist/scan/index.js +90 -39
- package/dist/scan/index.js.map +1 -1
- package/package.json +23 -22
- package/templates/claude/api.md +110 -0
package/dist/scan/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
));
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
|
-
// src/scan/index.ts
|
|
30
|
+
// src/scanner/scan/index.ts
|
|
31
31
|
var scan_exports = {};
|
|
32
32
|
__export(scan_exports, {
|
|
33
33
|
CONFIG_FILENAME: () => CONFIG_FILENAME,
|
|
@@ -54,11 +54,11 @@ __export(scan_exports, {
|
|
|
54
54
|
});
|
|
55
55
|
module.exports = __toCommonJS(scan_exports);
|
|
56
56
|
|
|
57
|
-
// src/scan/discover.ts
|
|
57
|
+
// src/scanner/scan/discover.ts
|
|
58
58
|
var fs = __toESM(require("fs"), 1);
|
|
59
59
|
var path = __toESM(require("path"), 1);
|
|
60
60
|
|
|
61
|
-
// src/scan/config.ts
|
|
61
|
+
// src/scanner/scan/config.ts
|
|
62
62
|
var DEFAULT_TYPE_MODE = "strict";
|
|
63
63
|
var WELL_KNOWN_FILES = {
|
|
64
64
|
page: "uidex.page.ts",
|
|
@@ -222,7 +222,7 @@ var DEFAULT_CONVENTIONS = {
|
|
|
222
222
|
regions: "landmarks"
|
|
223
223
|
};
|
|
224
224
|
|
|
225
|
-
// src/scan/discover.ts
|
|
225
|
+
// src/scanner/scan/discover.ts
|
|
226
226
|
var CONFIG_FILENAME = ".uidex.json";
|
|
227
227
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
228
228
|
"node_modules",
|
|
@@ -281,7 +281,7 @@ function discover(options = {}) {
|
|
|
281
281
|
return results.sort((a, b) => a.configPath.localeCompare(b.configPath));
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
// src/scan/walk.ts
|
|
284
|
+
// src/scanner/scan/walk.ts
|
|
285
285
|
var fs2 = __toESM(require("fs"), 1);
|
|
286
286
|
var path2 = __toESM(require("path"), 1);
|
|
287
287
|
var DEFAULT_INCLUDES = ["**/*.{ts,tsx,js,jsx,mjs,cjs}"];
|
|
@@ -406,7 +406,7 @@ function* walkDir(root, dir) {
|
|
|
406
406
|
}
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
// src/scan/extract-uidex-export.ts
|
|
409
|
+
// src/scanner/scan/extract-uidex-export.ts
|
|
410
410
|
var KIND_DISCRIMINATORS = [
|
|
411
411
|
"page",
|
|
412
412
|
"feature",
|
|
@@ -424,7 +424,13 @@ var ALLOWED_FIELDS = {
|
|
|
424
424
|
"acceptance",
|
|
425
425
|
"description"
|
|
426
426
|
]),
|
|
427
|
-
feature: /* @__PURE__ */ new Set([
|
|
427
|
+
feature: /* @__PURE__ */ new Set([
|
|
428
|
+
"feature",
|
|
429
|
+
"name",
|
|
430
|
+
"features",
|
|
431
|
+
"acceptance",
|
|
432
|
+
"description"
|
|
433
|
+
]),
|
|
428
434
|
primitive: /* @__PURE__ */ new Set(["primitive", "name", "description"]),
|
|
429
435
|
widget: /* @__PURE__ */ new Set(["widget", "name", "acceptance", "description"]),
|
|
430
436
|
flow: /* @__PURE__ */ new Set(["flow", "notFlow", "name", "description"])
|
|
@@ -1160,7 +1166,7 @@ function buildMetadata(value, file, headerPos, diagnostics) {
|
|
|
1160
1166
|
line: pos.line
|
|
1161
1167
|
});
|
|
1162
1168
|
}
|
|
1163
|
-
const features = kind === "page" ? readStringArrayField(byKey, "features") : void 0;
|
|
1169
|
+
const features = kind === "page" || kind === "feature" ? readStringArrayField(byKey, "features") : void 0;
|
|
1164
1170
|
const widgets = kind === "page" ? readStringArrayField(byKey, "widgets") : void 0;
|
|
1165
1171
|
const notFlow = kind === "flow" && discriminator === "notFlow" ? true : void 0;
|
|
1166
1172
|
const metadata = {
|
|
@@ -1255,7 +1261,7 @@ function posAt(content, offset) {
|
|
|
1255
1261
|
return { offset, line, column: offset - lineStart + 1 };
|
|
1256
1262
|
}
|
|
1257
1263
|
|
|
1258
|
-
// src/scan/jsx-ancestry.ts
|
|
1264
|
+
// src/scanner/scan/jsx-ancestry.ts
|
|
1259
1265
|
var DATA_ATTR_RE = /\bdata-uidex(?:-(region|widget|primitive))?\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
1260
1266
|
function parseDataAttrs(tagSource) {
|
|
1261
1267
|
if (!tagSource.includes("data-uidex")) return [];
|
|
@@ -1444,7 +1450,7 @@ function findTagEnd(content, start) {
|
|
|
1444
1450
|
return -1;
|
|
1445
1451
|
}
|
|
1446
1452
|
|
|
1447
|
-
// src/scan/extract.ts
|
|
1453
|
+
// src/scanner/scan/extract.ts
|
|
1448
1454
|
var JSDOC_BLOCK = /\/\*\*([\s\S]*?)\*\//g;
|
|
1449
1455
|
function lineAt(content, index) {
|
|
1450
1456
|
let line = 1;
|
|
@@ -1547,10 +1553,10 @@ function extractOne(file) {
|
|
|
1547
1553
|
return annotations;
|
|
1548
1554
|
}
|
|
1549
1555
|
|
|
1550
|
-
// src/scan/resolve.ts
|
|
1556
|
+
// src/scanner/scan/resolve.ts
|
|
1551
1557
|
var path3 = __toESM(require("path"), 1);
|
|
1552
1558
|
|
|
1553
|
-
// src/entities/types.ts
|
|
1559
|
+
// src/shared/entities/types.ts
|
|
1554
1560
|
var ENTITY_KINDS = [
|
|
1555
1561
|
"route",
|
|
1556
1562
|
"page",
|
|
@@ -1583,7 +1589,7 @@ function assertEntityKind(kind) {
|
|
|
1583
1589
|
if (!KIND_SET.has(kind)) throw new UnknownEntityKindError(kind);
|
|
1584
1590
|
}
|
|
1585
1591
|
|
|
1586
|
-
// src/entities/registry.ts
|
|
1592
|
+
// src/shared/entities/registry.ts
|
|
1587
1593
|
function emptyStore() {
|
|
1588
1594
|
return {
|
|
1589
1595
|
route: /* @__PURE__ */ new Map(),
|
|
@@ -1665,10 +1671,33 @@ function createRegistry() {
|
|
|
1665
1671
|
return ids.has(entity.id);
|
|
1666
1672
|
});
|
|
1667
1673
|
};
|
|
1668
|
-
|
|
1674
|
+
const reports = /* @__PURE__ */ new Map();
|
|
1675
|
+
const reportsCbs = /* @__PURE__ */ new Set();
|
|
1676
|
+
const setReports = (kind, id, records) => {
|
|
1677
|
+
reports.set(`${kind}:${id}`, records);
|
|
1678
|
+
for (const cb of reportsCbs) cb();
|
|
1679
|
+
};
|
|
1680
|
+
const getReports = (kind, id) => reports.get(`${kind}:${id}`) ?? [];
|
|
1681
|
+
const listReportKeys = () => Array.from(reports.keys());
|
|
1682
|
+
const onReportsChange = (cb) => {
|
|
1683
|
+
reportsCbs.add(cb);
|
|
1684
|
+
return () => reportsCbs.delete(cb);
|
|
1685
|
+
};
|
|
1686
|
+
return {
|
|
1687
|
+
add,
|
|
1688
|
+
get,
|
|
1689
|
+
list,
|
|
1690
|
+
query,
|
|
1691
|
+
byScope,
|
|
1692
|
+
touchedBy,
|
|
1693
|
+
setReports,
|
|
1694
|
+
getReports,
|
|
1695
|
+
listReportKeys,
|
|
1696
|
+
onReportsChange
|
|
1697
|
+
};
|
|
1669
1698
|
}
|
|
1670
1699
|
|
|
1671
|
-
// src/scan/routes.ts
|
|
1700
|
+
// src/scanner/scan/routes.ts
|
|
1672
1701
|
var PAGE_BASENAME = /^page\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
1673
1702
|
var PAGES_ROUTER_BASENAME = /\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
1674
1703
|
var ROUTE_BASENAME = /^route\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
@@ -1734,7 +1763,7 @@ function pathToId(routePath) {
|
|
|
1734
1763
|
return routePath.replace(/^\/+/, "").replace(/\[\.{3}([^\]]+)\]/g, "$1").replace(/\[([^\]]+)\]/g, "$1").replace(/\//g, "-").replace(/[^a-zA-Z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
1735
1764
|
}
|
|
1736
1765
|
|
|
1737
|
-
// src/scan/resolve.ts
|
|
1766
|
+
// src/scanner/scan/resolve.ts
|
|
1738
1767
|
var DOM_ATTR_KINDS = /* @__PURE__ */ new Set([
|
|
1739
1768
|
"element",
|
|
1740
1769
|
"region",
|
|
@@ -2219,7 +2248,7 @@ function dedupe(arr) {
|
|
|
2219
2248
|
return Array.from(new Set(arr));
|
|
2220
2249
|
}
|
|
2221
2250
|
|
|
2222
|
-
// src/scan/audit.ts
|
|
2251
|
+
// src/scanner/scan/audit.ts
|
|
2223
2252
|
var path4 = __toESM(require("path"), 1);
|
|
2224
2253
|
var MARKER_FILENAMES = ["UIDEX_PAGE.md", "UIDEX_FEATURE.md"];
|
|
2225
2254
|
function audit(opts) {
|
|
@@ -2374,6 +2403,15 @@ function audit(opts) {
|
|
|
2374
2403
|
const primitives = registry.list("primitive");
|
|
2375
2404
|
const byName = /* @__PURE__ */ new Map();
|
|
2376
2405
|
for (const p2 of primitives) byName.set(p2.id, p2);
|
|
2406
|
+
const declaredFeatures = /* @__PURE__ */ new Map();
|
|
2407
|
+
for (const ef of extracted) {
|
|
2408
|
+
if (!ef.metadata) continue;
|
|
2409
|
+
for (const m of ef.metadata) {
|
|
2410
|
+
if (m.features && m.features.length > 0) {
|
|
2411
|
+
declaredFeatures.set(ef.file.displayPath, new Set(m.features));
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2377
2415
|
for (const f of files) {
|
|
2378
2416
|
const importRe = /import\s+(?:[^'"]+)\s+from\s+['"]([^'"]+)['"]/g;
|
|
2379
2417
|
let m;
|
|
@@ -2388,14 +2426,19 @@ function audit(opts) {
|
|
|
2388
2426
|
if (!scope) continue;
|
|
2389
2427
|
const [kind, id] = scope.split(":");
|
|
2390
2428
|
const importerSegments = f.displayPath.split("/");
|
|
2391
|
-
if (
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
});
|
|
2429
|
+
if (importerSegments.includes(id) && importerSegments.includes(kind + "s")) {
|
|
2430
|
+
continue;
|
|
2431
|
+
}
|
|
2432
|
+
if (kind === "feature" && importerSegments.includes(id)) continue;
|
|
2433
|
+
if (kind === "feature" && declaredFeatures.get(f.displayPath)?.has(id)) {
|
|
2434
|
+
continue;
|
|
2398
2435
|
}
|
|
2436
|
+
diagnostics.push({
|
|
2437
|
+
code: "scope-leak",
|
|
2438
|
+
severity: "warning",
|
|
2439
|
+
message: `Primitive "${primitive.id}" is scoped to ${scope} but is imported from ${f.displayPath}`,
|
|
2440
|
+
file: f.displayPath
|
|
2441
|
+
});
|
|
2399
2442
|
}
|
|
2400
2443
|
}
|
|
2401
2444
|
}
|
|
@@ -2569,7 +2612,7 @@ function stableReplacer(_key, value) {
|
|
|
2569
2612
|
return value;
|
|
2570
2613
|
}
|
|
2571
2614
|
|
|
2572
|
-
// src/scan/emit.ts
|
|
2615
|
+
// src/scanner/scan/emit.ts
|
|
2573
2616
|
function sortById(arr) {
|
|
2574
2617
|
return [...arr].sort((a, b) => a.id.localeCompare(b.id));
|
|
2575
2618
|
}
|
|
@@ -2693,6 +2736,7 @@ function emit(opts) {
|
|
|
2693
2736
|
lines.push(" export interface Feature {");
|
|
2694
2737
|
lines.push(" feature: FeatureId | false");
|
|
2695
2738
|
lines.push(" name?: string");
|
|
2739
|
+
lines.push(" features?: readonly FeatureId[]");
|
|
2696
2740
|
lines.push(" acceptance?: readonly string[]");
|
|
2697
2741
|
lines.push(" description?: string");
|
|
2698
2742
|
lines.push(" }");
|
|
@@ -2749,7 +2793,7 @@ function emit(opts) {
|
|
|
2749
2793
|
return lines.join("\n");
|
|
2750
2794
|
}
|
|
2751
2795
|
|
|
2752
|
-
// src/scan/git.ts
|
|
2796
|
+
// src/scanner/scan/git.ts
|
|
2753
2797
|
var import_node_child_process = require("child_process");
|
|
2754
2798
|
function runGit(args, cwd) {
|
|
2755
2799
|
try {
|
|
@@ -2781,7 +2825,7 @@ function parseGitHubRef(ref) {
|
|
|
2781
2825
|
return m ? m[1] : null;
|
|
2782
2826
|
}
|
|
2783
2827
|
|
|
2784
|
-
// src/scan/scaffold.ts
|
|
2828
|
+
// src/scanner/scan/scaffold.ts
|
|
2785
2829
|
var fs3 = __toESM(require("fs"), 1);
|
|
2786
2830
|
var path5 = __toESM(require("path"), 1);
|
|
2787
2831
|
function scaffoldWidgetSpec(opts) {
|
|
@@ -2844,7 +2888,7 @@ function renderSpec(args) {
|
|
|
2844
2888
|
return lines.join("\n");
|
|
2845
2889
|
}
|
|
2846
2890
|
|
|
2847
|
-
// src/scan/pipeline.ts
|
|
2891
|
+
// src/scanner/scan/pipeline.ts
|
|
2848
2892
|
var fs4 = __toESM(require("fs"), 1);
|
|
2849
2893
|
var path6 = __toESM(require("path"), 1);
|
|
2850
2894
|
function runScan(opts = {}) {
|
|
@@ -2918,18 +2962,18 @@ function writeScanResult(result) {
|
|
|
2918
2962
|
fs4.writeFileSync(result.outputPath, result.generated, "utf8");
|
|
2919
2963
|
}
|
|
2920
2964
|
|
|
2921
|
-
// src/scan/cli.ts
|
|
2965
|
+
// src/scanner/scan/cli.ts
|
|
2922
2966
|
var fs7 = __toESM(require("fs"), 1);
|
|
2923
2967
|
var path9 = __toESM(require("path"), 1);
|
|
2924
2968
|
|
|
2925
|
-
// src/scan/ai/index.ts
|
|
2969
|
+
// src/scanner/scan/ai/index.ts
|
|
2926
2970
|
var p = __toESM(require("@clack/prompts"), 1);
|
|
2927
2971
|
|
|
2928
|
-
// src/scan/ai/providers/claude.ts
|
|
2972
|
+
// src/scanner/scan/ai/providers/claude.ts
|
|
2929
2973
|
var fs6 = __toESM(require("fs"), 1);
|
|
2930
2974
|
var path8 = __toESM(require("path"), 1);
|
|
2931
2975
|
|
|
2932
|
-
// src/scan/ai/templates.ts
|
|
2976
|
+
// src/scanner/scan/ai/templates.ts
|
|
2933
2977
|
var fs5 = __toESM(require("fs"), 1);
|
|
2934
2978
|
var path7 = __toESM(require("path"), 1);
|
|
2935
2979
|
function templatePath(rel) {
|
|
@@ -2956,15 +3000,16 @@ function readTemplate(rel) {
|
|
|
2956
3000
|
return fs5.readFileSync(templatePath(rel), "utf8");
|
|
2957
3001
|
}
|
|
2958
3002
|
|
|
2959
|
-
// src/scan/ai/providers/claude.ts
|
|
3003
|
+
// src/scanner/scan/ai/providers/claude.ts
|
|
2960
3004
|
var CLAUDE_FILES = [
|
|
2961
3005
|
{ dest: ".claude/rules/uidex.md", template: "claude/rules.md" },
|
|
2962
|
-
{ dest: ".claude/commands/uidex/audit.md", template: "claude/audit.md" }
|
|
3006
|
+
{ dest: ".claude/commands/uidex/audit.md", template: "claude/audit.md" },
|
|
3007
|
+
{ dest: ".claude/commands/uidex/api.md", template: "claude/api.md" }
|
|
2963
3008
|
];
|
|
2964
3009
|
var claudeProvider = {
|
|
2965
3010
|
id: "claude",
|
|
2966
3011
|
label: "Claude Code",
|
|
2967
|
-
description: "Adds .claude/rules/uidex.md and
|
|
3012
|
+
description: "Adds .claude/rules/uidex.md, /uidex:audit, and /uidex:api slash commands.",
|
|
2968
3013
|
async install({ cwd, force }) {
|
|
2969
3014
|
const changes = [];
|
|
2970
3015
|
for (const file of CLAUDE_FILES) {
|
|
@@ -3012,13 +3057,13 @@ function cleanupEmpty(dir) {
|
|
|
3012
3057
|
}
|
|
3013
3058
|
}
|
|
3014
3059
|
|
|
3015
|
-
// src/scan/ai/providers/index.ts
|
|
3060
|
+
// src/scanner/scan/ai/providers/index.ts
|
|
3016
3061
|
var PROVIDERS = [claudeProvider];
|
|
3017
3062
|
function getProvider(id) {
|
|
3018
3063
|
return PROVIDERS.find((p2) => p2.id === id);
|
|
3019
3064
|
}
|
|
3020
3065
|
|
|
3021
|
-
// src/scan/ai/index.ts
|
|
3066
|
+
// src/scanner/scan/ai/index.ts
|
|
3022
3067
|
async function runAiCommand(opts) {
|
|
3023
3068
|
const { cwd, argv } = opts;
|
|
3024
3069
|
const sub = argv[0];
|
|
@@ -3129,8 +3174,8 @@ function err(exitCode, stderr) {
|
|
|
3129
3174
|
return { exitCode, stdout: "", stderr };
|
|
3130
3175
|
}
|
|
3131
3176
|
|
|
3132
|
-
// src/
|
|
3133
|
-
function
|
|
3177
|
+
// src/scanner/cli/parse-args.ts
|
|
3178
|
+
function parseArgs(args) {
|
|
3134
3179
|
const positional = [];
|
|
3135
3180
|
const flags = {};
|
|
3136
3181
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -3154,9 +3199,11 @@ function parseFlags2(args) {
|
|
|
3154
3199
|
}
|
|
3155
3200
|
return { positional, flags };
|
|
3156
3201
|
}
|
|
3202
|
+
|
|
3203
|
+
// src/scanner/scan/cli.ts
|
|
3157
3204
|
async function run(opts) {
|
|
3158
3205
|
const cwd = opts.cwd ?? process.cwd();
|
|
3159
|
-
const { positional, flags } =
|
|
3206
|
+
const { positional, flags } = parseArgs(opts.argv);
|
|
3160
3207
|
const command = positional[0] ?? "help";
|
|
3161
3208
|
const writer = createWriter();
|
|
3162
3209
|
try {
|
|
@@ -3200,6 +3247,10 @@ function helpText2() {
|
|
|
3200
3247
|
" scan [flags] Run the scanner pipeline",
|
|
3201
3248
|
" scaffold widget <id> Emit a Playwright spec from a widget's acceptance",
|
|
3202
3249
|
" ai <install|uninstall|providers> Manage AI assistant integrations",
|
|
3250
|
+
" api <METHOD> <PATH> Call the uidex API",
|
|
3251
|
+
" api --list Show available API routes",
|
|
3252
|
+
" api login Authenticate via browser",
|
|
3253
|
+
" api login --token <tok> Store an auth token directly",
|
|
3203
3254
|
"",
|
|
3204
3255
|
"Flags:",
|
|
3205
3256
|
" --check Verify the on-disk gen file matches a fresh scan; exit non-zero on drift (read-only)",
|