@parity-app/cli 0.7.6 → 0.8.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.
@@ -1,7 +1,7 @@
1
1
  import { i as jsonText, o as parseData, r as finiteNumber, s as plainObject } from "./schema-Dp5Jhloe.mjs";
2
- import { B as packageManifest, P as collectCustomProperties, _ as renderSlotOf, c as isMadeValue, f as libraryManifestExtension, g as parseLibraryManifest, h as parseLibraryEdits, l as isSampleElement, o as applyLibraryEdits, u as isSampleRender, z as lengthToPixels } from "./src-BZFjMWhp.mjs";
3
- import { r as readLibraryEdits, s as parseJsonc } from "./src-CdMzjFSa.mjs";
4
- import { a as publishedVersions, n as packageFile, o as repositoryFiles, r as publishedSource } from "./published-CdXoUgfD.mjs";
2
+ import { $ as lengthToPixels, C as isSampleRender, E as renderSlotOf, J as collectCustomProperties, O as valueImports, S as isSampleElement, f as parseLibraryEdits, l as libraryManifestExtension, o as applyLibraryEdits, p as parseLibraryManifest, tt as parseManifest, v as evaluateValue, x as isMadeValue, y as exportOf } from "./src-Ck9A-Gxr.mjs";
3
+ import { r as readLibraryEdits, s as parseJsonc } from "./src-gCnKQqH5.mjs";
4
+ import { a as publishedVersions, l as packageDocument, n as packageFile, o as repositoryFiles, r as publishedSource } from "./published-DYY8_8m9.mjs";
5
5
  import { createRequire } from "node:module";
6
6
  import { mkdir, readFile, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
7
7
  import { basename, dirname, extname, join, posix, relative, resolve, sep } from "node:path";
@@ -86,6 +86,39 @@ function iconVariants(names, variants) {
86
86
  });
87
87
  return result;
88
88
  }
89
+ /** Compares two strings by their UTF-16 code units, as `sort` does without a comparer. */
90
+ function byCodeUnit(a, b) {
91
+ if (a < b) return -1;
92
+ return a > b ? 1 : 0;
93
+ }
94
+ /** Shorter names first, then by code unit: the order an icon's names are tried in for the one to insert. */
95
+ function shorterName(a, b) {
96
+ return a.length - b.length || byCodeUnit(a, b);
97
+ }
98
+ /**
99
+ * A set's icons, each once: the capitalised exports `drawable` accepts, grouped by the value they export, so aliases of
100
+ * one icon (`Heart`, `HeartIcon`) are one group. Each keeps the shortest name the set's pattern matches, and every name
101
+ * it's exported under in the module's order, so aliases the pattern leaves out (Hugeicons' `Gear` and `Cog` for
102
+ * `Settings01Icon`) still find it. A group the pattern matches none of is left out.
103
+ */
104
+ function iconAliases(module, icons, drawable) {
105
+ const pattern = icons?.match ? new RegExp(icons.match) : /^[A-Z]/;
106
+ const excluded = new Set(icons?.exclude);
107
+ const byValue = /* @__PURE__ */ new Map();
108
+ for (const [name, value] of Object.entries(module)) {
109
+ if (!/^[A-Z]/.test(name) || excluded.has(name) || !drawable(value, name)) continue;
110
+ const group = byValue.get(value);
111
+ if (group) group.push(name);
112
+ else byValue.set(value, [name]);
113
+ }
114
+ return [...byValue.values()].flatMap((names) => {
115
+ const name = names.filter((candidate) => pattern.test(candidate)).sort(shorterName)[0];
116
+ return name ? [{
117
+ name,
118
+ names
119
+ }] : [];
120
+ });
121
+ }
89
122
  // ../code/src/checker.ts
90
123
  const probeName = "__parity_probe__.ts";
91
124
  const probeText = "import type { ReactNode } from \"react\"\nexport type ParityNode = ReactNode\n";
