@contentful/experience-design-system-cli 2.37.1-dev-build-414ce827.0 → 2.37.1-dev-build-e051d273.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/app.js CHANGED
@@ -2116,21 +2116,71 @@ var init_config = __esm({
2116
2116
  });
2117
2117
 
2118
2118
  // packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts
2119
+ function toRetentionDays(value) {
2120
+ return RETENTION_CHOICES.find((choice) => choice === value) ?? DEFAULT_RETENTION_DAYS;
2121
+ }
2119
2122
  async function readDebugModeSetting() {
2120
2123
  const { debugMode } = await readSettings2();
2121
- return { ...DEFAULT_DEBUG_MODE_SETTING, ...debugMode };
2124
+ const saved = debugMode ?? {};
2125
+ return {
2126
+ enabled: typeof saved.enabled === "boolean" ? saved.enabled : true,
2127
+ retentionDays: toRetentionDays(saved.retentionDays)
2128
+ };
2122
2129
  }
2123
- async function writeDebugModeSetting(setting) {
2124
- await updateSettings2({ debugMode: setting });
2130
+ async function writeDebugModeSetting(change) {
2131
+ await updateSettings2({ debugMode: { ...await readDebugModeSetting(), ...change } });
2125
2132
  }
2126
- var DEFAULT_DEBUG_MODE_SETTING;
2133
+ var RETENTION_CHOICES, DEFAULT_RETENTION_DAYS;
2127
2134
  var init_debug_mode_store = __esm({
2128
2135
  "packages/experience-design-system-cli/src/tui/settings/debug-mode/debug-mode-store.ts"() {
2129
2136
  "use strict";
2130
2137
  init_config();
2131
- DEFAULT_DEBUG_MODE_SETTING = {
2132
- enabled: true
2133
- };
2138
+ RETENTION_CHOICES = [30, 60, 90];
2139
+ DEFAULT_RETENTION_DAYS = 30;
2140
+ }
2141
+ });
2142
+
2143
+ // packages/experience-design-system-cli/src/tui/debug-prune.ts
2144
+ import { readdir as readdir3, rm, stat as stat5 } from "node:fs/promises";
2145
+ import { join as join24 } from "node:path";
2146
+ async function logFilesIn(dir) {
2147
+ const entries = await readdir3(dir, { withFileTypes: true });
2148
+ const nested = await Promise.all(
2149
+ entries.map(async (entry) => {
2150
+ const path5 = join24(dir, entry.name);
2151
+ if (entry.isDirectory()) return logFilesIn(path5);
2152
+ return entry.isFile() && entry.name.endsWith(".md") ? [path5] : [];
2153
+ })
2154
+ );
2155
+ return nested.flat();
2156
+ }
2157
+ async function pruneExpiredLogs(base, retentionDays, now = Date.now()) {
2158
+ const cutoff = now - retentionDays * DAY_MS;
2159
+ const contentfulDir = join24(base, ".contentful");
2160
+ let deleted = 0;
2161
+ try {
2162
+ const sessions = (await readdir3(contentfulDir)).filter((name) => SESSION_FOLDER.test(name));
2163
+ for (const session of sessions) {
2164
+ const files = await logFilesIn(join24(contentfulDir, session, "debug")).catch(() => []);
2165
+ for (const file of files) {
2166
+ try {
2167
+ if ((await stat5(file)).mtimeMs >= cutoff) continue;
2168
+ await rm(file);
2169
+ deleted += 1;
2170
+ } catch {
2171
+ }
2172
+ }
2173
+ }
2174
+ } catch {
2175
+ }
2176
+ return deleted;
2177
+ }
2178
+ var DAY_MS, SESSION_FOLDER;
2179
+ var init_debug_prune = __esm({
2180
+ "packages/experience-design-system-cli/src/tui/debug-prune.ts"() {
2181
+ "use strict";
2182
+ DAY_MS = 24 * 60 * 60 * 1e3;
2183
+ SESSION_FOLDER = /^\d{2}-\d{2}-\d{4}-session-\d+$/;
2134
2184
  }
2135
2185
  });
2136
2186
 
@@ -2146,7 +2196,7 @@ __export(debug_store_exports, {
2146
2196
  });
2147
2197
  import { mkdir as mkdir9, writeFile as writeFile8 } from "node:fs/promises";
2148
2198
  import { existsSync as existsSync9, readdirSync as readdirSync4 } from "node:fs";
2149
- import { join as join24, resolve as resolve26 } from "node:path";
2199
+ import { join as join25, resolve as resolve26 } from "node:path";
2150
2200
  function generateRunId() {
2151
2201
  const now = /* @__PURE__ */ new Date();
2152
2202
  const pad = (n) => String(n).padStart(2, "0");
@@ -2178,12 +2228,12 @@ function nextSessionId(contentfulDir) {
2178
2228
  return `${today}-session-${maxSeq + 1}`;
2179
2229
  }
2180
2230
  function startSession(base, { replace }) {
2181
- const contentfulDir = join24(base, ".contentful");
2182
- if (replace || !sessionDir) sessionDir = join24(contentfulDir, nextSessionId(contentfulDir));
2231
+ const contentfulDir = join25(base, ".contentful");
2232
+ if (replace || !sessionDir) sessionDir = join25(contentfulDir, nextSessionId(contentfulDir));
2183
2233
  return sessionDir;
2184
2234
  }
2185
2235
  function currentDebugSessionDir() {
2186
- return sessionDir && join24(sessionDir, "debug");
2236
+ return sessionDir && join25(sessionDir, "debug");
2187
2237
  }
2188
2238
  function currentSessionDir() {
2189
2239
  return sessionDir;
@@ -2191,7 +2241,7 @@ function currentSessionDir() {
2191
2241
  async function startDebugSessionIn(base, { replace = false } = {}) {
2192
2242
  try {
2193
2243
  if (!await isDebugModeEnabled()) return;
2194
- await mkdir9(join24(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
2244
+ await mkdir9(join25(startSession(resolve26(base), { replace }), "debug"), { recursive: true });
2195
2245
  } catch {
2196
2246
  }
2197
2247
  }
@@ -2201,11 +2251,11 @@ function nextImportRunDir(session) {
2201
2251
  const match2 = /^dsi-import-(\d+)$/.exec(entry);
2202
2252
  return match2 ? Math.max(max, Number(match2[1])) : max;
2203
2253
  }, 0);
2204
- return join24(session, `dsi-import-${maxRun + 1}`);
2254
+ return join25(session, `dsi-import-${maxRun + 1}`);
2205
2255
  }
2206
2256
  async function startImportRun(projectPath) {
2207
2257
  await startDebugSessionIn(projectPath);
2208
- if (!sessionDir) return join24(resolve26(projectPath), ".contentful");
2258
+ if (!sessionDir) return join25(resolve26(projectPath), ".contentful");
2209
2259
  const dir = nextImportRunDir(sessionDir);
2210
2260
  await mkdir9(dir, { recursive: true });
2211
2261
  return dir;
@@ -2252,10 +2302,10 @@ async function finishDebugRun({
2252
2302
  const root = currentDebugSessionDir();
2253
2303
  if (!root) return;
2254
2304
  const flowSegments = run.flow.split("/");
2255
- const dir = join24(root, ...flowSegments);
2305
+ const dir = join25(root, ...flowSegments);
2256
2306
  await mkdir9(dir, { recursive: true });
2257
2307
  const filename = nextAttemptFilename(dir, run.menuOption);
2258
- await writeFile8(join24(dir, filename), content, { mode: 384 });
2308
+ await writeFile8(join25(dir, filename), content, { mode: 384 });
2259
2309
  }
2260
2310
  function nextAttemptFilename(dir, menuOption) {
2261
2311
  const today = datePrefix();
@@ -2306,9 +2356,11 @@ var init_debug_store = __esm({
2306
2356
  init_config();
2307
2357
  init_version();
2308
2358
  init_debug_mode_store();
2309
- void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(([enabled, base]) => {
2310
- if (!enabled || !base) return void 0;
2311
- return mkdir9(join24(startSession(base, { replace: false }), "debug"), { recursive: true });
2359
+ init_debug_prune();
2360
+ void Promise.all([isDebugModeEnabled(), readBaseDir()]).then(async ([enabled, base]) => {
2361
+ if (!base) return;
2362
+ await readDebugModeSetting().then(({ retentionDays }) => pruneExpiredLogs(base, retentionDays)).catch(() => void 0);
2363
+ if (enabled) await mkdir9(join25(startSession(base, { replace: false }), "debug"), { recursive: true });
2312
2364
  });
2313
2365
  process.once("uncaughtException", (err) => {
2314
2366
  void handleCrash().finally(() => {
@@ -2329,7 +2381,7 @@ var init_debug_store = __esm({
2329
2381
  });
2330
2382
 
2331
2383
  // packages/experience-design-system-cli/app.tsx
2332
- import { join as join26 } from "node:path";
2384
+ import { join as join27 } from "node:path";
2333
2385
  import { useEffect as useEffect27, useState as useState36 } from "react";
2334
2386
 
2335
2387
  // packages/experience-design-system-cli/src/tui/home/home.tsx
@@ -2586,8 +2638,7 @@ function WelcomeScreen({ onContinue, onQuit, initialPath = "" }) {
2586
2638
  /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", gap: 1, children: [
2587
2639
  /* @__PURE__ */ jsx4(Text4, { children: "Where is your component library?" }),
2588
2640
  /* @__PURE__ */ jsxs3(Box3, { children: [
2589
- /* @__PURE__ */ jsx4(Text4, { color: PALETTE.text, children: "?" }),
2590
- /* @__PURE__ */ jsx4(Text4, { children: "Project path:" }),
2641
+ /* @__PURE__ */ jsx4(Text4, { children: "Project path: " }),
2591
2642
  /* @__PURE__ */ jsx4(TextInput, { value: projectPath, onChange: setProjectPath, onSubmit: submit })
2592
2643
  ] })
2593
2644
  ] }),
@@ -8779,8 +8830,8 @@ function getWorkspacePackageDirs(workspaceRoot) {
8779
8830
  continue;
8780
8831
  const entryPath = join7(dir, entry);
8781
8832
  try {
8782
- const stat5 = statSync3(entryPath);
8783
- if (stat5.isDirectory()) {
8833
+ const stat6 = statSync3(entryPath);
8834
+ if (stat6.isDirectory()) {
8784
8835
  scanDir(entryPath, depth + 1);
8785
8836
  }
8786
8837
  } catch {
@@ -9648,8 +9699,8 @@ function extractAccessorProperties(classDecl, applyRuntimeFieldDenylist = false)
9648
9699
  accessors.set(name, entry);
9649
9700
  }
9650
9701
  for (const [name, { getter, setter }] of accessors) {
9651
- const hasPropertyDecorator2 = getter?.getDecorators().some((decorator) => decorator.getName() === "property") || setter?.getDecorators().some((decorator) => decorator.getName() === "property");
9652
- if (!hasPropertyDecorator2 && !(getter && setter))
9702
+ const hasPropertyDecorator = getter?.getDecorators().some((decorator) => decorator.getName() === "property") || setter?.getDecorators().some((decorator) => decorator.getName() === "property");
9703
+ if (!hasPropertyDecorator && !(getter && setter))
9653
9704
  continue;
9654
9705
  const type = getter?.getReturnTypeNode()?.getText() ?? setter?.getParameters()[0]?.getTypeNode()?.getText() ?? "any";
9655
9706
  const accessorNode = getter ?? setter;
@@ -12867,15 +12918,15 @@ function walkProjectTree(dir, result, includeContent) {
12867
12918
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/helpers/collect-files/collect-files.js
12868
12919
  function collectFiles(root, options = {}) {
12869
12920
  const resolved = path4.resolve(root);
12870
- let stat5;
12921
+ let stat6;
12871
12922
  try {
12872
- stat5 = statSync4(resolved);
12923
+ stat6 = statSync4(resolved);
12873
12924
  } catch (err) {
12874
12925
  return { ok: false, failure: classifyStatError(err.code), rootPath: resolved };
12875
12926
  }
12876
- if (stat5.isFile())
12927
+ if (stat6.isFile())
12877
12928
  return { ok: false, failure: "is-file", rootPath: resolved };
12878
- if (!stat5.isDirectory())
12929
+ if (!stat6.isDirectory())
12879
12930
  return { ok: false, failure: "not-directory", rootPath: resolved };
12880
12931
  const result = {
12881
12932
  filePaths: [],
@@ -12919,9 +12970,9 @@ function generateUlid(now = Date.now()) {
12919
12970
  tsBytes[i] = n & 255;
12920
12971
  n = Math.floor(n / 256);
12921
12972
  }
12922
- const ts6 = encodeBase32(tsBytes, 10);
12973
+ const ts3 = encodeBase32(tsBytes, 10);
12923
12974
  const rand = encodeBase32(randomBytes2(10), 16);
12924
- return (ts6 + rand).toUpperCase();
12975
+ return (ts3 + rand).toUpperCase();
12925
12976
  }
12926
12977
 
12927
12978
  // packages/experience-design-system-backend-pipeline/dist/src/persistence/src/runs/repositories/read-runs-file.js
@@ -15335,691 +15386,93 @@ async function runMapTokens(request) {
15335
15386
  import { mkdir as mkdir4 } from "node:fs/promises";
15336
15387
  import { relative as relative2 } from "node:path";
15337
15388
 
15338
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/astro/helpers/collect-astro-props-bindings.js
15339
- import { Node as Node10, Project as Project7 } from "ts-morph";
15340
-
15341
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-shared.js
15342
- import { Project as Project8 } from "ts-morph";
15343
-
15344
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-node-utils.js
15345
- import { Node as Node12, SyntaxKind as SyntaxKind7 } from "ts-morph";
15346
-
15347
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-workspace-imports.js
15348
- import { Node as Node11 } from "ts-morph";
15349
-
15350
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/resolve-tsx-tsconfig-path.js
15351
- import ts3 from "typescript";
15352
-
15353
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/shared/helpers/tsx-renderable-exports.js
15354
- import { Node as Node13 } from "ts-morph";
15355
-
15356
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/collect-jsx-component-references.js
15357
- import { Node as Node15, SyntaxKind as SyntaxKind9 } from "ts-morph";
15358
-
15359
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/ast/get-jsx-ast-data.js
15360
- import { Node as Node14 } from "ts-morph";
15361
-
15362
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/ast/collect-structural-jsx-evidence.js
15363
- import { SyntaxKind as SyntaxKind8 } from "ts-morph";
15364
-
15365
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-from-react-source-file.js
15366
- import { SyntaxKind as SyntaxKind14 } from "ts-morph";
15367
-
15368
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-component-from-export.js
15369
- import { Node as Node32 } from "ts-morph";
15370
-
15371
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-prop-dataflow.js
15372
- import { Node as Node17, SyntaxKind as SyntaxKind10 } from "ts-morph";
15389
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/quality/non-authorable-filter.js
15390
+ var HANDLER_TYPE_PATTERN = /=>|EventHandler|Dispatch<|SetStateAction/;
15391
+ var REF_TYPE_PATTERN = /Ref<|RefObject<|MutableRefObject/;
15392
+ function isHandlerOrRefProp(prop) {
15393
+ if (HANDLER_TYPE_PATTERN.test(prop.type))
15394
+ return true;
15395
+ if (REF_TYPE_PATTERN.test(prop.type))
15396
+ return true;
15397
+ if (/^on[A-Z]/.test(prop.name) || /^set[A-Z]/.test(prop.name))
15398
+ return true;
15399
+ if (prop.name === "ref" || prop.name === "innerRef")
15400
+ return true;
15401
+ return false;
15402
+ }
15403
+ function hasNoPropsAndNoSlots(props, slots) {
15404
+ return props.length === 0 && slots.length === 0;
15405
+ }
15406
+ function isContextProviderWithValueProp(props, usesCreateContext) {
15407
+ return !!usesCreateContext && props.some((p) => p.name === "value");
15408
+ }
15409
+ function isHardwiredContextProvider(props, usesCreateContext) {
15410
+ return !!usesCreateContext && props.length === 0;
15411
+ }
15412
+ function isSingleDataPropContextWrapper(props, usesCreateContext) {
15413
+ return !!usesCreateContext && props.length === 1 && !isHandlerOrRefProp(props[0]);
15414
+ }
15415
+ function hasOnlyEventHandlers(props) {
15416
+ return props.length > 0 && props.every(isHandlerOrRefProp);
15417
+ }
15418
+ function hasNoAuthoringSurface(component) {
15419
+ const { props, slots, usesCreateContext } = component;
15420
+ if (hasNoPropsAndNoSlots(props, slots))
15421
+ return { skip: true, reason: "component has no props and no slots" };
15422
+ if (isContextProviderWithValueProp(props, usesCreateContext))
15423
+ return {
15424
+ skip: true,
15425
+ reason: "source uses createContext and component exposes a Context.Provider value prop"
15426
+ };
15427
+ if (isHardwiredContextProvider(props, usesCreateContext))
15428
+ return {
15429
+ skip: true,
15430
+ reason: "source uses createContext and component has no props"
15431
+ };
15432
+ if (isSingleDataPropContextWrapper(props, usesCreateContext))
15433
+ return {
15434
+ skip: true,
15435
+ reason: "source uses createContext and component has a single non-handler prop"
15436
+ };
15437
+ if (hasOnlyEventHandlers(props))
15438
+ return { skip: true, reason: "every prop is a handler or ref" };
15439
+ return { skip: false };
15440
+ }
15373
15441
 
15374
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/resolve-component-function.js
15375
- import { Node as Node16 } from "ts-morph";
15442
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/evidence/source-inspection.js
15443
+ import { readFile as readFile15 } from "node:fs/promises";
15376
15444
 
15377
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-props-from-type.js
15378
- import { Node as Node24 } from "ts-morph";
15445
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/constants/review-reasons.js
15446
+ var HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON = "data-fetch-wrapper";
15447
+ var POSSIBLE_DATA_FETCH_WRAPPER_REASON = "possible-data-fetch-wrapper";
15448
+ var ZERO_SURFACE_RENDERED_UI_REASON = "zero-surface:rendered-ui";
15379
15449
 
15380
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/dom-attribute-surfaces.js
15381
- import { Node as Node18 } from "ts-morph";
15382
- function createTextControlSurface2(onChangeType, specificProps) {
15383
- return [
15384
- { name: "autoComplete", type: "string", required: false },
15385
- ...specificProps,
15386
- { name: "disabled", type: "boolean", required: false },
15387
- { name: "name", type: "string", required: false },
15388
- { name: "onChange", type: onChangeType, required: false },
15389
- { name: "placeholder", type: "string", required: false },
15390
- { name: "readOnly", type: "boolean", required: false },
15391
- { name: "required", type: "boolean", required: false },
15392
- {
15393
- name: "value",
15394
- type: "string | number | readonly string[]",
15395
- required: false
15450
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/framework-adapters/shared/parse-imported-names.js
15451
+ function parseImportedNames(importClause) {
15452
+ const trimmed = importClause.trim();
15453
+ if (!trimmed)
15454
+ return [];
15455
+ const names = [];
15456
+ const defaultAndNamed = trimmed.split(",").map((part) => part.trim());
15457
+ for (const part of defaultAndNamed) {
15458
+ if (!part)
15459
+ continue;
15460
+ if (part.startsWith("{") && part.endsWith("}")) {
15461
+ for (const named of part.slice(1, -1).split(",").map((item) => item.trim()).filter(Boolean)) {
15462
+ const [local2] = named.split(/\s+as\s+/i);
15463
+ if (local2)
15464
+ names.push(local2.trim());
15465
+ }
15466
+ continue;
15396
15467
  }
15397
- ];
15468
+ const [local] = part.split(/\s+as\s+/i);
15469
+ if (local)
15470
+ names.push(local.trim());
15471
+ }
15472
+ return names;
15398
15473
  }
15399
- var DOM_ATTRIBUTE_PROP_SURFACES2 = {
15400
- HTMLProps: [],
15401
- HTMLAttributes: [
15402
- { name: "className", type: "string", required: false },
15403
- { name: "hidden", type: "boolean", required: false },
15404
- { name: "id", type: "string", required: false },
15405
- {
15406
- name: "onClick",
15407
- type: "MouseEventHandler<HTMLElement>",
15408
- required: false
15409
- },
15410
- { name: "style", type: "CSSProperties", required: false },
15411
- { name: "tabIndex", type: "number", required: false },
15412
- { name: "title", type: "string", required: false }
15413
- ],
15414
- ImgHTMLAttributes: [
15415
- { name: "alt", type: "string", required: false },
15416
- { name: "crossOrigin", type: "string", required: false },
15417
- { name: "height", type: "number | string", required: false },
15418
- {
15419
- name: "loading",
15420
- type: "string",
15421
- required: false,
15422
- allowedValues: ["eager", "lazy"]
15423
- },
15424
- { name: "sizes", type: "string", required: false },
15425
- { name: "src", type: "string", required: false },
15426
- { name: "srcSet", type: "string", required: false },
15427
- { name: "width", type: "number | string", required: false }
15428
- ],
15429
- LiHTMLAttributes: [],
15430
- AnchorHTMLAttributes: [
15431
- { name: "download", type: "boolean | string", required: false },
15432
- { name: "href", type: "string", required: false },
15433
- { name: "hrefLang", type: "string", required: false },
15434
- { name: "referrerPolicy", type: "string", required: false },
15435
- { name: "rel", type: "string", required: false },
15436
- {
15437
- name: "target",
15438
- type: "string",
15439
- required: false,
15440
- allowedValues: ["_blank", "_parent", "_self", "_top"]
15441
- }
15442
- ],
15443
- ButtonHTMLAttributes: [
15444
- { name: "autoFocus", type: "boolean", required: false },
15445
- { name: "disabled", type: "boolean", required: false },
15446
- { name: "form", type: "string", required: false },
15447
- { name: "formAction", type: "string", required: false },
15448
- { name: "formMethod", type: "string", required: false },
15449
- { name: "formNoValidate", type: "boolean", required: false },
15450
- { name: "formTarget", type: "string", required: false },
15451
- { name: "name", type: "string", required: false },
15452
- {
15453
- name: "type",
15454
- type: "string",
15455
- required: false,
15456
- allowedValues: ["button", "reset", "submit"]
15457
- },
15458
- {
15459
- name: "value",
15460
- type: "string | number | readonly string[]",
15461
- required: false
15462
- }
15463
- ],
15464
- InputHTMLAttributes: createTextControlSurface2("ChangeEventHandler<HTMLInputElement>", [
15465
- { name: "checked", type: "boolean", required: false },
15466
- { name: "max", type: "number | string", required: false },
15467
- { name: "maxLength", type: "number", required: false },
15468
- { name: "min", type: "number | string", required: false },
15469
- { name: "minLength", type: "number", required: false },
15470
- { name: "type", type: "string", required: false }
15471
- ]),
15472
- FieldsetHTMLAttributes: [
15473
- { name: "disabled", type: "boolean", required: false },
15474
- { name: "form", type: "string", required: false },
15475
- { name: "name", type: "string", required: false }
15476
- ],
15477
- LabelHTMLAttributes: [
15478
- { name: "form", type: "string", required: false },
15479
- { name: "htmlFor", type: "string", required: false }
15480
- ],
15481
- SelectHTMLAttributes: [
15482
- { name: "autoComplete", type: "string", required: false },
15483
- { name: "disabled", type: "boolean", required: false },
15484
- { name: "form", type: "string", required: false },
15485
- { name: "multiple", type: "boolean", required: false },
15486
- { name: "name", type: "string", required: false },
15487
- {
15488
- name: "onChange",
15489
- type: "ChangeEventHandler<HTMLSelectElement>",
15490
- required: false
15491
- },
15492
- { name: "required", type: "boolean", required: false },
15493
- { name: "size", type: "number", required: false },
15494
- {
15495
- name: "value",
15496
- type: "string | number | readonly string[]",
15497
- required: false
15498
- }
15499
- ],
15500
- SVGAttributes: [
15501
- {
15502
- name: "focusable",
15503
- type: 'boolean | "auto"',
15504
- required: false,
15505
- allowedValues: ["auto"]
15506
- },
15507
- { name: "height", type: "number | string", required: false },
15508
- { name: "viewBox", type: "string", required: false },
15509
- { name: "width", type: "number | string", required: false }
15510
- ],
15511
- SVGProps: [],
15512
- TextareaHTMLAttributes: createTextControlSurface2("ChangeEventHandler<HTMLTextAreaElement>", [
15513
- { name: "cols", type: "number", required: false },
15514
- { name: "rows", type: "number", required: false },
15515
- { name: "wrap", type: "string", required: false }
15516
- ]),
15517
- TdHTMLAttributes: [
15518
- {
15519
- name: "align",
15520
- type: "string",
15521
- required: false,
15522
- allowedValues: ["center", "char", "justify", "left", "right"]
15523
- },
15524
- { name: "colSpan", type: "number", required: false },
15525
- { name: "headers", type: "string", required: false },
15526
- { name: "rowSpan", type: "number", required: false },
15527
- { name: "scope", type: "string", required: false }
15528
- ]
15529
- };
15530
-
15531
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-dom-wrapper-contexts.js
15532
- import { Node as Node19 } from "ts-morph";
15533
-
15534
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-dom-is-pure-wrapper.js
15535
- import { Node as Node20 } from "ts-morph";
15536
-
15537
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-omit-wrapped-custom-props.js
15538
- import { Node as Node21 } from "ts-morph";
15539
-
15540
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-pick-type-patterns.js
15541
- import { Node as Node22 } from "ts-morph";
15542
-
15543
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/detect-react-polymorphic.js
15544
- import { Node as Node23 } from "ts-morph";
15545
15474
 
15546
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/resolve-react-props-type.js
15547
- import { Node as Node25 } from "ts-morph";
15548
-
15549
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-binding-defaults.js
15550
- import { Node as Node28 } from "ts-morph";
15551
-
15552
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/filter-impl-alias-props.js
15553
- import { Node as Node26 } from "ts-morph";
15554
-
15555
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-binding-fallback-props.js
15556
- import { Node as Node27, SyntaxKind as SyntaxKind11 } from "ts-morph";
15557
-
15558
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/collect-react-impl-hints.js
15559
- import { Node as Node30, SyntaxKind as SyntaxKind13 } from "ts-morph";
15560
-
15561
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/infer-primitive-dom-props.js
15562
- import { Node as Node29, SyntaxKind as SyntaxKind12 } from "ts-morph";
15563
-
15564
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/react/helpers/extract-react-prop-types.js
15565
- import { Node as Node31 } from "ts-morph";
15566
-
15567
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/extractor.js
15568
- import { Project as Project9, Node as Node37 } from "ts-morph";
15569
-
15570
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/detect-stencil-class.js
15571
- import { Node as Node33 } from "ts-morph";
15572
-
15573
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-props.js
15574
- import { Node as Node35 } from "ts-morph";
15575
-
15576
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/stencil-prop-helpers.js
15577
- import { Node as Node34, SyntaxKind as SyntaxKind15 } from "ts-morph";
15578
-
15579
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/stencil/helpers/extract-stencil-slots.js
15580
- import { Node as Node36 } from "ts-morph";
15581
-
15582
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-unresolved-retry.js
15583
- import { Project as Project12, ScriptTarget as ScriptTarget4, ModuleKind as ModuleKind4, ts as ts5 } from "ts-morph";
15584
-
15585
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/scoring/collect-scoring-inputs.js
15586
- var OPAQUE_TYPES2 = /* @__PURE__ */ new Set(["any", "unknown", "object", "Record<string, unknown>", "Record<string, any>"]);
15587
- var OBVIOUS_PROP_NAMES2 = /* @__PURE__ */ new Set([
15588
- "className",
15589
- "style",
15590
- "id",
15591
- "children",
15592
- "disabled",
15593
- "hidden",
15594
- "onClick",
15595
- "onChange",
15596
- "onSubmit",
15597
- "onBlur",
15598
- "onFocus",
15599
- "href",
15600
- "src",
15601
- "alt",
15602
- "type",
15603
- "value",
15604
- "checked",
15605
- "placeholder",
15606
- "label",
15607
- "title",
15608
- "name",
15609
- "required",
15610
- "readOnly",
15611
- "autoFocus",
15612
- "tabIndex",
15613
- "role",
15614
- "aria-label",
15615
- "aria-describedby"
15616
- ]);
15617
- function isWidePrimitiveUnion2(type) {
15618
- const parts = type.split("|").map((p) => p.trim());
15619
- if (parts.length < 3)
15620
- return false;
15621
- const basePrimitives = /* @__PURE__ */ new Set(["string", "number", "boolean"]);
15622
- const nullability = /* @__PURE__ */ new Set(["null", "undefined"]);
15623
- const baseCount = parts.filter((p) => basePrimitives.has(p)).length;
15624
- const nullabilityCount = parts.filter((p) => nullability.has(p)).length;
15625
- return baseCount >= 3 || baseCount >= 2 && nullabilityCount > 0 && baseCount + nullabilityCount >= 3;
15626
- }
15627
- function countExtractionIssues(component, options = {}) {
15628
- let count = 0;
15629
- const reasons = [];
15630
- if (component.props.length === 0 && component.slots.length === 0) {
15631
- count++;
15632
- reasons.push("no-props-or-slots");
15633
- }
15634
- if (component.props.length > 50) {
15635
- count++;
15636
- reasons.push(`high-prop-count:${component.props.length}`);
15637
- }
15638
- for (const prop of component.props) {
15639
- if (OPAQUE_TYPES2.has(prop.type.trim())) {
15640
- count++;
15641
- reasons.push(`opaque-type:${prop.name}`);
15642
- break;
15643
- }
15644
- if (isWidePrimitiveUnion2(prop.type)) {
15645
- count++;
15646
- reasons.push(`wide-union:${prop.name}`);
15647
- break;
15648
- }
15649
- if (!prop.description && !OBVIOUS_PROP_NAMES2.has(prop.name)) {
15650
- count++;
15651
- reasons.push("props-missing-description");
15652
- break;
15653
- }
15654
- }
15655
- count += options.additionalIssueCount ?? 0;
15656
- if (options.additionalReasons && options.additionalReasons.length > 0) {
15657
- reasons.push(...options.additionalReasons);
15658
- }
15659
- return { count, reasons: [...new Set(reasons)] };
15660
- }
15661
- function mapIssueCountToConfidence(count) {
15662
- if (count === 0)
15663
- return 5;
15664
- if (count === 1)
15665
- return 4;
15666
- if (count === 2)
15667
- return 3;
15668
- if (count === 3)
15669
- return 2;
15670
- return 1;
15671
- }
15672
-
15673
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/scoring/compute-extraction-score.js
15674
- function computeExtractionScore2(component, options = {}) {
15675
- const { count, reasons } = countExtractionIssues(component, options);
15676
- return {
15677
- confidence: mapIssueCountToConfidence(count),
15678
- reasons
15679
- };
15680
- }
15681
- function deriveNeedsReview2(confidence) {
15682
- return confidence <= 2;
15683
- }
15684
-
15685
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-type-checker.js
15686
- import { Project as Project10, ScriptTarget as ScriptTarget2, ModuleKind as ModuleKind2, ts as ts4 } from "ts-morph";
15687
-
15688
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-declaration-data.js
15689
- import { Node as Node38 } from "ts-morph";
15690
-
15691
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/resolve-svelte-external-type-readers.js
15692
- import { Node as Node40, Project as Project11, ScriptTarget as ScriptTarget3, ModuleKind as ModuleKind3 } from "ts-morph";
15693
-
15694
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-svelte-external-type-members.js
15695
- import { Node as Node39 } from "ts-morph";
15696
-
15697
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/svelte/helpers/extract-from-svelte-file.js
15698
- import { parse as parseSvelte2 } from "svelte/compiler";
15699
-
15700
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/extractor.js
15701
- import { Node as Node44 } from "ts-morph";
15702
-
15703
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-props.js
15704
- import { Node as Node42 } from "ts-morph";
15705
-
15706
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/resolve-ast-object.js
15707
- import { Node as Node41, SyntaxKind as SyntaxKind16 } from "ts-morph";
15708
-
15709
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue-tsx/helpers/extract-vue-tsx-slots.js
15710
- import { Node as Node43, SyntaxKind as SyntaxKind17 } from "ts-morph";
15711
-
15712
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/extractor.js
15713
- import { parse as parseSFC3 } from "@vue/compiler-sfc";
15714
-
15715
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-props.js
15716
- import { Project as Project14, Node as Node47 } from "ts-morph";
15717
-
15718
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-setup-object-props.js
15719
- import { Project as Project13, Node as Node46 } from "ts-morph";
15720
-
15721
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-object-props.js
15722
- import { Node as Node45 } from "ts-morph";
15723
-
15724
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/vue/helpers/extract-vue-options-props.js
15725
- import { parse as parseSFC2 } from "@vue/compiler-sfc";
15726
- import { Node as Node48, Project as Project15 } from "ts-morph";
15727
-
15728
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/extractor.js
15729
- import { Project as Project16 } from "ts-morph";
15730
-
15731
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-observed-attrs.js
15732
- import { Node as Node49 } from "ts-morph";
15733
-
15734
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-class-properties.js
15735
- import { Node as Node50 } from "ts-morph";
15736
-
15737
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-decorator-tag.js
15738
- import { Node as Node51 } from "ts-morph";
15739
-
15740
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-sibling-definition.js
15741
- import { Node as Node54, SyntaxKind as SyntaxKind19 } from "ts-morph";
15742
-
15743
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import.js
15744
- import { Node as Node53, SyntaxKind as SyntaxKind18 } from "ts-morph";
15745
-
15746
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-import-source.js
15747
- import { Node as Node52 } from "ts-morph";
15748
-
15749
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/extract-wc-template-content.js
15750
- import { Node as Node56 } from "ts-morph";
15751
-
15752
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/collect-wc-html-templates.js
15753
- import { Node as Node55 } from "ts-morph";
15754
-
15755
- // packages/experience-design-system-extraction/dist/src/extract/framework-adapters/web-components/helpers/resolve-wc-base-class.js
15756
- import { Node as Node57, SyntaxKind as SyntaxKind20 } from "ts-morph";
15757
-
15758
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/helpers/check-prop-types.js
15759
- function isStringLiteralUnion(type) {
15760
- return type.includes("|") && type.includes("'");
15761
- }
15762
- function isSimpleType(type) {
15763
- const t = type.trim();
15764
- if (t === "string" || t === "boolean" || t === "number")
15765
- return true;
15766
- return isStringLiteralUnion(t);
15767
- }
15768
- function isBooleanType(type) {
15769
- return type.trim() === "boolean";
15770
- }
15771
- function isStringType(type) {
15772
- return type.trim() === "string";
15773
- }
15774
- function isNumberType(type) {
15775
- return type.trim() === "number";
15776
- }
15777
- function isComplexType(type) {
15778
- return !isSimpleType(type);
15779
- }
15780
-
15781
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/helpers/detect-dom-props.js
15782
- var DOM_PASS_THROUGH_PROPS = /* @__PURE__ */ new Set([
15783
- // Bare HTML / framework styling pass-through
15784
- "className",
15785
- "class",
15786
- "classes",
15787
- "classNames",
15788
- "rootClassName",
15789
- "prefixCls",
15790
- "style",
15791
- "styles",
15792
- // Bare HTML attributes
15793
- "id",
15794
- "role",
15795
- "tabIndex",
15796
- "tabindex",
15797
- "htmlFor",
15798
- "for",
15799
- "slot",
15800
- "is",
15801
- "lang",
15802
- "dir",
15803
- "hidden",
15804
- "draggable",
15805
- "spellCheck",
15806
- "spellcheck",
15807
- "contentEditable",
15808
- "contenteditable",
15809
- "inputMode",
15810
- "inputmode",
15811
- "autoComplete",
15812
- "autocomplete",
15813
- "autoFocus",
15814
- "autofocus",
15815
- "translate",
15816
- "part",
15817
- "exportparts",
15818
- "aria",
15819
- // Framework theming / pass-through escape hatches — dev-facing, never marketer-configurable
15820
- "dt",
15821
- "pt",
15822
- "ptOptions",
15823
- "unstyled",
15824
- "sx",
15825
- // Polymorphic component props — change rendered HTML/component, not marketer-visible behavior
15826
- "as",
15827
- "element",
15828
- "component",
15829
- // QA / vendor test attributes
15830
- "dataQa",
15831
- "data-qa",
15832
- // Vue v-model internals — framework wiring, never marketer-configurable
15833
- "modelValue",
15834
- "modelModifiers"
15835
- ]);
15836
- function isDomPassThroughProp(name) {
15837
- if (DOM_PASS_THROUGH_PROPS.has(name))
15838
- return true;
15839
- if (/^aria[-A-Z]/.test(name))
15840
- return true;
15841
- return name.startsWith("data-");
15842
- }
15843
-
15844
- // packages/experience-design-system-extraction/dist/src/extract/services/classification/classify-component-props.js
15845
- function preClassifyProp(prop) {
15846
- const { name, type } = prop;
15847
- if (/^on[A-Z]/.test(name) || type.includes("=> void") || type.includes("EventHandler")) {
15848
- return { category: "exclude" };
15849
- }
15850
- if (name === "ref" || name === "innerRef" || type.includes("Ref<") || type.includes("RefObject<")) {
15851
- return { category: "exclude" };
15852
- }
15853
- if (name === "testId" || name === "data-testid" || name === "dataTestId") {
15854
- return { category: "exclude" };
15855
- }
15856
- if (name === "key") {
15857
- return { category: "exclude" };
15858
- }
15859
- if (type.includes("Dispatch<") || type.includes("SetStateAction")) {
15860
- return { category: "exclude" };
15861
- }
15862
- if (isDomPassThroughProp(name)) {
15863
- return { category: "exclude" };
15864
- }
15865
- if (name === "name" && prop.domAttribute) {
15866
- return { category: "exclude" };
15867
- }
15868
- if (isStringLiteralUnion(type)) {
15869
- return { category: "design", cdfTypeHint: "enum" };
15870
- }
15871
- if (!isComplexType(type)) {
15872
- const designNameStart = /^(variant|size|spacing|gap|color|bg|theme|align|layout|orientation|position)/i;
15873
- const designNameEnd = /(Color|Size|Variant|Style)$/;
15874
- if (designNameStart.test(name) || designNameEnd.test(name)) {
15875
- return { category: "design", cdfTypeHint: "string" };
15876
- }
15877
- }
15878
- if (isBooleanType(type)) {
15879
- const stateNames = ["disabled", "loading", "expanded", "isOpen", "selected", "checked", "active", "preview"];
15880
- if (stateNames.includes(name)) {
15881
- return { category: "state", cdfTypeHint: "boolean" };
15882
- }
15883
- }
15884
- if (isBooleanType(type)) {
15885
- const visualToggle = /^(hide|show|enable|disable|vertical|horizontal|reverse|bold|italic|imageOn|with)/i;
15886
- if (visualToggle.test(name)) {
15887
- return { category: "design", cdfTypeHint: "boolean" };
15888
- }
15889
- }
15890
- if (name === "componentId" || name === "sectionKey" || name === "locale" || name === "variantIndex") {
15891
- return { category: "state", cdfTypeHint: "string" };
15892
- }
15893
- if (isStringType(type)) {
15894
- const urlNameStart = /^(href|url|link|src)/i;
15895
- const urlNameEnd = /(Url|Href|Link|Src)$/;
15896
- if (urlNameStart.test(name) || urlNameEnd.test(name)) {
15897
- return { category: "content", cdfTypeHint: "string" };
15898
- }
15899
- }
15900
- if (isStringType(type)) {
15901
- const textNameStart = /^(label|title|text|description|caption|heading|subheading|body|alt|name|placeholder|summary)/i;
15902
- const textNameEnd = /(Text|Label|Title|Name)$/;
15903
- if (textNameStart.test(name) || textNameEnd.test(name)) {
15904
- return { category: "content", cdfTypeHint: "string" };
15905
- }
15906
- }
15907
- if (isStringType(type)) {
15908
- return { category: "content", cdfTypeHint: "string" };
15909
- }
15910
- if (isBooleanType(type)) {
15911
- return { category: "design", cdfTypeHint: "boolean" };
15912
- }
15913
- if (isNumberType(type)) {
15914
- return { category: "design", cdfTypeHint: "string" };
15915
- }
15916
- return void 0;
15917
- }
15918
- function preClassifyComponent(component) {
15919
- const props = component.props.flatMap((prop) => {
15920
- const result = preClassifyProp(prop);
15921
- if (result?.category === "exclude") {
15922
- return [];
15923
- }
15924
- const { domAttribute: _domAttribute, ...authorableProp } = prop;
15925
- if (prop.category) {
15926
- return [authorableProp];
15927
- }
15928
- if (!result) {
15929
- return [authorableProp];
15930
- }
15931
- return [
15932
- {
15933
- ...authorableProp,
15934
- category: result.category
15935
- }
15936
- ];
15937
- });
15938
- return { ...component, props };
15939
- }
15940
-
15941
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/authorability/evaluate-authorability.js
15942
- var HANDLER_TYPE_PATTERN = /=>|EventHandler|Dispatch<|SetStateAction/;
15943
- var REF_TYPE_PATTERN = /Ref<|RefObject<|MutableRefObject/;
15944
- function isHandlerOrRefProp(prop) {
15945
- if (HANDLER_TYPE_PATTERN.test(prop.type))
15946
- return true;
15947
- if (REF_TYPE_PATTERN.test(prop.type))
15948
- return true;
15949
- if (/^on[A-Z]/.test(prop.name) || /^set[A-Z]/.test(prop.name))
15950
- return true;
15951
- if (prop.name === "ref" || prop.name === "innerRef")
15952
- return true;
15953
- return false;
15954
- }
15955
- function hasNoPropsAndNoSlots(props, slots) {
15956
- return props.length === 0 && slots.length === 0;
15957
- }
15958
- function isContextProviderWithValueProp(props, usesCreateContext) {
15959
- return !!usesCreateContext && props.some((p) => p.name === "value");
15960
- }
15961
- function isHardwiredContextProvider(props, usesCreateContext) {
15962
- return !!usesCreateContext && props.length === 0;
15963
- }
15964
- function isSingleDataPropContextWrapper(props, usesCreateContext) {
15965
- return !!usesCreateContext && props.length === 1 && !isHandlerOrRefProp(props[0]);
15966
- }
15967
- function hasOnlyEventHandlers(props) {
15968
- return props.length > 0 && props.every(isHandlerOrRefProp);
15969
- }
15970
- function hasNoAuthoringSurface(component) {
15971
- const { props, slots, usesCreateContext } = component;
15972
- if (hasNoPropsAndNoSlots(props, slots))
15973
- return { skip: true, reason: "component has no props and no slots" };
15974
- if (isContextProviderWithValueProp(props, usesCreateContext))
15975
- return {
15976
- skip: true,
15977
- reason: "source uses createContext and component exposes a Context.Provider value prop"
15978
- };
15979
- if (isHardwiredContextProvider(props, usesCreateContext))
15980
- return {
15981
- skip: true,
15982
- reason: "source uses createContext and component has no props"
15983
- };
15984
- if (isSingleDataPropContextWrapper(props, usesCreateContext))
15985
- return {
15986
- skip: true,
15987
- reason: "source uses createContext and component has a single non-handler prop"
15988
- };
15989
- if (hasOnlyEventHandlers(props))
15990
- return { skip: true, reason: "every prop is a handler or ref" };
15991
- return { skip: false };
15992
- }
15993
-
15994
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/inspect-component-source.js
15995
- import { readFile as readFile15 } from "node:fs/promises";
15996
-
15997
- // packages/experience-design-system-extraction/dist/src/extract/helpers/evidence/parse-source-imports.js
15998
- function parseImportedNames(importClause) {
15999
- const trimmed = importClause.trim();
16000
- if (!trimmed)
16001
- return [];
16002
- const names = [];
16003
- const defaultAndNamed = trimmed.split(",").map((part) => part.trim());
16004
- for (const part of defaultAndNamed) {
16005
- if (!part)
16006
- continue;
16007
- if (part.startsWith("{") && part.endsWith("}")) {
16008
- for (const named of part.slice(1, -1).split(",").map((item) => item.trim()).filter(Boolean)) {
16009
- const [local2] = named.split(/\s+as\s+/i);
16010
- if (local2)
16011
- names.push(local2.trim());
16012
- }
16013
- continue;
16014
- }
16015
- const [local] = part.split(/\s+as\s+/i);
16016
- if (local)
16017
- names.push(local.trim());
16018
- }
16019
- return names;
16020
- }
16021
-
16022
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/detect-data-wrapper-patterns.js
15475
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/evidence/source-inspection.js
16023
15476
  var INFRA_PROP_NAMES = /* @__PURE__ */ new Set(["id", "locale", "preview", "slug", "topic", "previousComponent", "__typename"]);
16024
15477
  var VISIBLE_UI_TAG_PATTERN = /<(?:[A-Z][A-Za-z0-9_.]*|div|span|section|main|article|header|footer|nav|aside|img|video|p|h[1-6]|ul|ol|li|button|input|textarea|select|form|label|table|tbody|thead|tr|td|th)\b/;
16025
15478
  var GENERATED_IMPORT_PATTERN = /from\s+['"][^'"]*__generated[^'"]*['"]/;
@@ -16061,11 +15514,11 @@ function hasSiblingForwardRender(sourceText, siblingImports) {
16061
15514
  function hasVisibleUiRender(sourceText) {
16062
15515
  return /return\s*(?:\(|<)/.test(sourceText) && VISIBLE_UI_TAG_PATTERN.test(sourceText);
16063
15516
  }
16064
- function collectInfraPropNames(component) {
15517
+ function infraPropNames(component) {
16065
15518
  const props = component.props.map((prop) => prop.name);
16066
15519
  return props.length > 0 && props.every((prop) => INFRA_PROP_NAMES.has(prop)) ? props : [];
16067
15520
  }
16068
- function mapScoreToWrapperConfidence(score) {
15521
+ function scoreToConfidence(score) {
16069
15522
  if (score <= 0)
16070
15523
  return 0;
16071
15524
  if (score <= 2)
@@ -16076,14 +15529,9 @@ function mapScoreToWrapperConfidence(score) {
16076
15529
  return 4;
16077
15530
  return 5;
16078
15531
  }
16079
- function dedupeStrings(values) {
16080
- return [...new Set(values)];
15532
+ function dedupeReasons(reasons) {
15533
+ return [...new Set(reasons)];
16081
15534
  }
16082
-
16083
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/inspect-component-source.js
16084
- var HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON = "data-fetch-wrapper";
16085
- var POSSIBLE_DATA_FETCH_WRAPPER_REASON = "possible-data-fetch-wrapper";
16086
- var ZERO_SURFACE_RENDERED_UI_REASON = "zero-surface:rendered-ui";
16087
15535
  async function inspectComponentSource(component) {
16088
15536
  let sourceText = "";
16089
15537
  try {
@@ -16098,7 +15546,7 @@ async function inspectComponentSource(component) {
16098
15546
  const reviewReasons = [];
16099
15547
  let wrapperScore = 0;
16100
15548
  const hasGeneratedQueryHook = GENERATED_IMPORT_PATTERN.test(sourceText) && GENERATED_QUERY_HOOK_PATTERN.test(sourceText);
16101
- const infraProps = collectInfraPropNames(component);
15549
+ const infraProps = infraPropNames(component);
16102
15550
  const siblingImports = collectSiblingRendererImports(sourceText);
16103
15551
  if (GQL_FILENAME_PATTERN.test(component.source)) {
16104
15552
  reviewReasons.push("data-wrapper:gql-filename");
@@ -16112,136 +15560,69 @@ async function inspectComponentSource(component) {
16112
15560
  reviewReasons.push("data-wrapper:sibling-renderer-import");
16113
15561
  wrapperScore += 1;
16114
15562
  }
16115
- if (hasSiblingForwardRender(sourceText, siblingImports)) {
16116
- reviewReasons.push("data-wrapper:fetch-forward-render");
16117
- wrapperScore += 3;
16118
- }
16119
- if (sourceText.includes("useContentfulLiveUpdates(") || sourceText.includes("useContentfulContext(")) {
16120
- reviewReasons.push("data-wrapper:contentful-runtime");
16121
- wrapperScore += 1;
16122
- }
16123
- if (infraProps.length > 0) {
16124
- reviewReasons.push("data-wrapper:infra-props");
16125
- wrapperScore += 2;
16126
- }
16127
- if (LOADING_NULL_GUARD_PATTERN.test(sourceText)) {
16128
- reviewReasons.push("data-wrapper:loading-null-guard");
16129
- wrapperScore += 1;
16130
- }
16131
- const wrapperConfidence = mapScoreToWrapperConfidence(wrapperScore);
16132
- if (wrapperConfidence >= 4) {
16133
- reviewReasons.unshift(HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON);
16134
- } else if (wrapperConfidence === 3) {
16135
- reviewReasons.unshift(POSSIBLE_DATA_FETCH_WRAPPER_REASON);
16136
- }
16137
- const keepDespiteZeroSurface = component.props.length === 0 && component.slots.length === 0 && hasVisibleUiRender(sourceText);
16138
- if (keepDespiteZeroSurface) {
16139
- reviewReasons.push(ZERO_SURFACE_RENDERED_UI_REASON);
16140
- }
16141
- return {
16142
- wrapperConfidence,
16143
- reviewReasons: dedupeStrings(reviewReasons),
16144
- keepDespiteZeroSurface
16145
- };
16146
- }
16147
- function describeReviewReason(reason) {
16148
- switch (reason) {
16149
- case HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON:
16150
- return "high-confidence data-fetch wrapper";
16151
- case POSSIBLE_DATA_FETCH_WRAPPER_REASON:
16152
- return "possible data-fetch wrapper";
16153
- case "data-wrapper:gql-filename":
16154
- return "source file follows a gql wrapper naming pattern";
16155
- case "data-wrapper:generated-query-hook":
16156
- return "imports and calls a generated query hook";
16157
- case "data-wrapper:sibling-renderer-import":
16158
- return "imports a sibling renderer from the same folder";
16159
- case "data-wrapper:fetch-forward-render":
16160
- return "forwards fetched data into a sibling renderer";
16161
- case "data-wrapper:contentful-runtime":
16162
- return "uses Contentful runtime hooks";
16163
- case "data-wrapper:infra-props":
16164
- return "only exposes infra-fetch props";
16165
- case "data-wrapper:loading-null-guard":
16166
- return "returns early while loading or when fetched data is missing";
16167
- case ZERO_SURFACE_RENDERED_UI_REASON:
16168
- return "source renders visible/compositional UI despite zero extracted props and slots";
16169
- default:
16170
- return reason;
16171
- }
16172
- }
16173
- function describeReviewReasons(reasons) {
16174
- return dedupeStrings(reasons.map(describeReviewReason));
16175
- }
16176
-
16177
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/helpers/inspection/validate-extracted-components.js
16178
- function validateExtractedComponents2(components) {
16179
- const nameCounts = /* @__PURE__ */ new Map();
16180
- for (const component of components) {
16181
- const key = component.name.trim();
16182
- nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);
16183
- }
16184
- return components.map((component) => {
16185
- const issues = [];
16186
- if (!component.name.trim()) {
16187
- issues.push({
16188
- severity: "error",
16189
- code: "EMPTY_COMPONENT_NAME",
16190
- message: "Component name must not be empty"
16191
- });
16192
- }
16193
- for (let i = 0; i < component.props.length; i++) {
16194
- if (!component.props[i].name.trim()) {
16195
- issues.push({
16196
- severity: "error",
16197
- code: "EMPTY_PROP_NAME",
16198
- message: `Prop at index ${i} has an empty name`,
16199
- field: `props[${i}].name`
16200
- });
16201
- }
16202
- }
16203
- for (let i = 0; i < component.slots.length; i++) {
16204
- if (!component.slots[i].name.trim()) {
16205
- issues.push({
16206
- severity: "warning",
16207
- code: "EMPTY_SLOT_NAME",
16208
- message: `Slot at index ${i} has an empty name`,
16209
- field: `slots[${i}].name`
16210
- });
16211
- }
16212
- }
16213
- const propNames = new Set(component.props.map((p) => p.name.trim()).filter(Boolean));
16214
- for (let i = 0; i < component.slots.length; i++) {
16215
- const slotName = component.slots[i].name.trim();
16216
- if (slotName && propNames.has(slotName)) {
16217
- issues.push({
16218
- severity: "error",
16219
- code: "PROP_SLOT_NAME_COLLISION",
16220
- message: `"${slotName}" is used as both a prop name and a slot name`,
16221
- field: `slots[${i}].name`
16222
- });
16223
- }
16224
- }
16225
- const nameKey = component.name.trim();
16226
- if (nameKey && (nameCounts.get(nameKey) ?? 0) > 1) {
16227
- issues.push({
16228
- severity: "error",
16229
- code: "DUPLICATE_COMPONENT_NAME",
16230
- message: `Component name "${component.name}" appears more than once in the extracted set`
16231
- });
16232
- }
16233
- if (component.props.length === 0 && component.slots.length === 0) {
16234
- issues.push({
16235
- severity: "warning",
16236
- code: "EMPTY_COMPONENT",
16237
- message: "Component has no props or slots and will be filtered out during generation"
16238
- });
16239
- }
16240
- return { ...component, validationIssues: issues };
16241
- });
15563
+ if (hasSiblingForwardRender(sourceText, siblingImports)) {
15564
+ reviewReasons.push("data-wrapper:fetch-forward-render");
15565
+ wrapperScore += 3;
15566
+ }
15567
+ if (sourceText.includes("useContentfulLiveUpdates(") || sourceText.includes("useContentfulContext(")) {
15568
+ reviewReasons.push("data-wrapper:contentful-runtime");
15569
+ wrapperScore += 1;
15570
+ }
15571
+ if (infraProps.length > 0) {
15572
+ reviewReasons.push("data-wrapper:infra-props");
15573
+ wrapperScore += 2;
15574
+ }
15575
+ if (LOADING_NULL_GUARD_PATTERN.test(sourceText)) {
15576
+ reviewReasons.push("data-wrapper:loading-null-guard");
15577
+ wrapperScore += 1;
15578
+ }
15579
+ const wrapperConfidence = scoreToConfidence(wrapperScore);
15580
+ if (wrapperConfidence >= 4) {
15581
+ reviewReasons.unshift(HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON);
15582
+ } else if (wrapperConfidence === 3) {
15583
+ reviewReasons.unshift(POSSIBLE_DATA_FETCH_WRAPPER_REASON);
15584
+ }
15585
+ const keepDespiteZeroSurface = component.props.length === 0 && component.slots.length === 0 && hasVisibleUiRender(sourceText);
15586
+ if (keepDespiteZeroSurface) {
15587
+ reviewReasons.push(ZERO_SURFACE_RENDERED_UI_REASON);
15588
+ }
15589
+ return {
15590
+ wrapperConfidence,
15591
+ reviewReasons: dedupeReasons(reviewReasons),
15592
+ keepDespiteZeroSurface
15593
+ };
15594
+ }
15595
+ function describeReviewReason(reason) {
15596
+ switch (reason) {
15597
+ case HIGH_CONFIDENCE_DATA_FETCH_WRAPPER_REASON:
15598
+ return "high-confidence data-fetch wrapper";
15599
+ case POSSIBLE_DATA_FETCH_WRAPPER_REASON:
15600
+ return "possible data-fetch wrapper";
15601
+ case "data-wrapper:gql-filename":
15602
+ return "source file follows a gql wrapper naming pattern";
15603
+ case "data-wrapper:generated-query-hook":
15604
+ return "imports and calls a generated query hook";
15605
+ case "data-wrapper:sibling-renderer-import":
15606
+ return "imports a sibling renderer from the same folder";
15607
+ case "data-wrapper:fetch-forward-render":
15608
+ return "forwards fetched data into a sibling renderer";
15609
+ case "data-wrapper:contentful-runtime":
15610
+ return "uses Contentful runtime hooks";
15611
+ case "data-wrapper:infra-props":
15612
+ return "only exposes infra-fetch props";
15613
+ case "data-wrapper:loading-null-guard":
15614
+ return "returns early while loading or when fetched data is missing";
15615
+ case ZERO_SURFACE_RENDERED_UI_REASON:
15616
+ return "source renders visible/compositional UI despite zero extracted props and slots";
15617
+ default:
15618
+ return reason;
15619
+ }
15620
+ }
15621
+ function describeReviewReasons(reasons) {
15622
+ return dedupeReasons(reasons.map(describeReviewReason));
16242
15623
  }
16243
15624
 
16244
- // packages/experience-design-system-extraction/dist/src/extract/services/quality/evaluate-extraction-quality.js
15625
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/quality/evaluate-extraction-quality.js
16245
15626
  function wrapperConfidenceToIssueCount(confidence) {
16246
15627
  if (confidence >= 4)
16247
15628
  return 2;
@@ -16273,7 +15654,7 @@ async function evaluateExtractionQuality(components, initialWarnings = []) {
16273
15654
  }
16274
15655
  const extractorReasons = component.reviewReasons ?? [];
16275
15656
  const nonAuthorableReason = retainedForReview ? [`non-authorable:${verdict.reason}`] : [];
16276
- const { confidence, reasons } = computeExtractionScore2(component, {
15657
+ const { confidence, reasons } = computeExtractionScore(component, {
16277
15658
  additionalIssueCount: wrapperConfidenceToIssueCount(inspection.wrapperConfidence) + extractorReasons.length + nonAuthorableReason.length,
16278
15659
  additionalReasons: [...extractorReasons, ...inspection.reviewReasons, ...nonAuthorableReason]
16279
15660
  });
@@ -16281,15 +15662,194 @@ async function evaluateExtractionQuality(components, initialWarnings = []) {
16281
15662
  ...component,
16282
15663
  extractionConfidence: confidence,
16283
15664
  reviewReasons: reasons,
16284
- needsReview: deriveNeedsReview2(confidence) || inspection.wrapperConfidence >= 4 || inspection.keepDespiteZeroSurface || retainedForReview || extractorReasons.includes("props-type-unresolved") || (component.needsReview ?? false)
15665
+ needsReview: deriveNeedsReview(confidence) || inspection.wrapperConfidence >= 4 || inspection.keepDespiteZeroSurface || retainedForReview || extractorReasons.includes("props-type-unresolved") || (component.needsReview ?? false)
16285
15666
  });
16286
15667
  }
16287
15668
  return {
16288
- components: validateExtractedComponents2(scoredComponents),
15669
+ components: validateExtractedComponents(scoredComponents),
16289
15670
  warnings
16290
15671
  };
16291
15672
  }
16292
15673
 
15674
+ // packages/experience-design-system-backend-pipeline/dist/src/steps/extraction/src/helpers/pre-classify.js
15675
+ function isStringLiteralUnion(type) {
15676
+ return type.includes("|") && type.includes("'");
15677
+ }
15678
+ function isSimpleType(type) {
15679
+ const t = type.trim();
15680
+ if (t === "string" || t === "boolean" || t === "number")
15681
+ return true;
15682
+ return isStringLiteralUnion(t);
15683
+ }
15684
+ function isBooleanType(type) {
15685
+ return type.trim() === "boolean";
15686
+ }
15687
+ function isStringType(type) {
15688
+ return type.trim() === "string";
15689
+ }
15690
+ function isNumberType(type) {
15691
+ return type.trim() === "number";
15692
+ }
15693
+ function isComplexType(type) {
15694
+ return !isSimpleType(type);
15695
+ }
15696
+ var DOM_PASS_THROUGH_PROPS = /* @__PURE__ */ new Set([
15697
+ // Bare HTML / framework styling pass-through
15698
+ "className",
15699
+ "class",
15700
+ "classes",
15701
+ "classNames",
15702
+ "rootClassName",
15703
+ "prefixCls",
15704
+ "style",
15705
+ "styles",
15706
+ // Bare HTML attributes
15707
+ "id",
15708
+ "role",
15709
+ "tabIndex",
15710
+ "tabindex",
15711
+ "htmlFor",
15712
+ "for",
15713
+ "slot",
15714
+ "is",
15715
+ "lang",
15716
+ "dir",
15717
+ "hidden",
15718
+ "draggable",
15719
+ "spellCheck",
15720
+ "spellcheck",
15721
+ "contentEditable",
15722
+ "contenteditable",
15723
+ "inputMode",
15724
+ "inputmode",
15725
+ "autoComplete",
15726
+ "autocomplete",
15727
+ "autoFocus",
15728
+ "autofocus",
15729
+ "translate",
15730
+ "part",
15731
+ "exportparts",
15732
+ "aria",
15733
+ // Framework theming / pass-through escape hatches — dev-facing, never marketer-configurable
15734
+ "dt",
15735
+ "pt",
15736
+ "ptOptions",
15737
+ "unstyled",
15738
+ "sx",
15739
+ // Polymorphic component props — change rendered HTML/component, not marketer-visible behavior
15740
+ "as",
15741
+ "element",
15742
+ "component",
15743
+ // QA / vendor test attributes
15744
+ "dataQa",
15745
+ "data-qa",
15746
+ // Vue v-model internals — framework wiring, never marketer-configurable
15747
+ "modelValue",
15748
+ "modelModifiers"
15749
+ ]);
15750
+ function isDomPassThroughProp(name) {
15751
+ if (DOM_PASS_THROUGH_PROPS.has(name))
15752
+ return true;
15753
+ if (/^aria[-A-Z]/.test(name))
15754
+ return true;
15755
+ return name.startsWith("data-");
15756
+ }
15757
+ function preClassifyProp(prop) {
15758
+ const { name, type } = prop;
15759
+ if (/^on[A-Z]/.test(name) || type.includes("=> void") || type.includes("EventHandler")) {
15760
+ return { category: "exclude" };
15761
+ }
15762
+ if (name === "ref" || name === "innerRef" || type.includes("Ref<") || type.includes("RefObject<")) {
15763
+ return { category: "exclude" };
15764
+ }
15765
+ if (name === "testId" || name === "data-testid" || name === "dataTestId") {
15766
+ return { category: "exclude" };
15767
+ }
15768
+ if (name === "key") {
15769
+ return { category: "exclude" };
15770
+ }
15771
+ if (type.includes("Dispatch<") || type.includes("SetStateAction")) {
15772
+ return { category: "exclude" };
15773
+ }
15774
+ if (isDomPassThroughProp(name)) {
15775
+ return { category: "exclude" };
15776
+ }
15777
+ if (name === "name" && prop.domAttribute) {
15778
+ return { category: "exclude" };
15779
+ }
15780
+ if (isStringLiteralUnion(type)) {
15781
+ return { category: "design", cdfTypeHint: "enum" };
15782
+ }
15783
+ if (!isComplexType(type)) {
15784
+ const designNameStart = /^(variant|size|spacing|gap|color|bg|theme|align|layout|orientation|position)/i;
15785
+ const designNameEnd = /(Color|Size|Variant|Style)$/;
15786
+ if (designNameStart.test(name) || designNameEnd.test(name)) {
15787
+ return { category: "design", cdfTypeHint: "string" };
15788
+ }
15789
+ }
15790
+ if (isBooleanType(type)) {
15791
+ const stateNames = ["disabled", "loading", "expanded", "isOpen", "selected", "checked", "active", "preview"];
15792
+ if (stateNames.includes(name)) {
15793
+ return { category: "state", cdfTypeHint: "boolean" };
15794
+ }
15795
+ }
15796
+ if (isBooleanType(type)) {
15797
+ const visualToggle = /^(hide|show|enable|disable|vertical|horizontal|reverse|bold|italic|imageOn|with)/i;
15798
+ if (visualToggle.test(name)) {
15799
+ return { category: "design", cdfTypeHint: "boolean" };
15800
+ }
15801
+ }
15802
+ if (name === "componentId" || name === "sectionKey" || name === "locale" || name === "variantIndex") {
15803
+ return { category: "state", cdfTypeHint: "string" };
15804
+ }
15805
+ if (isStringType(type)) {
15806
+ const urlNameStart = /^(href|url|link|src)/i;
15807
+ const urlNameEnd = /(Url|Href|Link|Src)$/;
15808
+ if (urlNameStart.test(name) || urlNameEnd.test(name)) {
15809
+ return { category: "content", cdfTypeHint: "string" };
15810
+ }
15811
+ }
15812
+ if (isStringType(type)) {
15813
+ const textNameStart = /^(label|title|text|description|caption|heading|subheading|body|alt|name|placeholder|summary)/i;
15814
+ const textNameEnd = /(Text|Label|Title|Name)$/;
15815
+ if (textNameStart.test(name) || textNameEnd.test(name)) {
15816
+ return { category: "content", cdfTypeHint: "string" };
15817
+ }
15818
+ }
15819
+ if (isStringType(type)) {
15820
+ return { category: "content", cdfTypeHint: "string" };
15821
+ }
15822
+ if (isBooleanType(type)) {
15823
+ return { category: "design", cdfTypeHint: "boolean" };
15824
+ }
15825
+ if (isNumberType(type)) {
15826
+ return { category: "design", cdfTypeHint: "string" };
15827
+ }
15828
+ return void 0;
15829
+ }
15830
+ function preClassifyComponent(component) {
15831
+ const props = component.props.flatMap((prop) => {
15832
+ const result = preClassifyProp(prop);
15833
+ if (result?.category === "exclude") {
15834
+ return [];
15835
+ }
15836
+ const { domAttribute: _domAttribute, ...authorableProp } = prop;
15837
+ if (prop.category) {
15838
+ return [authorableProp];
15839
+ }
15840
+ if (!result) {
15841
+ return [authorableProp];
15842
+ }
15843
+ return [
15844
+ {
15845
+ ...authorableProp,
15846
+ category: result.category
15847
+ }
15848
+ ];
15849
+ });
15850
+ return { ...component, props };
15851
+ }
15852
+
16293
15853
  // packages/experience-design-system-backend-pipeline/dist/src/orchestrators/run-extract-and-compose-session/helpers/emit-pre-classification-exclusions.js
16294
15854
  function emitPreClassificationExclusions(extraction, onExclusion) {
16295
15855
  if (!onExclusion)
@@ -28408,7 +27968,7 @@ init_debug_mode_store();
28408
27968
  init_version();
28409
27969
 
28410
27970
  // packages/experience-design-system-cli/src/tui/help/file-locations.ts
28411
- import { join as join25, resolve as resolve27 } from "node:path";
27971
+ import { join as join26, resolve as resolve27 } from "node:path";
28412
27972
  function describeFileLocations({
28413
27973
  contentfulBaseDir,
28414
27974
  debugModeEnabled,
@@ -28417,14 +27977,14 @@ function describeFileLocations({
28417
27977
  if (!debugModeEnabled) {
28418
27978
  return {
28419
27979
  debugLogs: "none while Debug Mode is off",
28420
- importFiles: `${join25("<project>", ".contentful")}/ (tokens.json, components.json)`
27980
+ importFiles: `${join26("<project>", ".contentful")}/ (tokens.json, components.json)`
28421
27981
  };
28422
27982
  }
28423
27983
  const base = contentfulBaseDir ? resolve27(contentfulBaseDir) : "<project>";
28424
- const session = currentSessionDir2 ?? join25(base, ".contentful", "<date>-session-<n>");
27984
+ const session = currentSessionDir2 ?? join26(base, ".contentful", "<date>-session-<n>");
28425
27985
  return {
28426
- debugLogs: join25(session, "debug"),
28427
- importFiles: `${join25(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
27986
+ debugLogs: join26(session, "debug"),
27987
+ importFiles: `${join26(session, "dsi-import-<n>")}/ (tokens.json, components.json)`
28428
27988
  };
28429
27989
  }
28430
27990
 
@@ -29677,51 +29237,74 @@ import { useEffect as useEffect26, useState as useState35 } from "react";
29677
29237
  import { Box as Box50, Text as Text53, useInput as useInput16 } from "ink";
29678
29238
  init_debug_mode_store();
29679
29239
  init_debug_store();
29680
- import { jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
29240
+ import { Fragment as Fragment21, jsx as jsx62, jsxs as jsxs51 } from "react/jsx-runtime";
29241
+ var ROWS = ["enabled", "retentionDays"];
29242
+ var nextRetention = (current) => RETENTION_CHOICES[(RETENTION_CHOICES.indexOf(current) + 1) % RETENTION_CHOICES.length];
29681
29243
  function DebugModeScreen({ onDone }) {
29682
- const [loading, setLoading] = useState35(true);
29683
- const [enabled, setEnabled] = useState35(true);
29244
+ const [setting, setSetting] = useState35(null);
29245
+ const [focus, setFocus] = useState35("enabled");
29684
29246
  useEffect26(() => {
29685
- readDebugModeSetting().then((setting) => {
29686
- setEnabled(setting.enabled);
29687
- setLoading(false);
29247
+ readDebugModeSetting().then((loaded) => {
29248
+ setSetting(loaded);
29688
29249
  startDebugRun({
29689
29250
  flow: "settings/debug-mode",
29690
29251
  step: "01-debug-mode",
29691
29252
  menuOption: "Debug Mode",
29692
- inputs: { enabled: setting.enabled }
29253
+ inputs: { ...loaded }
29693
29254
  });
29694
29255
  });
29695
29256
  }, []);
29257
+ const change = (patch) => {
29258
+ if (!setting) return;
29259
+ setSetting({ ...setting, ...patch });
29260
+ void writeDebugModeSetting(patch);
29261
+ };
29696
29262
  useInput16((input, key) => {
29697
- if (loading) return;
29263
+ if (!setting) return;
29264
+ if (key.upArrow || key.downArrow) {
29265
+ setFocus((current) => ROWS[(ROWS.indexOf(current) + (key.downArrow ? 1 : ROWS.length - 1)) % ROWS.length]);
29266
+ return;
29267
+ }
29698
29268
  if (key.return || input === " ") {
29699
- setEnabled((current) => {
29700
- const next = !current;
29701
- void writeDebugModeSetting({ enabled: next });
29702
- return next;
29703
- });
29269
+ if (focus === "enabled") change({ enabled: !setting.enabled });
29270
+ else change({ retentionDays: nextRetention(setting.retentionDays) });
29704
29271
  return;
29705
29272
  }
29706
29273
  if (key.escape || input === "q") {
29707
- void finishDebugRun({ outputs: { enabled }, status: "success", exitMethod: "saved" });
29274
+ void finishDebugRun({ outputs: { ...setting }, status: "success", exitMethod: "saved" });
29708
29275
  onDone();
29709
29276
  }
29710
29277
  });
29278
+ const marker = (row) => focus === row ? "\u276F" : " ";
29711
29279
  return /* @__PURE__ */ jsxs51(Box50, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [
29712
29280
  /* @__PURE__ */ jsx62(Text53, { bold: true, children: "Settings \u203A Debug Mode" }),
29713
29281
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
29714
- loading ? /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }) : /* @__PURE__ */ jsxs51(Text53, { children: [
29715
- "Debug logging:",
29716
- " ",
29717
- /* @__PURE__ */ jsx62(Text53, { bold: true, color: enabled ? PALETTE.success : PALETTE.muted, children: enabled ? "On" : "Off" })
29718
- ] }),
29282
+ setting ? /* @__PURE__ */ jsxs51(Fragment21, { children: [
29283
+ /* @__PURE__ */ jsxs51(Text53, { children: [
29284
+ marker("enabled"),
29285
+ " Debug logging:",
29286
+ " ",
29287
+ /* @__PURE__ */ jsx62(Text53, { bold: true, color: setting.enabled ? PALETTE.success : PALETTE.muted, children: setting.enabled ? "On" : "Off" })
29288
+ ] }),
29289
+ /* @__PURE__ */ jsxs51(Text53, { children: [
29290
+ marker("retentionDays"),
29291
+ " Delete logs after:",
29292
+ " ",
29293
+ /* @__PURE__ */ jsxs51(Text53, { bold: true, color: PALETTE.accent, children: [
29294
+ setting.retentionDays,
29295
+ " days"
29296
+ ] })
29297
+ ] }),
29298
+ /* @__PURE__ */ jsx62(Text53, { children: " " }),
29299
+ /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Older logs are deleted the next time the CLI starts." })
29300
+ ] }) : /* @__PURE__ */ jsx62(Text53, { color: PALETTE.muted, children: "Loading\u2026" }),
29719
29301
  /* @__PURE__ */ jsx62(Text53, { children: " " }),
29720
29302
  /* @__PURE__ */ jsx62(
29721
29303
  ControlHints,
29722
29304
  {
29723
29305
  hints: [
29724
- { keys: "\u23CE/Space", label: "toggle" },
29306
+ { keys: "\u2191/\u2193", label: "move" },
29307
+ { keys: "\u23CE/Space", label: "change" },
29725
29308
  { keys: "Esc/q", label: "back" }
29726
29309
  ]
29727
29310
  }
@@ -29730,7 +29313,7 @@ function DebugModeScreen({ onDone }) {
29730
29313
  }
29731
29314
 
29732
29315
  // packages/experience-design-system-cli/app.tsx
29733
- import { Fragment as Fragment21, jsx as jsx63 } from "react/jsx-runtime";
29316
+ import { Fragment as Fragment22, jsx as jsx63 } from "react/jsx-runtime";
29734
29317
  function App({ importOptions, inkClear }) {
29735
29318
  const [screen, setScreen] = useState36("start");
29736
29319
  const [importExitCode, setImportExitCode] = useState36();
@@ -29779,7 +29362,7 @@ function App({ importOptions, inkClear }) {
29779
29362
  const launch = { projectPath: projectPath2, tokens, filePaths, ...importOptions };
29780
29363
  const state2 = await inspectTokens({
29781
29364
  rawTokensPath: tokens,
29782
- contentfulDir: join26(resolveUserPath(projectPath2), ".contentful"),
29365
+ contentfulDir: join27(resolveUserPath(projectPath2), ".contentful"),
29783
29366
  cache: importOptions.cache
29784
29367
  });
29785
29368
  if (state2.kind === "cached") {
@@ -29899,7 +29482,7 @@ function App({ importOptions, inkClear }) {
29899
29482
  }
29900
29483
  );
29901
29484
  }
29902
- if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment21, {});
29485
+ if (importDefaults === void 0) return /* @__PURE__ */ jsx63(Fragment22, {});
29903
29486
  if (projectPath === void 0) {
29904
29487
  return /* @__PURE__ */ jsx63(WelcomeScreen, { onContinue: setProjectPath, onQuit: leaveImport, initialPath: importDefaults.componentDir });
29905
29488
  }
@@ -29938,7 +29521,7 @@ function App({ importOptions, inkClear }) {
29938
29521
  }
29939
29522
  );
29940
29523
  }
29941
- return /* @__PURE__ */ jsx63(Fragment21, {});
29524
+ return /* @__PURE__ */ jsx63(Fragment22, {});
29942
29525
  }
29943
29526
  if (scopeRun && scopeFlow) {
29944
29527
  if (scopeFlow.status === "failed") {
@@ -29975,7 +29558,7 @@ function App({ importOptions, inkClear }) {
29975
29558
  }
29976
29559
  );
29977
29560
  }
29978
- return /* @__PURE__ */ jsx63(Fragment21, {});
29561
+ return /* @__PURE__ */ jsx63(Fragment22, {});
29979
29562
  }
29980
29563
  if (pendingLaunch?.cached) {
29981
29564
  return /* @__PURE__ */ jsx63(