@parity-app/cli 0.6.2 → 0.6.3

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/bin.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { a as CodedError, c as errorDetails, l as readErrorDetails, o as closest, s as errorCodes } from "./schema-zRNxotYl.mjs";
3
- import { a as describeExec, c as describeProps, f as setCaller, i as describeConsole, l as describeStatus, n as describeAccessibility, o as describeModes, p as mcpCallerName, r as describeComponents, s as describeProblems, t as call, u as describeTokens } from "./client-BUaE9b77.mjs";
2
+ import { c as errorCodes, l as errorDetails, o as CodedError, s as closest, u as readErrorDetails } from "./schema-CiVy9tZT.mjs";
3
+ import { a as describeExec, c as describeProps, f as setCaller, i as describeConsole, l as describeStatus, n as describeAccessibility, o as describeModes, p as mcpCallerName, r as describeComponents, s as describeProblems, t as call, u as describeTokens } from "./client-C4An81o9.mjs";
4
4
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
5
5
  import { dirname, join, normalize, relative, resolve, sep } from "node:path";
6
6
  import { parseArgs } from "node:util";
@@ -387,16 +387,11 @@ const executeOperation = {
387
387
  */
388
388
  async function runCheck(library, options) {
389
389
  if (!library) throw new Error("parity lib check <library> [--tab t] [--mode m]");
390
- const { applyLibraryEdits, componentNode, generateId, librarySource, parseLibraryEdits, withLibraryContext } = await import("./src-BgQ7gnXE.mjs");
391
- const { registryDir, registryEntries } = await import("./src-CiqdFzei.mjs");
392
- const entry = (await registryEntries()).find((item) => item.manifest.id === library);
390
+ const { componentNode, generateId, librarySource, withLibraryContext } = await import("./src-AKjejfTT.mjs");
391
+ const { newestEntries, registryDir } = await import("./src-B40wy5fK.mjs");
392
+ const entry = (await newestEntries()).find((item) => item.manifest.id === library);
393
393
  if (!entry) throw new Error(`The registry has no library "${library}"`);
394
- let manifest = entry.manifest;
395
- if (manifest.edits) {
396
- const edits = typeof manifest.edits === "string" ? parseLibraryEdits(JSON.parse(await readFile(join(dirname(entry.path), manifest.edits), "utf8"))) : manifest.edits;
397
- manifest = applyLibraryEdits(manifest, edits).manifest;
398
- }
399
- const list = manifest.components?.list ?? {};
394
+ const list = entry.manifest.components?.list ?? {};
400
395
  const names = Object.keys(list).filter((name) => list[name].visual !== false);
401
396
  const id = (name) => `${library}/${name}`;
402
397
  const sources = Object.fromEntries(Object.keys(list).map((name) => [id(name), {
@@ -516,8 +511,8 @@ function describeCheck(report) {
516
511
  * because it reads the project's files and its own copy of TypeScript.
517
512
  */
518
513
  async function runLib(packageName, options) {
519
- const { appManifestPath, generateLibrary, manifestText, mergeManifest, reviseLibrary } = await import("./src-BvKhu6dX.mjs");
520
- const { covers, registryDir, registryEntries } = await import("./src-CiqdFzei.mjs");
514
+ const { appManifestPath, generateLibrary, manifestText, mergeManifest, reviseLibrary } = await import("./src-C5-HaJcA.mjs");
515
+ const { covers, registryDir, registryEntries } = await import("./src-B40wy5fK.mjs");
521
516
  const spec = packageName === void 0 ? void 0 : packageSpec(packageName);
522
517
  let root = resolve(options.root ?? ".");
523
518
  if (spec && (spec.version !== void 0 || options.registry && !options.root)) {
@@ -528,7 +523,7 @@ async function runLib(packageName, options) {
528
523
  console.error(`Installing ${spec.name} ${version} on its own…`);
529
524
  root = await installedVersion(spec.name, version);
530
525
  }
531
- const { parseLibraryEdits } = await import("./src-BvKhu6dX.mjs");
526
+ const { parseLibraryEdits } = await import("./src-C5-HaJcA.mjs");
532
527
  const trialEdits = options.edits ? parseLibraryEdits(JSON.parse(await readFile(resolve(options.edits), "utf8"))) : void 0;
533
528
  const recordedId = options.registry && spec ? options.id ?? (await registryEntries()).find((entry) => entry.manifest.package?.name === spec.name)?.manifest.id : void 0;
534
529
  const appErrors = recordedId ? await readAppErrors(registryDir(), recordedId) : void 0;
@@ -1,4 +1,4 @@
1
- import { a as CodedError, l as readErrorDetails, n as jsonText, r as nonBlankString, u as unknownReference } from "./schema-zRNxotYl.mjs";
1
+ import { d as unknownReference, n as jsonText, o as CodedError, r as nonBlankString, u as readErrorDetails } from "./schema-CiVy9tZT.mjs";
2
2
  import { join } from "node:path";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { readFileSync, readdirSync, realpathSync, rmSync } from "node:fs";
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export { t as call, n as describeAccessibility, r as describeComponents, i as describeConsole, a as describeExec, o as describeModes, s as describeProblems, c as describeProps, l as describeStatus, u as describeTokens, d as registry, f as setCaller } from "./client-BUaE9b77.mjs";
1
+ export { t as call, n as describeAccessibility, r as describeComponents, i as describeConsole, a as describeExec, o as describeModes, s as describeProblems, c as describeProps, l as describeStatus, u as describeTokens, d as registry, f as setCaller } from "./client-C4An81o9.mjs";
@@ -0,0 +1,227 @@
1
+ import { z } from "zod";
2
+ // ../core/src/errors.ts
3
+ /**
4
+ * Why an agent's call failed, as a stable code it can act on without reading the message. The CLI and MCP publish
5
+ * these; the app throws them where it knows the cause.
6
+ */
7
+ const errorCodes = [
8
+ "invalid_input",
9
+ "not_running",
10
+ "not_answering",
11
+ "unknown_tab",
12
+ "tab_not_ready",
13
+ "unknown_design",
14
+ "unknown_node",
15
+ "ambiguous_reference",
16
+ "unknown_state",
17
+ "unknown_mode",
18
+ "unknown_viewport",
19
+ "unknown_component",
20
+ "unknown_icon_set",
21
+ "unknown_edit_id",
22
+ "conflict",
23
+ "execution_failed",
24
+ "app_error"
25
+ ];
26
+ /** Details as another process sends them. Each field that's malformed falls back on its own; only the code must hold. */
27
+ const errorDetailsSchema = z.object({
28
+ code: z.enum(errorCodes),
29
+ /** Whether sending the same request again, unchanged, can succeed. */
30
+ retryable: z.boolean().catch(false),
31
+ /** The request field at fault, as a path: `design`, `state`, `edits/0/find`. */
32
+ field: z.string().min(1).optional().catch(void 0),
33
+ /** Valid references to use instead of an unknown or ambiguous one, at most `alternativeLimit` of them. */
34
+ alternatives: z.array(z.unknown()).transform((items) => items.filter((item) => typeof item === "string").slice(0, 20)).optional().catch(void 0)
35
+ });
36
+ /** An error with a stable code, the field it's about and what to use instead. */
37
+ var CodedError = class extends Error {
38
+ details;
39
+ constructor(message, details) {
40
+ super(message);
41
+ this.name = "CodedError";
42
+ this.details = {
43
+ ...details,
44
+ retryable: details.retryable ?? false
45
+ };
46
+ }
47
+ };
48
+ /** An unknown reference, naming the valid ones closest to what was asked for, up to `alternativeLimit`. */
49
+ function unknownReference(code, message, reference, candidates, field) {
50
+ return new CodedError(message, {
51
+ code,
52
+ ...field === void 0 ? {} : { field },
53
+ alternatives: closest(reference, candidates)
54
+ });
55
+ }
56
+ /**
57
+ * Candidates sharing text with the reference first, ignoring case, then the rest by how few single-character edits
58
+ * away they are, so a typo's intended id makes the cut; ties keep their own order. All of them when they fit.
59
+ */
60
+ function closest(reference, candidates, limit = 20) {
61
+ const unique = [...new Set(candidates)];
62
+ if (unique.length <= limit) return unique;
63
+ const wanted = reference.toLowerCase();
64
+ const ranked = unique.map((candidate, index) => {
65
+ const lower = candidate.toLowerCase();
66
+ const near = wanted.length > 0 && (lower.includes(wanted) || wanted.includes(lower));
67
+ return {
68
+ candidate,
69
+ index,
70
+ near: near ? 0 : 1,
71
+ distance: near ? 0 : editDistance(wanted, lower)
72
+ };
73
+ });
74
+ ranked.sort((a, b) => a.near - b.near || a.distance - b.distance || a.index - b.index);
75
+ return ranked.slice(0, limit).map(({ candidate }) => candidate);
76
+ }
77
+ /** How many single-character insertions, deletions or substitutions turn one string into the other. */
78
+ function editDistance(a, b) {
79
+ let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
80
+ for (let i = 1; i <= a.length; i++) {
81
+ const row = [i];
82
+ for (let j = 1; j <= b.length; j++) row[j] = Math.min(previous[j] + 1, row[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
83
+ previous = row;
84
+ }
85
+ return previous[b.length];
86
+ }
87
+ /** A thrown value's details, when it carries them. */
88
+ function errorDetails(error) {
89
+ return error instanceof CodedError ? error.details : void 0;
90
+ }
91
+ /** Details that came from another process, checked before they're trusted. Anything malformed reads as none. */
92
+ function readErrorDetails(value) {
93
+ return errorDetailsSchema.safeParse(value).data;
94
+ }
95
+ // ../core/src/schema.ts
96
+ /**
97
+ * Checks for data Parity didn't make (PAR-578): files, agent input, environment variables, other programs' JSON. A zod
98
+ * schema is both the check and the type. A failed check reads as core's hand-written ones in `validate.ts` do: a JSON
99
+ * pointer to the value at fault, then what was expected there, as in `/containers/0/name: expected a string`.
100
+ */
101
+ /** An object with string keys, and not an array or null. */
102
+ const plainObject = z.record(z.string(), z.unknown());
103
+ /** Text with something besides whitespace, trimmed. */
104
+ const nonBlankString = z.string().trim().min(1, "can't be blank");
105
+ /** A number other than NaN or ±Infinity, which zod 4 refuses on its own. */
106
+ const finiteNumber = z.number();
107
+ /** JSON text holding what `schema` checks. Text that isn't JSON fails as `expected JSON`. */
108
+ function jsonText(schema) {
109
+ return z.string().transform((text, context) => {
110
+ try {
111
+ return JSON.parse(text);
112
+ } catch {
113
+ context.addIssue({
114
+ code: "custom",
115
+ message: "expected JSON"
116
+ });
117
+ return z.NEVER;
118
+ }
119
+ }).pipe(schema);
120
+ }
121
+ /**
122
+ * Checks data Parity didn't make and returns what the schema reads from it, or throws `TypeError` with the first
123
+ * problem as `/json/pointer: message`. `at` is where the value sits in a larger one, so its pointers start there.
124
+ */
125
+ function parseData(schema, value, at = "") {
126
+ const result = schema.safeParse(value, { error: issueText });
127
+ if (result.success) return result.data;
128
+ const { pointer, message } = firstProblem(result.error.issues, at);
129
+ throw new TypeError(`${pointer || "/"}: ${message}`);
130
+ }
131
+ /** A path inside a value as a JSON pointer (RFC 6901): `/edits/0/find`, or `` for the value itself. */
132
+ function jsonPointer(path) {
133
+ return path.map((key) => `/${String(key).replaceAll("~", "~0").replaceAll("/", "~1")}`).join("");
134
+ }
135
+ /**
136
+ * The problem to report from a failed check: its first issue. An unknown property points at that property. A union
137
+ * that no option matched reports the option that came closest, or every type it takes when none got past the value's
138
+ * type. An option for another type of value isn't close, so `{ size: "big" }` against a string or an object with a
139
+ * numeric size reports the size, however many issues the object has.
140
+ */
141
+ function firstProblem(issues, at) {
142
+ const [issue] = issues;
143
+ if (!issue) return {
144
+ pointer: at,
145
+ message: "isn't valid"
146
+ };
147
+ const pointer = at + jsonPointer(issue.path);
148
+ if (issue.code === "unrecognized_keys") return {
149
+ pointer: pointer + jsonPointer(issue.keys.slice(0, 1)),
150
+ message: issue.message
151
+ };
152
+ if (issue.code === "invalid_union" && issue.errors.length > 0) return unionProblem(issue.errors, pointer);
153
+ return {
154
+ pointer,
155
+ message: issue.message
156
+ };
157
+ }
158
+ function unionProblem(options, pointer) {
159
+ const issues = options.flat();
160
+ const shallow = issues.every((issue) => issue.path.length === 0);
161
+ const expected = issues.map(expectation);
162
+ if (shallow && expected.every((text) => text !== void 0)) return {
163
+ pointer,
164
+ message: `expected ${[...new Set(expected)].join(" or ")}`
165
+ };
166
+ const depth = (option) => option[0]?.path.length ?? 0;
167
+ const typed = options.filter((option) => !refusesType(option));
168
+ return firstProblem((typed.length > 0 ? typed : options).reduce((best, option) => option.length < best.length || option.length === best.length && depth(option) > depth(best) ? option : best), pointer);
169
+ }
170
+ /** Whether a union's option failed on the value's type itself, as a string option does for an object. */
171
+ function refusesType(option) {
172
+ const [first] = option;
173
+ return first?.code === "invalid_type" && first.path.length === 0;
174
+ }
175
+ /** What one type or value check wanted, as `a string` or `"row"`; nothing for other checks. */
176
+ function expectation(issue) {
177
+ if (issue.code === "invalid_type") return typeName(issue.expected);
178
+ if (issue.code === "invalid_value") return issue.values.map(literal).join(" or ");
179
+ }
180
+ /** Zod's issues in `validate.ts`'s words. Messages a schema gives itself win, and anything else keeps zod's own. */
181
+ function issueText(issue) {
182
+ switch (issue.code) {
183
+ case "invalid_type": return `expected ${typeName(issue.expected)}`;
184
+ case "invalid_value": return issue.values.length === 1 ? `expected ${literal(issue.values[0])}` : `expected one of ${issue.values.map(literal).join(", ")}`;
185
+ case "unrecognized_keys": return "unknown property";
186
+ case "invalid_union": {
187
+ const options = "options" in issue ? issue.options : void 0;
188
+ return Array.isArray(options) && options.length > 0 ? `expected one of ${options.map(literal).join(", ")}` : void 0;
189
+ }
190
+ case "too_small": return bound("at least", "more than", issue.origin, issue.minimum, issue.inclusive);
191
+ case "too_big": return bound("at most", "less than", issue.origin, issue.maximum, issue.inclusive);
192
+ default: return;
193
+ }
194
+ }
195
+ const typeNames = {
196
+ array: "an array",
197
+ boolean: "true or false",
198
+ int: "a whole number",
199
+ number: "a number",
200
+ object: "an object",
201
+ record: "an object",
202
+ string: "a string",
203
+ tuple: "an array"
204
+ };
205
+ function typeName(expected) {
206
+ return typeNames[expected] ?? expected;
207
+ }
208
+ function literal(value) {
209
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
210
+ }
211
+ const units = {
212
+ string: "character",
213
+ array: "item",
214
+ set: "item"
215
+ };
216
+ /** A size or range check's limit, as `expected at least 1 item` or `expected less than 10`. */
217
+ function bound(inclusiveWords, exclusiveWords, origin, limit, inclusive = true) {
218
+ const words = inclusive ? inclusiveWords : exclusiveWords;
219
+ const unit = units[origin];
220
+ if (unit) return `expected ${words} ${limit} ${unit}${Number(limit) === 1 ? "" : "s"}`;
221
+ return [
222
+ "number",
223
+ "int",
224
+ "bigint"
225
+ ].includes(origin) ? `expected ${words} ${limit}` : void 0;
226
+ }
227
+ export { plainObject as a, errorCodes as c, unknownReference as d, parseData as i, errorDetails as l, jsonText as n, CodedError as o, nonBlankString as r, closest as s, finiteNumber as t, readErrorDetails as u };
@@ -0,0 +1,4 @@
1
+ import "./schema-CiVy9tZT.mjs";
2
+ export { t as componentNode, T as generateId, n as librarySource, i as withLibraryContext } from "./src-YQY8r4mh.mjs";
3
+ import "./src-DzU4U2rh.mjs";
4
+ import "./src-C5-HaJcA.mjs";
@@ -0,0 +1 @@
1
+ export { t as covers, n as newestEntries, i as registryDir, a as registryEntries } from "./src-DzU4U2rh.mjs";
@@ -1,13 +1,13 @@
1
- import { i as plainObject, t as finiteNumber } from "./schema-zRNxotYl.mjs";
2
- import { D as collectCustomProperties, a as applyLibraryEdits, c as isSampleElement, f as parseLibraryEdits, j as lengthToPixels, l as isSampleRender, m as renderSlotOf, p as parseLibraryManifest, s as isMadeValue, u as libraryManifestExtension } from "./src-V9wTMkxO.mjs";
3
- import "./src-BIVDlIGc.mjs";
1
+ import { a as plainObject, i as parseData, n as jsonText, t as finiteNumber } from "./schema-CiVy9tZT.mjs";
2
+ import { D as collectCustomProperties, M as packageManifest, a as applyLibraryEdits, c as isSampleElement, f as parseLibraryEdits, j as lengthToPixels, l as isSampleRender, m as renderSlotOf, p as parseLibraryManifest, s as isMadeValue, u as libraryManifestExtension } from "./src-YQY8r4mh.mjs";
3
+ import { r as readLibraryEdits, s as parseJsonc } from "./src-DzU4U2rh.mjs";
4
4
  import { a as publishedVersions, n as packageFile, o as repositoryFiles, r as publishedSource } from "./published-CdXoUgfD.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";
8
8
  import { promisify } from "node:util";
9
9
  import { createHash } from "node:crypto";
10
- import { existsSync, realpathSync } from "node:fs";
10
+ import { existsSync, realpathSync, statSync } from "node:fs";
11
11
  import { homedir } from "node:os";
12
12
  import { z } from "zod";
13
13
  import { pathToFileURL } from "node:url";
@@ -528,28 +528,6 @@ function slashes(path) {
528
528
  return path.replaceAll("\\", "/");
529
529
  }
530
530
  ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.NonPrimitive | ts.TypeFlags.TypeParameter;
531
- // ../project/src/jsonc.ts
532
- /** Parses JSON with comments and trailing commas, as tsconfig files allow. Comment markers inside strings are kept. */
533
- function parseJsonc(text) {
534
- let output = "";
535
- let index = 0;
536
- while (index < text.length) {
537
- const char = text[index];
538
- if (char === "\"") {
539
- const start = index++;
540
- while (index < text.length && text[index] !== "\"") index += text[index] === "\\" ? 2 : 1;
541
- output += text.slice(start, ++index);
542
- } else if (char === "/" && text[index + 1] === "/") while (index < text.length && text[index] !== "\n") index++;
543
- else if (char === "/" && text[index + 1] === "*") {
544
- const end = text.indexOf("*/", index + 2);
545
- index = end === -1 ? text.length : end + 2;
546
- } else {
547
- output += char;
548
- index++;
549
- }
550
- }
551
- return JSON.parse(output.replace(/,(\s*[}\]])/g, "$1"));
552
- }
553
531
  // ../tokens/src/dtcg-values.ts
554
532
  /** A value written as CSS. */
555
533
  const css = z.string();
@@ -935,6 +913,247 @@ new Intl.Collator("en", {
935
913
  numeric: true,
936
914
  sensitivity: "base"
937
915
  });
916
+ // ../project/src/packages.ts
917
+ /**
918
+ * The package a folder's code gets for `name`, found the way Node finds packages: in `node_modules` here or in a folder
919
+ * above, with links followed. It reads the package's own package.json, which its `exports` may leave out of reach of
920
+ * `require.resolve`, and never falls back to NODE_PATH, which pnpm's bin shims point at Parity's own dependencies.
921
+ * Throws when the manifest isn't a package's.
922
+ */
923
+ async function findPackage(from, name) {
924
+ for (let folder = resolve(from);; folder = dirname(folder)) {
925
+ const installedAt = join(folder, "node_modules", name);
926
+ const text = await readFile(join(installedAt, "package.json"), "utf8").catch(() => void 0);
927
+ if (text !== void 0) {
928
+ const manifest = readManifest(text, join(installedAt, "package.json"));
929
+ return {
930
+ dir: await realpath(installedAt),
931
+ installedAt,
932
+ manifest
933
+ };
934
+ }
935
+ if (dirname(folder) === folder) return void 0;
936
+ }
937
+ }
938
+ /** The package in a folder, or nothing when it has no package.json. Throws when the manifest isn't a package's. */
939
+ async function readPackage(dir) {
940
+ const file = join(dir, "package.json");
941
+ const text = await readFile(file, "utf8").catch(() => void 0);
942
+ return text === void 0 ? void 0 : {
943
+ dir,
944
+ manifest: readManifest(text, file)
945
+ };
946
+ }
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
+ /** A bare specifier's package and the entry point in it: `@acme/ui/button` is `@acme/ui` and `./button`. */
955
+ function splitSpecifier(specifier) {
956
+ const parts = specifier.split("/");
957
+ const length = specifier.startsWith("@") ? 2 : 1;
958
+ const rest = parts.slice(length).join("/");
959
+ return {
960
+ name: parts.slice(0, length).join("/"),
961
+ subpath: rest ? `./${rest}` : "."
962
+ };
963
+ }
964
+ const conditions = {
965
+ types: [
966
+ "types",
967
+ "import",
968
+ "default",
969
+ "require"
970
+ ],
971
+ runtime: [
972
+ "node",
973
+ "import",
974
+ "default"
975
+ ],
976
+ source: [
977
+ "source",
978
+ "types",
979
+ "import",
980
+ "default"
981
+ ],
982
+ style: [
983
+ "style",
984
+ "import",
985
+ "default"
986
+ ]
987
+ };
988
+ /** Which files a target may lead to for each use: declarations for types, anything but them otherwise. */
989
+ const accepts = {
990
+ types: (file) => isDeclaration(file),
991
+ runtime: (file) => !isDeclaration(file),
992
+ source: () => true,
993
+ style: (file) => !isDeclaration(file)
994
+ };
995
+ /**
996
+ * The file one of a package's entry points leads to for a use, or nothing when no file is there. `subpath` is the
997
+ * entry point as `exports` names it: `.` for the package itself, or one such as `./tailwind.css`, which can be written
998
+ * `tailwind.css`. A package that doesn't list an entry point in `exports` is read as older packages are: `types` or
999
+ * `typings` for declarations, `module` or `main` for its module, and `style` for its stylesheet.
1000
+ */
1001
+ function packageEntry(pkg, use, subpath = ".") {
1002
+ const entry = subpath === "." || subpath.startsWith("./") ? subpath : `./${subpath}`;
1003
+ for (const candidate of entryCandidates(pkg.manifest, use, entry)) {
1004
+ const file = candidate && join(pkg.dir, candidate);
1005
+ if (file && isFile(file)) return file;
1006
+ }
1007
+ }
1008
+ function entryCandidates(manifest, use, entry) {
1009
+ const root = entry === ".";
1010
+ const path = entry.slice(2);
1011
+ const exported = exportTarget(manifest.exports, entry, conditions[use], accepts[use]);
1012
+ switch (use) {
1013
+ case "types": return [
1014
+ exported,
1015
+ ...root ? [manifest.types, manifest.typings] : [],
1016
+ ...entryCandidates(manifest, "runtime", entry).map((file) => file && declarationOf(file)),
1017
+ root ? "index.d.ts" : `${path}/index.d.ts`,
1018
+ root ? void 0 : `${path}.d.ts`
1019
+ ];
1020
+ case "runtime": return [
1021
+ exported,
1022
+ ...root ? [manifest.module, ...moduleFiles(manifest.main)] : [],
1023
+ ...root || manifest.exports !== void 0 ? [] : moduleFiles(path)
1024
+ ];
1025
+ case "source": {
1026
+ const named = [exported, ...root ? [
1027
+ manifest.types,
1028
+ manifest.typings,
1029
+ manifest.module,
1030
+ manifest.main
1031
+ ] : []].find((file) => file !== void 0);
1032
+ return [...named && isBuilt(named) ? sourcesOf(named) : [named], ...root ? [
1033
+ "src/index.tsx",
1034
+ "src/index.ts",
1035
+ "src/index.jsx",
1036
+ "src/index.js",
1037
+ "index.tsx",
1038
+ "index.ts"
1039
+ ] : []];
1040
+ }
1041
+ case "style": return root ? [manifest.style, exported] : [exported, path];
1042
+ }
1043
+ }
1044
+ /** A `main` as Node reads it: the file, the file with `.js`, or a folder's `index.js`; `index.js` without one. */
1045
+ function moduleFiles(main) {
1046
+ return main ? [
1047
+ main,
1048
+ `${main}.js`,
1049
+ `${main}/index.js`
1050
+ ] : ["index.js"];
1051
+ }
1052
+ const stylesheetNames = [
1053
+ "tailwind.css",
1054
+ "styles.css",
1055
+ "style.css",
1056
+ "index.css",
1057
+ "theme.css"
1058
+ ];
1059
+ /**
1060
+ * The stylesheet a project imports to use a package, as a path from the package: its `style` field, else the CSS its
1061
+ * `exports` lists, the usual names first. Only one that leads to a file counts.
1062
+ */
1063
+ function packageStylesheet(pkg) {
1064
+ const { style, exports } = pkg.manifest;
1065
+ if (style && isFile(join(pkg.dir, style))) return style;
1066
+ const css = Object.keys(exports === void 0 ? {} : subpaths(exports)).filter((key) => key.endsWith(".css") && !key.includes("*")).map((key) => key.slice(2));
1067
+ const pick = stylesheetNames.find((name) => css.includes(name)) ?? css[0];
1068
+ return pick && packageEntry(pkg, "style", pick) ? pick : void 0;
1069
+ }
1070
+ /** `exports` by subpath: a map as written, or the package's one entry point, which is `.`. */
1071
+ function subpaths(exports) {
1072
+ if (typeof exports !== "object" || exports === null || Array.isArray(exports)) return { ".": exports };
1073
+ return Object.keys(exports).some((key) => key.startsWith(".")) ? exports : { ".": exports };
1074
+ }
1075
+ /**
1076
+ * Where `exports` leads for an entry point under these conditions: the entry point as written, else the longest
1077
+ * pattern that matches it (`./icons/*`), with what `*` stood for put in.
1078
+ */
1079
+ function exportTarget(exports, entry, wanted, accept) {
1080
+ if (exports === void 0) return void 0;
1081
+ const map = subpaths(exports);
1082
+ if (Object.hasOwn(map, entry)) return resolveTarget(map[entry], wanted, accept);
1083
+ let best;
1084
+ for (const key of Object.keys(map)) {
1085
+ const star = key.indexOf("*");
1086
+ if (star === -1) continue;
1087
+ const [prefix, suffix] = [key.slice(0, star), key.slice(star + 1)];
1088
+ if (entry.length < key.length || !entry.startsWith(prefix) || !entry.endsWith(suffix)) continue;
1089
+ if (!best || prefix.length > best.prefix.length) best = {
1090
+ key,
1091
+ prefix,
1092
+ match: entry.slice(prefix.length, entry.length - suffix.length)
1093
+ };
1094
+ }
1095
+ if (!best) return void 0;
1096
+ const { key, match } = best;
1097
+ return resolveTarget(map[key], wanted, (file) => accept(file.replaceAll("*", match)))?.replaceAll("*", match);
1098
+ }
1099
+ /** The first file a target leads to under the wanted conditions, taken in the order they're wanted. */
1100
+ function resolveTarget(target, wanted, accept) {
1101
+ if (typeof target === "string") return accept(target) ? target : void 0;
1102
+ if (target === null) return void 0;
1103
+ if (Array.isArray(target)) {
1104
+ for (const each of target) {
1105
+ const found = resolveTarget(each, wanted, accept);
1106
+ if (found) return found;
1107
+ }
1108
+ return;
1109
+ }
1110
+ for (const condition of wanted) {
1111
+ const found = Object.hasOwn(target, condition) ? resolveTarget(target[condition], wanted, accept) : void 0;
1112
+ if (found) return found;
1113
+ }
1114
+ }
1115
+ function isDeclaration(file) {
1116
+ return /\.d\.[cm]?ts$/.test(file);
1117
+ }
1118
+ /** The declarations TypeScript looks for beside a module: `index.d.ts` for `index.js`, `index.d.mts` for `index.mjs`. */
1119
+ function declarationOf(file) {
1120
+ const match = /\.([cm]?)jsx?$/.exec(file);
1121
+ return match ? `${file.slice(0, match.index)}.d.${match[1]}ts` : void 0;
1122
+ }
1123
+ /** Folders a package's build writes to, which its source isn't in. */
1124
+ const builtFolders = /* @__PURE__ */ new Set([
1125
+ "dist",
1126
+ "build",
1127
+ "lib",
1128
+ "out",
1129
+ "esm",
1130
+ "cjs"
1131
+ ]);
1132
+ /** A file a build wrote: declarations, or anything in a build folder at the package's root. */
1133
+ function isBuilt(file) {
1134
+ return isDeclaration(file) || builtFolders.has(file.replace(/^\.\//, "").split("/")[0]);
1135
+ }
1136
+ const sourceExtensions = [
1137
+ ".tsx",
1138
+ ".ts",
1139
+ ".jsx",
1140
+ ".js"
1141
+ ];
1142
+ /**
1143
+ * Where a built file's source may be, in the order to look: `dist/index.js` and `dist/index.d.ts` were built from
1144
+ * `src/index.tsx`, `src/index.ts`, `src/index.jsx` or `src/index.js`, and `dist/esm/button.js` from `src/button.tsx`.
1145
+ */
1146
+ function sourcesOf(file) {
1147
+ const parts = file.replace(/^\.\//, "").split("/");
1148
+ let start = 0;
1149
+ while (start < parts.length - 1 && builtFolders.has(parts[start])) start++;
1150
+ const rest = parts.slice(start).join("/").replace(/\.d\.[cm]?ts$|\.[cm]?jsx?$/, "");
1151
+ const stem = start > 0 ? `src/${rest}` : rest;
1152
+ return sourceExtensions.map((extension) => stem + extension);
1153
+ }
1154
+ function isFile(path) {
1155
+ return statSync(path, { throwIfNoEntry: false })?.isFile() ?? false;
1156
+ }
938
1157
  // ../project/src/styles.ts
939
1158
  /**
940
1159
  * Where an app keeps its global styles when neither `components.json` nor the entry says: Vite's and Create React App's
@@ -1047,21 +1266,6 @@ async function readText(path) {
1047
1266
  function toPosix(path) {
1048
1267
  return path.replaceAll("\\", "/").replace(/^\.\//, "");
1049
1268
  }
1050
- // ../project/src/libraries.ts
1051
- /**
1052
- * Where a dependency is installed, found the way Node finds packages: in `node_modules` here or in a folder above. It
1053
- * doesn't resolve `<name>/package.json`, because a package whose `exports` leaves that out can't be resolved that way.
1054
- */
1055
- async function installedPackage(root, importName) {
1056
- for (let folder = resolve(root);; folder = dirname(folder)) {
1057
- const candidate = join(folder, "node_modules", importName);
1058
- if (await isFile(join(candidate, "package.json"))) return realpath(candidate);
1059
- if (dirname(folder) === folder) return void 0;
1060
- }
1061
- }
1062
- async function isFile(path) {
1063
- return stat(path).then((stats) => stats.isFile(), () => false);
1064
- }
1065
1269
  /** A sentence that ends this far in is kept whole, rather than its words cut down to the length. */
1066
1270
  const shortestSentence = 20;
1067
1271
  /**
@@ -3924,7 +4128,6 @@ const presets = {
3924
4128
  id: style,
3925
4129
  name: `Shadcn ${style.charAt(0).toUpperCase()}${style.slice(1)}`,
3926
4130
  description: `Every shadcn component on Base UI, in the ${style} style, kept in step with upstream.`,
3927
- styles: "tailwind.css",
3928
4131
  examples: {
3929
4132
  paths: ["apps/v4/examples/base/"],
3930
4133
  anatomy: ["apps/v4/content/docs/components/base/"]
@@ -4627,16 +4830,16 @@ async function generateLibrary(options) {
4627
4830
  }
4628
4831
  async function describePackage(options, importName) {
4629
4832
  const root = resolve(options.root);
4630
- const dir = await installedPackage(root, importName);
4631
- if (!dir) throw new Error(`${importName} isn't installed in ${root}. Install it with the project's package manager first.`);
4632
- const pkg = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
4833
+ const installed = await findPackage(root, importName);
4834
+ if (!installed) throw new Error(`${importName} isn't installed in ${root}. Install it with the project's package manager first.`);
4835
+ const { dir, manifest: pkg } = installed;
4633
4836
  const name = pkg.name ?? importName;
4634
4837
  const version = pkg.version ?? "0.0.0";
4635
4838
  const preset = presets[name];
4636
4839
  const notes = [...preset?.notes ?? []];
4637
4840
  const iconImport = preset?.icons?.import;
4638
4841
  const componentImport = iconImport ?? preset?.components;
4639
- const entry = typesEntry(dir, pkg, componentImport ? subpath(componentImport, name) : ".");
4842
+ const entry = packageEntry(installed, "types", componentImport ? splitSpecifier(componentImport).subpath : ".")?.replaceAll("\\", "/");
4640
4843
  if (!entry) notes.push("No type declarations were found, so no components could be read.");
4641
4844
  const scan = entry ? findComponents({
4642
4845
  entries: [entry],
@@ -4651,8 +4854,9 @@ async function describePackage(options, importName) {
4651
4854
  const dataIcons = preset?.icons?.render !== void 0 && preset.icons.render !== "export";
4652
4855
  const isIcons = preset?.icons !== void 0 || looksLikeIcons(scan);
4653
4856
  const tokens = /* @__PURE__ */ new Map();
4654
- const styles = preset?.styles ?? stylesheetOf(dir, pkg);
4655
- if (styles) for (const token of cssTokens(await readStylesheet(exportedFile(dir, pkg, styles)))) tokens.set(token.var, token);
4857
+ const styles = preset?.styles ?? packageStylesheet(installed);
4858
+ const stylesheet = styles && packageEntry(installed, "style", styles);
4859
+ if (stylesheet) for (const token of cssTokens(await readStylesheet(stylesheet))) tokens.set(token.var, token);
4656
4860
  let breakpoints;
4657
4861
  if (preset?.theme) try {
4658
4862
  const theme = await preset.theme(loader(root, dir));
@@ -4700,7 +4904,7 @@ async function describePackage(options, importName) {
4700
4904
  if (preset?.icons?.variants) icons.variants = preset.icons.variants;
4701
4905
  if (!dataIcons) {
4702
4906
  const load = loader(root, dir);
4703
- const modules = await styleModules(name, typeof pkg.exports === "object" && pkg.exports !== null ? Object.keys(pkg.exports) : [], iconImport ?? name, load, await iconDrawer(load));
4907
+ const modules = await styleModules(name, typeof pkg.exports === "object" && pkg.exports !== null && !Array.isArray(pkg.exports) ? Object.keys(pkg.exports) : [], iconImport ?? name, load, await iconDrawer(load));
4704
4908
  if (modules) {
4705
4909
  const main = Object.keys(modules).find((style) => modules[style] === (iconImport ?? name));
4706
4910
  icons.variants = {
@@ -4841,7 +5045,7 @@ async function reviseLibrary(generated, options) {
4841
5045
  const edits = options.edits ?? kept;
4842
5046
  if (edits !== void 0) {
4843
5047
  manifest.edits = edits;
4844
- const resolved = parseLibraryEdits(typeof edits === "string" ? parseJsonc(await readFile(resolve(options.editsBase ?? options.root, edits), "utf8")) : edits);
5048
+ const resolved = await readLibraryEdits(edits, resolve(options.editsBase ?? options.root));
4845
5049
  const { orphans } = applyLibraryEdits(parseLibraryManifest(manifest), resolved);
4846
5050
  if (orphans.length > 0) report.orphanEdits = orphans;
4847
5051
  }
@@ -4931,7 +5135,7 @@ function summarizeParts(relations) {
4931
5135
  const appExtensions = [".tsx", ".jsx"];
4932
5136
  async function describeApp(options) {
4933
5137
  const root = resolve(options.root);
4934
- const pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
5138
+ const pkg = (await readPackage(root))?.manifest ?? {};
4935
5139
  const notes = [];
4936
5140
  const tsconfig = readTsconfig(root);
4937
5141
  const { files } = await appFiles(root, { componentExtensions: appExtensions }, tsconfig);
@@ -4988,8 +5192,8 @@ async function describeApp(options) {
4988
5192
  async function appManifestPath(root) {
4989
5193
  const existing = (await readdir(root)).find((file) => file.endsWith(libraryManifestExtension));
4990
5194
  if (existing) return join(root, existing);
4991
- const pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
4992
- return join(root, `${(pkg.name ?? basename(root)).replace(/^@[^/]+\//, "")}${libraryManifestExtension}`);
5195
+ const name = (await readPackage(root))?.manifest.name ?? basename(root);
5196
+ return join(root, `${name.replace(/^@[^/]+\//, "")}${libraryManifestExtension}`);
4993
5197
  }
4994
5198
  /**
4995
5199
  * A generated manifest laid over the file already there: what generating finds replaces what it found before, and
@@ -5050,56 +5254,6 @@ function defaultRange(version) {
5050
5254
  const [major = "0", minor = "0"] = version.split(/[.-]/);
5051
5255
  return major === "0" ? `^0.${minor}.0` : `^${major}.0.0`;
5052
5256
  }
5053
- function subpath(specifier, packageName) {
5054
- return specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
5055
- }
5056
- /** The type declarations for one of a package's entry points, from `exports`, else `types`, else `index.d.ts`. */
5057
- function typesEntry(dir, pkg, entry) {
5058
- const exported = typeof pkg.exports === "object" && pkg.exports !== null ? pkg.exports : {};
5059
- const condition = (value) => {
5060
- if (typeof value === "string") return /\.d\.[cm]?ts$/.test(value) ? value : void 0;
5061
- if (typeof value !== "object" || value === null) return void 0;
5062
- const record = value;
5063
- for (const key of [
5064
- "types",
5065
- "import",
5066
- "default",
5067
- "require"
5068
- ]) {
5069
- const found = condition(record[key]);
5070
- if (found) return found;
5071
- }
5072
- };
5073
- const candidates = [
5074
- condition(exported[entry]),
5075
- entry === "." ? pkg.types ?? pkg.typings : void 0,
5076
- entry === "." ? "index.d.ts" : `${entry.slice(2)}/index.d.ts`,
5077
- entry === "." ? void 0 : `${entry.slice(2)}.d.ts`
5078
- ];
5079
- for (const candidate of candidates) if (candidate && existsSync(join(dir, candidate))) return join(dir, candidate).replaceAll("\\", "/");
5080
- }
5081
- /** The stylesheet a project imports to use a package: its `style` field, else the CSS its `exports` list first. */
5082
- function stylesheetOf(dir, pkg) {
5083
- if (pkg.style && existsSync(join(dir, pkg.style))) return pkg.style;
5084
- const css = (typeof pkg.exports === "object" && pkg.exports !== null ? Object.keys(pkg.exports) : []).filter((key) => key.endsWith(".css")).map((key) => key.slice(2));
5085
- const pick = [
5086
- "tailwind.css",
5087
- "styles.css",
5088
- "style.css",
5089
- "index.css",
5090
- "theme.css"
5091
- ].find((name) => css.includes(name)) ?? css[0];
5092
- if (!pick) return void 0;
5093
- const target = pkg.exports[`./${pick}`];
5094
- const file = typeof target === "string" ? target : target?.default;
5095
- return typeof file === "string" && existsSync(join(dir, file)) ? pick : void 0;
5096
- }
5097
- /** The file an export such as `tailwind.css` points at: `dist/tailwind.css` for Buildkit's styles. */
5098
- function exportedFile(dir, pkg, specifier) {
5099
- const target = (typeof pkg.exports === "object" && pkg.exports !== null ? pkg.exports : {})[`./${specifier}`];
5100
- const file = typeof target === "string" ? target : target?.default;
5101
- return join(dir, typeof file === "string" ? file : specifier);
5102
- }
5103
5257
  /** A DTCG token file the package ships, if it has one in the format; Buildkit's `tokens.json` isn't yet. */
5104
5258
  async function dtcgIn(dir) {
5105
5259
  for (const candidate of [
@@ -5230,25 +5384,8 @@ function resolveRequire(from, specifier) {
5230
5384
  }
5231
5385
  /** An ESM-only package's entry, from the `import` condition of its `exports`, which `require` can't see. */
5232
5386
  async function resolveImport(from, specifier) {
5233
- const name = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
5234
- const dir = await installedPackage(from, name);
5235
- if (!dir) return void 0;
5236
- const pkg = JSON.parse(await readFile(join(dir, "package.json"), "utf8"));
5237
- const exported = typeof pkg.exports === "object" && pkg.exports !== null ? pkg.exports : {};
5238
- const pick = (value) => {
5239
- if (typeof value === "string") return /\.d\.[cm]?ts$/.test(value) ? void 0 : value;
5240
- if (typeof value !== "object" || value === null) return void 0;
5241
- const record = value;
5242
- for (const key of [
5243
- "node",
5244
- "import",
5245
- "default"
5246
- ]) {
5247
- const found = pick(record[key]);
5248
- if (found) return found;
5249
- }
5250
- };
5251
- const file = pick(exported[subpath(specifier, name)]) ?? (specifier === name ? pkg.module : void 0);
5252
- return file ? join(dir, file) : void 0;
5387
+ const { name, subpath } = splitSpecifier(specifier);
5388
+ const installed = await findPackage(from, name);
5389
+ return installed && packageEntry(installed, "runtime", subpath);
5253
5390
  }
5254
5391
  export { appManifestPath, generateLibrary, manifestText, mergeManifest, parseLibraryEdits, reviseLibrary, iconVariants as t };
@@ -0,0 +1,129 @@
1
+ import { a as applyLibraryEdits, f as parseLibraryEdits, p as parseLibraryManifest, u as libraryManifestExtension } from "./src-YQY8r4mh.mjs";
2
+ import { createRequire } from "node:module";
3
+ import { readFile, readdir } from "node:fs/promises";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { existsSync } from "node:fs";
6
+ import semver from "semver";
7
+ // ../core/src/jsonc.ts
8
+ /** Parses JSON with comments and trailing commas, as tsconfig files allow. Comment markers inside strings are kept. */
9
+ function parseJsonc(text) {
10
+ let output = "";
11
+ let index = 0;
12
+ while (index < text.length) {
13
+ const char = text[index];
14
+ if (char === "\"") {
15
+ const start = index++;
16
+ while (index < text.length && text[index] !== "\"") index += text[index] === "\\" ? 2 : 1;
17
+ output += text.slice(start, ++index);
18
+ } else if (char === "/" && text[index + 1] === "/") while (index < text.length && text[index] !== "\n") index++;
19
+ else if (char === "/" && text[index + 1] === "*") {
20
+ const end = text.indexOf("*/", index + 2);
21
+ index = end === -1 ? text.length : end + 2;
22
+ } else {
23
+ output += char;
24
+ index++;
25
+ }
26
+ }
27
+ return JSON.parse(output.replace(/,(\s*[}\]])/g, "$1"));
28
+ }
29
+ // ../registry/src/index.ts
30
+ const require = createRequire(import.meta.url);
31
+ /**
32
+ * The folder the registry's files are in. The published CLI bundles this module and ships the files beside it, where
33
+ * the package can't be resolved. Otherwise they're found through the package's own `package.json`, so it's the same
34
+ * whether this module runs from source or bundled into the app.
35
+ */
36
+ function registryDir() {
37
+ const bundled = join(import.meta.dirname, "libraries");
38
+ if (existsSync(bundled)) return bundled;
39
+ return join(dirname(require.resolve("@parity-app/registry/package.json")), "libraries");
40
+ }
41
+ let cache;
42
+ /** Every file in the registry, read once. One that doesn't parse is skipped with a warning. */
43
+ function registryEntries(dir = registryDir()) {
44
+ if (dir !== registryDir()) return readEntries(dir);
45
+ cache ??= readEntries(dir);
46
+ return cache;
47
+ }
48
+ async function readEntries(dir) {
49
+ const files = (await readdir(dir).catch(() => [])).filter((file) => file.endsWith(libraryManifestExtension)).sort();
50
+ const entries = [];
51
+ for (const file of files) {
52
+ const path = join(dir, file);
53
+ try {
54
+ const manifest = parseLibraryManifest(JSON.parse(await readFile(path, "utf8")));
55
+ if (!manifest.package) throw new TypeError("/package: a registry file names the package it describes");
56
+ entries.push({
57
+ file,
58
+ path,
59
+ manifest
60
+ });
61
+ } catch (error) {
62
+ console.warn(`Skipping registry file ${file}: ${errorText(error)}`);
63
+ }
64
+ }
65
+ return entries;
66
+ }
67
+ /**
68
+ * The newest file for each package the registry describes, by the version it was made from, with its hand edits
69
+ * applied. A file whose edits can't be read is used as it is, with a warning.
70
+ */
71
+ async function newestEntries(dir) {
72
+ const newest = /* @__PURE__ */ new Map();
73
+ for (const entry of await registryEntries(dir)) {
74
+ const name = entry.manifest.package.name;
75
+ const current = newest.get(name);
76
+ if (!current || compareGenerated(entry.manifest, current.manifest) > 0) newest.set(name, entry);
77
+ }
78
+ return Promise.all([...newest.values()].map(async (entry) => {
79
+ try {
80
+ return {
81
+ ...entry,
82
+ manifest: (await withEdits(entry.path, entry.manifest)).manifest
83
+ };
84
+ } catch (error) {
85
+ console.warn(`Using registry file ${entry.file} without its edits: ${errorText(error)}`);
86
+ return entry;
87
+ }
88
+ }));
89
+ }
90
+ /**
91
+ * A library file at `path` with its hand edits applied: its own `edits`, or the shared file it names beside it. Edits
92
+ * for exports it doesn't have are its `orphans`, reported rather than dropped silently. Throws when the edits can't be
93
+ * read.
94
+ */
95
+ async function withEdits(path, manifest) {
96
+ if (manifest.edits === void 0) return {
97
+ manifest,
98
+ orphans: []
99
+ };
100
+ return applyLibraryEdits(manifest, await readLibraryEdits(manifest.edits, dirname(path)));
101
+ }
102
+ /**
103
+ * Hand edits as a library file writes them: inline, or the path of a shared file, which is read from `from` and may
104
+ * have comments.
105
+ */
106
+ async function readLibraryEdits(edits, from) {
107
+ return parseLibraryEdits(typeof edits === "string" ? parseJsonc(await readFile(resolve(from, edits), "utf8")) : edits);
108
+ }
109
+ function errorText(error) {
110
+ return error instanceof Error ? error.message : String(error);
111
+ }
112
+ /** Whether a manifest describes this version of its package. A manifest without a range covers every version. */
113
+ function covers(manifest, version) {
114
+ const range = manifest.package?.range;
115
+ if (!range) return true;
116
+ if (!version) return false;
117
+ const parsed = semver.coerce(version, { includePrerelease: true });
118
+ return parsed !== null && semver.satisfies(parsed, range, { includePrerelease: true });
119
+ }
120
+ function compareGenerated(a, b) {
121
+ const left = semver.coerce(a.package?.version);
122
+ const right = semver.coerce(b.package?.version);
123
+ if (!left || !right) {
124
+ if (left) return 1;
125
+ return right ? -1 : 0;
126
+ }
127
+ return semver.compare(left, right);
128
+ }
129
+ export { registryEntries as a, registryDir as i, newestEntries as n, withEdits as o, readLibraryEdits as r, parseJsonc as s, covers as t };
@@ -1,12 +1,34 @@
1
- import "./schema-zRNxotYl.mjs";
1
+ import "./schema-CiVy9tZT.mjs";
2
2
  import { z } from "zod";
3
3
  // ../core/src/adapters.ts
4
4
  const packageVersions = z.record(z.string(), z.string());
5
- z.looseObject({
5
+ const exportsTarget = z.lazy(() => z.union([
6
+ z.string(),
7
+ z.null(),
8
+ z.array(exportsTarget),
9
+ z.record(z.string(), exportsTarget)
10
+ ]));
11
+ /**
12
+ * The parts of a package.json Parity reads: the dependencies adapters detect a stack by, and where an installed
13
+ * package's entry points and a workspace's packages are (PAR-573). It's someone else's file, so the fields Parity
14
+ * doesn't read pass through unchecked.
15
+ */
16
+ const packageManifest = z.looseObject({
6
17
  name: z.string().optional(),
18
+ version: z.string().optional(),
7
19
  dependencies: packageVersions.optional(),
8
20
  devDependencies: packageVersions.optional(),
9
- scripts: z.record(z.string(), z.string()).optional()
21
+ scripts: z.record(z.string(), z.string()).optional(),
22
+ /** Entry points by subpath (`.`, `./tailwind.css`), or where the package's one entry point leads. */
23
+ exports: exportsTarget.optional(),
24
+ types: z.string().optional(),
25
+ typings: z.string().optional(),
26
+ module: z.string().optional(),
27
+ main: z.string().optional(),
28
+ /** The stylesheet a project imports to use the package, as some packages name it. */
29
+ style: z.string().optional(),
30
+ /** A workspace root's package folders, as npm, Yarn and Bun write them. */
31
+ workspaces: z.union([z.array(z.string()), z.looseObject({ packages: z.array(z.string()).optional() })]).optional()
10
32
  });
11
33
  // ../core/src/devices.ts
12
34
  const deviceKinds = [
@@ -1341,7 +1363,8 @@ function expectStringRecord(value, path) {
1341
1363
  const named = /* @__PURE__ */ new WeakSet();
1342
1364
  /**
1343
1365
  * A new node for a component, ready to show something: required props get their default or first option, and a
1344
- * component that takes children gets its own name as text, so it isn't an empty box, unless `given` has its own.
1366
+ * component that takes children gets its own name as text, so it isn't an empty box, unless `given` has its own or the
1367
+ * component sets its own size (`fixedSize`), where the name would be cut off ("Avata").
1345
1368
  */
1346
1369
  function componentNode(component, info, taken, given = {}) {
1347
1370
  const props = { ...given };
@@ -1353,7 +1376,7 @@ function componentNode(component, info, taken, given = {}) {
1353
1376
  else if (prop.kind === "number") props[prop.name] = 0;
1354
1377
  else if (prop.kind === "string") props[prop.name] = prop.name;
1355
1378
  }
1356
- const labelled = !("children" in given) && info?.props.some((prop) => prop.name === "children" && prop.kind === "node");
1379
+ const labelled = !("children" in given) && !info?.fixedSize && info?.props.some((prop) => prop.name === "children" && prop.kind === "node");
1357
1380
  if (labelled) props.children = component.split("/").at(-1) ?? component;
1358
1381
  const node = {
1359
1382
  type: "component",
@@ -1434,10 +1457,10 @@ function withLibraryContext(node, sources, around, taken) {
1434
1457
  };
1435
1458
  };
1436
1459
  let placed = node;
1437
- const sample = source.sample;
1460
+ const sample = source.sample ?? (named.has(node) ? usedIn(node.component, sources) : void 0);
1438
1461
  if (sample) {
1439
1462
  const given = { ...node.props };
1440
- if (sample.props && "children" in sample.props && named.has(node)) delete given.children;
1463
+ if (named.has(node)) delete given.children;
1441
1464
  const { props, slots } = held({
1442
1465
  ...sample.props,
1443
1466
  ...given
@@ -1514,6 +1537,39 @@ function withLibraryContext(node, sources, around, taken) {
1514
1537
  }
1515
1538
  }
1516
1539
  /**
1540
+ * How a part with no sample of its own is used in its library's other samples: with the children the first use gives it,
1541
+ * or none when it's used without any (`<MarkerIcon />`) or with elements the sample can't show (an icon, `[]`).
1542
+ * Undefined when no sample uses it.
1543
+ */
1544
+ function usedIn(component, sources) {
1545
+ const find = (children) => {
1546
+ for (const child of children ?? []) {
1547
+ if (typeof child === "string") continue;
1548
+ if (isSampleRender(child)) {
1549
+ const found = find(child.$render);
1550
+ if (found) return found;
1551
+ continue;
1552
+ }
1553
+ if (child.component === component) return child;
1554
+ const found = find(child.children) ?? find(elementProps(child.props));
1555
+ if (found) return found;
1556
+ }
1557
+ };
1558
+ const library = sources[component]?.library;
1559
+ for (const source of Object.values(sources)) {
1560
+ if (source.library !== library || !source.sample) continue;
1561
+ const found = find(source.sample.children) ?? find(elementProps(source.sample.props));
1562
+ if (found) return { children: found.children ?? [] };
1563
+ }
1564
+ }
1565
+ /** The elements and render functions a sample gives as props' values, as children are. */
1566
+ function elementProps(props) {
1567
+ return Object.values(props ?? {}).flatMap((value) => {
1568
+ if (isSampleRender(value)) return [value];
1569
+ return isSampleElement(value) ? value.$element : [];
1570
+ });
1571
+ }
1572
+ /**
1517
1573
  * A library file's component as the canvas inserts it, with its parents and sample named by component id.
1518
1574
  * Discovery has already rewritten module imports for the name the project installed the package under.
1519
1575
  */
@@ -1564,4 +1620,4 @@ function sampleIds(sample, library) {
1564
1620
  ...sample.children ? { children: sample.children.map(child) } : {}
1565
1621
  };
1566
1622
  }
1567
- export { deviceKinds as A, parseCanvasDocument as C, collectCustomProperties as D, parseModeSettings as E, viewportHeightProperty as O, paramTypes as S, generateId as T, imageFits as _, applyLibraryEdits as a, linkEndKinds as b, isSampleElement as c, parentSignals as d, parseLibraryEdits as f, containerKinds as g, canvasObjectKinds as h, withLibraryContext as i, lengthToPixels as j, viewportWidthProperty as k, isSampleRender as l, renderSlotOf as m, librarySource as n, componentEvidence as o, parseLibraryManifest as p, sampleIds as r, isMadeValue as s, componentNode as t, libraryManifestExtension as u, lenses as v, styleKeys as w, linkTypes as x, linkAllowed as y };
1623
+ export { deviceKinds as A, parseCanvasDocument as C, collectCustomProperties as D, parseModeSettings as E, packageManifest as M, viewportHeightProperty as O, paramTypes as S, generateId as T, imageFits as _, applyLibraryEdits as a, linkEndKinds as b, isSampleElement as c, parentSignals as d, parseLibraryEdits as f, containerKinds as g, canvasObjectKinds as h, withLibraryContext as i, lengthToPixels as j, viewportWidthProperty as k, isSampleRender as l, renderSlotOf as m, librarySource as n, componentEvidence as o, parseLibraryManifest as p, sampleIds as r, isMadeValue as s, componentNode as t, libraryManifestExtension as u, lenses as v, styleKeys as w, linkTypes as x, linkAllowed as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parity-app/cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
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.",
@@ -1,121 +0,0 @@
1
- import { z } from "zod";
2
- // ../core/src/errors.ts
3
- /**
4
- * Why an agent's call failed, as a stable code it can act on without reading the message. The CLI and MCP publish
5
- * these; the app throws them where it knows the cause.
6
- */
7
- const errorCodes = [
8
- "invalid_input",
9
- "not_running",
10
- "not_answering",
11
- "unknown_tab",
12
- "tab_not_ready",
13
- "unknown_design",
14
- "unknown_node",
15
- "ambiguous_reference",
16
- "unknown_state",
17
- "unknown_mode",
18
- "unknown_viewport",
19
- "unknown_component",
20
- "unknown_icon_set",
21
- "unknown_edit_id",
22
- "conflict",
23
- "execution_failed",
24
- "app_error"
25
- ];
26
- /** Details as another process sends them. Each field that's malformed falls back on its own; only the code must hold. */
27
- const errorDetailsSchema = z.object({
28
- code: z.enum(errorCodes),
29
- /** Whether sending the same request again, unchanged, can succeed. */
30
- retryable: z.boolean().catch(false),
31
- /** The request field at fault, as a path: `design`, `state`, `edits/0/find`. */
32
- field: z.string().min(1).optional().catch(void 0),
33
- /** Valid references to use instead of an unknown or ambiguous one, at most `alternativeLimit` of them. */
34
- alternatives: z.array(z.unknown()).transform((items) => items.filter((item) => typeof item === "string").slice(0, 20)).optional().catch(void 0)
35
- });
36
- /** An error with a stable code, the field it's about and what to use instead. */
37
- var CodedError = class extends Error {
38
- details;
39
- constructor(message, details) {
40
- super(message);
41
- this.name = "CodedError";
42
- this.details = {
43
- ...details,
44
- retryable: details.retryable ?? false
45
- };
46
- }
47
- };
48
- /** An unknown reference, naming the valid ones closest to what was asked for, up to `alternativeLimit`. */
49
- function unknownReference(code, message, reference, candidates, field) {
50
- return new CodedError(message, {
51
- code,
52
- ...field === void 0 ? {} : { field },
53
- alternatives: closest(reference, candidates)
54
- });
55
- }
56
- /**
57
- * Candidates sharing text with the reference first, ignoring case, then the rest by how few single-character edits
58
- * away they are, so a typo's intended id makes the cut; ties keep their own order. All of them when they fit.
59
- */
60
- function closest(reference, candidates, limit = 20) {
61
- const unique = [...new Set(candidates)];
62
- if (unique.length <= limit) return unique;
63
- const wanted = reference.toLowerCase();
64
- const ranked = unique.map((candidate, index) => {
65
- const lower = candidate.toLowerCase();
66
- const near = wanted.length > 0 && (lower.includes(wanted) || wanted.includes(lower));
67
- return {
68
- candidate,
69
- index,
70
- near: near ? 0 : 1,
71
- distance: near ? 0 : editDistance(wanted, lower)
72
- };
73
- });
74
- ranked.sort((a, b) => a.near - b.near || a.distance - b.distance || a.index - b.index);
75
- return ranked.slice(0, limit).map(({ candidate }) => candidate);
76
- }
77
- /** How many single-character insertions, deletions or substitutions turn one string into the other. */
78
- function editDistance(a, b) {
79
- let previous = Array.from({ length: b.length + 1 }, (_, index) => index);
80
- for (let i = 1; i <= a.length; i++) {
81
- const row = [i];
82
- for (let j = 1; j <= b.length; j++) row[j] = Math.min(previous[j] + 1, row[j - 1] + 1, previous[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
83
- previous = row;
84
- }
85
- return previous[b.length];
86
- }
87
- /** A thrown value's details, when it carries them. */
88
- function errorDetails(error) {
89
- return error instanceof CodedError ? error.details : void 0;
90
- }
91
- /** Details that came from another process, checked before they're trusted. Anything malformed reads as none. */
92
- function readErrorDetails(value) {
93
- return errorDetailsSchema.safeParse(value).data;
94
- }
95
- // ../core/src/schema.ts
96
- /**
97
- * Checks for data Parity didn't make (PAR-578): files, agent input, environment variables, other programs' JSON. A zod
98
- * schema is both the check and the type. A failed check reads as core's hand-written ones in `validate.ts` do: a JSON
99
- * pointer to the value at fault, then what was expected there, as in `/containers/0/name: expected a string`.
100
- */
101
- /** An object with string keys, and not an array or null. */
102
- const plainObject = z.record(z.string(), z.unknown());
103
- /** Text with something besides whitespace, trimmed. */
104
- const nonBlankString = z.string().trim().min(1, "can't be blank");
105
- /** A number other than NaN or ±Infinity, which zod 4 refuses on its own. */
106
- const finiteNumber = z.number();
107
- /** JSON text holding what `schema` checks. Text that isn't JSON fails as `expected JSON`. */
108
- function jsonText(schema) {
109
- return z.string().transform((text, context) => {
110
- try {
111
- return JSON.parse(text);
112
- } catch {
113
- context.addIssue({
114
- code: "custom",
115
- message: "expected JSON"
116
- });
117
- return z.NEVER;
118
- }
119
- }).pipe(schema);
120
- }
121
- export { CodedError as a, errorDetails as c, plainObject as i, readErrorDetails as l, jsonText as n, closest as o, nonBlankString as r, errorCodes as s, finiteNumber as t, unknownReference as u };
@@ -1,53 +0,0 @@
1
- import { p as parseLibraryManifest, u as libraryManifestExtension } from "./src-V9wTMkxO.mjs";
2
- import { createRequire } from "node:module";
3
- import { readFile, readdir } from "node:fs/promises";
4
- import { dirname, join } from "node:path";
5
- import { existsSync } from "node:fs";
6
- import semver from "semver";
7
- // ../registry/src/index.ts
8
- const require = createRequire(import.meta.url);
9
- /**
10
- * The folder the registry's files are in. The published CLI bundles this module and ships the files beside it, where
11
- * the package can't be resolved. Otherwise they're found through the package's own `package.json`, so it's the same
12
- * whether this module runs from source or bundled into the app.
13
- */
14
- function registryDir() {
15
- const bundled = join(import.meta.dirname, "libraries");
16
- if (existsSync(bundled)) return bundled;
17
- return join(dirname(require.resolve("@parity-app/registry/package.json")), "libraries");
18
- }
19
- let cache;
20
- /** Every file in the registry, read once. One that doesn't parse is skipped with a warning. */
21
- function registryEntries(dir = registryDir()) {
22
- if (dir !== registryDir()) return readEntries(dir);
23
- cache ??= readEntries(dir);
24
- return cache;
25
- }
26
- async function readEntries(dir) {
27
- const files = (await readdir(dir).catch(() => [])).filter((file) => file.endsWith(libraryManifestExtension)).sort();
28
- const entries = [];
29
- for (const file of files) {
30
- const path = join(dir, file);
31
- try {
32
- const manifest = parseLibraryManifest(JSON.parse(await readFile(path, "utf8")));
33
- if (!manifest.package) throw new TypeError("/package: a registry file names the package it describes");
34
- entries.push({
35
- file,
36
- path,
37
- manifest
38
- });
39
- } catch (error) {
40
- console.warn(`Skipping registry file ${file}: ${error instanceof Error ? error.message : String(error)}`);
41
- }
42
- }
43
- return entries;
44
- }
45
- /** Whether a manifest describes this version of its package. A manifest without a range covers every version. */
46
- function covers(manifest, version) {
47
- const range = manifest.package?.range;
48
- if (!range) return true;
49
- if (!version) return false;
50
- const parsed = semver.coerce(version, { includePrerelease: true });
51
- return parsed !== null && semver.satisfies(parsed, range, { includePrerelease: true });
52
- }
53
- export { registryDir as n, registryEntries as r, covers as t };
@@ -1,3 +0,0 @@
1
- import "./schema-zRNxotYl.mjs";
2
- export { a as applyLibraryEdits, t as componentNode, T as generateId, n as librarySource, f as parseLibraryEdits, i as withLibraryContext } from "./src-V9wTMkxO.mjs";
3
- import "./src-BvKhu6dX.mjs";
@@ -1 +0,0 @@
1
- export { t as covers, n as registryDir, r as registryEntries } from "./src-BIVDlIGc.mjs";