@@ -925,7 +958,7 @@ async function findPackage(from, name) {
925
958
  const installedAt = join(folder, "node_modules", name);
926
959
  const text = await readFile(join(installedAt, "package.json"), "utf8").catch(() => void 0);
927
960
  if (text !== void 0) {
928
- const manifest = readManifest(text, join(installedAt, "package.json"));
961
+ const manifest = parseManifest(text, join(installedAt, "package.json"));
929
962
  return {
930
963
  dir: await realpath(installedAt),
931
964
  installedAt,
@@ -941,16 +974,9 @@ async function readPackage(dir) {
941
974
  const text = await readFile(file, "utf8").catch(() => void 0);
942
975
  return text === void 0 ? void 0 : {
943
976
  dir,
944
- manifest: readManifest(text, file)
977
+ manifest: parseManifest(text, file)
945
978
  };
946
979
  }
947
- function readManifest(text, file) {
948
- try {
949
- return parseData(jsonText(packageManifest), text);
950
- } catch (error) {
951
- throw new TypeError(`${file}: ${error instanceof Error ? error.message : String(error)}`);
952
- }
953
- }
954
980
  /** A bare specifier's package and the entry point in it: `@acme/ui/button` is `@acme/ui` and `./button`. */
955
981
  function splitSpecifier(specifier) {
956
982
  const parts = specifier.split("/");
@@ -1156,6 +1182,14 @@ function isFile(path) {
1156
1182
  }
1157
1183
  // ../project/src/styles.ts
1158
1184
  /**
1185
+ * The parts of shadcn's `components.json` Parity reads: the app's stylesheet and the UI kit's import alias. It's
1186
+ * shadcn's file, so the rest passes through unchecked.
1187
+ */
1188
+ const shadcnComponents = z.looseObject({
1189
+ tailwind: z.looseObject({ css: z.string().optional() }).optional(),
1190
+ aliases: z.looseObject({ ui: z.string().optional() }).optional()
1191
+ });
1192
+ /**
1159
1193
  * Where an app keeps its global styles when neither `components.json` nor the entry says: Vite's and Create React App's
1160
1194
  * `src/index.css`, the usual alternatives, and Next's `globals.css`, which its layout imports with no HTML entry.
1161
1195
  */
@@ -1178,8 +1212,8 @@ async function findStyles(root, notes = []) {
1178
1212
  }
1179
1213
  /** `findStyles`, with `components.json` already read. */
1180
1214
  async function stylesWith(root, shadcn, notes) {
1181
- const fromShadcn = field(shadcn, "tailwind", "css");
1182
- if (typeof fromShadcn === "string" && fromShadcn) {
1215
+ const fromShadcn = shadcn?.tailwind?.css;
1216
+ if (fromShadcn) {
1183
1217
  notes.push(`styles from components.json: ${fromShadcn}`);
1184
1218
  return {
1185
1219
  styles: [toPosix(fromShadcn)],
@@ -1246,20 +1280,12 @@ async function shadcnConfig(root, notes) {
1246
1280
  const text = await readText(join(root, "components.json"));
1247
1281
  if (text === void 0) return void 0;
1248
1282
  try {
1249
- return parseJsonc(text);
1283
+ return parseData(shadcnComponents, parseJsonc(text));
1250
1284
  } catch (error) {
1251
1285
  notes.push(`Couldn't load components: ${error instanceof Error ? error.message : String(error)}`);
1252
1286
  return;
1253
1287
  }
1254
1288
  }
1255
- function field(value, ...keys) {
1256
- let current = value;
1257
- for (const key of keys) {
1258
- if (typeof current !== "object" || current === null) return void 0;
1259
- current = current[key];
1260
- }
1261
- return current;
1262
- }
1263
1289
  async function readText(path) {
1264
1290
  return readFile(path, "utf8").catch(() => void 0);
1265
1291
  }
@@ -1297,7 +1323,15 @@ const skipped = /(?:^|\/)(?:node_modules|dist|build|__tests__|test|tests)\//;
1297
1323
  * says why, and generation goes on without them.
1298
1324
  */
1299
1325
  async function fetchExamples(pkg, packageDir, hints = {}, cacheRoot = join(homedir(), ".parity", "cache", "examples")) {
1300
- const upstream = await readUpstream(packageDir);
1326
+ let upstream;
1327
+ try {
1328
+ upstream = await readUpstream(packageDir);
1329
+ } catch (error) {
1330
+ return {
1331
+ files: [],
1332
+ note: `Examples weren't read: ${message$1(error)}`
1333
+ };
1334
+ }
1301
1335
  const repo = normalizeRepo(hints.repo ?? upstream?.repository ?? repositoryOf(pkg));
1302
1336
  if (!repo) return {
1303
1337
  files: [],
@@ -1335,11 +1369,20 @@ async function fetchExamples(pkg, packageDir, hints = {}, cacheRoot = join(homed
1335
1369
  };
1336
1370
  }
1337
1371
  }
1372
+ /** `upstream.json`, which a package built from another's source ships to say which repository and commit. */
1373
+ const upstreamFile = z.looseObject({
1374
+ repository: z.string().optional(),
1375
+ revision: z.string().optional()
1376
+ });
1377
+ /** The package's `upstream.json`, or nothing when it has none. Throws, naming the field, when it doesn't match. */
1338
1378
  async function readUpstream(packageDir) {
1379
+ const file = join(packageDir, "upstream.json");
1380
+ const text = await readFile(file, "utf8").catch(() => void 0);
1381
+ if (text === void 0) return void 0;
1339
1382
  try {
1340
- return JSON.parse(await readFile(join(packageDir, "upstream.json"), "utf8"));
1341
- } catch {
1342
- return;
1383
+ return parseData(jsonText(upstreamFile), text);
1384
+ } catch (error) {
1385
+ throw new TypeError(`${file}: ${message$1(error)}`, { cause: error });
1343
1386
  }
1344
1387
  }
1345
1388
  function repositoryOf(pkg) {
@@ -1417,16 +1460,15 @@ async function findCommit(repo, pkg, upstream, cacheRoot) {
1417
1460
  async function npmVersion(pkg) {
1418
1461
  if (!pkg.name || !pkg.version) return void 0;
1419
1462
  try {
1420
- const response = await fetch(`https://registry.npmjs.org/${pkg.name.replace("/", "%2F")}`, {
1421
- headers: { accept: "application/json" },
1463
+ const document = await packageDocument(pkg.name, {
1464
+ full: true,
1422
1465
  signal: AbortSignal.timeout(3e4)
1423
1466
  });
1424
- if (!response.ok) return void 0;
1425
- const packument = await response.json();
1426
- const gitHead = packument.versions?.[pkg.version]?.gitHead;
1467
+ const gitHead = document.versions?.[pkg.version]?.gitHead;
1468
+ const time = document.time?.[pkg.version];
1427
1469
  return {
1428
1470
  ...gitHead ? { gitHead } : {},
1429
- ...packument.time?.[pkg.version] ? { time: packument.time[pkg.version] } : {}
1471
+ ...typeof time === "string" ? { time } : {}
1430
1472
  };
1431
1473
  } catch {
1432
1474
  return;
@@ -1575,7 +1617,7 @@ function methodCallsOn(files, sourceOf, pkg, reexported) {
1575
1617
  const context = {
1576
1618
  source,
1577
1619
  resolve: () => void 0,
1578
- scope: declarations(source),
1620
+ scope: declarations$1(source),
1579
1621
  env: /* @__PURE__ */ new Map(),
1580
1622
  ...pkg ? { imports: packageImports(source, pkg, reexported) } : {}
1581
1623
  };
@@ -1698,7 +1740,7 @@ function readSource(source, uses, base, family, setBy, pkg, imported = /* @__PUR
1698
1740
  const context = {
1699
1741
  source,
1700
1742
  resolve,
1701
- scope: declarations(source),
1743
+ scope: declarations$1(source),
1702
1744
  env: /* @__PURE__ */ new Map(),
1703
1745
  wrapping,
1704
1746
  ...pkg ? { imports: packageImports(source, pkg, reexported) } : {},
@@ -2094,7 +2136,7 @@ function bind(name, value, env) {
2094
2136
  });
2095
2137
  }
2096
2138
  /** What each name a file declares is set to: `const x = ...`, and `const [x] = useState(...)`'s first value. */
2097
- function declarations(source) {
2139
+ function declarations$1(source) {
2098
2140
  const scope = /* @__PURE__ */ new Map();
2099
2141
  const visit = (node) => {
2100
2142
  if (ts.isVariableDeclaration(node) && node.initializer) {
@@ -2189,7 +2231,7 @@ function exampleItem(files, values) {
2189
2231
  const item = hookItem(source, values, {
2190
2232
  source,
2191
2233
  resolve: () => void 0,
2192
- scope: declarations(source),
2234
+ scope: declarations$1(source),
2193
2235
  env: /* @__PURE__ */ new Map()
2194
2236
  });
2195
2237
  if (item && Object.keys(item).length > Object.keys(best ?? {}).length) best = item;
@@ -2801,16 +2843,15 @@ function preferredExports(typesFile, groups, usable) {
2801
2843
  declared: target.name === symbol.name
2802
2844
  });
2803
2845
  }
2804
- const shortest = (a, b) => a.length - b.length || byCodeUnit$1(a, b);
2805
2846
  const preferred = [];
2806
2847
  for (const group of groups) {
2807
2848
  const names = group.filter(usable);
2808
- const fallback = [...names].sort(shortest)[0];
2849
+ const fallback = [...names].sort(shorterName)[0];
2809
2850
  const rank = (name) => {
2810
2851
  const mark = marks.get(name);
2811
2852
  return (mark?.deprecated ? 2 : 0) + (mark?.declared === false ? 1 : 0);
2812
2853
  };
2813
- const best = [...names].sort((a, b) => rank(a) - rank(b) || shortest(a, b))[0];
2854
+ const best = [...names].sort((a, b) => rank(a) - rank(b) || shorterName(a, b))[0];
2814
2855
  if (best && best !== fallback) preferred.push(best);
2815
2856
  }
2816
2857
  return preferred.sort();
@@ -2823,11 +2864,6 @@ function typesFor(specifier, from) {
2823
2864
  }, ts.sys).resolvedModule?.resolvedFileName;
2824
2865
  return resolved && /\.d\.[cm]?ts$/.test(resolved) ? resolved : void 0;
2825
2866
  }
2826
- /** Compares two strings by their UTF-16 code units, as `sort` does without a comparer. */
2827
- function byCodeUnit$1(a, b) {
2828
- if (a < b) return -1;
2829
- return a > b ? 1 : 0;
2830
- }
2831
2867
  // ../libgen/src/icon-styles.ts
2832
2868
  /** How many of a set's icons are drawn from each module to tell its styles apart. */
2833
2869
  const sampled = 5;
@@ -3183,6 +3219,7 @@ async function relateParts(load, specifier, components, providers = [], edits =
3183
3219
  note: "Parts weren't tried: React's server renderer wasn't found."
3184
3220
  };
3185
3221
  const byName = new Map(components.map((component) => [component.name, component]));
3222
+ const host = await trialHost(load, [...valueImports(providers.map((provider) => provider.props)), ...valueImports([...examples.values()].map((use) => use.sample), "sample")]);
3186
3223
  const wrappers = [];
3187
3224
  for (const provider of providers) {
3188
3225
  byName.delete(provider.component);
@@ -3191,7 +3228,7 @@ async function relateParts(load, specifier, components, providers = [], edits =
3191
3228
  for (const part of provider.component.split(".")) found = found?.[part];
3192
3229
  if (found) wrappers.push({
3193
3230
  type: found,
3194
- props: await trialValue(load, provider.props ?? {})
3231
+ props: evaluateValue(provider.props ?? {}, host)
3195
3232
  });
3196
3233
  } catch {}
3197
3234
  }
@@ -3229,7 +3266,7 @@ async function relateParts(load, specifier, components, providers = [], edits =
3229
3266
  for (const use of examples.values()) for (const call of callsIn(use.sample)) {
3230
3267
  const key = JSON.stringify(call);
3231
3268
  if (!byCall.has(key)) try {
3232
- byCall.set(key, await trialValue(load, call));
3269
+ byCall.set(key, evaluateValue(call, host, "sample"));
3233
3270
  } catch {
3234
3271
  byCall.set(key, void 0);
3235
3272
  }
@@ -4020,48 +4057,28 @@ function spelledOut(children, name) {
4020
4057
  }
4021
4058
  }
4022
4059
  /**
4023
- * A decorator's value outside a frame, for trying parts on the server: imports and calls are made, a mode's value is
4024
- * its default, and the frame's own nodes are left undefined, as there's no frame. Direction and language take the
4025
- * frame's defaults.
4060
+ * What values are worked out against outside a frame, for trying parts on the server: the modules they import, loaded
4061
+ * first, since evaluating is synchronous, a mode's value is its default, and the frame's own nodes are undefined, as there's no frame. Direction and
4062
+ * language take the frame's defaults. A module Node loads as CommonJS without a `default` is its own default export.
4026
4063
  */
4027
- async function trialValue(load, value) {
4028
- if (Array.isArray(value)) return Promise.all(value.map((item) => trialValue(load, item)));
4029
- if (typeof value !== "object" || value === null) return value;
4030
- const record = value;
4031
- if (typeof record.$import === "string") return exported(await load(record.$import), String(record.export ?? "default"));
4032
- if (typeof record.$call === "object" && record.$call !== null) {
4033
- const call = record.$call;
4034
- const fn = exported(await load(call.import), call.export ?? "default");
4035
- const args = await trialValue(load, record.args ?? []);
4036
- if (typeof fn !== "function") return void 0;
4037
- const made = fn(...args);
4038
- for (const step of record.methods ?? []) {
4039
- const method = made?.[step.method];
4040
- if (typeof method !== "function") continue;
4041
- const args = await trialValue(load, step.args ?? []);
4042
- try {
4043
- method.apply(made, args);
4044
- } catch {}
4045
- }
4046
- return made;
4047
- }
4048
- if (typeof record.$global === "string") return trialValue(load, record.default);
4049
- if (typeof record.$frame === "string") {
4050
- if (record.$frame === "dir") return "ltr";
4051
- return record.$frame === "lang" ? "en-US" : void 0;
4052
- }
4053
- if ("$function" in record) {
4054
- const result = await trialValue(load, record.$function);
4055
- return () => result;
4056
- }
4057
- const resolved = {};
4058
- for (const [key, item] of Object.entries(record)) resolved[key] = await trialValue(load, item);
4059
- return resolved;
4060
- }
4061
- function exported(module, name) {
4062
- let found = module;
4063
- for (const part of name.split(".")) found = found?.[part];
4064
- return found ?? (name === "default" ? module : void 0);
4064
+ async function trialHost(load, imports) {
4065
+ const modules = /* @__PURE__ */ new Map();
4066
+ for (const specifier of new Set(imports)) try {
4067
+ modules.set(specifier, await load(specifier));
4068
+ } catch {}
4069
+ return {
4070
+ exported(specifier, path) {
4071
+ const module = modules.get(specifier);
4072
+ if (!module) throw new Error(`${specifier} isn't loaded`);
4073
+ return exportOf(module, path) ?? (path === "default" ? module : void 0);
4074
+ },
4075
+ global: () => void 0,
4076
+ frame: (part) => ({
4077
+ dir: "ltr",
4078
+ lang: "en-US"
4079
+ })[part],
4080
+ made: /* @__PURE__ */ new Map()
4081
+ };
4065
4082
  }
4066
4083
  /** The parts the package puts inside another, as sample children, keeping only those it exports. */
4067
4084
  function exportedChildren(children, names) {
@@ -4079,6 +4096,38 @@ function componentsIn(children) {
4079
4096
  return children.flatMap((child) => typeof child === "object" && "component" in child ? [child.component, ...componentsIn(child.children ?? [])] : []);
4080
4097
  }
4081
4098
  // ../libgen/src/presets.ts
4099
+ /** A function, which a theme object's schema can only check is one. */
4100
+ const callable = z.custom((value) => typeof value === "function", "expected a function");
4101
+ /** Custom properties by name, as a stylesheet object holds them. */
4102
+ const declarations = z.record(z.string(), z.unknown());
4103
+ /** What libgen reads of MUI: `createTheme`, and the stylesheets and theme it makes. */
4104
+ const muiStyles = z.looseObject({ createTheme: callable });
4105
+ const muiVariablesTheme = z.looseObject({ generateStyleSheets: callable });
4106
+ const muiStyleSheets = z.array(z.record(z.string(), declarations));
4107
+ const muiPlainTheme = z.looseObject({
4108
+ breakpoints: z.looseObject({ values: z.record(z.string(), z.number()) }),
4109
+ typography: z.record(z.string(), z.unknown())
4110
+ });
4111
+ /** A typography variant; the theme's other entries, such as `pxToRem` and `fontSize`, aren't objects. */
4112
+ const muiVariant = z.looseObject({
4113
+ fontSize: z.unknown(),
4114
+ lineHeight: z.unknown()
4115
+ });
4116
+ /** What libgen reads of Chakra: its default system's token stylesheet. */
4117
+ const chakraModule = z.looseObject({ defaultSystem: z.looseObject({ getTokenCss: callable }) });
4118
+ /** What libgen reads of Fluent: each theme's tokens, where it exports them. */
4119
+ const fluentTheme = z.record(z.string(), z.union([z.string(), z.number()])).optional();
4120
+ /**
4121
+ * Checks a theme object libgen reads by running the library, so a change in the library names the field it moved,
4122
+ * as `MUI's createTheme(): /breakpoints/values/sm: expected a number`.
4123
+ */
4124
+ function readTheme(what, schema, value) {
4125
+ try {
4126
+ return parseData(schema, value);
4127
+ } catch (error) {
4128
+ throw new TypeError(`${what}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
4129
+ }
4130
+ }
4082
4131
  const createTheme = {
4083
4132
  import: "@mui/material/styles",
4084
4133
  export: "createTheme"
@@ -4246,18 +4295,20 @@ const presets = {
4246
4295
  } }
4247
4296
  ],
4248
4297
  async theme(load) {
4249
- const make = (await load("@mui/material/styles")).createTheme;
4250
- const theme = make({
4298
+ const { createTheme } = readTheme("@mui/material/styles", muiStyles, await load("@mui/material/styles"));
4299
+ const make = createTheme;
4300
+ const theme = readTheme("MUI's createTheme()", muiVariablesTheme, make({
4251
4301
  cssVariables: { colorSchemeSelector: "class" },
4252
4302
  colorSchemes: {
4253
4303
  light: true,
4254
4304
  dark: true
4255
4305
  }
4256
- });
4306
+ }));
4307
+ const sheets = readTheme("MUI's generateStyleSheets()", muiStyleSheets, theme.generateStyleSheets());
4257
4308
  const tokens = /* @__PURE__ */ new Map();
4258
- for (const sheet of theme.generateStyleSheets()) for (const [selector, declarations] of Object.entries(sheet)) {
4309
+ for (const sheet of sheets) for (const [selector, properties] of Object.entries(sheet)) {
4259
4310
  const context = /\bdark\b/.test(selector) ? "dark" : "default";
4260
- for (const [name, value] of Object.entries(declarations)) {
4311
+ for (const [name, value] of Object.entries(properties)) {
4261
4312
  if (!name.startsWith("--") || typeof value !== "string" && typeof value !== "number") continue;
4262
4313
  const property = name.slice(2);
4263
4314
  if (/Channel$|Opacity$/.test(property)) continue;
@@ -4276,7 +4327,7 @@ const presets = {
4276
4327
  category: "spacing",
4277
4328
  values: { default: unit }
4278
4329
  });
4279
- const plain = make({});
4330
+ const plain = readTheme("MUI's createTheme()", muiPlainTheme, make({}));
4280
4331
  const breakpoints = plain.breakpoints.values;
4281
4332
  for (const [id, width] of Object.entries(breakpoints)) if (width > 0) tokens.set(`mui-breakpoint-${id}`, {
4282
4333
  var: `mui-breakpoint-${id}`,
@@ -4284,7 +4335,9 @@ const presets = {
4284
4335
  values: { default: `${width}px` }
4285
4336
  });
4286
4337
  for (const [variant, style] of Object.entries(plain.typography)) {
4287
- const { fontSize, lineHeight } = style ?? {};
4338
+ const read = muiVariant.safeParse(style);
4339
+ if (!read.success) continue;
4340
+ const { fontSize, lineHeight } = read.data;
4288
4341
  if (typeof fontSize !== "string") continue;
4289
4342
  const size = `mui-font-size-${variant}`;
4290
4343
  const leading = `mui-line-height-${variant}`;
@@ -4355,7 +4408,7 @@ const presets = {
4355
4408
  ],
4356
4409
  notes: ["Chakra's Toaster is a snippet the app generates (`npx @chakra-ui/cli snippet add toaster`), not an export."],
4357
4410
  async theme(load) {
4358
- const system = (await load("@chakra-ui/react")).defaultSystem;
4411
+ const system = readTheme("@chakra-ui/react", chakraModule, await load("@chakra-ui/react")).defaultSystem;
4359
4412
  const tokens = /* @__PURE__ */ new Map();
4360
4413
  const visit = (styles, context) => {
4361
4414
  if (typeof styles !== "object" || styles === null) return;
@@ -4370,7 +4423,7 @@ const presets = {
4370
4423
  tokens.set(property, token);
4371
4424
  } else visit(value, /\bdark\b/.test(key) ? "dark" : context);
4372
4425
  };
4373
- visit(system.getTokenCss(), "default");
4426
+ visit(readTheme("Chakra's getTokenCss()", declarations, system.getTokenCss()), "default");
4374
4427
  const unit = tokens.get("chakra-spacing-1")?.values.default;
4375
4428
  if (unit) tokens.set("spacing", {
4376
4429
  var: "spacing",
@@ -4452,7 +4505,7 @@ const presets = {
4452
4505
  const fluent = await load("@fluentui/tokens");
4453
4506
  const tokens = /* @__PURE__ */ new Map();
4454
4507
  for (const [context, name] of Object.entries(fluentThemes)) {
4455
- const theme = fluent[name];
4508
+ const theme = readTheme(`@fluentui/tokens' ${name}`, fluentTheme, fluent[name]);
4456
4509
  if (!theme) continue;
4457
4510
  for (const [property, value] of Object.entries(theme)) {
4458
4511
  const token = tokens.get(property) ?? {
@@ -5032,7 +5085,8 @@ async function describePackage(options, importName) {
5032
5085
  async function reviseLibrary(generated, options) {
5033
5086
  const manifest = { ...generated.manifest };
5034
5087
  const report = { ...generated.report };
5035
- const previous = previousComponents(options.previous);
5088
+ const read = readPrevious(options.previous);
5089
+ const previous = read?.manifest.components?.list;
5036
5090
  const components = manifest.components;
5037
5091
  if (previous && components) {
5038
5092
  report.changes = compareComponents(previous, components.list);
@@ -5041,7 +5095,7 @@ async function reviseLibrary(generated, options) {
5041
5095
  list: selectComponents(previous, components.list, report.changes, options.only ?? "all")
5042
5096
  };
5043
5097
  }
5044
- const kept = options.previous?.edits;
5098
+ const kept = read?.file.edits;
5045
5099
  const edits = options.edits ?? kept;
5046
5100
  if (edits !== void 0) {
5047
5101
  manifest.edits = edits;
@@ -5054,12 +5108,21 @@ async function reviseLibrary(generated, options) {
5054
5108
  report
5055
5109
  };
5056
5110
  }
5057
- function previousComponents(previous) {
5058
- if (typeof previous !== "object" || previous === null) return void 0;
5111
+ /**
5112
+ * The library file being regenerated, read through the library schema (PAR-594), and the file's own object, whose
5113
+ * edits and authored fields are kept as written. One that doesn't read stops generation, naming the field, since
5114
+ * writing over it would lose what a person wrote there.
5115
+ */
5116
+ function readPrevious(previous) {
5117
+ if (previous === void 0) return void 0;
5059
5118
  try {
5060
- return parseLibraryManifest(previous).components?.list;
5061
- } catch {
5062
- return;
5119
+ return {
5120
+ manifest: parseLibraryManifest(previous),
5121
+ file: parseData(plainObject, previous)
5122
+ };
5123
+ } catch (error) {
5124
+ const reason = error instanceof Error ? error.message : String(error);
5125
+ throw new TypeError(`The library file being replaced doesn't read, so fix or delete it first: ${reason}`, { cause: error });
5063
5126
  }
5064
5127
  }
5065
5128
  /**
@@ -5200,8 +5263,8 @@ async function appManifestPath(root) {
5200
5263
  * what a person wrote (the canvas, decorators, a name or description) stays.
5201
5264
  */
5202
5265
  function mergeManifest(existing, generated) {
5203
- if (typeof existing !== "object" || existing === null) return generated;
5204
- const kept = existing;
5266
+ const kept = readPrevious(existing)?.file;
5267
+ if (!kept) return generated;
5205
5268
  const authored = [
5206
5269
  "$schema",
5207
5270
  "id",
@@ -5254,6 +5317,8 @@ function defaultRange(version) {
5254
5317
  const [major = "0", minor = "0"] = version.split(/[.-]/);
5255
5318
  return major === "0" ? `^0.${minor}.0` : `^${major}.0.0`;
5256
5319
  }
5320
+ /** A DTCG token file or resolver: a JSON object, with a resolver's `resolutionOrder` a list. */
5321
+ const tokenFile = jsonText(plainObject.pipe(z.looseObject({ resolutionOrder: z.array(z.unknown()).optional() })));
5257
5322
  /** A DTCG token file the package ships, if it has one in the format; Buildkit's `tokens.json` isn't yet. */
5258
5323
  async function dtcgIn(dir) {
5259
5324
  for (const candidate of [
@@ -5264,13 +5329,11 @@ async function dtcgIn(dir) {
5264
5329
  ]) {
5265
5330
  const text = await readFile(join(dir, candidate), "utf8").catch(() => void 0);
5266
5331
  if (!text) continue;
5267
- try {
5268
- const parsed = JSON.parse(text);
5269
- if (Array.isArray(parsed.resolutionOrder) || /"\$value"\s*:/.test(text)) return {
5270
- path: candidate,
5271
- tokens: parsed
5272
- };
5273
- } catch {}
5332
+ const parsed = tokenFile.safeParse(text).data;
5333
+ if (parsed && (parsed.resolutionOrder !== void 0 || /"\$value"\s*:/.test(text))) return {
5334
+ path: candidate,
5335
+ tokens: parsed
5336
+ };
5274
5337
  }
5275
5338
  }
5276
5339
  /** The prefix most custom properties share, as in `mantine-`, which token paths leave out. */
@@ -5290,23 +5353,8 @@ function commonPrefix(names) {
5290
5353
  */
5291
5354
  async function exportedIcons(load, specifier, icons) {
5292
5355
  const module = await load(specifier).catch(() => ({}));
5293
- const pattern = icons.match ? new RegExp(icons.match) : /^[A-Z]/;
5294
- const excluded = new Set(icons.exclude);
5295
5356
  const drawable = (value) => icons.render !== "export" ? value !== void 0 && typeof value !== "function" : typeof value === "function" || typeof value === "object" && value !== null && "$$typeof" in value;
5296
- const byValue = /* @__PURE__ */ new Map();
5297
- for (const [key, value] of Object.entries(module)) {
5298
- if (!/^[A-Z]/.test(key) || excluded.has(key) || !drawable(value)) continue;
5299
- const names = byValue.get(value);
5300
- if (names) names.push(key);
5301
- else byValue.set(value, [key]);
5302
- }
5303
- const kept = [...byValue.values()].flatMap((names) => {
5304
- const name = names.filter((candidate) => pattern.test(candidate)).sort((a, b) => a.length - b.length || byCodeUnit(a, b))[0];
5305
- return name ? [{
5306
- name,
5307
- names
5308
- }] : [];
5309
- });
5357
+ const kept = iconAliases(module, icons, drawable);
5310
5358
  const read = icons.variants?.pattern ? iconVariants(kept.map(({ name }) => name), icons.variants) : void 0;
5311
5359
  const byLabel = /* @__PURE__ */ new Map();
5312
5360
  for (const { name, names } of kept) {
@@ -5324,11 +5372,6 @@ async function exportedIcons(load, specifier, icons) {
5324
5372
  groups: kept.map(({ names }) => names)
5325
5373
  };
5326
5374
  }
5327
- /** Compares two strings by their UTF-16 code units, as `sort` does without a comparer. */
5328
- function byCodeUnit(a, b) {
5329
- if (a < b) return -1;
5330
- return a > b ? 1 : 0;
5331
- }
5332
5375
  /** Draws an icon with the project's own React, to tell a set's styles apart; nothing draws where React can't load. */
5333
5376
  async function iconDrawer(load) {
5334
5377
  try {
@@ -5388,4 +5431,4 @@ async function resolveImport(from, specifier) {
5388
5431
  const installed = await findPackage(from, name);
5389
5432
  return installed && packageEntry(installed, "runtime", subpath);
5390
5433
  }
5391
- export { appManifestPath, generateLibrary, manifestText, mergeManifest, parseLibraryEdits, reviseLibrary, iconVariants as t };
5434
+ export { appManifestPath, generateLibrary, shorterName as i, manifestText, mergeManifest, iconAliases as n, parseLibraryEdits, iconVariants as r, reviseLibrary, byCodeUnit as t };
@@ -1 +1 @@
1
- export { t as covers, n as newestEntries, i as registryDir, a as registryEntries } from "./src-CdMzjFSa.mjs";
1
+ export { t as covers, n as newestEntries, i as registryDir, a as registryEntries } from "./src-gCnKQqH5.mjs";
@@ -1,5 +1,5 @@
1
1
  import { n as fileObject, o as parseData } from "./schema-Dp5Jhloe.mjs";
2
- import { d as libraryManifest, f as libraryManifestExtension, h as parseLibraryEdits, o as applyLibraryEdits, p as libraryPackage } from "./src-BZFjMWhp.mjs";
2
+ import { c as libraryManifest, f as parseLibraryEdits, l as libraryManifestExtension, o as applyLibraryEdits, u as libraryPackage } from "./src-Ck9A-Gxr.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { readFile, readdir } from "node:fs/promises";
5
5
  import { dirname, join, resolve } from "node:path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parity-app/cli",
3
- "version": "0.7.6",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Drive the Parity app from a terminal or an agent: read state, run edits, take screenshots, serve MCP.",
package/skills/execute.md CHANGED
@@ -99,6 +99,15 @@ Overlaps(design?): Overlap[]
99
99
  Print(...values): void
100
100
  ```
101
101
 
102
+ Every function checks its arguments before it does anything. A wrong one fails the call with an `invalid_input` error
103
+ whose path names it, and the message starts with that path:
104
+
105
+ - An option or field by its key: `width`, `style/gap`, `changes/title/text`.
106
+ - A node by `node` (or `root` in `CreateDesign`) and where in it: `node/fontSize: unknown property`.
107
+ - Any other argument by its name: `design`, `path`, `patch`, `nodes`.
108
+
109
+ An option a function doesn't take is an error too, so check its spelling against the list above.
110
+
102
111
  ## Paths
103
112
 
104
113
  A design is named by its id or its name. A node is named by `design/node`, where `node` is the node's id or its name, or
@@ -1,5 +0,0 @@
1
- import "./schema-Dp5Jhloe.mjs";
2
- import "./client-BkLeG26A.mjs";
3
- export { t as componentNode, M as generateId, n as librarySource, i as withLibraryContext } from "./src-BZFjMWhp.mjs";
4
- import "./src-CdMzjFSa.mjs";
5
- import "./src-CMPL5C8p.mjs";