uidex 0.3.0 → 0.4.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 +122 -41
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/cloud/index.cjs +22 -2
- package/dist/cloud/index.cjs.map +1 -1
- package/dist/cloud/index.js +22 -2
- package/dist/cloud/index.js.map +1 -1
- package/dist/headless/index.cjs +909 -346
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +6 -0
- package/dist/headless/index.d.ts +6 -0
- package/dist/headless/index.js +914 -346
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +2887 -1167
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +83 -16
- package/dist/index.d.ts +83 -16
- package/dist/index.js +2919 -1175
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +2850 -1155
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +55 -8
- package/dist/react/index.d.ts +55 -8
- package/dist/react/index.js +2879 -1159
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +121 -42
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +5 -0
- package/dist/scan/index.d.ts +5 -0
- package/dist/scan/index.js +121 -42
- package/dist/scan/index.js.map +1 -1
- package/package.json +18 -17
- package/templates/claude/audit.md +8 -2
- package/templates/claude/rules.md +15 -0
- package/dist/cloud/index.d.cts +0 -108
- package/dist/cloud/index.d.ts +0 -108
package/dist/cli/cli.cjs
CHANGED
|
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
|
|
26
26
|
// src/scan/cli.ts
|
|
27
27
|
var fs7 = __toESM(require("fs"), 1);
|
|
28
|
-
var
|
|
28
|
+
var path9 = __toESM(require("path"), 1);
|
|
29
29
|
|
|
30
30
|
// src/scan/ai/index.ts
|
|
31
31
|
var p = __toESM(require("@clack/prompts"), 1);
|
|
@@ -240,6 +240,10 @@ var path3 = __toESM(require("path"), 1);
|
|
|
240
240
|
|
|
241
241
|
// src/scan/config.ts
|
|
242
242
|
var DEFAULT_TYPE_MODE = "strict";
|
|
243
|
+
var WELL_KNOWN_FILES = {
|
|
244
|
+
page: "uidex.page.ts",
|
|
245
|
+
feature: "uidex.feature.ts"
|
|
246
|
+
};
|
|
243
247
|
var ConfigError = class extends Error {
|
|
244
248
|
constructor(message) {
|
|
245
249
|
super(message);
|
|
@@ -277,14 +281,14 @@ var ALLOWED_AUDIT_KEYS = /* @__PURE__ */ new Set(["scopeLeak", "coverage", "acce
|
|
|
277
281
|
function fail(msg) {
|
|
278
282
|
throw new ConfigError(`Invalid .uidex.json: ${msg}`);
|
|
279
283
|
}
|
|
280
|
-
function assertObject(value,
|
|
284
|
+
function assertObject(value, path10) {
|
|
281
285
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
282
|
-
fail(`${
|
|
286
|
+
fail(`${path10} must be an object`);
|
|
283
287
|
}
|
|
284
288
|
}
|
|
285
|
-
function assertStringArray(value,
|
|
289
|
+
function assertStringArray(value, path10) {
|
|
286
290
|
if (!Array.isArray(value) || !value.every((v) => typeof v === "string")) {
|
|
287
|
-
fail(`${
|
|
291
|
+
fail(`${path10} must be a string[]`);
|
|
288
292
|
}
|
|
289
293
|
}
|
|
290
294
|
function validateConfig(raw) {
|
|
@@ -459,7 +463,10 @@ function discover(options = {}) {
|
|
|
459
463
|
|
|
460
464
|
// src/scan/pipeline.ts
|
|
461
465
|
var fs5 = __toESM(require("fs"), 1);
|
|
462
|
-
var
|
|
466
|
+
var path7 = __toESM(require("path"), 1);
|
|
467
|
+
|
|
468
|
+
// src/scan/audit.ts
|
|
469
|
+
var path4 = __toESM(require("path"), 1);
|
|
463
470
|
|
|
464
471
|
// src/entities/types.ts
|
|
465
472
|
var ENTITY_KINDS = [
|
|
@@ -681,6 +688,32 @@ function audit(opts) {
|
|
|
681
688
|
}
|
|
682
689
|
}
|
|
683
690
|
}
|
|
691
|
+
if (lint) {
|
|
692
|
+
const scannedPaths = new Set(files.map((f) => f.displayPath));
|
|
693
|
+
for (const ef of extracted) {
|
|
694
|
+
if (!ef.metadata) continue;
|
|
695
|
+
for (const m of ef.metadata) {
|
|
696
|
+
if (m.kind !== "page" && m.kind !== "feature") continue;
|
|
697
|
+
if (typeof m.id !== "string") continue;
|
|
698
|
+
const filePath = ef.file.displayPath;
|
|
699
|
+
const wellKnownName = WELL_KNOWN_FILES[m.kind];
|
|
700
|
+
if (path4.posix.basename(filePath) === wellKnownName) continue;
|
|
701
|
+
const dir = path4.posix.dirname(filePath);
|
|
702
|
+
const wellKnownPath = dir === "." ? wellKnownName : `${dir}/${wellKnownName}`;
|
|
703
|
+
if (scannedPaths.has(wellKnownPath)) continue;
|
|
704
|
+
const kindLabel = m.kind === "page" ? "Page" : "Feature";
|
|
705
|
+
diagnostics.push({
|
|
706
|
+
code: "prefer-well-known-file",
|
|
707
|
+
severity: "info",
|
|
708
|
+
message: `${kindLabel} "${m.id}" metadata lives on ${filePath}; prefer ${wellKnownPath}`,
|
|
709
|
+
file: filePath,
|
|
710
|
+
line: m.loc.line,
|
|
711
|
+
entity: { kind: m.kind, id: m.id },
|
|
712
|
+
hint: `Move the \`export const uidex\` block to ${wellKnownPath} and remove it from ${filePath}.`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
684
717
|
if (lint) {
|
|
685
718
|
for (const f of files) {
|
|
686
719
|
const lines = f.content.split("\n");
|
|
@@ -717,8 +750,8 @@ function audit(opts) {
|
|
|
717
750
|
baseName2.replace(/\.(tsx|ts|jsx|js|mjs|cjs)$/, "").replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase()
|
|
718
751
|
);
|
|
719
752
|
if (!primitive) continue;
|
|
720
|
-
const scope = primitive.scopes?.[0]
|
|
721
|
-
if (scope
|
|
753
|
+
const scope = primitive.scopes?.[0];
|
|
754
|
+
if (!scope) continue;
|
|
722
755
|
const [kind, id] = scope.split(":");
|
|
723
756
|
const importerSegments = f.displayPath.split("/");
|
|
724
757
|
if (!importerSegments.includes(id) || !importerSegments.includes(kind + "s")) {
|
|
@@ -2256,7 +2289,7 @@ function parseGitHubRef(ref) {
|
|
|
2256
2289
|
}
|
|
2257
2290
|
|
|
2258
2291
|
// src/scan/resolve.ts
|
|
2259
|
-
var
|
|
2292
|
+
var path6 = __toESM(require("path"), 1);
|
|
2260
2293
|
|
|
2261
2294
|
// src/scan/routes.ts
|
|
2262
2295
|
var PAGE_BASENAME = /^page\.(tsx|ts|jsx|js|mjs|cjs)$/;
|
|
@@ -2326,7 +2359,7 @@ function pathToId(routePath) {
|
|
|
2326
2359
|
|
|
2327
2360
|
// src/scan/walk.ts
|
|
2328
2361
|
var fs4 = __toESM(require("fs"), 1);
|
|
2329
|
-
var
|
|
2362
|
+
var path5 = __toESM(require("path"), 1);
|
|
2330
2363
|
var DEFAULT_INCLUDES = ["**/*.{ts,tsx,js,jsx,mjs,cjs}"];
|
|
2331
2364
|
var BASE_EXCLUDES = [
|
|
2332
2365
|
"**/node_modules/**",
|
|
@@ -2390,7 +2423,7 @@ function globToRegExp(glob) {
|
|
|
2390
2423
|
return new RegExp(`^${out2}$`);
|
|
2391
2424
|
}
|
|
2392
2425
|
function toPosix(p2) {
|
|
2393
|
-
return p2.split(
|
|
2426
|
+
return p2.split(path5.sep).join("/");
|
|
2394
2427
|
}
|
|
2395
2428
|
function matchesAny(rel, patterns) {
|
|
2396
2429
|
return patterns.some((g) => globToRegExp(g).test(rel));
|
|
@@ -2406,9 +2439,9 @@ function walk(sources, options) {
|
|
|
2406
2439
|
...globalExcludes,
|
|
2407
2440
|
...source.exclude ?? []
|
|
2408
2441
|
];
|
|
2409
|
-
const absRoot =
|
|
2442
|
+
const absRoot = path5.resolve(cwd, source.rootDir);
|
|
2410
2443
|
for (const filePath of walkDir(absRoot, absRoot)) {
|
|
2411
|
-
const rel = toPosix(
|
|
2444
|
+
const rel = toPosix(path5.relative(absRoot, filePath));
|
|
2412
2445
|
if (matchesAny(rel, excludes)) continue;
|
|
2413
2446
|
if (!matchesAny(rel, includes)) continue;
|
|
2414
2447
|
let content;
|
|
@@ -2417,7 +2450,7 @@ function walk(sources, options) {
|
|
|
2417
2450
|
} catch {
|
|
2418
2451
|
continue;
|
|
2419
2452
|
}
|
|
2420
|
-
const relFromCwd = toPosix(
|
|
2453
|
+
const relFromCwd = toPosix(path5.relative(cwd, filePath));
|
|
2421
2454
|
const displayPath = source.prefix ? `${source.prefix.replace(/\/$/, "")}/${rel}` : relFromCwd;
|
|
2422
2455
|
out2.push({
|
|
2423
2456
|
sourcePath: filePath,
|
|
@@ -2437,7 +2470,7 @@ function* walkDir(root, dir) {
|
|
|
2437
2470
|
return;
|
|
2438
2471
|
}
|
|
2439
2472
|
for (const entry of entries) {
|
|
2440
|
-
const full =
|
|
2473
|
+
const full = path5.join(dir, entry.name);
|
|
2441
2474
|
if (entry.isDirectory()) {
|
|
2442
2475
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === ".git" || entry.name === "build" || entry.name === ".next") {
|
|
2443
2476
|
continue;
|
|
@@ -2469,7 +2502,7 @@ function kebab(str) {
|
|
|
2469
2502
|
return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").replace(/[^a-zA-Z0-9-]/g, "").toLowerCase();
|
|
2470
2503
|
}
|
|
2471
2504
|
function baseName(file) {
|
|
2472
|
-
const b =
|
|
2505
|
+
const b = path6.posix.basename(file);
|
|
2473
2506
|
return b.replace(/\.(tsx|ts|jsx|js|mjs|cjs)$/, "");
|
|
2474
2507
|
}
|
|
2475
2508
|
var LANDMARK_RE = /<(header|nav|main|aside|footer)(\s[^>]*)?>|role=["']region["']/gi;
|
|
@@ -2544,7 +2577,24 @@ function resolve3(ctx) {
|
|
|
2544
2577
|
const routes = conventions.pages === "auto" ? detectRoutes(ctx.extracted.map((e) => e.file)) : [];
|
|
2545
2578
|
const handledPageFiles = /* @__PURE__ */ new Set();
|
|
2546
2579
|
for (const route of routes) {
|
|
2547
|
-
const
|
|
2580
|
+
const routeDir = path6.posix.dirname(route.file);
|
|
2581
|
+
const wellKnownPath = `${routeDir}/${WELL_KNOWN_FILES.page}`;
|
|
2582
|
+
const wellKnownExp = exportFor(wellKnownPath, "page");
|
|
2583
|
+
const routeExp = exportFor(route.file, "page");
|
|
2584
|
+
const exp = wellKnownExp ?? routeExp;
|
|
2585
|
+
const locFile = wellKnownExp ? wellKnownPath : route.file;
|
|
2586
|
+
if (wellKnownExp) handledPageFiles.add(wellKnownPath);
|
|
2587
|
+
handledPageFiles.add(route.file);
|
|
2588
|
+
if (wellKnownExp && routeExp) {
|
|
2589
|
+
diagnostics.push({
|
|
2590
|
+
code: "competing-uidex-export",
|
|
2591
|
+
severity: "warning",
|
|
2592
|
+
message: `Page metadata declared in both ${wellKnownPath} and ${route.file}; ${wellKnownPath} takes precedence.`,
|
|
2593
|
+
file: route.file,
|
|
2594
|
+
line: routeExp.loc.line,
|
|
2595
|
+
hint: `Remove the export from ${route.file} or delete ${wellKnownPath}.`
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2548
2598
|
if (exp && exp.id === false) continue;
|
|
2549
2599
|
const effectiveId = exp && typeof exp.id === "string" ? exp.id : route.id;
|
|
2550
2600
|
const meta = exp ? buildMetaFromExport(exp) : void 0;
|
|
@@ -2552,11 +2602,10 @@ function resolve3(ctx) {
|
|
|
2552
2602
|
const page = {
|
|
2553
2603
|
kind: "page",
|
|
2554
2604
|
id: effectiveId,
|
|
2555
|
-
loc: { file:
|
|
2605
|
+
loc: { file: locFile, line: exp?.loc.line },
|
|
2556
2606
|
...meta ? { meta } : {}
|
|
2557
2607
|
};
|
|
2558
2608
|
registry.add(page);
|
|
2559
|
-
handledPageFiles.add(route.file);
|
|
2560
2609
|
}
|
|
2561
2610
|
for (const ef of ctx.extracted) {
|
|
2562
2611
|
const exp = exportFor(ef.file.displayPath, "page");
|
|
@@ -2572,7 +2621,8 @@ function resolve3(ctx) {
|
|
|
2572
2621
|
}
|
|
2573
2622
|
const featureGlob = typeof conventions.features === "string" ? conventions.features : null;
|
|
2574
2623
|
const conventionalFeatureDirs = /* @__PURE__ */ new Set();
|
|
2575
|
-
const
|
|
2624
|
+
const featureExportFilesByDir = /* @__PURE__ */ new Map();
|
|
2625
|
+
const wellKnownFeatureFileByDir = /* @__PURE__ */ new Map();
|
|
2576
2626
|
const suppressedFeatureDirs = /* @__PURE__ */ new Set();
|
|
2577
2627
|
if (featureGlob) {
|
|
2578
2628
|
const re = globToRegExp(featureGlob + "/**");
|
|
@@ -2581,17 +2631,44 @@ function resolve3(ctx) {
|
|
|
2581
2631
|
const dir = extractFeatureDir(ef.file.displayPath, featureGlob);
|
|
2582
2632
|
if (!dir) continue;
|
|
2583
2633
|
conventionalFeatureDirs.add(dir);
|
|
2634
|
+
const isWellKnown = path6.posix.basename(ef.file.displayPath) === WELL_KNOWN_FILES.feature;
|
|
2635
|
+
if (isWellKnown) wellKnownFeatureFileByDir.set(dir, ef.file.displayPath);
|
|
2584
2636
|
const exp = exportFor(ef.file.displayPath, "feature");
|
|
2585
2637
|
if (exp) {
|
|
2586
2638
|
if (exp.id === false) suppressedFeatureDirs.add(dir);
|
|
2587
|
-
else
|
|
2588
|
-
|
|
2639
|
+
else {
|
|
2640
|
+
let arr = featureExportFilesByDir.get(dir);
|
|
2641
|
+
if (!arr) {
|
|
2642
|
+
arr = [];
|
|
2643
|
+
featureExportFilesByDir.set(dir, arr);
|
|
2644
|
+
}
|
|
2645
|
+
arr.push({ file: ef.file.displayPath, exp });
|
|
2646
|
+
}
|
|
2589
2647
|
}
|
|
2590
2648
|
}
|
|
2591
2649
|
for (const dir of conventionalFeatureDirs) {
|
|
2592
2650
|
if (suppressedFeatureDirs.has(dir)) continue;
|
|
2593
|
-
const
|
|
2594
|
-
const
|
|
2651
|
+
const allExports = featureExportFilesByDir.get(dir) ?? [];
|
|
2652
|
+
const wellKnownPath = wellKnownFeatureFileByDir.get(dir);
|
|
2653
|
+
const wellKnownEntry = wellKnownPath ? allExports.find((e) => e.file === wellKnownPath) : void 0;
|
|
2654
|
+
let exp;
|
|
2655
|
+
if (wellKnownEntry) {
|
|
2656
|
+
exp = wellKnownEntry.exp;
|
|
2657
|
+
for (const other of allExports) {
|
|
2658
|
+
if (other.file === wellKnownEntry.file) continue;
|
|
2659
|
+
diagnostics.push({
|
|
2660
|
+
code: "competing-uidex-export",
|
|
2661
|
+
severity: "warning",
|
|
2662
|
+
message: `Feature metadata declared in both ${wellKnownEntry.file} and ${other.file}; ${wellKnownEntry.file} takes precedence.`,
|
|
2663
|
+
file: other.file,
|
|
2664
|
+
line: other.exp.loc.line,
|
|
2665
|
+
hint: `Remove the export from ${other.file} or delete ${wellKnownEntry.file}.`
|
|
2666
|
+
});
|
|
2667
|
+
}
|
|
2668
|
+
} else if (allExports.length > 0) {
|
|
2669
|
+
exp = allExports[0].exp;
|
|
2670
|
+
}
|
|
2671
|
+
const id = exp && typeof exp.id === "string" ? exp.id : path6.posix.basename(dir);
|
|
2595
2672
|
const meta = exp ? buildMetaFromExport(exp) : void 0;
|
|
2596
2673
|
const feature = {
|
|
2597
2674
|
kind: "feature",
|
|
@@ -2723,11 +2800,12 @@ function resolve3(ctx) {
|
|
|
2723
2800
|
exp.id,
|
|
2724
2801
|
buildMetaFromExport(exp)
|
|
2725
2802
|
);
|
|
2803
|
+
const scope = computeScope(file);
|
|
2726
2804
|
const primitive = {
|
|
2727
2805
|
kind: "primitive",
|
|
2728
2806
|
id: exp.id,
|
|
2729
2807
|
loc: { file, line: exp.loc.line },
|
|
2730
|
-
scopes: [
|
|
2808
|
+
...scope ? { scopes: [scope] } : {},
|
|
2731
2809
|
...meta ? { meta } : {}
|
|
2732
2810
|
};
|
|
2733
2811
|
registry.add(primitive);
|
|
@@ -2739,11 +2817,12 @@ function resolve3(ctx) {
|
|
|
2739
2817
|
if (domPrimitives.length > 0) {
|
|
2740
2818
|
for (const p2 of domPrimitives) {
|
|
2741
2819
|
const meta = metaWithComposes("primitive", p2.id);
|
|
2820
|
+
const domScope = computeScope(p2.file);
|
|
2742
2821
|
const primitive = {
|
|
2743
2822
|
kind: "primitive",
|
|
2744
2823
|
id: p2.id,
|
|
2745
2824
|
loc: { file: p2.file, line: p2.line },
|
|
2746
|
-
scopes: [
|
|
2825
|
+
...domScope ? { scopes: [domScope] } : {},
|
|
2747
2826
|
...meta ? { meta } : {}
|
|
2748
2827
|
};
|
|
2749
2828
|
registry.add(primitive);
|
|
@@ -2753,13 +2832,13 @@ function resolve3(ctx) {
|
|
|
2753
2832
|
if (primitiveConventions && fileMatchesAny(file, primitiveConventions)) {
|
|
2754
2833
|
const name = kebab(baseName(file));
|
|
2755
2834
|
if (!name) continue;
|
|
2756
|
-
const
|
|
2835
|
+
const convScope = computeScope(file);
|
|
2757
2836
|
const meta = metaWithComposes("primitive", name);
|
|
2758
2837
|
const primitive = {
|
|
2759
2838
|
kind: "primitive",
|
|
2760
2839
|
id: name,
|
|
2761
2840
|
loc: { file },
|
|
2762
|
-
scopes: [
|
|
2841
|
+
...convScope ? { scopes: [convScope] } : {},
|
|
2763
2842
|
...meta ? { meta } : {}
|
|
2764
2843
|
};
|
|
2765
2844
|
registry.add(primitive);
|
|
@@ -2789,7 +2868,8 @@ function resolve3(ctx) {
|
|
|
2789
2868
|
kind: "flow",
|
|
2790
2869
|
id: flowExport.id,
|
|
2791
2870
|
loc: base.loc,
|
|
2792
|
-
touches: base.touches
|
|
2871
|
+
touches: base.touches,
|
|
2872
|
+
steps: base.steps
|
|
2793
2873
|
};
|
|
2794
2874
|
registry.add(flow);
|
|
2795
2875
|
} else {
|
|
@@ -2834,7 +2914,7 @@ function computeScope(displayPath) {
|
|
|
2834
2914
|
if (pagesIdx !== -1 && parts[pagesIdx + 1]) {
|
|
2835
2915
|
return `page:${parts[pagesIdx + 1]}`;
|
|
2836
2916
|
}
|
|
2837
|
-
return
|
|
2917
|
+
return null;
|
|
2838
2918
|
}
|
|
2839
2919
|
function extractFlowsFromSource(file) {
|
|
2840
2920
|
const flows = [];
|
|
@@ -2868,17 +2948,18 @@ function extractFlowsFromSource(file) {
|
|
|
2868
2948
|
kind: "flow",
|
|
2869
2949
|
id,
|
|
2870
2950
|
loc: { file: file.displayPath, line },
|
|
2871
|
-
touches: dedupe(touches.map((t) => t.id))
|
|
2951
|
+
touches: dedupe(touches.map((t) => t.id)),
|
|
2952
|
+
steps: touches.filter((t) => t.action).map((t) => ({ entityId: t.id, action: t.action }))
|
|
2872
2953
|
});
|
|
2873
2954
|
}
|
|
2874
2955
|
return flows;
|
|
2875
2956
|
}
|
|
2876
2957
|
function captureUidexIds(body) {
|
|
2877
2958
|
const out2 = [];
|
|
2878
|
-
const re = /uidex\(\s*(?:'([^']+)'|"([^"]+)"|`([^`$]+)`)\s*\)
|
|
2959
|
+
const re = /uidex\(\s*(?:'([^']+)'|"([^"]+)"|`([^`$]+)`)\s*\)(?:\.(\w+)\s*\()?/g;
|
|
2879
2960
|
let m;
|
|
2880
2961
|
while ((m = re.exec(body)) !== null) {
|
|
2881
|
-
out2.push({ id: m[1] || m[2] || m[3] });
|
|
2962
|
+
out2.push({ id: m[1] || m[2] || m[3], action: m[4] });
|
|
2882
2963
|
}
|
|
2883
2964
|
return out2;
|
|
2884
2965
|
}
|
|
@@ -2918,7 +2999,7 @@ function runOne(dc, opts) {
|
|
|
2918
2999
|
gitContext,
|
|
2919
3000
|
typeMode: config.typeMode
|
|
2920
3001
|
});
|
|
2921
|
-
const outputPath =
|
|
3002
|
+
const outputPath = path7.resolve(configDir, config.output);
|
|
2922
3003
|
const outputRel = config.output;
|
|
2923
3004
|
let existingOnDisk = null;
|
|
2924
3005
|
if (opts.check) {
|
|
@@ -2954,13 +3035,13 @@ function runOne(dc, opts) {
|
|
|
2954
3035
|
};
|
|
2955
3036
|
}
|
|
2956
3037
|
function writeScanResult(result) {
|
|
2957
|
-
fs5.mkdirSync(
|
|
3038
|
+
fs5.mkdirSync(path7.dirname(result.outputPath), { recursive: true });
|
|
2958
3039
|
fs5.writeFileSync(result.outputPath, result.generated, "utf8");
|
|
2959
3040
|
}
|
|
2960
3041
|
|
|
2961
3042
|
// src/scan/scaffold.ts
|
|
2962
3043
|
var fs6 = __toESM(require("fs"), 1);
|
|
2963
|
-
var
|
|
3044
|
+
var path8 = __toESM(require("path"), 1);
|
|
2964
3045
|
function scaffoldWidgetSpec(opts) {
|
|
2965
3046
|
const {
|
|
2966
3047
|
registry,
|
|
@@ -2975,7 +3056,7 @@ function scaffoldWidgetSpec(opts) {
|
|
|
2975
3056
|
}
|
|
2976
3057
|
const criteria = widget.meta?.acceptance ?? [];
|
|
2977
3058
|
const filename = `widget-${widgetId}.spec.ts`;
|
|
2978
|
-
const outputPath =
|
|
3059
|
+
const outputPath = path8.resolve(outDir, filename);
|
|
2979
3060
|
if (fs6.existsSync(outputPath) && !force) {
|
|
2980
3061
|
return {
|
|
2981
3062
|
outputPath,
|
|
@@ -2989,7 +3070,7 @@ function scaffoldWidgetSpec(opts) {
|
|
|
2989
3070
|
criteria,
|
|
2990
3071
|
fixtureImport
|
|
2991
3072
|
});
|
|
2992
|
-
fs6.mkdirSync(
|
|
3073
|
+
fs6.mkdirSync(path8.dirname(outputPath), { recursive: true });
|
|
2993
3074
|
fs6.writeFileSync(outputPath, content, "utf8");
|
|
2994
3075
|
return { outputPath, written: true, skipped: false };
|
|
2995
3076
|
}
|
|
@@ -3103,7 +3184,7 @@ function helpText2() {
|
|
|
3103
3184
|
].join("\n");
|
|
3104
3185
|
}
|
|
3105
3186
|
function runInit(cwd, w) {
|
|
3106
|
-
const configPath =
|
|
3187
|
+
const configPath = path9.join(cwd, CONFIG_FILENAME);
|
|
3107
3188
|
if (fs7.existsSync(configPath)) {
|
|
3108
3189
|
w.err(`.uidex.json already exists at ${configPath}`);
|
|
3109
3190
|
return w.result(1);
|
|
@@ -3115,7 +3196,7 @@ function runInit(cwd, w) {
|
|
|
3115
3196
|
};
|
|
3116
3197
|
fs7.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
3117
3198
|
w.out(`Created ${configPath}`);
|
|
3118
|
-
const gitignorePath =
|
|
3199
|
+
const gitignorePath = path9.join(cwd, ".gitignore");
|
|
3119
3200
|
const entry = "*.gen.ts";
|
|
3120
3201
|
if (fs7.existsSync(gitignorePath)) {
|
|
3121
3202
|
const existing = fs7.readFileSync(gitignorePath, "utf8");
|
|
@@ -3193,7 +3274,7 @@ function runScaffold(cwd, args, flags, w) {
|
|
|
3193
3274
|
for (const r of results) {
|
|
3194
3275
|
const widget = r.registry.get("widget", id);
|
|
3195
3276
|
if (!widget) continue;
|
|
3196
|
-
const outDir =
|
|
3277
|
+
const outDir = path9.resolve(r.configDir, "e2e");
|
|
3197
3278
|
const result = scaffoldWidgetSpec({
|
|
3198
3279
|
registry: r.registry,
|
|
3199
3280
|
widgetId: id,
|