@weme-ui/weme-ui 0.1.5 → 0.2.1

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.
Files changed (46) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +19 -11
  3. package/dist/add-DESSspHh.js +56 -0
  4. package/dist/add-DESSspHh.js.map +1 -0
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.js +58 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/init-DZjeMuf3.js +219 -0
  9. package/dist/init-DZjeMuf3.js.map +1 -0
  10. package/dist/project-BZkWl9YJ.js +685 -0
  11. package/dist/project-BZkWl9YJ.js.map +1 -0
  12. package/package.json +72 -48
  13. package/LICENSE +0 -21
  14. package/dist/add-5ZrkTNC3.mjs +0 -53
  15. package/dist/add-5ZrkTNC3.mjs.map +0 -1
  16. package/dist/build-DAAgZct5.mjs +0 -23
  17. package/dist/build-DAAgZct5.mjs.map +0 -1
  18. package/dist/index.d.mts +0 -1
  19. package/dist/index.mjs +0 -31
  20. package/dist/index.mjs.map +0 -1
  21. package/dist/info-BBRg1Z-t.mjs +0 -41
  22. package/dist/info-BBRg1Z-t.mjs.map +0 -1
  23. package/dist/init-BlbSgl_W.mjs +0 -64
  24. package/dist/init-BlbSgl_W.mjs.map +0 -1
  25. package/dist/manifest-DtYvp2uU.mjs +0 -77
  26. package/dist/manifest-DtYvp2uU.mjs.map +0 -1
  27. package/dist/package-DPYgVv-f.mjs +0 -85
  28. package/dist/package-DPYgVv-f.mjs.map +0 -1
  29. package/dist/project-BpqIQqfR.mjs +0 -361
  30. package/dist/project-BpqIQqfR.mjs.map +0 -1
  31. package/dist/project-COPHBstt.mjs +0 -58
  32. package/dist/project-COPHBstt.mjs.map +0 -1
  33. package/dist/project-kIk5Kz3k.mjs +0 -148
  34. package/dist/project-kIk5Kz3k.mjs.map +0 -1
  35. package/dist/registry-CU5Ejwes.mjs +0 -82
  36. package/dist/registry-CU5Ejwes.mjs.map +0 -1
  37. package/dist/registry-DtG09FVz.mjs +0 -147
  38. package/dist/registry-DtG09FVz.mjs.map +0 -1
  39. package/dist/registry-NSadym2Q.mjs +0 -8
  40. package/dist/registry-NSadym2Q.mjs.map +0 -1
  41. package/dist/registry-bjxXghAl.mjs +0 -355
  42. package/dist/registry-bjxXghAl.mjs.map +0 -1
  43. package/dist/registry-item-B_neG4VO.mjs +0 -143
  44. package/dist/registry-item-B_neG4VO.mjs.map +0 -1
  45. package/dist/verify-CXBxJkzK.mjs +0 -78
  46. package/dist/verify-CXBxJkzK.mjs.map +0 -1
