@lovo/matter-cli 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +68 -4
- package/dist/add-T7IRU2NK.js +11 -0
- package/dist/{chunk-4XUN2PKU.js → chunk-53DI7V2J.js} +22 -21
- package/dist/chunk-53DI7V2J.js.map +1 -0
- package/dist/chunk-D4HDZEJT.js +37 -0
- package/dist/chunk-D4HDZEJT.js.map +1 -0
- package/dist/{chunk-OJWKSIZ5.js → chunk-FHRQIHCN.js} +32 -25
- package/dist/chunk-FHRQIHCN.js.map +1 -0
- package/dist/chunk-Q7CQW6AH.js +27 -0
- package/dist/chunk-Q7CQW6AH.js.map +1 -0
- package/dist/{chunk-M6S6HYHE.js → chunk-R7OX6KUP.js} +48 -44
- package/dist/chunk-R7OX6KUP.js.map +1 -0
- package/dist/chunk-RRL35RGP.js +104 -0
- package/dist/chunk-RRL35RGP.js.map +1 -0
- package/dist/chunk-TBB7CTPP.js +77 -0
- package/dist/chunk-TBB7CTPP.js.map +1 -0
- package/dist/chunk-YADIAD35.js +16322 -0
- package/dist/chunk-YADIAD35.js.map +1 -0
- package/dist/chunk-YAWX2IU3.js +46 -0
- package/dist/chunk-YAWX2IU3.js.map +1 -0
- package/dist/chunk-YSFTOGZX.js +119 -0
- package/dist/chunk-YSFTOGZX.js.map +1 -0
- package/dist/commands/poster.d.ts +19 -0
- package/dist/commands/poster.js +15 -0
- package/dist/commands/poster.js.map +1 -0
- package/dist/dist-I76TGDBX.js +547 -0
- package/dist/dist-I76TGDBX.js.map +1 -0
- package/dist/harness/frameReady.ts +35 -0
- package/dist/harness/index.html +20 -0
- package/dist/harness/index.tsx +40 -0
- package/dist/index.js +50 -21
- package/dist/index.js.map +1 -1
- package/dist/{init-W43YVGBI.js → init-NB5EOU5H.js} +3 -2
- package/dist/init-NB5EOU5H.js.map +1 -0
- package/dist/{list-S626E7NZ.js → list-L725RQM3.js} +6 -5
- package/dist/list-L725RQM3.js.map +1 -0
- package/dist/magic-string.es-DKS3S7WW.js +1310 -0
- package/dist/magic-string.es-DKS3S7WW.js.map +1 -0
- package/dist/poster/bundle.d.ts +12 -0
- package/dist/poster/bundle.js +9 -0
- package/dist/poster/bundle.js.map +1 -0
- package/dist/poster/bundle.test.d.ts +2 -0
- package/dist/poster/bundle.test.js +49 -0
- package/dist/poster/bundle.test.js.map +1 -0
- package/dist/poster/e2e.test.d.ts +2 -0
- package/dist/poster/e2e.test.js +103 -0
- package/dist/poster/e2e.test.js.map +1 -0
- package/dist/poster/playwright.d.ts +19 -0
- package/dist/poster/playwright.js +11 -0
- package/dist/poster/playwright.js.map +1 -0
- package/dist/poster/playwright.test.d.ts +2 -0
- package/dist/poster/playwright.test.js +28 -0
- package/dist/poster/playwright.test.js.map +1 -0
- package/dist/poster/projectRoot.d.ts +3 -0
- package/dist/poster/projectRoot.js +9 -0
- package/dist/poster/projectRoot.js.map +1 -0
- package/dist/poster/projectRoot.test.d.ts +2 -0
- package/dist/poster/projectRoot.test.js +47 -0
- package/dist/poster/projectRoot.test.js.map +1 -0
- package/dist/poster/server.d.ts +18 -0
- package/dist/poster/server.js +9 -0
- package/dist/poster/server.js.map +1 -0
- package/dist/poster/server.test.d.ts +2 -0
- package/dist/poster/server.test.js +54 -0
- package/dist/poster/server.test.js.map +1 -0
- package/dist/{update-3BHHOUCS.js → update-WK7CA42P.js} +26 -17
- package/dist/update-WK7CA42P.js.map +1 -0
- package/package.json +19 -3
- package/dist/add-ABC455QH.js +0 -10
- package/dist/chunk-4XUN2PKU.js.map +0 -1
- package/dist/chunk-M6S6HYHE.js.map +0 -1
- package/dist/chunk-OJWKSIZ5.js.map +0 -1
- package/dist/init-W43YVGBI.js.map +0 -1
- package/dist/list-S626E7NZ.js.map +0 -1
- package/dist/update-3BHHOUCS.js.map +0 -1
- /package/dist/{add-ABC455QH.js.map → add-T7IRU2NK.js.map} +0 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createPosterServer
|
|
4
|
+
} from "../chunk-YAWX2IU3.js";
|
|
5
|
+
import {
|
|
6
|
+
afterEach,
|
|
7
|
+
beforeEach,
|
|
8
|
+
describe,
|
|
9
|
+
globalExpect,
|
|
10
|
+
it
|
|
11
|
+
} from "../chunk-YADIAD35.js";
|
|
12
|
+
import "../chunk-D4HDZEJT.js";
|
|
13
|
+
|
|
14
|
+
// src/poster/server.test.ts
|
|
15
|
+
var bundle = {
|
|
16
|
+
html: "<!doctype html><html><body>ok</body></html>",
|
|
17
|
+
js: 'console.log("bundle")'
|
|
18
|
+
};
|
|
19
|
+
var server;
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
server = await createPosterServer({ bundle, config: { width: 1280, height: 720 } });
|
|
22
|
+
});
|
|
23
|
+
afterEach(async () => {
|
|
24
|
+
await server.close();
|
|
25
|
+
});
|
|
26
|
+
describe("createPosterServer", () => {
|
|
27
|
+
it("listens on a random localhost port", () => {
|
|
28
|
+
globalExpect(server.url).toMatch(/^http:\/\/127\.0\.0\.1:\d+$/);
|
|
29
|
+
});
|
|
30
|
+
it("serves the harness HTML at /", async () => {
|
|
31
|
+
const res = await fetch(`${server.url}/`);
|
|
32
|
+
globalExpect(res.status).toBe(200);
|
|
33
|
+
globalExpect(res.headers.get("content-type")).toMatch(/text\/html/);
|
|
34
|
+
globalExpect(await res.text()).toContain("ok");
|
|
35
|
+
});
|
|
36
|
+
it("serves the harness JS at /harness.js", async () => {
|
|
37
|
+
const res = await fetch(`${server.url}/harness.js`);
|
|
38
|
+
globalExpect(res.status).toBe(200);
|
|
39
|
+
globalExpect(res.headers.get("content-type")).toMatch(/javascript/);
|
|
40
|
+
globalExpect(await res.text()).toContain("bundle");
|
|
41
|
+
});
|
|
42
|
+
it("serves the render config as JSON at /config.json", async () => {
|
|
43
|
+
const res = await fetch(`${server.url}/config.json`);
|
|
44
|
+
globalExpect(res.status).toBe(200);
|
|
45
|
+
const json = await res.json();
|
|
46
|
+
globalExpect(json.width).toBe(1280);
|
|
47
|
+
globalExpect(json.height).toBe(720);
|
|
48
|
+
});
|
|
49
|
+
it("404s unknown paths", async () => {
|
|
50
|
+
const res = await fetch(`${server.url}/nope`);
|
|
51
|
+
globalExpect(res.status).toBe(404);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//# sourceMappingURL=server.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/poster/server.test.ts"],"sourcesContent":["import { afterEach, beforeEach, describe, expect, it } from 'vitest';\n\nimport { createPosterServer, type PosterServer } from './server.js';\n\nconst bundle = {\n html: '<!doctype html><html><body>ok</body></html>',\n js: 'console.log(\"bundle\")',\n};\n\nlet server: PosterServer;\n\nbeforeEach(async () => {\n server = await createPosterServer({ bundle, config: { width: 1280, height: 720 } });\n});\n\nafterEach(async () => {\n await server.close();\n});\n\ndescribe('createPosterServer', () => {\n it('listens on a random localhost port', () => {\n expect(server.url).toMatch(/^http:\\/\\/127\\.0\\.0\\.1:\\d+$/);\n });\n\n it('serves the harness HTML at /', async () => {\n const res = await fetch(`${server.url}/`);\n\n expect(res.status).toBe(200);\n expect(res.headers.get('content-type')).toMatch(/text\\/html/);\n expect(await res.text()).toContain('ok');\n });\n\n it('serves the harness JS at /harness.js', async () => {\n const res = await fetch(`${server.url}/harness.js`);\n\n expect(res.status).toBe(200);\n expect(res.headers.get('content-type')).toMatch(/javascript/);\n expect(await res.text()).toContain('bundle');\n });\n\n it('serves the render config as JSON at /config.json', async () => {\n const res = await fetch(`${server.url}/config.json`);\n\n expect(res.status).toBe(200);\n const json = (await res.json()) as { width: number; height: number };\n\n expect(json.width).toBe(1280);\n expect(json.height).toBe(720);\n });\n\n it('404s unknown paths', async () => {\n const res = await fetch(`${server.url}/nope`);\n\n expect(res.status).toBe(404);\n });\n});\n"],"mappings":";;;;;;;;;;;;;;AAIA,IAAM,SAAS;AAAA,EACb,MAAM;AAAA,EACN,IAAI;AACN;AAEA,IAAI;AAEJ,WAAW,YAAY;AACrB,WAAS,MAAM,mBAAmB,EAAE,QAAQ,QAAQ,EAAE,OAAO,MAAM,QAAQ,IAAI,EAAE,CAAC;AACpF,CAAC;AAED,UAAU,YAAY;AACpB,QAAM,OAAO,MAAM;AACrB,CAAC;AAED,SAAS,sBAAsB,MAAM;AACnC,KAAG,sCAAsC,MAAM;AAC7C,iBAAO,OAAO,GAAG,EAAE,QAAQ,6BAA6B;AAAA,EAC1D,CAAC;AAED,KAAG,gCAAgC,YAAY;AAC7C,UAAM,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,GAAG;AAExC,iBAAO,IAAI,MAAM,EAAE,KAAK,GAAG;AAC3B,iBAAO,IAAI,QAAQ,IAAI,cAAc,CAAC,EAAE,QAAQ,YAAY;AAC5D,iBAAO,MAAM,IAAI,KAAK,CAAC,EAAE,UAAU,IAAI;AAAA,EACzC,CAAC;AAED,KAAG,wCAAwC,YAAY;AACrD,UAAM,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,aAAa;AAElD,iBAAO,IAAI,MAAM,EAAE,KAAK,GAAG;AAC3B,iBAAO,IAAI,QAAQ,IAAI,cAAc,CAAC,EAAE,QAAQ,YAAY;AAC5D,iBAAO,MAAM,IAAI,KAAK,CAAC,EAAE,UAAU,QAAQ;AAAA,EAC7C,CAAC;AAED,KAAG,oDAAoD,YAAY;AACjE,UAAM,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,cAAc;AAEnD,iBAAO,IAAI,MAAM,EAAE,KAAK,GAAG;AAC3B,UAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,iBAAO,KAAK,KAAK,EAAE,KAAK,IAAI;AAC5B,iBAAO,KAAK,MAAM,EAAE,KAAK,GAAG;AAAA,EAC9B,CAAC;AAED,KAAG,sBAAsB,YAAY;AACnC,UAAM,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO;AAE5C,iBAAO,IAAI,MAAM,EAAE,KAAK,GAAG;AAAA,EAC7B,CAAC;AACH,CAAC;","names":[]}
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runAdd
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-53DI7V2J.js";
|
|
5
5
|
import {
|
|
6
6
|
fetchRegistry,
|
|
7
7
|
resolveRef
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-FHRQIHCN.js";
|
|
9
9
|
import {
|
|
10
|
-
readMatterConfig
|
|
11
|
-
|
|
10
|
+
readMatterConfig,
|
|
11
|
+
resolveRegistryUrl
|
|
12
|
+
} from "./chunk-R7OX6KUP.js";
|
|
13
|
+
import "./chunk-D4HDZEJT.js";
|
|
12
14
|
|
|
13
15
|
// src/commands/update.ts
|
|
14
16
|
import { readdir } from "fs/promises";
|
|
15
|
-
import { extname, join } from "path";
|
|
17
|
+
import { basename, extname, join } from "path";
|
|
16
18
|
async function runUpdate(components, opts, io = { cwd: process.cwd(), log: console.log }) {
|
|
17
|
-
const
|
|
18
|
-
const baseUrl = opts.registry ?? cfg.registryUrl;
|
|
19
|
+
const matterConfig = await readMatterConfig(io.cwd);
|
|
19
20
|
const ref = resolveRef(opts.ref, opts.cliVersion);
|
|
20
|
-
const registryUrl =
|
|
21
|
-
const componentsDir = join(io.cwd,
|
|
22
|
-
const
|
|
23
|
-
const localSlugs =
|
|
21
|
+
const registryUrl = resolveRegistryUrl(matterConfig, { registry: opts.registry, ref });
|
|
22
|
+
const componentsDir = join(io.cwd, matterConfig.componentsDir);
|
|
23
|
+
const localEntries = await safeReaddir(componentsDir);
|
|
24
|
+
const localSlugs = localEntries.flatMap((entry) => {
|
|
25
|
+
if (entry.isFile() && (extname(entry.name) === ".tsx" || extname(entry.name) === ".ts")) {
|
|
26
|
+
return [entry.name.replace(/\.(tsx|ts)$/, "")];
|
|
27
|
+
}
|
|
28
|
+
if (entry.isDirectory()) return [entry.name];
|
|
29
|
+
return [];
|
|
30
|
+
});
|
|
24
31
|
const registry = await fetchRegistry(registryUrl);
|
|
25
32
|
let toUpdate;
|
|
26
33
|
if (components.length === 0) {
|
|
@@ -59,17 +66,19 @@ async function runUpdate(components, opts, io = { cwd: process.cwd(), log: conso
|
|
|
59
66
|
}
|
|
60
67
|
async function safeReaddir(path) {
|
|
61
68
|
try {
|
|
62
|
-
return await readdir(path);
|
|
63
|
-
} catch (
|
|
64
|
-
if (
|
|
65
|
-
|
|
69
|
+
return await readdir(path, { withFileTypes: true });
|
|
70
|
+
} catch (caughtError) {
|
|
71
|
+
if (caughtError instanceof Error && "code" in caughtError && caughtError.code === "ENOENT")
|
|
72
|
+
return [];
|
|
73
|
+
throw caughtError;
|
|
66
74
|
}
|
|
67
75
|
}
|
|
68
76
|
function slugIsInRegistry(slug, registry) {
|
|
69
77
|
const entry = registry.components[slug];
|
|
70
|
-
|
|
78
|
+
if (entry === void 0) return false;
|
|
79
|
+
return basename(entry.file).replace(/\.(tsx|ts)$/, "") === slug;
|
|
71
80
|
}
|
|
72
81
|
export {
|
|
73
82
|
runUpdate
|
|
74
83
|
};
|
|
75
|
-
//# sourceMappingURL=update-
|
|
84
|
+
//# sourceMappingURL=update-WK7CA42P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import type { Dirent } from 'node:fs';\nimport { readdir } from 'node:fs/promises';\nimport { basename, extname, join } from 'node:path';\n\nimport { readMatterConfig, resolveRegistryUrl } from '../config/matterConfig.js';\nimport { fetchRegistry, type Registry } from '../registry/fetchRegistry.js';\nimport { resolveRef } from '../registry/ref.js';\nimport { runAdd } from './add.js';\n\nexport interface UpdateOptions {\n registry?: string;\n ref?: string;\n force?: boolean;\n cliVersion: string;\n}\n\nexport interface UpdateIO {\n cwd: string;\n log: (line: string) => void;\n}\n\nexport async function runUpdate(\n components: string[],\n opts: UpdateOptions,\n io: UpdateIO = { cwd: process.cwd(), log: console.log },\n): Promise<void> {\n const matterConfig = await readMatterConfig(io.cwd);\n const ref = resolveRef(opts.ref, opts.cliVersion);\n const registryUrl = resolveRegistryUrl(matterConfig, { registry: opts.registry, ref });\n\n const componentsDir = join(io.cwd, matterConfig.componentsDir);\n const localEntries = await safeReaddir(componentsDir);\n // Recognize both layouts: top-level `<slug>.tsx` AND subdir `<slug>/<slug>.tsx`\n // (the latter is how multi-file components like aurora and linear-gradient live).\n const localSlugs = localEntries.flatMap((entry) => {\n if (entry.isFile() && (extname(entry.name) === '.tsx' || extname(entry.name) === '.ts')) {\n return [entry.name.replace(/\\.(tsx|ts)$/, '')];\n }\n if (entry.isDirectory()) return [entry.name];\n\n return [];\n });\n\n const registry = await fetchRegistry(registryUrl);\n\n let toUpdate: string[];\n\n if (components.length === 0) {\n if (localSlugs.length === 0) {\n throw new Error(\n `No components found in ${componentsDir}. Run \\`matter-cli add <name>\\` first.`,\n );\n }\n toUpdate = localSlugs.filter((slug) => slugIsInRegistry(slug, registry));\n if (toUpdate.length === 0) {\n throw new Error(`No components in ${componentsDir} match any registry entry.`);\n }\n } else {\n for (const slug of components) {\n const file = registry.components[slug]?.file;\n const present = file !== undefined && localSlugs.includes(slug);\n\n if (!present) {\n throw new Error(\n `Component \"${slug}\" is not present in ${componentsDir}. Use \\`matter-cli add ${slug}\\` instead.`,\n );\n }\n }\n toUpdate = components;\n }\n\n io.log(`Updating ${toUpdate.length} component(s) from ${registryUrl}…`);\n\n await runAdd(\n toUpdate,\n {\n registry: registryUrl,\n ref: undefined,\n force: opts.force,\n cliVersion: opts.cliVersion,\n },\n io,\n );\n}\n\nasync function safeReaddir(path: string): Promise<Dirent[]> {\n try {\n return await readdir(path, { withFileTypes: true });\n } catch (caughtError) {\n if (caughtError instanceof Error && 'code' in caughtError && caughtError.code === 'ENOENT')\n return [];\n throw caughtError;\n }\n}\n\nfunction slugIsInRegistry(slug: string, registry: Registry): boolean {\n const entry = registry.components[slug];\n\n if (entry === undefined) return false;\n\n // Registry `file` is either `<slug>.tsx` (flat) or `<slug>/<slug>.tsx` (subdir).\n // Match the basename without extension against the slug.\n return basename(entry.file).replace(/\\.(tsx|ts)$/, '') === slug;\n}\n"],"mappings":";;;;;;;;;;;;;;;AACA,SAAS,eAAe;AACxB,SAAS,UAAU,SAAS,YAAY;AAmBxC,eAAsB,UACpB,YACA,MACA,KAAe,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,GACvC;AACf,QAAM,eAAe,MAAM,iBAAiB,GAAG,GAAG;AAClD,QAAM,MAAM,WAAW,KAAK,KAAK,KAAK,UAAU;AAChD,QAAM,cAAc,mBAAmB,cAAc,EAAE,UAAU,KAAK,UAAU,IAAI,CAAC;AAErF,QAAM,gBAAgB,KAAK,GAAG,KAAK,aAAa,aAAa;AAC7D,QAAM,eAAe,MAAM,YAAY,aAAa;AAGpD,QAAM,aAAa,aAAa,QAAQ,CAAC,UAAU;AACjD,QAAI,MAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,UAAU,QAAQ,MAAM,IAAI,MAAM,QAAQ;AACvF,aAAO,CAAC,MAAM,KAAK,QAAQ,eAAe,EAAE,CAAC;AAAA,IAC/C;AACA,QAAI,MAAM,YAAY,EAAG,QAAO,CAAC,MAAM,IAAI;AAE3C,WAAO,CAAC;AAAA,EACV,CAAC;AAED,QAAM,WAAW,MAAM,cAAc,WAAW;AAEhD,MAAI;AAEJ,MAAI,WAAW,WAAW,GAAG;AAC3B,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,0BAA0B,aAAa;AAAA,MACzC;AAAA,IACF;AACA,eAAW,WAAW,OAAO,CAAC,SAAS,iBAAiB,MAAM,QAAQ,CAAC;AACvE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,MAAM,oBAAoB,aAAa,4BAA4B;AAAA,IAC/E;AAAA,EACF,OAAO;AACL,eAAW,QAAQ,YAAY;AAC7B,YAAM,OAAO,SAAS,WAAW,IAAI,GAAG;AACxC,YAAM,UAAU,SAAS,UAAa,WAAW,SAAS,IAAI;AAE9D,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,cAAc,IAAI,uBAAuB,aAAa,0BAA0B,IAAI;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AACA,eAAW;AAAA,EACb;AAEA,KAAG,IAAI,YAAY,SAAS,MAAM,sBAAsB,WAAW,QAAG;AAEtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,MACE,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,YAAY,MAAiC;AAC1D,MAAI;AACF,WAAO,MAAM,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,SAAS,aAAa;AACpB,QAAI,uBAAuB,SAAS,UAAU,eAAe,YAAY,SAAS;AAChF,aAAO,CAAC;AACV,UAAM;AAAA,EACR;AACF;AAEA,SAAS,iBAAiB,MAAc,UAA6B;AACnE,QAAM,QAAQ,SAAS,WAAW,IAAI;AAEtC,MAAI,UAAU,OAAW,QAAO;AAIhC,SAAO,SAAS,MAAM,IAAI,EAAE,QAAQ,eAAe,EAAE,MAAM;AAC7D;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovo/matter-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "CLI for Matter — copy-paste components from the registry into your project.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -34,16 +34,32 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"commander": "^12.1.0"
|
|
37
|
+
"commander": "^12.1.0",
|
|
38
|
+
"esbuild": "^0.27.0"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@types/node": "^22.7.0",
|
|
42
|
+
"@types/react": "^19.0.0",
|
|
43
|
+
"@types/react-dom": "^19.0.0",
|
|
44
|
+
"playwright": "^1.50.0",
|
|
45
|
+
"react": "^19.0.0",
|
|
46
|
+
"react-dom": "^19.0.0",
|
|
41
47
|
"tsup": "^8.3.0",
|
|
42
48
|
"typescript": "^5.6.0",
|
|
43
49
|
"vite": "^8.0.14",
|
|
44
50
|
"vitest": "^4.1.7",
|
|
51
|
+
"@lovo/matter-react": "0.5.0",
|
|
52
|
+
"@matter/registry": "0.0.0",
|
|
45
53
|
"@matter/tsconfig": "0.0.0"
|
|
46
54
|
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"playwright": "*"
|
|
57
|
+
},
|
|
58
|
+
"peerDependenciesMeta": {
|
|
59
|
+
"playwright": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
62
|
+
},
|
|
47
63
|
"engines": {
|
|
48
64
|
"node": ">=22"
|
|
49
65
|
},
|
|
@@ -51,7 +67,7 @@
|
|
|
51
67
|
"build": "tsup",
|
|
52
68
|
"dev": "tsup --watch",
|
|
53
69
|
"typecheck": "tsc --noEmit",
|
|
54
|
-
"lint": "eslint
|
|
70
|
+
"lint": "eslint .",
|
|
55
71
|
"test": "vitest run",
|
|
56
72
|
"clean": "rm -rf dist .turbo *.tsbuildinfo"
|
|
57
73
|
}
|
package/dist/add-ABC455QH.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/add.ts","../src/transforms/rewriteImports.ts"],"sourcesContent":["import { access, mkdir, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\n\nimport { readMatterConfig } from '../config/matterConfig.js'\nimport {\n fetchComponentSource,\n fetchRegistry,\n type Registry,\n type RegistryEntry,\n} from '../registry/fetchRegistry.js'\nimport { resolveRef } from '../registry/ref.js'\nimport { rewriteImports } from '../transforms/rewriteImports.js'\n\nexport interface AddOptions {\n registry?: string\n ref?: string\n force?: boolean\n cliVersion: string\n}\n\nexport interface AddIO {\n cwd: string\n log: (line: string) => void\n}\n\nexport async function runAdd(\n components: string[],\n opts: AddOptions,\n io: AddIO = { cwd: process.cwd(), log: console.log },\n): Promise<void> {\n if (components.length === 0) {\n throw new Error('add: at least one component name is required')\n }\n\n const cfg = await readMatterConfig(io.cwd)\n const baseUrl = opts.registry ?? cfg.registryUrl\n const ref = resolveRef(opts.ref, opts.cliVersion)\n const registryUrl = baseUrl.replace('${ref}', ref)\n const registry = await fetchRegistry(registryUrl)\n\n // Resolve every component up front so we fail fast on missing slugs\n // before any disk write.\n const resolved = components.map((slug) => resolveComponent(slug, registry, registryUrl))\n\n // Pre-flight overwrite check on every target.\n if (opts.force !== true) {\n for (const r of resolved) {\n const targetPath = join(io.cwd, cfg.componentsDir, r.entry.file)\n\n if (await fileExists(targetPath)) {\n throw new Error(`${targetPath} already exists. Pass --force to overwrite.`)\n }\n }\n }\n\n // Fetch all sources concurrently. If any fetch fails, the throw\n // propagates before we touch disk — no partial-write states.\n const fetched = await Promise.all(\n resolved.map(async (r) => {\n const source = await fetchComponentSource(registryUrl, r.entry.file)\n\n return { ...r, source }\n }),\n )\n\n // Now write sequentially (mkdir + writeFile per target). Sequential\n // here is fine: the bottleneck has already passed.\n const allDeps = new Set<string>()\n\n for (const f of fetched) {\n const targetPath = join(io.cwd, cfg.componentsDir, f.entry.file)\n const rewritten = rewriteImports(f.source, cfg.aliases)\n\n await mkdir(dirname(targetPath), { recursive: true })\n await writeFile(targetPath, rewritten, 'utf-8')\n io.log(`Wrote ${targetPath}`)\n for (const dep of f.entry.dependencies) allDeps.add(dep)\n }\n\n // Dedup + alphabetize install hint.\n const sortedDeps = [...allDeps].sort()\n\n io.log('')\n io.log(`This component requires: ${sortedDeps.join(', ')}`)\n io.log('Install with your package manager, e.g.:')\n io.log(`npm install ${sortedDeps.join(' ')}`)\n}\n\nfunction resolveComponent(\n slug: string,\n registry: Registry,\n registryUrl: string,\n): { slug: string; entry: RegistryEntry } {\n const entry = registry.components[slug]\n\n if (!entry) {\n throw new Error(\n `Component \"${slug}\" not found in registry at ${registryUrl}. Run \\`matter-cli list\\` to see available components.`,\n )\n }\n\n return { slug, entry }\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n try {\n await access(p)\n\n return true\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT') return false\n throw err\n }\n}\n","/**\n * Rewrite import specifiers in a TS/TSX source string per a prefix-match\n * alias map. Each alias key is treated as a literal prefix; if a specifier\n * starts with the key, the prefix is replaced with the value.\n *\n * v1's Tier 1 components don't actually use any internal aliases — every\n * import resolves to a published npm package (`@lovo/matter`,\n * `@lovo/matter-react`, `react`, `three`). The synthetic test fixture\n * imports `@matter-internal/lib` to exercise this code path. When future\n * components do share internal utilities, this rewriter is what shapes\n * those imports per the user's project layout.\n *\n * Longer alias keys win over shorter ones (so `@matter-internal/` beats\n * `@/` when both match).\n */\nexport function rewriteImports(source: string, aliases: Record<string, string>): string {\n const sortedAliases = Object.entries(aliases).sort(([a], [b]) => b.length - a.length)\n\n if (sortedAliases.length === 0) return source\n\n // Match `from '...'` / `from \"...\"` / `import('...')` / `import(\"...\")`.\n const importRe = /(\\bfrom\\s+|\\bimport\\s*\\(\\s*)(['\"])([^'\"]+)\\2/g\n\n return source.replace(importRe, (full, lead: string, quote: string, spec: string) => {\n for (const [key, value] of sortedAliases) {\n if (spec.startsWith(key)) {\n return `${lead}${quote}${value}${spec.slice(key.length)}${quote}`\n }\n }\n\n return full\n })\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config/matterConfig.ts"],"sourcesContent":["import { access, readFile, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nexport interface MatterConfig {\n componentsDir: string\n registryUrl: string\n aliases: Record<string, string>\n tsx: boolean\n}\n\n/**\n * Defaults align with spec §4.3. componentsDir mirrors shadcn's\n * `src/components/ui` convention but namespaced under `matter` so a project\n * using both shadcn and matter doesn't collide.\n */\nexport const DEFAULT_MATTER_CONFIG: MatterConfig = {\n componentsDir: 'src/components/matter',\n registryUrl: 'https://raw.githubusercontent.com/lovo-hq/matter/${ref}/registry',\n aliases: { '@/': 'src/' },\n tsx: true,\n}\n\nconst CONFIG_FILENAME = 'matter.config.json'\n\nexport function configPath(projectRoot: string): string {\n return join(projectRoot, CONFIG_FILENAME)\n}\n\nexport async function configExists(projectRoot: string): Promise<boolean> {\n try {\n await access(configPath(projectRoot))\n\n return true\n } catch {\n return false\n }\n}\n\nexport async function readMatterConfig(projectRoot: string): Promise<MatterConfig> {\n const path = configPath(projectRoot)\n let raw: string\n\n try {\n raw = await readFile(path, 'utf-8')\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {\n throw new Error(\n `matter.config.json not found in ${projectRoot}. Run \\`matter-cli init\\` first.`,\n )\n }\n throw err\n }\n let parsed: unknown\n\n try {\n parsed = JSON.parse(raw)\n } catch (err) {\n throw new Error(\n `${path} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n\n return validateMatterConfig(parsed, path)\n}\n\nexport async function writeMatterConfig(projectRoot: string, cfg: MatterConfig): Promise<void> {\n const path = configPath(projectRoot)\n const json = `${JSON.stringify(cfg, null, 2)}\\n`\n\n await writeFile(path, json, 'utf-8')\n}\n\nfunction isRecord(x: unknown): x is Record<string, unknown> {\n return typeof x === 'object' && x !== null\n}\n\nfunction validateMatterConfig(parsed: unknown, path: string): MatterConfig {\n if (!isRecord(parsed)) {\n throw new Error(`${path}: expected an object`)\n }\n const obj = parsed\n\n if (typeof obj.componentsDir !== 'string' || obj.componentsDir === '') {\n throw new Error(`${path}: missing or empty \"componentsDir\" string`)\n }\n if (typeof obj.registryUrl !== 'string' || obj.registryUrl === '') {\n throw new Error(`${path}: missing or empty \"registryUrl\" string`)\n }\n if (!isRecord(obj.aliases)) {\n throw new Error(`${path}: missing \"aliases\" object`)\n }\n if (typeof obj.tsx !== 'boolean') {\n throw new Error(`${path}: missing \"tsx\" boolean`)\n }\n const aliases: Record<string, string> = {}\n\n for (const [k, v] of Object.entries(obj.aliases)) {\n if (typeof v !== 'string') {\n throw new Error(`${path}: aliases.${k} must be a string`)\n }\n aliases[k] = v\n }\n\n return {\n componentsDir: obj.componentsDir,\n registryUrl: obj.registryUrl,\n aliases,\n tsx: obj.tsx,\n }\n}\n"],"mappings":";;;AAAA,SAAS,QAAQ,UAAU,iBAAiB;AAC5C,SAAS,YAAY;AAcd,IAAM,wBAAsC;AAAA,EACjD,eAAe;AAAA,EACf,aAAa;AAAA,EACb,SAAS,EAAE,MAAM,OAAO;AAAA,EACxB,KAAK;AACP;AAEA,IAAM,kBAAkB;AAEjB,SAAS,WAAW,aAA6B;AACtD,SAAO,KAAK,aAAa,eAAe;AAC1C;AAEA,eAAsB,aAAa,aAAuC;AACxE,MAAI;AACF,UAAM,OAAO,WAAW,WAAW,CAAC;AAEpC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,iBAAiB,aAA4C;AACjF,QAAM,OAAO,WAAW,WAAW;AACnC,MAAI;AAEJ,MAAI;AACF,UAAM,MAAM,SAAS,MAAM,OAAO;AAAA,EACpC,SAAS,KAAK;AACZ,QAAI,eAAe,SAAS,UAAU,OAAO,IAAI,SAAS,UAAU;AAClE,YAAM,IAAI;AAAA,QACR,mCAAmC,WAAW;AAAA,MAChD;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACA,MAAI;AAEJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,GAAG,IAAI,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAChF;AAAA,EACF;AAEA,SAAO,qBAAqB,QAAQ,IAAI;AAC1C;AAEA,eAAsB,kBAAkB,aAAqB,KAAkC;AAC7F,QAAM,OAAO,WAAW,WAAW;AACnC,QAAM,OAAO,GAAG,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA;AAE5C,QAAM,UAAU,MAAM,MAAM,OAAO;AACrC;AAEA,SAAS,SAAS,GAA0C;AAC1D,SAAO,OAAO,MAAM,YAAY,MAAM;AACxC;AAEA,SAAS,qBAAqB,QAAiB,MAA4B;AACzE,MAAI,CAAC,SAAS,MAAM,GAAG;AACrB,UAAM,IAAI,MAAM,GAAG,IAAI,sBAAsB;AAAA,EAC/C;AACA,QAAM,MAAM;AAEZ,MAAI,OAAO,IAAI,kBAAkB,YAAY,IAAI,kBAAkB,IAAI;AACrE,UAAM,IAAI,MAAM,GAAG,IAAI,2CAA2C;AAAA,EACpE;AACA,MAAI,OAAO,IAAI,gBAAgB,YAAY,IAAI,gBAAgB,IAAI;AACjE,UAAM,IAAI,MAAM,GAAG,IAAI,yCAAyC;AAAA,EAClE;AACA,MAAI,CAAC,SAAS,IAAI,OAAO,GAAG;AAC1B,UAAM,IAAI,MAAM,GAAG,IAAI,4BAA4B;AAAA,EACrD;AACA,MAAI,OAAO,IAAI,QAAQ,WAAW;AAChC,UAAM,IAAI,MAAM,GAAG,IAAI,yBAAyB;AAAA,EAClD;AACA,QAAM,UAAkC,CAAC;AAEzC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AAChD,QAAI,OAAO,MAAM,UAAU;AACzB,YAAM,IAAI,MAAM,GAAG,IAAI,aAAa,CAAC,mBAAmB;AAAA,IAC1D;AACA,YAAQ,CAAC,IAAI;AAAA,EACf;AAEA,SAAO;AAAA,IACL,eAAe,IAAI;AAAA,IACnB,aAAa,IAAI;AAAA,IACjB;AAAA,IACA,KAAK,IAAI;AAAA,EACX;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/registry/readUrl.ts","../src/registry/fetchRegistry.ts","../src/registry/ref.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport { fileURLToPath } from 'node:url'\n\n/**\n * Read a URL and return its contents as a UTF-8 string. Supports `file://`\n * and `http(s)://` schemes. Used internally by registry fetching and\n * component source fetching — the same code path serves dev (`file://`\n * pointing at the local registry) and production (`https://raw.githubusercontent.com/...`).\n */\nexport async function readUrl(url: string): Promise<string> {\n const parsed = new URL(url)\n\n if (parsed.protocol === 'file:') {\n const path = fileURLToPath(parsed)\n\n try {\n return await readFile(path, 'utf-8')\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT') {\n throw new Error(`File not found: ${path}`)\n }\n throw err\n }\n }\n\n if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {\n let res: Response\n\n try {\n res = await fetch(url)\n } catch (err) {\n throw new Error(`Failed to fetch ${url}: ${err instanceof Error ? err.message : String(err)}`)\n }\n if (!res.ok) {\n throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`)\n }\n\n return await res.text()\n }\n\n throw new Error(\n `Unsupported protocol: ${parsed.protocol} (only file://, http://, https:// are supported)`,\n )\n}\n","import { readUrl } from './readUrl.js'\n\nexport interface RegistryEntry {\n file: string\n description?: string\n dependencies: string[]\n uses_primitives?: string[]\n tier: 1 | 2 | 3\n}\n\nexport interface Registry {\n version: string\n components: Record<string, RegistryEntry>\n}\n\n/**\n * Join a base URL with a relative filename, normalizing the trailing slash.\n * `joinUrl(\"https://x/registry\", \"foo.tsx\")` and `joinUrl(\"https://x/registry/\", \"foo.tsx\")`\n * both return `https://x/registry/foo.tsx`.\n */\nexport function joinUrl(base: string, file: string): string {\n const trimmed = base.endsWith('/') ? base.slice(0, -1) : base\n\n return `${trimmed}/${file}`\n}\n\n/**\n * Fetch and parse `registry.json` from a base registry URL.\n * The base URL points at the directory containing registry.json\n * (e.g. `file:///.../registry/` or\n * `https://raw.githubusercontent.com/lovo/matter/main/registry`).\n */\nexport async function fetchRegistry(baseUrl: string): Promise<Registry> {\n const url = joinUrl(baseUrl, 'registry.json')\n const json = await readUrl(url)\n let parsed: unknown\n\n try {\n parsed = JSON.parse(json)\n } catch (err) {\n throw new Error(\n `Registry at ${url} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n )\n }\n if (!looksLikeRegistry(parsed)) {\n throw new Error(`Registry at ${url} is missing a \"components\" object`)\n }\n\n return parsed\n}\n\nfunction looksLikeRegistry(x: unknown): x is Registry {\n if (typeof x !== 'object' || x === null || !('components' in x)) return false\n const components = x.components\n\n return typeof components === 'object' && components !== null && !Array.isArray(components)\n}\n\n/**\n * Fetch the raw source of a component file referenced by a registry entry.\n */\nexport async function fetchComponentSource(baseUrl: string, file: string): Promise<string> {\n return await readUrl(joinUrl(baseUrl, file))\n}\n","/**\n * Resolve which git ref the CLI should fetch from.\n *\n * - If `ref` is supplied, use it verbatim.\n * - If the CLI version is `0.0.0`, default to `main` (development build —\n * no published v0.0.0 tag exists).\n * - Otherwise, default to `v<version>` (e.g. `0.1.0` → `v0.1.0`).\n *\n * This matches the shadcn pattern: the published CLI's default ref is the\n * version it was published at, so users aren't blindly tracking `main`.\n */\nexport function resolveRef(ref: string | undefined, cliVersion: string): string {\n if (ref !== undefined && ref !== '') return ref\n if (cliVersion === '0.0.0') return 'main'\n\n return `v${cliVersion}`\n}\n"],"mappings":";;;AAAA,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAQ9B,eAAsB,QAAQ,KAA8B;AAC1D,QAAM,SAAS,IAAI,IAAI,GAAG;AAE1B,MAAI,OAAO,aAAa,SAAS;AAC/B,UAAM,OAAO,cAAc,MAAM;AAEjC,QAAI;AACF,aAAO,MAAM,SAAS,MAAM,OAAO;AAAA,IACrC,SAAS,KAAK;AACZ,UAAI,eAAe,SAAS,UAAU,OAAO,IAAI,SAAS,UAAU;AAClE,cAAM,IAAI,MAAM,mBAAmB,IAAI,EAAE;AAAA,MAC3C;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,WAAW,OAAO,aAAa,UAAU;AAC/D,QAAI;AAEJ,QAAI;AACF,YAAM,MAAM,MAAM,GAAG;AAAA,IACvB,SAAS,KAAK;AACZ,YAAM,IAAI,MAAM,mBAAmB,GAAG,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IAC/F;AACA,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,mBAAmB,GAAG,KAAK,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,IAC3E;AAEA,WAAO,MAAM,IAAI,KAAK;AAAA,EACxB;AAEA,QAAM,IAAI;AAAA,IACR,yBAAyB,OAAO,QAAQ;AAAA,EAC1C;AACF;;;ACvBO,SAAS,QAAQ,MAAc,MAAsB;AAC1D,QAAM,UAAU,KAAK,SAAS,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AAEzD,SAAO,GAAG,OAAO,IAAI,IAAI;AAC3B;AAQA,eAAsB,cAAc,SAAoC;AACtE,QAAM,MAAM,QAAQ,SAAS,eAAe;AAC5C,QAAM,OAAO,MAAM,QAAQ,GAAG;AAC9B,MAAI;AAEJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,SAAS,KAAK;AACZ,UAAM,IAAI;AAAA,MACR,eAAe,GAAG,uBAAuB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3F;AAAA,EACF;AACA,MAAI,CAAC,kBAAkB,MAAM,GAAG;AAC9B,UAAM,IAAI,MAAM,eAAe,GAAG,mCAAmC;AAAA,EACvE;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,GAA2B;AACpD,MAAI,OAAO,MAAM,YAAY,MAAM,QAAQ,EAAE,gBAAgB,GAAI,QAAO;AACxE,QAAM,aAAa,EAAE;AAErB,SAAO,OAAO,eAAe,YAAY,eAAe,QAAQ,CAAC,MAAM,QAAQ,UAAU;AAC3F;AAKA,eAAsB,qBAAqB,SAAiB,MAA+B;AACzF,SAAO,MAAM,QAAQ,QAAQ,SAAS,IAAI,CAAC;AAC7C;;;ACpDO,SAAS,WAAW,KAAyB,YAA4B;AAC9E,MAAI,QAAQ,UAAa,QAAQ,GAAI,QAAO;AAC5C,MAAI,eAAe,QAAS,QAAO;AAEnC,SAAO,IAAI,UAAU;AACvB;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import {\n configExists,\n configPath,\n DEFAULT_MATTER_CONFIG,\n writeMatterConfig,\n} from '../config/matterConfig.js'\n\nexport interface InitOptions {\n force?: boolean\n}\n\nexport interface InitIO {\n cwd: string\n log: (line: string) => void\n}\n\nexport async function runInit(\n opts: InitOptions,\n io: InitIO = { cwd: process.cwd(), log: console.log },\n): Promise<void> {\n const exists = await configExists(io.cwd)\n\n if (exists && opts.force !== true) {\n throw new Error(`matter.config.json already exists in ${io.cwd}. Pass --force to overwrite.`)\n }\n await writeMatterConfig(io.cwd, DEFAULT_MATTER_CONFIG)\n io.log(`Created matter.config.json at ${configPath(io.cwd)}`)\n io.log(\n 'Edit `componentsDir` if your project uses a different layout, ' +\n 'and adjust `aliases` to match your tsconfig paths.',\n )\n}\n"],"mappings":";;;;;;;;;AAgBA,eAAsB,QACpB,MACA,KAAa,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,GACrC;AACf,QAAM,SAAS,MAAM,aAAa,GAAG,GAAG;AAExC,MAAI,UAAU,KAAK,UAAU,MAAM;AACjC,UAAM,IAAI,MAAM,wCAAwC,GAAG,GAAG,8BAA8B;AAAA,EAC9F;AACA,QAAM,kBAAkB,GAAG,KAAK,qBAAqB;AACrD,KAAG,IAAI,iCAAiC,WAAW,GAAG,GAAG,CAAC,EAAE;AAC5D,KAAG;AAAA,IACD;AAAA,EAEF;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/list.ts"],"sourcesContent":["import { configExists, DEFAULT_MATTER_CONFIG, readMatterConfig } from '../config/matterConfig.js'\nimport { fetchRegistry } from '../registry/fetchRegistry.js'\nimport { resolveRef } from '../registry/ref.js'\n\nexport interface ListOptions {\n registry?: string\n ref?: string\n cliVersion: string\n}\n\nexport interface ListIO {\n cwd: string\n log: (line: string) => void\n}\n\nexport async function runList(\n opts: ListOptions,\n io: ListIO = { cwd: process.cwd(), log: console.log },\n): Promise<void> {\n // URL resolution: --registry > matter.config.json > built-in default.\n // Missing config → default (lets users `list` before `init`). Malformed\n // config (invalid JSON, missing fields) → propagate so the user sees the\n // problem instead of silently falling back to the GitHub URL.\n let baseUrl: string\n\n if (opts.registry !== undefined && opts.registry !== '') {\n baseUrl = opts.registry\n } else if (await configExists(io.cwd)) {\n const cfg = await readMatterConfig(io.cwd)\n\n baseUrl = cfg.registryUrl\n } else {\n baseUrl = DEFAULT_MATTER_CONFIG.registryUrl\n }\n\n const ref = resolveRef(opts.ref, opts.cliVersion)\n const url = baseUrl.replace('${ref}', ref)\n const registry = await fetchRegistry(url)\n const entries = Object.entries(registry.components).sort(([a], [b]) => a.localeCompare(b))\n\n if (entries.length === 0) {\n io.log('No components in registry.')\n\n return\n }\n\n for (const [slug, entry] of entries) {\n const description = entry.description ?? '(no description)'\n\n io.log(`${slug} · ${description} · tier ${entry.tier}`)\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,eAAsB,QACpB,MACA,KAAa,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,GACrC;AAKf,MAAI;AAEJ,MAAI,KAAK,aAAa,UAAa,KAAK,aAAa,IAAI;AACvD,cAAU,KAAK;AAAA,EACjB,WAAW,MAAM,aAAa,GAAG,GAAG,GAAG;AACrC,UAAM,MAAM,MAAM,iBAAiB,GAAG,GAAG;AAEzC,cAAU,IAAI;AAAA,EAChB,OAAO;AACL,cAAU,sBAAsB;AAAA,EAClC;AAEA,QAAM,MAAM,WAAW,KAAK,KAAK,KAAK,UAAU;AAChD,QAAM,MAAM,QAAQ,QAAQ,UAAU,GAAG;AACzC,QAAM,WAAW,MAAM,cAAc,GAAG;AACxC,QAAM,UAAU,OAAO,QAAQ,SAAS,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAEzF,MAAI,QAAQ,WAAW,GAAG;AACxB,OAAG,IAAI,4BAA4B;AAEnC;AAAA,EACF;AAEA,aAAW,CAAC,MAAM,KAAK,KAAK,SAAS;AACnC,UAAM,cAAc,MAAM,eAAe;AAEzC,OAAG,IAAI,GAAG,IAAI,SAAM,WAAW,cAAW,MAAM,IAAI,EAAE;AAAA,EACxD;AACF;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/update.ts"],"sourcesContent":["import { readdir } from 'node:fs/promises'\nimport { extname, join } from 'node:path'\n\nimport { readMatterConfig } from '../config/matterConfig.js'\nimport { fetchRegistry, type Registry } from '../registry/fetchRegistry.js'\nimport { resolveRef } from '../registry/ref.js'\n\nimport { runAdd } from './add.js'\n\nexport interface UpdateOptions {\n registry?: string\n ref?: string\n force?: boolean\n cliVersion: string\n}\n\nexport interface UpdateIO {\n cwd: string\n log: (line: string) => void\n}\n\nexport async function runUpdate(\n components: string[],\n opts: UpdateOptions,\n io: UpdateIO = { cwd: process.cwd(), log: console.log },\n): Promise<void> {\n const cfg = await readMatterConfig(io.cwd)\n const baseUrl = opts.registry ?? cfg.registryUrl\n const ref = resolveRef(opts.ref, opts.cliVersion)\n const registryUrl = baseUrl.replace('${ref}', ref)\n\n const componentsDir = join(io.cwd, cfg.componentsDir)\n const localFiles = await safeReaddir(componentsDir)\n const localSlugs = localFiles\n .filter((f) => extname(f) === '.tsx' || extname(f) === '.ts')\n .map((f) => f.replace(/\\.(tsx|ts)$/, ''))\n\n const registry = await fetchRegistry(registryUrl)\n\n let toUpdate: string[]\n\n if (components.length === 0) {\n if (localSlugs.length === 0) {\n throw new Error(\n `No components found in ${componentsDir}. Run \\`matter-cli add <name>\\` first.`,\n )\n }\n toUpdate = localSlugs.filter((slug) => slugIsInRegistry(slug, registry))\n if (toUpdate.length === 0) {\n throw new Error(`No components in ${componentsDir} match any registry entry.`)\n }\n } else {\n for (const slug of components) {\n const file = registry.components[slug]?.file\n const present = file !== undefined && localSlugs.includes(slug)\n\n if (!present) {\n throw new Error(\n `Component \"${slug}\" is not present in ${componentsDir}. Use \\`matter-cli add ${slug}\\` instead.`,\n )\n }\n }\n toUpdate = components\n }\n\n io.log(`Updating ${toUpdate.length} component(s) from ${registryUrl}…`)\n // registryUrl already has ${ref} substituted above; pass ref: undefined so\n // runAdd doesn't try to resolve again over an already-substituted URL.\n await runAdd(\n toUpdate,\n {\n registry: registryUrl,\n ref: undefined,\n force: opts.force,\n cliVersion: opts.cliVersion,\n },\n io,\n )\n}\n\nasync function safeReaddir(path: string): Promise<string[]> {\n try {\n return await readdir(path)\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT') return []\n throw err\n }\n}\n\n// Convention in v1: slug equals the basename of entry.file. update keys off\n// the local filename, so a registry whose slug and filename diverge would\n// silently get skipped here. The single check guards both invariants.\nfunction slugIsInRegistry(slug: string, registry: Registry): boolean {\n const entry = registry.components[slug]\n\n return entry?.file.replace(/\\.(tsx|ts)$/, '') === slug\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,eAAe;AACxB,SAAS,SAAS,YAAY;AAoB9B,eAAsB,UACpB,YACA,MACA,KAAe,EAAE,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ,IAAI,GACvC;AACf,QAAM,MAAM,MAAM,iBAAiB,GAAG,GAAG;AACzC,QAAM,UAAU,KAAK,YAAY,IAAI;AACrC,QAAM,MAAM,WAAW,KAAK,KAAK,KAAK,UAAU;AAChD,QAAM,cAAc,QAAQ,QAAQ,UAAU,GAAG;AAEjD,QAAM,gBAAgB,KAAK,GAAG,KAAK,IAAI,aAAa;AACpD,QAAM,aAAa,MAAM,YAAY,aAAa;AAClD,QAAM,aAAa,WAChB,OAAO,CAAC,MAAM,QAAQ,CAAC,MAAM,UAAU,QAAQ,CAAC,MAAM,KAAK,EAC3D,IAAI,CAAC,MAAM,EAAE,QAAQ,eAAe,EAAE,CAAC;AAE1C,QAAM,WAAW,MAAM,cAAc,WAAW;AAEhD,MAAI;AAEJ,MAAI,WAAW,WAAW,GAAG;AAC3B,QAAI,WAAW,WAAW,GAAG;AAC3B,YAAM,IAAI;AAAA,QACR,0BAA0B,aAAa;AAAA,MACzC;AAAA,IACF;AACA,eAAW,WAAW,OAAO,CAAC,SAAS,iBAAiB,MAAM,QAAQ,CAAC;AACvE,QAAI,SAAS,WAAW,GAAG;AACzB,YAAM,IAAI,MAAM,oBAAoB,aAAa,4BAA4B;AAAA,IAC/E;AAAA,EACF,OAAO;AACL,eAAW,QAAQ,YAAY;AAC7B,YAAM,OAAO,SAAS,WAAW,IAAI,GAAG;AACxC,YAAM,UAAU,SAAS,UAAa,WAAW,SAAS,IAAI;AAE9D,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI;AAAA,UACR,cAAc,IAAI,uBAAuB,aAAa,0BAA0B,IAAI;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AACA,eAAW;AAAA,EACb;AAEA,KAAG,IAAI,YAAY,SAAS,MAAM,sBAAsB,WAAW,QAAG;AAGtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,MACE,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,YAAY,KAAK;AAAA,IACnB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,YAAY,MAAiC;AAC1D,MAAI;AACF,WAAO,MAAM,QAAQ,IAAI;AAAA,EAC3B,SAAS,KAAK;AACZ,QAAI,eAAe,SAAS,UAAU,OAAO,IAAI,SAAS,SAAU,QAAO,CAAC;AAC5E,UAAM;AAAA,EACR;AACF;AAKA,SAAS,iBAAiB,MAAc,UAA6B;AACnE,QAAM,QAAQ,SAAS,WAAW,IAAI;AAEtC,SAAO,OAAO,KAAK,QAAQ,eAAe,EAAE,MAAM;AACpD;","names":[]}
|
|
File without changes
|