@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 +9 -14
- package/dist/{client-BUaE9b77.mjs → client-C4An81o9.mjs} +1 -1
- package/dist/index.mjs +1 -1
- package/dist/schema-CiVy9tZT.mjs +227 -0
- package/dist/src-AKjejfTT.mjs +4 -0
- package/dist/src-B40wy5fK.mjs +1 -0
- package/dist/{src-BvKhu6dX.mjs → src-C5-HaJcA.mjs} +260 -123
- package/dist/src-DzU4U2rh.mjs +129 -0
- package/dist/{src-V9wTMkxO.mjs → src-YQY8r4mh.mjs} +64 -8
- package/package.json +1 -1
- package/dist/schema-zRNxotYl.mjs +0 -121
- package/dist/src-BIVDlIGc.mjs +0 -53
- package/dist/src-BgQ7gnXE.mjs +0 -3
- package/dist/src-CiqdFzei.mjs +0 -1
package/dist/bin.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
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-
|
|
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 {
|
|
391
|
-
const {
|
|
392
|
-
const entry = (await
|
|
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
|
-
|
|
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-
|
|
520
|
-
const { covers, registryDir, registryEntries } = await import("./src-
|
|
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-
|
|
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 {
|
|
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-
|
|
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 @@
|
|
|
1
|
+
export { t as covers, n as newestEntries, i as registryDir, a as registryEntries } from "./src-DzU4U2rh.mjs";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
3
|
-
import "./src-
|
|
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
|
|
4631
|
-
if (!
|
|
4632
|
-
const
|
|
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 =
|
|
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 ??
|
|
4655
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
4992
|
-
return join(root, `${
|
|
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
|
|
5234
|
-
const
|
|
5235
|
-
|
|
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-
|
|
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.
|
|
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 (
|
|
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
package/dist/schema-zRNxotYl.mjs
DELETED
|
@@ -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 };
|
package/dist/src-BIVDlIGc.mjs
DELETED
|
@@ -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 };
|
package/dist/src-BgQ7gnXE.mjs
DELETED
package/dist/src-CiqdFzei.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { t as covers, n as registryDir, r as registryEntries } from "./src-BIVDlIGc.mjs";
|