@@ -0,0 +1,685 @@
1
+ import { a as DEFAULT_REGISTRY_NAME, i as DEFAULT_REGISTRY_BRANCH, n as DEFAULT_PATHS, o as PROJECT_CONFIG_FILENAME, r as DEFAULT_REGISTRIES, s as PROJECT_LOCKFILE_FILENAME, t as CLI_TMP_DIR } from "./index.js";
2
+ import { basename, isAbsolute, join, relative, resolve } from "node:path/posix";
3
+ import { cwd, exit } from "node:process";
4
+ import makeFetch from "make-fetch-happen";
5
+ import { LOCKFILE_SCHEMA_URL, ProjectConfigSchema, ProjectLockFileSchema, RegistryConfigSchema } from "@weme-ui/schema";
6
+ import { defu } from "defu";
7
+ import { hash } from "hasha";
8
+ import { addDependency } from "nypm";
9
+ import * as v from "valibot";
10
+ import { existsSync, mkdirSync } from "node:fs";
11
+ import fs from "node:fs/promises";
12
+ import { parseURL } from "ufo";
13
+
14
+ // src/utils/fetcher.ts
15
+ const fetch = makeFetch.defaults({
16
+ cachePath: CLI_TMP_DIR,
17
+ noProxy: ["raw.githubusercontent.com"]
18
+ });
19
+ /**
20
+ * Fetch a URL.
21
+ *
22
+ * @param url - The URL to fetch.
23
+ * @returns The text response.
24
+ */
25
+ async function fetchURL(url) {
26
+ return (await fetch(url)).text();
27
+ }
28
+ /**
29
+ * Fetch a JSON file.
30
+ *
31
+ * @param url - The URL to fetch.
32
+ * @returns The JSON response.
33
+ */
34
+ async function fetchJSON(url) {
35
+ return (await fetch(url)).json();
36
+ }
37
+
38
+ // src/utils/registry.ts
39
+ var Registry = class {
40
+ /**
41
+ * The name of the registry.
42
+ */
43
+ name;
44
+ /**
45
+ * The branch of the registry.
46
+ */
47
+ branch;
48
+ /**
49
+ * The cache of the registry.
50
+ */
51
+ cache = null;
52
+ constructor(name, branch) {
53
+ this.name = name;
54
+ this.branch = branch;
55
+ }
56
+ /**
57
+ * Get the registry metadata.
58
+ *
59
+ * @returns The registry metadata.
60
+ */
61
+ async metadata() {
62
+ const { config } = await this.load();
63
+ return {
64
+ name: config.name,
65
+ description: config.description,
66
+ version: config.version,
67
+ homepage: config.homepage,
68
+ repository: config.repository,
69
+ issues: config.issues,
70
+ contributors: config.contributors,
71
+ access: config.access
72
+ };
73
+ }
74
+ /**
75
+ * Get the registry dependencies.
76
+ *
77
+ * @returns The registry dependencies.
78
+ */
79
+ async dependencies() {
80
+ return (await this.load()).config.dependencies ?? [];
81
+ }
82
+ /**
83
+ * Get the registry dev dependencies.
84
+ *
85
+ * @returns The registry dev dependencies.
86
+ */
87
+ async devDependencies() {
88
+ return (await this.load()).config.devDependencies ?? [];
89
+ }
90
+ /**
91
+ * Find the items in the registry.
92
+ *
93
+ * @param filter - The filter function.
94
+ * @returns The items that match the filter.
95
+ */
96
+ async getItems(filter) {
97
+ const { config, index } = await this.load();
98
+ const items = filter ? config.items.filter(filter) : config.items;
99
+ const visited = /* @__PURE__ */ new Set();
100
+ const result = [];
101
+ const visit = (item) => {
102
+ if (visited.has(item.name)) return;
103
+ visited.add(item.name);
104
+ for (const name of item.registryDependencies ?? []) {
105
+ const dep = index.get(name);
106
+ if (!dep) continue;
107
+ visit(dep);
108
+ }
109
+ result.push(item);
110
+ };
111
+ items.forEach(visit);
112
+ return result;
113
+ }
114
+ /**
115
+ * Get the files of an item.
116
+ *
117
+ * @param item - The item to get the files from.
118
+ * @returns The resolved files of the item.
119
+ */
120
+ async getItemFiles(item) {
121
+ return await Promise.all(item.files.map(async (file) => {
122
+ const result = await this.getItemFileContent(file.path);
123
+ return {
124
+ type: file.type,
125
+ kind: file.kind,
126
+ path: file.path,
127
+ target: file.target,
128
+ content: result.content,
129
+ hash: result.hash
130
+ };
131
+ }));
132
+ }
133
+ /**
134
+ * Get the content of a file.
135
+ *
136
+ * @param source - The source of the file.
137
+ * @returns The content of the file.
138
+ */
139
+ async getItemFileContent(source) {
140
+ const url = this.joinURL(source);
141
+ const content = await fetchURL(url);
142
+ return {
143
+ content,
144
+ hash: await hash(content)
145
+ };
146
+ }
147
+ /**
148
+ * Load the registry cache.
149
+ *
150
+ * @throws If the registry cache fails to load.
151
+ * @returns The registry cache.
152
+ */
153
+ async load() {
154
+ this.cache ??= this.fetchRegistryJson().catch((err) => {
155
+ this.cache = null;
156
+ throw err;
157
+ });
158
+ return this.cache;
159
+ }
160
+ /**
161
+ * Fetch the registry JSON.
162
+ *
163
+ * @throws If the registry JSON fails to parse.
164
+ * @returns The registry cache.
165
+ */
166
+ async fetchRegistryJson() {
167
+ const url = this.joinURL("registry.json");
168
+ const raw = await fetchJSON(url);
169
+ const parsed = v.safeParse(RegistryConfigSchema, raw);
170
+ if (!parsed.success) throw new Error("Failed to parse registry config", { cause: parsed.issues });
171
+ const config = parsed.output;
172
+ const index = /* @__PURE__ */ new Map();
173
+ for (const item of config.items) {
174
+ if (index.has(item.name)) throw new Error(`Duplicate item name: ${item.name}`);
175
+ index.set(item.name, item);
176
+ }
177
+ return {
178
+ config,
179
+ index
180
+ };
181
+ }
182
+ /**
183
+ * Join the URL with the name and branch.
184
+ *
185
+ * @param path The path to join.
186
+ * @returns The joined URL.
187
+ */
188
+ joinURL(path) {
189
+ return `https://raw.githubusercontent.com/${this.name}/refs/heads/${this.branch}/${path}`;
190
+ }
191
+ };
192
+ /**
193
+ * Use the registry.
194
+ *
195
+ * @param name The name of the registry.
196
+ * @param branch The branch of the registry.
197
+ * @returns The registry instance.
198
+ */
199
+ function useRegistry(name, branch = DEFAULT_REGISTRY_BRANCH) {
200
+ return new Registry(name, branch);
201
+ }
202
+
203
+ // src/utils/utilities.ts
204
+ /**
205
+ * Ensure the working directory.
206
+ *
207
+ * @param path - The working directory to ensure.
208
+ * @returns The ensured working directory. If the directory does not exist, it will be created.
209
+ */
210
+ function ensureDir(path) {
211
+ if (path === cwd()) return path;
212
+ const resolved = resolve(path);
213
+ if (!existsSync(resolved)) mkdirSync(resolved, { recursive: true });
214
+ return resolved;
215
+ }
216
+ /**
217
+ * Check if a file exists.
218
+ *
219
+ * @param root - The root directory of the project.
220
+ * @param filename - The name of the file.
221
+ * @returns Whether the file exists.
222
+ */
223
+ async function existsFile(root, filename) {
224
+ const filePath = resolve(root, filename);
225
+ const exists = existsSync(filePath);
226
+ if (!exists) return false;
227
+ const content = await fs.readFile(filePath, "utf-8");
228
+ return exists && content !== null && content.trim() !== "";
229
+ }
230
+ /**
231
+ * Read a file.
232
+ *
233
+ * @param root - The root directory of the project.
234
+ * @param filename - The name of the file.
235
+ * @returns The content of the file. If the file does not exist, it will return `null`.
236
+ */
237
+ async function readFile(root, filename) {
238
+ try {
239
+ if (!await existsFile(root, filename)) return null;
240
+ const content = await fs.readFile(join(ensureDir(root), filename), "utf-8");
241
+ if (!content) return null;
242
+ return content;
243
+ } catch {
244
+ return null;
245
+ }
246
+ }
247
+ /**
248
+ * Write a file.
249
+ *
250
+ * @param root - The root directory of the project.
251
+ * @param filename - The name of the file.
252
+ * @param content - The content of the file.
253
+ * @returns Whether the file was written successfully.
254
+ */
255
+ async function writeFile(root, filename, content) {
256
+ try {
257
+ const path = join(ensureDir(root), filename);
258
+ await fs.writeFile(path, `${content}\n`, {
259
+ encoding: "utf-8",
260
+ flag: "w"
261
+ });
262
+ } catch {
263
+ return false;
264
+ }
265
+ return true;
266
+ }
267
+ /**
268
+ * Parse a repository URL.
269
+ *
270
+ * @param url - The URL to parse.
271
+ * @returns The parsed repository URL.
272
+ */
273
+ function parseRepoURL(url) {
274
+ if (!url) return {
275
+ name: DEFAULT_REGISTRY_NAME,
276
+ branch: DEFAULT_REGISTRY_BRANCH
277
+ };
278
+ const { host, pathname, hash } = parseURL(url);
279
+ if (host && host !== "github.com" || !pathname) throw new Error(`Invalid repository URL: ${url}`);
280
+ let branch = hash ? hash.replace(/^#/, "") : DEFAULT_REGISTRY_BRANCH;
281
+ let name = removeLeadingSlash(pathname);
282
+ if (name.split("/").length !== 2 && name.includes("/tree/")) {
283
+ branch = name.split("/tree/")[1];
284
+ name = name.split("/tree/")[0];
285
+ }
286
+ return {
287
+ name,
288
+ branch
289
+ };
290
+ }
291
+ /**
292
+ * Remove the leading slash from a path.
293
+ *
294
+ * @param path - The path to remove the leading slash from.
295
+ * @returns The path without the leading slash.
296
+ */
297
+ function removeLeadingSlash(path) {
298
+ return path.replace(/^\//, "");
299
+ }
300
+ /**
301
+ * Unwrap an error.
302
+ *
303
+ * @param error - The error to unwrap.
304
+ * @returns The unwrapped error.
305
+ */
306
+ function unwrapError(error) {
307
+ return error instanceof Error ? error.message : "Unknown error";
308
+ }
309
+ /**
310
+ * Call a callback when a condition is met.
311
+ *
312
+ * @param condition - The condition to check.
313
+ * @param callback - The callback to call.
314
+ * @param finalizer - The finalizer to call.
315
+ * @returns Whether the callback was called successfully.
316
+ */
317
+ async function callWhen(condition, callback, finalizer) {
318
+ if (condition) try {
319
+ await callback();
320
+ } catch (e) {
321
+ console.error(unwrapError(e));
322
+ exit(1);
323
+ } finally {
324
+ if (finalizer) await finalizer();
325
+ }
326
+ }
327
+ /**
328
+ * Generate a random color.
329
+ *
330
+ * @returns The random color.
331
+ */
332
+ function randomColor() {
333
+ const colors = [
334
+ "black",
335
+ "red",
336
+ "green",
337
+ "yellow",
338
+ "blue",
339
+ "magenta",
340
+ "cyan",
341
+ "white",
342
+ "gray"
343
+ ];
344
+ return colors[Math.floor(Math.random() * colors.length)];
345
+ }
346
+
347
+ // src/utils/project.ts
348
+ /**
349
+ * Project management class.
350
+ *
351
+ * @example
352
+ * ```ts
353
+ * const project = new Project(cwd)
354
+ * ```
355
+ *
356
+ * @param root - The root directory of the project.
357
+ * @returns The project instance.
358
+ */
359
+ var Project = class {
360
+ /**
361
+ * The root directory of the project.
362
+ */
363
+ root;
364
+ constructor(root) {
365
+ this.root = root;
366
+ }
367
+ /**
368
+ * Get the project info.
369
+ *
370
+ * @returns The project info.
371
+ */
372
+ async info() {
373
+ const config = await this.hasProjectConfig() ? await this.loadProjectConfig() : null;
374
+ return {
375
+ root: this.root,
376
+ paths: this.resolvePaths(config?.paths),
377
+ registries: config?.registries ?? DEFAULT_REGISTRIES,
378
+ defaultRegistry: config?.registries?.[0] ?? DEFAULT_REGISTRIES[0]
379
+ };
380
+ }
381
+ /**
382
+ * Add an item to the project.
383
+ *
384
+ * @param name - The name of the item to add.
385
+ * @returns Whether the item was added.
386
+ */
387
+ async addItem(name, kinds = ["file"]) {
388
+ if (await this.hasAddedItem(name)) return await this.updateItem(name);
389
+ const parsed = await this.parseItemName(name);
390
+ const registry = useRegistry(parsed.registry);
391
+ const items = await registry.getItems((item) => item.name === parsed.name);
392
+ if (items.length === 0) throw new Error(`Item ${parsed.name} not found in the registry ${parsed.registry}`);
393
+ const { paths, registries, defaultRegistry } = await this.info();
394
+ const itemRegistry = registries.find((registry) => registry.registry === parsed.registry) ?? defaultRegistry;
395
+ const addedItems = [];
396
+ for (const item of items) {
397
+ const files = await registry.getItemFiles(item);
398
+ const addedItem = {
399
+ name: item.name,
400
+ type: item.type,
401
+ registry: itemRegistry.registry,
402
+ repo: itemRegistry.repo,
403
+ prefix: itemRegistry.prefix,
404
+ files: []
405
+ };
406
+ for (const file of files) {
407
+ if (!kinds.includes(file.kind)) continue;
408
+ const fileName = basename(file.path);
409
+ const fileDir = paths[file.type] ?? paths["~"];
410
+ let filePath = fileDir;
411
+ if (file.type === "component") filePath = itemRegistry.prefix ? join(fileDir, itemRegistry.prefix, item.name) : join(fileDir, item.name);
412
+ await writeFile(this.joinPath(filePath), fileName, file.content);
413
+ addedItem.files.push({
414
+ kind: file.kind,
415
+ source: file.path,
416
+ dest: join(filePath, fileName)
417
+ });
418
+ }
419
+ if (addedItem.files.length > 0) addedItems.push(addedItem);
420
+ }
421
+ if (addedItems.length === 0) return false;
422
+ const lockfile = await this.loadLockfile() ?? {
423
+ $schema: LOCKFILE_SCHEMA_URL,
424
+ items: []
425
+ };
426
+ lockfile.items.push(...addedItems);
427
+ const written = await writeFile(join(this.root, CLI_TMP_DIR), PROJECT_LOCKFILE_FILENAME, JSON.stringify(lockfile, null, 2));
428
+ const dependencies = items.map((item) => item.dependencies ?? []).flat();
429
+ const devDependencies = items.map((item) => item.devDependencies ?? []).flat();
430
+ if (dependencies.length > 0) await this.addDependencies(dependencies);
431
+ if (devDependencies.length > 0) await this.addDevDependencies(devDependencies);
432
+ const cssVariables = items.map((item) => item.cssVars ?? {}).reduce((acc, curr) => defu(acc, curr), {});
433
+ if (Object.keys(cssVariables).length > 0) await this.addCssVariables(cssVariables);
434
+ return written;
435
+ }
436
+ /**
437
+ * Update an added item by name in the project.
438
+ *
439
+ * @param name - The name of the item to update.
440
+ * @returns Whether the item was updated.
441
+ */
442
+ async updateItem(name) {
443
+ return false;
444
+ }
445
+ /**
446
+ * Add css variables to the project.
447
+ *
448
+ * @param cssVariables - The css variables to add.
449
+ * @throws If the project config is not found.
450
+ * @throws If the project config is not writable.
451
+ */
452
+ async addCssVariables(cssVariables) {
453
+ const projectConfig = await this.loadProjectConfig();
454
+ if (!projectConfig) throw new Error("Project config not found");
455
+ projectConfig.unocss = projectConfig.unocss ?? {};
456
+ projectConfig.unocss.cssVars = defu(projectConfig.unocss.cssVars ?? {}, cssVariables);
457
+ await writeFile(this.root, PROJECT_CONFIG_FILENAME, JSON.stringify(projectConfig, null, 2));
458
+ }
459
+ /**
460
+ * Check if an item was added to the project.
461
+ *
462
+ * @param name - The name of the item to check.
463
+ * @returns Whether the item was added.
464
+ */
465
+ async hasAddedItem(name) {
466
+ const lockfile = await this.loadLockfile();
467
+ if (lockfile) {
468
+ const parsed = await this.parseItemName(name);
469
+ return lockfile.items.some((item) => item.name === parsed.name && item.registry === parsed.registry);
470
+ }
471
+ return false;
472
+ }
473
+ /**
474
+ * Get the files of an added item.
475
+ *
476
+ * @param itemName - The name of the item to get the files from.
477
+ * @returns The resolved files of the item.
478
+ * @throws If the item is not found in the lockfile.
479
+ * @throws If the file is not found in the project.
480
+ */
481
+ async getAddedItemFiles(itemName) {
482
+ const lockfile = await this.loadLockfile();
483
+ if (lockfile) {
484
+ const addedItem = lockfile.items.find((item) => item.name === itemName);
485
+ if (!addedItem) throw new Error(`Item ${itemName} not found in the lockfile`);
486
+ return await Promise.all(addedItem.files.map(async (file) => {
487
+ const result = await this.getAddedItemFileContent(file.dest);
488
+ return {
489
+ type: addedItem.type,
490
+ registry: addedItem.registry,
491
+ repo: addedItem.repo,
492
+ prefix: addedItem.prefix,
493
+ kind: file.kind,
494
+ source: file.source,
495
+ dest: file.dest,
496
+ content: result.content,
497
+ hash: result.hash
498
+ };
499
+ }));
500
+ }
501
+ return [];
502
+ }
503
+ /**
504
+ * Get the content of an added item file by filepath.
505
+ *
506
+ * @param filepath - The filepath of the file.
507
+ * @returns The content of the file.
508
+ * @throws If the file is not found in the project.
509
+ */
510
+ async getAddedItemFileContent(filepath) {
511
+ const content = await readFile(this.root, filepath);
512
+ if (!content) throw new Error(`File ${filepath} not found in the project`);
513
+ return {
514
+ content,
515
+ hash: await hash(content)
516
+ };
517
+ }
518
+ /**
519
+ * Add dependencies to the project.
520
+ *
521
+ * @param dependencies - The dependencies to add.
522
+ */
523
+ async addDependencies(dependencies) {
524
+ await addDependency(dependencies, {
525
+ cwd: this.root,
526
+ silent: true
527
+ });
528
+ }
529
+ /**
530
+ * Add dev dependencies to the project.
531
+ *
532
+ * @param dependencies - The dev dependencies to add.
533
+ */
534
+ async addDevDependencies(dependencies) {
535
+ await addDependency(dependencies, {
536
+ cwd: this.root,
537
+ silent: true,
538
+ dev: true
539
+ });
540
+ }
541
+ /**
542
+ * Check if the project is initialized.
543
+ *
544
+ * @returns Whether the project is initialized.
545
+ */
546
+ async isInitialized() {
547
+ const checkList = [
548
+ this.joinPath("uno.config.ts"),
549
+ this.joinPath(PROJECT_CONFIG_FILENAME),
550
+ this.joinPath(CLI_TMP_DIR, PROJECT_LOCKFILE_FILENAME),
551
+ this.joinPath("package.json"),
552
+ this.joinPath(CLI_TMP_DIR, "uno.config.ts")
553
+ ];
554
+ return (await Promise.all(checkList.map(async (path) => await existsFile(this.root, path)))).every(Boolean);
555
+ }
556
+ /**
557
+ * Check if the project has a package.json file.
558
+ *
559
+ * @returns Whether the project has a package.json file.
560
+ */
561
+ async hasPackageJson() {
562
+ return await existsFile(this.root, "package.json");
563
+ }
564
+ /**
565
+ * Check if the project has a project config file.
566
+ *
567
+ * @returns Whether the project has a project config file.
568
+ */
569
+ async hasProjectConfig() {
570
+ return await existsFile(this.root, PROJECT_CONFIG_FILENAME);
571
+ }
572
+ /**
573
+ * Check if the project has a lockfile.
574
+ *
575
+ * @returns Whether the project has a lockfile.
576
+ */
577
+ async hasLockfile() {
578
+ return await existsFile(this.root, join(CLI_TMP_DIR, PROJECT_LOCKFILE_FILENAME));
579
+ }
580
+ /**
581
+ * Check if the project has a uno config file.
582
+ *
583
+ * @returns Whether the project has a uno config file.
584
+ */
585
+ async hasUnoConfig() {
586
+ return await existsFile(this.root, join(CLI_TMP_DIR, "uno.config.ts"));
587
+ }
588
+ /**
589
+ * Load the project config file.
590
+ *
591
+ * @returns The loaded project config if it exists, otherwise null.
592
+ */
593
+ async loadProjectConfig() {
594
+ const content = await readFile(this.root, PROJECT_CONFIG_FILENAME);
595
+ if (content) try {
596
+ const configJson = JSON.parse(content);
597
+ const parsed = v.safeParse(ProjectConfigSchema, configJson);
598
+ if (parsed.success) return parsed.output;
599
+ return null;
600
+ } catch {}
601
+ return null;
602
+ }
603
+ /**
604
+ * Load the lockfile.
605
+ *
606
+ * @returns The loaded lockfile if it exists, otherwise null.
607
+ */
608
+ async loadLockfile() {
609
+ const content = await readFile(join(this.root, CLI_TMP_DIR), PROJECT_LOCKFILE_FILENAME);
610
+ if (content) try {
611
+ const lockfileJson = JSON.parse(content);
612
+ const parsed = v.safeParse(ProjectLockFileSchema, lockfileJson);
613
+ if (parsed.success) return parsed.output;
614
+ } catch {}
615
+ return null;
616
+ }
617
+ /**
618
+ * Resolve project config paths to locations relative to the project root.
619
+ *
620
+ * @param paths - The paths from project config.
621
+ * @returns The resolved paths.
622
+ */
623
+ resolvePaths(paths) {
624
+ const merged = defu(paths ?? {}, DEFAULT_PATHS);
625
+ const alias = this.toProjectRelative(this.root, merged["~"]);
626
+ return Object.fromEntries(Object.entries(merged).map(([key, value]) => [key, key === "~" ? alias : this.toProjectRelative(this.root, this.expandTildeAlias(value, alias))]));
627
+ }
628
+ /**
629
+ * Expand a tilde alias.
630
+ *
631
+ * @param value - The value to expand.
632
+ * @param alias - The alias to expand.
633
+ * @returns The expanded value.
634
+ */
635
+ expandTildeAlias(value, alias) {
636
+ if (value === "~") return alias;
637
+ if (value.startsWith("~/")) {
638
+ const rest = value.slice(2);
639
+ return rest ? join(alias, rest) : alias;
640
+ }
641
+ return value;
642
+ }
643
+ /**
644
+ * Convert a path to a project relative path.
645
+ *
646
+ * @param root - The project root directory.
647
+ * @param path - The path to convert.
648
+ * @returns The project relative path.
649
+ */
650
+ toProjectRelative(root, path) {
651
+ const abs = isAbsolute(path) ? resolve(path) : resolve(root, path);
652
+ if (abs === root || abs.startsWith(`${root}/`)) return relative(root, abs) || ".";
653
+ return abs;
654
+ }
655
+ /**
656
+ * Parse the item name.
657
+ *
658
+ * @param input - The item name to parse, format: `<registry>/<item-name>`.
659
+ * @returns The parsed item name.
660
+ */
661
+ async parseItemName(input) {
662
+ const s = input.trim().replace(/\/+$/, "");
663
+ const i = s.lastIndexOf("/");
664
+ if (i === -1) return {
665
+ registry: (await this.info()).defaultRegistry.registry,
666
+ name: s
667
+ };
668
+ return {
669
+ registry: s.slice(0, i),
670
+ name: s.slice(i + 1)
671
+ };
672
+ }
673
+ /**
674
+ * Join a path to the workplace directory.
675
+ *
676
+ * @param paths - The paths to join.
677
+ * @returns The joined path.
678
+ */
679
+ joinPath(...paths) {
680
+ return join(this.root, ...paths.map(removeLeadingSlash));
681
+ }
682
+ };
683
+
684
+ export { parseRepoURL as a, writeFile as c, existsFile as i, useRegistry as l, callWhen as n, randomColor as o, ensureDir as r, unwrapError as s, Project as t };
685
+ //# sourceMappingURL=project-BZkWl9YJ.js.map