@hanzo/docs-cli 1.2.2 → 1.2.5

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.
@@ -0,0 +1,72 @@
1
+ import path from "node:path";
2
+ import { Visitor } from "oxc-parser";
3
+
4
+ //#region src/constants.ts
5
+ const typescriptExtensions = [
6
+ ".ts",
7
+ ".tsx",
8
+ ".js",
9
+ ".jsx"
10
+ ];
11
+
12
+ //#endregion
13
+ //#region src/utils/ast.ts
14
+ /**
15
+ * Return the import modifier for `sourceFile` to import `referenceFile`
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * toReferencePath('index.ts', 'dir/hello.ts')
20
+ * // should output './dir/hello'
21
+ * ```
22
+ */
23
+ function toImportSpecifier(sourceFile, referenceFile) {
24
+ const extname = path.extname(referenceFile);
25
+ const removeExt = typescriptExtensions.includes(extname);
26
+ let importPath = path.relative(path.dirname(sourceFile), removeExt ? referenceFile.substring(0, referenceFile.length - extname.length) : referenceFile).replaceAll(path.sep, "/");
27
+ if (removeExt && importPath.endsWith("/index")) importPath = importPath.slice(0, -6);
28
+ return importPath.startsWith("../") ? importPath : `./${importPath}`;
29
+ }
30
+ function transformSpecifiers(program, s, transformSpecifier) {
31
+ new Visitor({
32
+ ImportDeclaration(node) {
33
+ const source = node.source;
34
+ const out = transformSpecifier(source.value);
35
+ if (out) {
36
+ s.update(source.start + 1, source.end - 1, out);
37
+ source.value = out;
38
+ }
39
+ },
40
+ ImportExpression(node) {
41
+ if (node.source.type === "Literal") {
42
+ const source = node.source;
43
+ const out = transformSpecifier(source.value);
44
+ if (out) {
45
+ s.update(source.start + 1, source.end - 1, out);
46
+ source.value = out;
47
+ }
48
+ }
49
+ },
50
+ ExportAllDeclaration(node) {
51
+ const source = node.source;
52
+ const out = transformSpecifier(source.value);
53
+ if (out) {
54
+ s.update(source.start + 1, source.end - 1, out);
55
+ source.value = out;
56
+ }
57
+ },
58
+ ExportNamedDeclaration(node) {
59
+ const source = node.source;
60
+ if (!source) return;
61
+ const out = transformSpecifier(source.value);
62
+ if (out) {
63
+ s.update(source.start + 1, source.end - 1, out);
64
+ source.value = out;
65
+ }
66
+ }
67
+ }).visit(program);
68
+ }
69
+
70
+ //#endregion
71
+ export { transformSpecifiers as n, typescriptExtensions as r, toImportSpecifier as t };
72
+ //# sourceMappingURL=ast-BS3xj9uY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-BS3xj9uY.js","names":[],"sources":["../src/constants.ts","../src/utils/ast.ts"],"sourcesContent":["export const typescriptExtensions = ['.ts', '.tsx', '.js', '.jsx'];\n","import path from 'node:path';\nimport { typescriptExtensions } from '@/constants';\nimport { type Program, Visitor } from 'oxc-parser';\nimport type MagicString from 'magic-string';\n\n/**\n * Return the import modifier for `sourceFile` to import `referenceFile`\n *\n * @example\n * ```ts\n * toReferencePath('index.ts', 'dir/hello.ts')\n * // should output './dir/hello'\n * ```\n */\nexport function toImportSpecifier(sourceFile: string, referenceFile: string): string {\n const extname = path.extname(referenceFile);\n const removeExt = typescriptExtensions.includes(extname);\n\n let importPath = path\n .relative(\n path.dirname(sourceFile),\n removeExt ? referenceFile.substring(0, referenceFile.length - extname.length) : referenceFile,\n )\n .replaceAll(path.sep, '/');\n\n if (removeExt && importPath.endsWith('/index')) {\n importPath = importPath.slice(0, -'/index'.length);\n }\n\n return importPath.startsWith('../') ? importPath : `./${importPath}`;\n}\n\nexport function transformSpecifiers(\n program: Program,\n s: MagicString,\n transformSpecifier: (value: string) => string | undefined,\n) {\n new Visitor({\n // static imports\n ImportDeclaration(node) {\n const source = node.source;\n const out = transformSpecifier(source.value);\n if (out) {\n s.update(source.start + 1, source.end - 1, out);\n source.value = out;\n }\n },\n // dynamic imports\n ImportExpression(node) {\n if (node.source.type === 'Literal') {\n const source = node.source;\n const out = transformSpecifier(source.value as string);\n if (out) {\n s.update(source.start + 1, source.end - 1, out);\n source.value = out;\n }\n }\n },\n // exports\n ExportAllDeclaration(node) {\n const source = node.source;\n const out = transformSpecifier(source.value);\n if (out) {\n s.update(source.start + 1, source.end - 1, out);\n source.value = out;\n }\n },\n ExportNamedDeclaration(node) {\n const source = node.source;\n if (!source) return;\n const out = transformSpecifier(source.value);\n if (out) {\n s.update(source.start + 1, source.end - 1, out);\n source.value = out;\n }\n },\n }).visit(program);\n}\n"],"mappings":";;;;AAAA,MAAa,uBAAuB;CAAC;CAAO;CAAQ;CAAO;CAAO;;;;;;;;;;;;;ACclE,SAAgB,kBAAkB,YAAoB,eAA+B;CACnF,MAAM,UAAU,KAAK,QAAQ,cAAc;CAC3C,MAAM,YAAY,qBAAqB,SAAS,QAAQ;CAExD,IAAI,aAAa,KACd,SACC,KAAK,QAAQ,WAAW,EACxB,YAAY,cAAc,UAAU,GAAG,cAAc,SAAS,QAAQ,OAAO,GAAG,cACjF,CACA,WAAW,KAAK,KAAK,IAAI;AAE5B,KAAI,aAAa,WAAW,SAAS,SAAS,CAC5C,cAAa,WAAW,MAAM,GAAG,GAAiB;AAGpD,QAAO,WAAW,WAAW,MAAM,GAAG,aAAa,KAAK;;AAG1D,SAAgB,oBACd,SACA,GACA,oBACA;AACA,KAAI,QAAQ;EAEV,kBAAkB,MAAM;GACtB,MAAM,SAAS,KAAK;GACpB,MAAM,MAAM,mBAAmB,OAAO,MAAM;AAC5C,OAAI,KAAK;AACP,MAAE,OAAO,OAAO,QAAQ,GAAG,OAAO,MAAM,GAAG,IAAI;AAC/C,WAAO,QAAQ;;;EAInB,iBAAiB,MAAM;AACrB,OAAI,KAAK,OAAO,SAAS,WAAW;IAClC,MAAM,SAAS,KAAK;IACpB,MAAM,MAAM,mBAAmB,OAAO,MAAgB;AACtD,QAAI,KAAK;AACP,OAAE,OAAO,OAAO,QAAQ,GAAG,OAAO,MAAM,GAAG,IAAI;AAC/C,YAAO,QAAQ;;;;EAKrB,qBAAqB,MAAM;GACzB,MAAM,SAAS,KAAK;GACpB,MAAM,MAAM,mBAAmB,OAAO,MAAM;AAC5C,OAAI,KAAK;AACP,MAAE,OAAO,OAAO,QAAQ,GAAG,OAAO,MAAM,GAAG,IAAI;AAC/C,WAAO,QAAQ;;;EAGnB,uBAAuB,MAAM;GAC3B,MAAM,SAAS,KAAK;AACpB,OAAI,CAAC,OAAQ;GACb,MAAM,MAAM,mBAAmB,OAAO,MAAM;AAC5C,OAAI,KAAK;AACP,MAAE,OAAO,OAAO,QAAQ,GAAG,OAAO,MAAM,GAAG,IAAI;AAC/C,WAAO,QAAQ;;;EAGpB,CAAC,CAAC,MAAM,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Project, SourceFile } from "ts-morph";
2
+ import { ResolverFactory } from "oxc-resolver";
3
3
 
4
4
  //#region src/registry/schema.d.ts
5
5
  type NamespaceType = (typeof namespaces)[number];
@@ -90,11 +90,9 @@ interface Registry extends Omit<z.input<typeof registryInfoSchema>, 'indexes'> {
90
90
  }
91
91
  declare class RegistryCompiler {
92
92
  readonly raw: Registry;
93
- readonly project: Project;
94
93
  resolver: RegistryResolver;
95
94
  constructor(registry: Registry);
96
95
  private readPackageJson;
97
- createSourceFile(file: string): Promise<SourceFile>;
98
96
  compile(): Promise<CompiledRegistry>;
99
97
  }
100
98
  declare class RegistryResolver {
@@ -102,6 +100,7 @@ declare class RegistryResolver {
102
100
  private readonly deps;
103
101
  private readonly devDeps;
104
102
  private readonly fileToComponent;
103
+ readonly oxc: ResolverFactory;
105
104
  constructor(compiler: RegistryCompiler, packageJson?: PackageJson);
106
105
  getDepFromSpecifier(specifier: string): string;
107
106
  getDepInfo(name: string): {
@@ -137,6 +136,9 @@ type SourceReference = {
137
136
  file: ComponentFile;
138
137
  registryName: string;
139
138
  };
139
+ } | {
140
+ type: 'unknown-specifier';
141
+ specifier: string;
140
142
  };
141
143
  type Reference = SourceReference | {
142
144
  type: 'custom';
@@ -153,8 +155,7 @@ declare class ComponentCompiler {
153
155
  constructor(compiler: RegistryCompiler, component: Component);
154
156
  private toImportPath;
155
157
  build(): Promise<CompiledComponent>;
156
- private buildFileAndDeps;
157
- private resolveImport;
158
+ private onBuildFile;
158
159
  private buildFile;
159
160
  }
160
161
  declare function resolveFromRemote(r: Registry, component: string, selectFile: (file: ComponentFile) => boolean): Reference | undefined;
@@ -164,7 +165,7 @@ interface MonoRegistry extends CompiledRegistry {
164
165
  registries: CompiledRegistry[];
165
166
  }
166
167
  declare function combineRegistry(root: CompiledRegistry, ...items: CompiledRegistry[]): MonoRegistry;
167
- declare function writeFumadocsRegistry(out: CompiledRegistry | MonoRegistry, options: {
168
+ declare function writeDocsRegistry(out: CompiledRegistry | MonoRegistry, options: {
168
169
  dir: string;
169
170
  /**
170
171
  * Remove previous outputs
@@ -175,5 +176,5 @@ declare function writeFumadocsRegistry(out: CompiledRegistry | MonoRegistry, opt
175
176
  log?: boolean;
176
177
  }): Promise<void>;
177
178
  //#endregion
178
- export { CompiledRegistry, Component, ComponentCompiler, ComponentFile, MonoRegistry, OnResolve, PackageJson, Reference, Registry, RegistryCompiler, SourceReference, combineRegistry, resolveFromRemote, writeFumadocsRegistry };
179
+ export { CompiledRegistry, Component, ComponentCompiler, ComponentFile, MonoRegistry, OnResolve, PackageJson, Reference, Registry, RegistryCompiler, SourceReference, combineRegistry, resolveFromRemote, writeDocsRegistry };
179
180
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/registry/schema.ts","../../src/build/compiler.ts","../../src/build/index.ts"],"sourcesContent":[],"mappings":";;;;KAEY,aAAA,WAAwB;KAExB,iBAAA,GAAoB,CAAA,CAAE,aAAa;cAMlC;cAqBA,iBAAe,CAAA,CAAA;;;;;;;;;;;;;;;;EAAA,CAAA,eAAA,CAAA,CAAA,CAAA,CAAA,CAAA;CAAA,eAAA,CAAA;AAaf,cAAA,kBAoBX,EApB6B,CAAA,CAAA,SAoB7B,CAAA;;;;;;;;;;;;;;;KCpDU,SAAA,eAAwB,oBAAoB;ADV5C,UCYK,gBAAA,CDZmB;EAExB,IAAA,EAAA,MAAA;EAMC,UAAA,ECMC,iBDNyE,EAAA;EAqB1E,IAAA,ECdL,CAAA,CAAE,MDcG,CAAA,OCdW,kBDyBtB,CAAA;;UCtBe,aAAA;QACT;;;;UAKS,SAAA;;;;SAIR;;;;;;;;cAUK;;UAGG,WAAA;iBACA;oBACG;;UAGH,QAAA,SAAiB,KAAK,CAAA,CAAE,aAAa;;wBAE9B;;cAEV;;;;;EDrBc;;AAa5B;cCkBc;;;;;4CAK8B;iBAE3B;oBACG;;cAGP,gBAAA;gBACG;oBACI;YACP;wBAEW;;kCAgBa,QAAA;aAOlB,QAAQ;;cAqCrB,gBAAA;;;;;wBAMyB,gCACd;;;IDrGc,IAAA,EAAA,SAAA,GAAA,KAAA;IAAA,IAAA,EAAA,MAAA;;;oCC4JK;EA5LxB,eAAS,CAAA,IAAA,EAAA,MAAe,CAAA,EAAA;IAEnB,SAAA,WAAgB;IAEnB,IAAA,eAAA;EACU,CAAA,GAAA,SAAA;;AAAR,KAuMJ,eAAA,GAvMI;EAGC,IAAA,EAAA,MAAA;EAMA;AAiBjB;AAKA;EAAsD,IAAA,EAAA,MAAA;CAAf,GAAE;EAEjB,IAAA,EAAA,YAAA;EAEV,GAAA,EAAA,MAAA;EAUA,SAAA,EAAA,MAAA;CAK8B,GAAA;EAE3B,IAAA,EAAA,eAAA;EACG,QAAA,EAAA;IAtBc,IAAA,EAAA,OAAA;IAAI,SAAA,EA0Lf,SA1Le;IAyBzB,IAAA,EAkKK,aAlKW;EACb,CAAA,GAAA;IACI,IAAA,EAAA,QAAA;IACP,SAAA,EAmKU,SAnKV;IAEW,IAAA,EAkKN,aAlKM;IAgBa,YAAA,EAAA,MAAA;EAAA,CAAA;CAOV;AAAR,KAgJP,SAAA,GACR,eAjJe,GAAA;EAAO,IAAA,EAAA,QAAA;EAqCpB,SAAA,EAAA,MAAA;CAMyB;AACd,cA2GJ,iBAAA,CA3GI;EAuDmB,iBAAA,QAAA;;;;EAgBxB,iBAAA,aAAe;EAkBJ,iBAAA,eAAA;EACL,iBAAA,YAAA;EAIK,WAAA,CAAA,QAAA,EAqBQ,gBArBR,EAAA,SAAA,EAsBS,SAtBT;EACL,QAAA,YAAA;EAAa,KAAA,CAAA,CAAA,EAoCd,OApCc,CAoCN,iBApCM,CAAA;EAKnB,QAAA,gBACR;EAMS,QAAA,aAAiB;EAQC,QAAA,SAAA;;AAgBN,iBAiLT,iBAAA,CAjLS,CAAA,EAkLpB,QAlLoB,EAAA,SAAA,EAAA,MAAA,EAAA,UAAA,EAAA,CAAA,IAAA,EAoLJ,aApLI,EAAA,GAAA,OAAA,CAAA,EAqLtB,SArLsB,GAAA,SAAA;;;UC7QR,YAAA,SAAqB;cACxB;AFNd;AAEY,iBEOI,eAAA,CFP+B,IAAA,EEQvC,gBFR+B,EAAA,GAAA,KAAA,EES3B,gBFT2B,EAAA,CAAA,EEUpC,YFVoC;AAM1B,iBEeS,qBAAA,CFfiE,GAAA,EEgBhF,gBFhBgF,GEgB7D,YFhB6D,EAAA,OAAA,EAAA;EAqB1E,GAAA,EAAA,MAAA;;;;;;;;IEQV"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/registry/schema.ts","../../src/build/compiler.ts","../../src/build/index.ts"],"mappings":";;;;KAEY,aAAA,WAAwB,UAAA;AAAA,KAExB,iBAAA,GAAoB,CAAA,CAAE,KAAA,QAAa,eAAA;AAAA,cAMlC,UAAA;AAAA,cAqBA,eAAA,EAAe,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;cAaf,kBAAA,EAAkB,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;KC7BnB,SAAA,IAAa,SAAA,EAAW,eAAA,KAAoB,SAAA;AAAA,UAEvC,gBAAA;EACf,IAAA;EACA,UAAA,EAAY,iBAAA;EACZ,IAAA,EAAM,CAAA,CAAE,MAAA,QAAc,kBAAA;AAAA;AAAA,UAGP,aAAA;EACf,IAAA,EAAM,aAAA;EACN,IAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,KAAA,EAAO,aAAA;EDvB8E;;;EC4BrF,QAAA;EDPW;;;ECYX,SAAA,GAAY,SAAA;AAAA;AAAA,UAGG,WAAA;EACf,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,UAGH,QAAA,SAAiB,IAAA,CAAK,CAAA,CAAE,KAAA,QAAa,kBAAA;EACpD,IAAA;EACA,WAAA,WAAsB,WAAA;EACtB,YAAA;EACA,UAAA,EAAY,SAAA;;;;EAKZ,GAAA;;;;EAKA,SAAA,GAAY,SAAA;;;;;EAKZ,aAAA,IAAiB,YAAA,aAAyB,aAAA;EAE1C,YAAA,GAAe,MAAA;EACf,eAAA,GAAkB,MAAA;AAAA;AAAA,cAGP,gBAAA;EAAA,SACF,GAAA,EAAK,QAAA;EACd,QAAA,EAAW,gBAAA;cAEC,QAAA,EAAU,QAAA;EAAA,QAIR,eAAA;EASR,OAAA,CAAA,GAAW,OAAA,CAAQ,gBAAA;AAAA;AAAA,cAqCrB,gBAAA;EAAA,iBAOe,QAAA;EAAA,iBANF,IAAA;EAAA,iBACA,OAAA;EAAA,iBACA,eAAA;EAAA,SACR,GAAA,EAAK,eAAA;cAGK,QAAA,EAAU,gBAAA,EAC3B,WAAA,GAAa,WAAA;EAkCf,mBAAA,CAAoB,SAAA;EAMpB,UAAA,CAAW,IAAA;IAEL,IAAA;IACA,IAAA;IACA,OAAA;EAAA;EAoBN,kBAAA,CAAmB,IAAA,WAAe,SAAA;EAIlC,eAAA,CAAgB,IAAA;;;;;KAYN,eAAA;EAEN,IAAA;;;;EAIA,IAAA;AAAA;EAGA,IAAA;EACA,GAAA;EACA,SAAA;AAAA;EAGA,IAAA;EACA,QAAA;IAEM,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;EAAA;IAGN,IAAA;IACA,SAAA,EAAW,SAAA;IACX,IAAA,EAAM,aAAA;IACN,YAAA;EAAA;AAAA;EAIN,IAAA;EACA,SAAA;AAAA;AAAA,KAGM,SAAA,GACR,eAAA;EAEE,IAAA;EACA,SAAA;AAAA;AAAA,cAGO,iBAAA;EAAA,iBAQQ,QAAA;EAAA,iBACA,SAAA;EAAA,iBARF,cAAA;EAAA,iBACA,QAAA;EAAA,iBACA,aAAA;EAAA,iBACA,eAAA;EAAA,iBACA,YAAA;cAGE,QAAA,EAAU,gBAAA,EACV,SAAA,EAAW,SAAA;EAAA,QAOtB,YAAA;EAQF,KAAA,CAAA,GAAS,OAAA,CAAQ,iBAAA;EAAA,QAYT,WAAA;EAAA,QA2DA,SAAA;AAAA;AAAA,iBA0FA,iBAAA,CACd,CAAA,EAAG,QAAA,EACH,SAAA,UACA,UAAA,GAAa,IAAA,EAAM,aAAA,eAClB,SAAA;;;UCxbc,YAAA,SAAqB,gBAAA;EACpC,UAAA,EAAY,gBAAA;AAAA;AAAA,iBAGE,eAAA,CACd,IAAA,EAAM,gBAAA,KACH,KAAA,EAAO,gBAAA,KACT,YAAA;AAAA,iBAWmB,iBAAA,CACpB,GAAA,EAAK,gBAAA,GAAmB,YAAA,EACxB,OAAA;EACE,GAAA;EF1B0C;AAE9C;;;;EE+BI,QAAA;EAEA,GAAA;AAAA,IAED,OAAA"}
@@ -1,22 +1,20 @@
1
+ import { n as transformSpecifiers } from "../ast-BS3xj9uY.js";
1
2
  import * as fs$1 from "node:fs/promises";
2
3
  import * as path$1 from "node:path";
3
4
  import picocolors from "picocolors";
4
- import { Project, ts } from "ts-morph";
5
+ import { parse } from "oxc-parser";
6
+ import MagicString from "magic-string";
7
+ import { ResolverFactory } from "oxc-resolver";
5
8
 
6
9
  //#region src/build/compiler.ts
7
10
  var RegistryCompiler = class {
8
11
  constructor(registry) {
9
12
  this.raw = registry;
10
- this.project = new Project({ tsConfigFilePath: path$1.join(registry.dir, registry.tsconfigPath) });
11
13
  }
12
14
  async readPackageJson() {
13
15
  if (typeof this.raw.packageJson !== "string") return this.raw.packageJson;
14
16
  return fs$1.readFile(path$1.join(this.raw.dir, this.raw.packageJson)).then((res) => JSON.parse(res.toString())).catch(() => void 0);
15
17
  }
16
- async createSourceFile(file) {
17
- const content = await fs$1.readFile(file);
18
- return this.project.createSourceFile(file, content.toString(), { overwrite: true });
19
- }
20
18
  async compile() {
21
19
  const registry = this.raw;
22
20
  this.resolver = new RegistryResolver(this, await this.readPackageJson());
@@ -60,6 +58,23 @@ var RegistryResolver = class {
60
58
  ...packageJson?.devDependencies,
61
59
  ...registry.devDependencies
62
60
  };
61
+ this.oxc = new ResolverFactory({
62
+ extensions: [
63
+ ".js",
64
+ ".jsx",
65
+ ".ts",
66
+ ".tsx",
67
+ ".node"
68
+ ],
69
+ conditionNames: [
70
+ "node",
71
+ "import",
72
+ "require",
73
+ "default",
74
+ "types"
75
+ ],
76
+ tsconfig: { configFile: path$1.join(registry.dir, registry.tsconfigPath) }
77
+ });
63
78
  }
64
79
  getDepFromSpecifier(specifier) {
65
80
  return specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
@@ -95,7 +110,7 @@ var ComponentCompiler = class {
95
110
  this.compiler = compiler;
96
111
  this.component = component;
97
112
  this.processedFiles = /* @__PURE__ */ new Set();
98
- this.subComponents = /* @__PURE__ */ new Set();
113
+ this.subComponents = /* @__PURE__ */ new Map();
99
114
  this.devDependencies = /* @__PURE__ */ new Map();
100
115
  this.dependencies = /* @__PURE__ */ new Map();
101
116
  this.registry = compiler.raw;
@@ -110,18 +125,22 @@ var ComponentCompiler = class {
110
125
  name: this.component.name,
111
126
  title: this.component.title,
112
127
  description: this.component.description,
113
- files: (await Promise.all(this.component.files.map((file) => this.buildFileAndDeps(file)))).flat(),
114
- subComponents: Array.from(this.subComponents),
128
+ files: (await Promise.all(this.component.files.map((file) => this.onBuildFile(file)))).flat(),
129
+ subComponents: Array.from(this.subComponents.values()),
115
130
  dependencies: Object.fromEntries(this.dependencies),
116
131
  devDependencies: Object.fromEntries(this.devDependencies)
117
132
  };
118
133
  }
119
- async buildFileAndDeps(file) {
134
+ async onBuildFile(file) {
120
135
  if (this.processedFiles.has(file.path)) return [];
121
136
  this.processedFiles.add(file.path);
122
137
  const resolver = this.compiler.resolver;
123
138
  const queue = [];
124
139
  return [await this.buildFile(file, (reference) => {
140
+ if (reference.type === "unknown-specifier") {
141
+ if (!reference.specifier.startsWith("node:")) console.warn(`Unknown specifier ${reference.specifier}, skipping for now`);
142
+ return reference.specifier;
143
+ }
125
144
  if (reference.type === "custom") return reference.specifier;
126
145
  if (reference.type === "file") {
127
146
  const refFile = this.registry.onUnknownFile?.(reference.file);
@@ -134,75 +153,74 @@ var ComponentCompiler = class {
134
153
  }
135
154
  if (reference.type === "sub-component") {
136
155
  const resolved = reference.resolved;
137
- if (resolved.component.name !== this.component.name) if (resolved.type === "remote") this.subComponents.add({
156
+ if (resolved.component.name === this.component.name) return this.toImportPath(resolved.file);
157
+ if (resolved.type === "remote") this.subComponents.set(`${resolved.registryName}:${resolved.component.name}`, {
138
158
  type: "http",
139
159
  baseUrl: resolved.registryName,
140
160
  component: resolved.component.name
141
161
  });
142
- else this.subComponents.add(resolved.component.name);
162
+ else this.subComponents.set(resolved.component.name, resolved.component.name);
143
163
  return this.toImportPath(resolved.file);
144
164
  }
145
165
  const dep = resolver.getDepInfo(reference.dep);
146
166
  if (dep) (dep.type === "dev" ? this.devDependencies : this.dependencies).set(dep.name, dep.version);
147
167
  return reference.specifier;
148
- }), ...(await Promise.all(queue.map((file$1) => this.buildFileAndDeps(file$1)))).flat()];
149
- }
150
- resolveImport(sourceFilePath, specifier, specified) {
151
- let filePath;
152
- if (specified) filePath = specified.getFilePath();
153
- else if (specifier.startsWith("./") || specifier.startsWith("../")) filePath = path$1.join(path$1.dirname(sourceFilePath), specifier);
154
- else {
155
- if (!specifier.startsWith("node:")) console.warn(`Unknown specifier ${specifier}, skipping for now`);
156
- return;
157
- }
158
- const resolver = this.compiler.resolver;
159
- if (path$1.relative(this.registry.dir, filePath).startsWith("../")) return {
160
- type: "dependency",
161
- dep: resolver.getDepFromSpecifier(specifier),
162
- specifier
163
- };
164
- const sub = resolver.getSubComponent(filePath);
165
- if (sub) return {
166
- type: "sub-component",
167
- resolved: {
168
- type: "local",
169
- component: sub.component,
170
- file: sub.file
171
- }
172
- };
173
- return {
174
- type: "file",
175
- file: filePath
176
- };
168
+ }), ...(await Promise.all(queue.map((file) => this.onBuildFile(file)))).flat()];
177
169
  }
178
170
  async buildFile(file, writeReference) {
179
171
  const sourceFilePath = path$1.join(this.registry.dir, file.path);
172
+ const astType = {
173
+ ".ts": "ts",
174
+ ".tsx": "ts",
175
+ ".js": "js",
176
+ ".jsx": "js"
177
+ }[path$1.extname(file.path)];
178
+ const content = (await fs$1.readFile(sourceFilePath)).toString();
179
+ if (!astType) return {
180
+ content,
181
+ path: file.path,
182
+ type: file.type,
183
+ target: file.target
184
+ };
185
+ const resolver = this.compiler.resolver;
186
+ const ast = await parse(sourceFilePath, content, { astType });
187
+ if (ast.errors.length > 0) throw new Error(`failed to parse file ${sourceFilePath}: \n${ast.errors.join("\n")}`);
188
+ const s = new MagicString(content);
180
189
  /**
181
190
  * Process import paths
182
191
  */
183
- const process$1 = (specifier, specifiedFile) => {
192
+ transformSpecifiers(ast.program, s, (specifier) => {
193
+ let resolved = {
194
+ type: "unknown-specifier",
195
+ specifier
196
+ };
184
197
  const onResolve = this.component.onResolve ?? this.registry.onResolve;
185
- let resolved = this.resolveImport(sourceFilePath, specifier.getLiteralValue(), specifiedFile);
186
- if (!resolved) return;
187
- if (onResolve) resolved = onResolve(resolved);
188
- const out = writeReference(resolved);
189
- if (out) specifier.setLiteralValue(out);
190
- };
191
- const sourceFile = await this.compiler.createSourceFile(sourceFilePath);
192
- for (const item of sourceFile.getImportDeclarations()) process$1(item.getModuleSpecifier(), item.getModuleSpecifierSourceFile());
193
- for (const item of sourceFile.getExportDeclarations()) {
194
- const specifier = item.getModuleSpecifier();
195
- if (!specifier) continue;
196
- process$1(specifier, item.getModuleSpecifierSourceFile());
197
- }
198
- const calls = sourceFile.getDescendantsOfKind(ts.SyntaxKind.CallExpression);
199
- for (const expression of calls) if (expression.getExpression().isKind(ts.SyntaxKind.ImportKeyword) && expression.getArguments().length === 1) {
200
- const argument = expression.getArguments()[0];
201
- if (!argument.isKind(ts.SyntaxKind.StringLiteral)) continue;
202
- process$1(argument, argument.getSymbol()?.getDeclarations()[0].getSourceFile());
203
- }
198
+ const resolvedSpecifier = resolver.oxc.resolveFileSync(sourceFilePath, specifier);
199
+ if (resolvedSpecifier.error || !resolvedSpecifier.path) return writeReference(onResolve ? onResolve(resolved) : resolved);
200
+ resolved = {
201
+ type: "file",
202
+ file: resolvedSpecifier.path
203
+ };
204
+ if (path$1.relative(this.registry.dir, resolvedSpecifier.path).startsWith("../")) resolved = {
205
+ type: "dependency",
206
+ dep: resolver.getDepFromSpecifier(specifier),
207
+ specifier
208
+ };
209
+ else {
210
+ const sub = resolver.getSubComponent(resolvedSpecifier.path);
211
+ if (sub) resolved = {
212
+ type: "sub-component",
213
+ resolved: {
214
+ type: "local",
215
+ component: sub.component,
216
+ file: sub.file
217
+ }
218
+ };
219
+ }
220
+ return writeReference(onResolve ? onResolve(resolved) : resolved);
221
+ });
204
222
  return {
205
- content: sourceFile.getFullText(),
223
+ content: s.toString(),
206
224
  type: file.type,
207
225
  path: file.path,
208
226
  target: file.target
@@ -210,7 +228,7 @@ var ComponentCompiler = class {
210
228
  }
211
229
  };
212
230
  function resolveFromRemote(r, component, selectFile) {
213
- const comp = r.components.find((comp$1) => comp$1.name === component);
231
+ const comp = r.components.find((comp) => comp.name === component);
214
232
  if (!comp) return;
215
233
  const file = comp.files.find(selectFile);
216
234
  if (!file) return;
@@ -237,7 +255,7 @@ function combineRegistry(root, ...items) {
237
255
  registries: items
238
256
  };
239
257
  }
240
- async function writeFumadocsRegistry(out, options) {
258
+ async function writeDocsRegistry(out, options) {
241
259
  const { dir, cleanDir = false, log = true } = options;
242
260
  if (cleanDir) {
243
261
  await fs$1.rm(dir, {
@@ -253,7 +271,7 @@ async function writeFumadocsRegistry(out, options) {
253
271
  await writeFile(path$1.join(dir, `${comp.name}.json`), JSON.stringify(comp, null, 2), log);
254
272
  });
255
273
  write.push(writeInfo());
256
- if ("registries" in out) for (const child of out.registries) write.push(writeFumadocsRegistry(child, {
274
+ if ("registries" in out) for (const child of out.registries) write.push(writeDocsRegistry(child, {
257
275
  dir: path$1.join(dir, child.name),
258
276
  log: options.log
259
277
  }));
@@ -269,5 +287,5 @@ async function writeFile(file, content, log = true) {
269
287
  }
270
288
 
271
289
  //#endregion
272
- export { ComponentCompiler, RegistryCompiler, combineRegistry, resolveFromRemote, writeFumadocsRegistry };
290
+ export { ComponentCompiler, RegistryCompiler, combineRegistry, resolveFromRemote, writeDocsRegistry };
273
291
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["path","fs","output: CompiledRegistry","compiler: RegistryCompiler","component: Component","queue: ComponentFile[]","file","filePath: string","process","resolved: Reference | undefined","comp","fs","path"],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type {\n CompiledComponent,\n CompiledFile,\n httpSubComponent,\n NamespaceType,\n registryInfoSchema,\n} from '@/registry/schema';\nimport type { z } from 'zod';\nimport { Project, SourceFile, StringLiteral, ts } from 'ts-morph';\n\nexport type OnResolve = (reference: SourceReference) => Reference;\n\nexport interface CompiledRegistry {\n name: string;\n components: CompiledComponent[];\n info: z.output<typeof registryInfoSchema>;\n}\n\nexport interface ComponentFile {\n type: NamespaceType;\n path: string;\n target?: string;\n}\n\nexport interface Component {\n name: string;\n title?: string;\n description?: string;\n files: ComponentFile[];\n\n /**\n * Don't list the component in registry index file\n */\n unlisted?: boolean;\n\n /**\n * Map imported file paths, inherit from registry if not defined.\n */\n onResolve?: OnResolve;\n}\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface Registry extends Omit<z.input<typeof registryInfoSchema>, 'indexes'> {\n name: string;\n packageJson: string | PackageJson;\n tsconfigPath: string;\n components: Component[];\n\n /**\n * The directory of registry, used to resolve relative paths\n */\n dir: string;\n\n /**\n * Map import paths of components\n */\n onResolve?: OnResolve;\n /**\n * When a referenced file is not found in component files, this function is called.\n * @returns file, or `false` to mark as external.\n */\n onUnknownFile?: (absolutePath: string) => ComponentFile | false | undefined;\n\n dependencies?: Record<string, string | null>;\n devDependencies?: Record<string, string | null>;\n}\n\nexport class RegistryCompiler {\n readonly raw: Registry;\n readonly project: Project;\n resolver!: RegistryResolver;\n\n constructor(registry: Registry) {\n this.raw = registry;\n this.project = new Project({\n tsConfigFilePath: path.join(registry.dir, registry.tsconfigPath),\n });\n }\n\n private async readPackageJson(): Promise<PackageJson | undefined> {\n if (typeof this.raw.packageJson !== 'string') return this.raw.packageJson;\n\n return fs\n .readFile(path.join(this.raw.dir, this.raw.packageJson))\n .then((res) => JSON.parse(res.toString()) as PackageJson)\n .catch(() => undefined);\n }\n\n async createSourceFile(file: string) {\n const content = await fs.readFile(file);\n return this.project.createSourceFile(file, content.toString(), {\n overwrite: true,\n });\n }\n\n async compile(): Promise<CompiledRegistry> {\n const registry = this.raw;\n this.resolver = new RegistryResolver(this, await this.readPackageJson());\n const output: CompiledRegistry = {\n name: registry.name,\n info: {\n indexes: [],\n env: registry.env,\n variables: registry.variables,\n },\n components: [],\n };\n\n const builtComps = await Promise.all(\n registry.components.map(async (component) => {\n const compiler = new ComponentCompiler(this, component);\n\n return [component, await compiler.build()] as [Component, CompiledComponent];\n }),\n );\n\n for (const [input, comp] of builtComps) {\n if (!input.unlisted) {\n output.info.indexes.push({\n name: input.name,\n title: input.title,\n description: input.description,\n });\n }\n\n output.components.push(comp);\n }\n\n return output;\n }\n}\n\nclass RegistryResolver {\n private readonly deps: Record<string, string | null>;\n private readonly devDeps: Record<string, string | null>;\n private readonly fileToComponent = new Map<string, [Component, ComponentFile]>();\n\n constructor(\n private readonly compiler: RegistryCompiler,\n packageJson: PackageJson = {},\n ) {\n const registry = compiler.raw;\n\n for (const comp of registry.components) {\n for (const file of comp.files) {\n if (this.fileToComponent.has(file.path))\n console.warn(\n `the same file ${file.path} exists in multiple component, you should make the shared file a separate component.`,\n );\n this.fileToComponent.set(file.path, [comp, file]);\n }\n }\n\n this.deps = {\n ...packageJson?.dependencies,\n ...registry.dependencies,\n };\n\n this.devDeps = {\n ...packageJson?.devDependencies,\n ...registry.devDependencies,\n };\n }\n\n getDepFromSpecifier(specifier: string) {\n return specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0];\n }\n\n getDepInfo(name: string):\n | {\n type: 'runtime' | 'dev';\n name: string;\n version: string | null;\n }\n | undefined {\n if (name in this.deps)\n return {\n name,\n type: 'runtime',\n version: this.deps[name],\n };\n\n if (name in this.devDeps)\n return {\n name,\n type: 'dev',\n version: this.devDeps[name],\n };\n\n console.warn(`dep info for ${name} cannot be found`);\n }\n\n getComponentByName(name: string): Component | undefined {\n return this.compiler.raw.components.find((comp) => comp.name === name);\n }\n\n getSubComponent(file: string) {\n const relativeFile = path.relative(this.compiler.raw.dir, file);\n const comp = this.fileToComponent.get(relativeFile);\n\n if (!comp) return;\n return {\n component: comp[0],\n file: comp[1],\n };\n }\n}\n\nexport type SourceReference =\n | {\n type: 'file';\n /**\n * Absolute path\n */\n file: string;\n }\n | {\n type: 'dependency';\n dep: string;\n specifier: string;\n }\n | {\n type: 'sub-component';\n resolved:\n | {\n type: 'local';\n component: Component;\n file: ComponentFile;\n }\n | {\n type: 'remote';\n component: Component;\n file: ComponentFile;\n registryName: string;\n };\n };\n\nexport type Reference =\n | SourceReference\n | {\n type: 'custom';\n specifier: string;\n };\n\nexport class ComponentCompiler {\n private readonly processedFiles = new Set<string>();\n private readonly registry: Registry;\n private readonly subComponents = new Set<string | z.input<typeof httpSubComponent>>();\n private readonly devDependencies = new Map<string, string | null>();\n private readonly dependencies = new Map<string, string | null>();\n\n constructor(\n private readonly compiler: RegistryCompiler,\n private readonly component: Component,\n ) {\n this.registry = compiler.raw;\n }\n\n // see https://github.com/shadcn-ui/ui/blob/396275e46a58333caa1fa0a991bd9bc5237d2ee3/packages/shadcn/src/utils/updaters/update-files.ts#L585\n // to hit the fast-path step, we need to import `target` path first because it's detected from `fileSet`, a set of output file paths\n private toImportPath(file: ComponentFile): string {\n let filePath = file.target ?? file.path;\n\n if (filePath.startsWith('./')) filePath = filePath.slice(2);\n\n return `@/${filePath.replaceAll(path.sep, '/')}`;\n }\n\n async build(): Promise<CompiledComponent> {\n return {\n name: this.component.name,\n title: this.component.title,\n description: this.component.description,\n files: (\n await Promise.all(this.component.files.map((file) => this.buildFileAndDeps(file)))\n ).flat(),\n subComponents: Array.from(this.subComponents),\n dependencies: Object.fromEntries(this.dependencies),\n devDependencies: Object.fromEntries(this.devDependencies),\n };\n }\n\n private async buildFileAndDeps(file: ComponentFile): Promise<CompiledFile[]> {\n if (this.processedFiles.has(file.path)) return [];\n this.processedFiles.add(file.path);\n const resolver = this.compiler.resolver;\n\n const queue: ComponentFile[] = [];\n const result = await this.buildFile(file, (reference) => {\n if (reference.type === 'custom') return reference.specifier;\n\n if (reference.type === 'file') {\n const refFile = this.registry.onUnknownFile?.(reference.file);\n if (refFile) {\n queue.push(refFile);\n return this.toImportPath(refFile);\n }\n\n if (refFile === false) return;\n\n throw new Error(`Unknown file ${reference.file} referenced by ${file.path}`);\n }\n\n if (reference.type === 'sub-component') {\n const resolved = reference.resolved;\n if (resolved.component.name !== this.component.name) {\n if (resolved.type === 'remote') {\n this.subComponents.add({\n type: 'http',\n baseUrl: resolved.registryName,\n component: resolved.component.name,\n });\n } else {\n this.subComponents.add(resolved.component.name);\n }\n }\n\n return this.toImportPath(resolved.file);\n }\n\n const dep = resolver.getDepInfo(reference.dep);\n if (dep) {\n const map = dep.type === 'dev' ? this.devDependencies : this.dependencies;\n map.set(dep.name, dep.version);\n }\n\n return reference.specifier;\n });\n\n return [\n result,\n ...(await Promise.all(queue.map((file) => this.buildFileAndDeps(file)))).flat(),\n ];\n }\n\n private resolveImport(\n sourceFilePath: string,\n specifier: string,\n specified: SourceFile | undefined,\n ): SourceReference | undefined {\n let filePath: string;\n if (specified) {\n filePath = specified.getFilePath();\n } else if (specifier.startsWith('./') || specifier.startsWith('../')) {\n filePath = path.join(path.dirname(sourceFilePath), specifier);\n } else {\n if (!specifier.startsWith('node:'))\n console.warn(`Unknown specifier ${specifier}, skipping for now`);\n return;\n }\n\n const resolver = this.compiler.resolver;\n // outside of registry dir\n if (path.relative(this.registry.dir, filePath).startsWith('../')) {\n return {\n type: 'dependency',\n dep: resolver.getDepFromSpecifier(specifier),\n specifier,\n };\n }\n\n const sub = resolver.getSubComponent(filePath);\n if (sub) {\n return {\n type: 'sub-component',\n resolved: {\n type: 'local',\n component: sub.component,\n file: sub.file,\n },\n };\n }\n\n return {\n type: 'file',\n file: filePath,\n };\n }\n\n private async buildFile(\n file: ComponentFile,\n /**\n * write references back to import specifiers\n *\n * keep original one if `undefined`\n */\n writeReference: (reference: Reference) => string | undefined,\n ): Promise<CompiledFile> {\n const sourceFilePath = path.join(this.registry.dir, file.path);\n\n /**\n * Process import paths\n */\n const process = (specifier: StringLiteral, specifiedFile: SourceFile | undefined) => {\n const onResolve = this.component.onResolve ?? this.registry.onResolve;\n let resolved: Reference | undefined = this.resolveImport(\n sourceFilePath,\n specifier.getLiteralValue(),\n specifiedFile,\n );\n\n if (!resolved) return;\n if (onResolve) resolved = onResolve(resolved);\n const out = writeReference(resolved);\n if (out) specifier.setLiteralValue(out);\n };\n\n const sourceFile = await this.compiler.createSourceFile(sourceFilePath);\n\n for (const item of sourceFile.getImportDeclarations()) {\n process(item.getModuleSpecifier(), item.getModuleSpecifierSourceFile());\n }\n\n for (const item of sourceFile.getExportDeclarations()) {\n const specifier = item.getModuleSpecifier();\n if (!specifier) continue;\n\n process(specifier, item.getModuleSpecifierSourceFile());\n }\n\n // transform async imports\n const calls = sourceFile.getDescendantsOfKind(ts.SyntaxKind.CallExpression);\n\n for (const expression of calls) {\n if (\n expression.getExpression().isKind(ts.SyntaxKind.ImportKeyword) &&\n expression.getArguments().length === 1\n ) {\n const argument = expression.getArguments()[0];\n\n if (!argument.isKind(ts.SyntaxKind.StringLiteral)) continue;\n\n process(argument, argument.getSymbol()?.getDeclarations()[0].getSourceFile());\n }\n }\n\n return {\n content: sourceFile.getFullText(),\n type: file.type,\n path: file.path,\n target: file.target,\n };\n }\n}\n\nexport function resolveFromRemote(\n r: Registry,\n component: string,\n selectFile: (file: ComponentFile) => boolean,\n): Reference | undefined {\n const comp = r.components.find((comp) => comp.name === component);\n if (!comp) return;\n const file = comp.files.find(selectFile);\n if (!file) return;\n\n return {\n type: 'sub-component',\n resolved: {\n type: 'remote',\n registryName: r.name,\n component: comp,\n file,\n },\n };\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport picocolors from 'picocolors';\nimport type { CompiledRegistry } from '@/build/compiler';\n\nexport * from './compiler';\n\nexport interface MonoRegistry extends CompiledRegistry {\n registries: CompiledRegistry[];\n}\n\nexport function combineRegistry(\n root: CompiledRegistry,\n ...items: CompiledRegistry[]\n): MonoRegistry {\n return {\n ...root,\n info: {\n ...root.info,\n registries: items.map((item) => item.name),\n },\n registries: items,\n };\n}\n\nexport async function writeFumadocsRegistry(\n out: CompiledRegistry | MonoRegistry,\n options: {\n dir: string;\n\n /**\n * Remove previous outputs\n *\n * @defaultValue false\n */\n cleanDir?: boolean;\n\n log?: boolean;\n },\n): Promise<void> {\n const { dir, cleanDir = false, log = true } = options;\n\n if (cleanDir) {\n await fs.rm(dir, {\n recursive: true,\n force: true,\n });\n console.log(picocolors.bold(picocolors.greenBright('Cleaned directory')));\n }\n\n async function writeInfo() {\n const file = path.join(dir, '_registry.json');\n const json = JSON.stringify(out.info, null, 2);\n\n await writeFile(file, json, log);\n }\n\n const write = out.components.map(async (comp) => {\n const file = path.join(dir, `${comp.name}.json`);\n const json = JSON.stringify(comp, null, 2);\n\n await writeFile(file, json, log);\n });\n\n write.push(writeInfo());\n if ('registries' in out) {\n for (const child of out.registries) {\n write.push(\n writeFumadocsRegistry(child, {\n dir: path.join(dir, child.name),\n log: options.log,\n }),\n );\n }\n }\n\n await Promise.all(write);\n}\n\nasync function writeFile(file: string, content: string, log = true): Promise<void> {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content);\n\n if (log) {\n const size = (Buffer.byteLength(content) / 1024).toFixed(2);\n\n console.log(\n `${picocolors.greenBright('+')} ${path.relative(process.cwd(), file)} ${picocolors.dim(`${size} KB`)}`,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["fs","path","fs","path"],"sources":["../../src/build/compiler.ts","../../src/build/index.ts"],"sourcesContent":["import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type {\n CompiledComponent,\n CompiledFile,\n httpSubComponent,\n NamespaceType,\n registryInfoSchema,\n} from '@/registry/schema';\nimport type { z } from 'zod';\nimport { parse } from 'oxc-parser';\nimport { ResolverFactory } from 'oxc-resolver';\nimport MagicString from 'magic-string';\nimport { transformSpecifiers } from '@/utils/ast';\n\nexport type OnResolve = (reference: SourceReference) => Reference;\n\nexport interface CompiledRegistry {\n name: string;\n components: CompiledComponent[];\n info: z.output<typeof registryInfoSchema>;\n}\n\nexport interface ComponentFile {\n type: NamespaceType;\n path: string;\n target?: string;\n}\n\nexport interface Component {\n name: string;\n title?: string;\n description?: string;\n files: ComponentFile[];\n\n /**\n * Don't list the component in registry index file\n */\n unlisted?: boolean;\n\n /**\n * Map imported file paths, inherit from registry if not defined.\n */\n onResolve?: OnResolve;\n}\n\nexport interface PackageJson {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n}\n\nexport interface Registry extends Omit<z.input<typeof registryInfoSchema>, 'indexes'> {\n name: string;\n packageJson: string | PackageJson;\n tsconfigPath: string;\n components: Component[];\n\n /**\n * The directory of registry, used to resolve relative paths\n */\n dir: string;\n\n /**\n * Map import paths of components\n */\n onResolve?: OnResolve;\n /**\n * When a referenced file is not found in component files, this function is called.\n * @returns file, or `false` to mark as external.\n */\n onUnknownFile?: (absolutePath: string) => ComponentFile | false | undefined;\n\n dependencies?: Record<string, string | null>;\n devDependencies?: Record<string, string | null>;\n}\n\nexport class RegistryCompiler {\n readonly raw: Registry;\n resolver!: RegistryResolver;\n\n constructor(registry: Registry) {\n this.raw = registry;\n }\n\n private async readPackageJson(): Promise<PackageJson | undefined> {\n if (typeof this.raw.packageJson !== 'string') return this.raw.packageJson;\n\n return fs\n .readFile(path.join(this.raw.dir, this.raw.packageJson))\n .then((res) => JSON.parse(res.toString()) as PackageJson)\n .catch(() => undefined);\n }\n\n async compile(): Promise<CompiledRegistry> {\n const registry = this.raw;\n this.resolver = new RegistryResolver(this, await this.readPackageJson());\n const output: CompiledRegistry = {\n name: registry.name,\n info: {\n indexes: [],\n env: registry.env,\n variables: registry.variables,\n },\n components: [],\n };\n\n const builtComps = await Promise.all(\n registry.components.map(async (component) => {\n const compiler = new ComponentCompiler(this, component);\n\n return [component, await compiler.build()] as [Component, CompiledComponent];\n }),\n );\n\n for (const [input, comp] of builtComps) {\n if (!input.unlisted) {\n output.info.indexes.push({\n name: input.name,\n title: input.title,\n description: input.description,\n });\n }\n\n output.components.push(comp);\n }\n\n return output;\n }\n}\n\nclass RegistryResolver {\n private readonly deps: Record<string, string | null>;\n private readonly devDeps: Record<string, string | null>;\n private readonly fileToComponent = new Map<string, [Component, ComponentFile]>();\n readonly oxc: ResolverFactory;\n\n constructor(\n private readonly compiler: RegistryCompiler,\n packageJson: PackageJson = {},\n ) {\n const registry = compiler.raw;\n\n for (const comp of registry.components) {\n for (const file of comp.files) {\n if (this.fileToComponent.has(file.path))\n console.warn(\n `the same file ${file.path} exists in multiple component, you should make the shared file a separate component.`,\n );\n this.fileToComponent.set(file.path, [comp, file]);\n }\n }\n\n this.deps = {\n ...packageJson?.dependencies,\n ...registry.dependencies,\n };\n\n this.devDeps = {\n ...packageJson?.devDependencies,\n ...registry.devDependencies,\n };\n\n // resolve anything possible\n this.oxc = new ResolverFactory({\n extensions: ['.js', '.jsx', '.ts', '.tsx', '.node'],\n conditionNames: ['node', 'import', 'require', 'default', 'types'],\n tsconfig: {\n configFile: path.join(registry.dir, registry.tsconfigPath),\n },\n });\n }\n\n getDepFromSpecifier(specifier: string) {\n return specifier.startsWith('@')\n ? specifier.split('/').slice(0, 2).join('/')\n : specifier.split('/')[0];\n }\n\n getDepInfo(name: string):\n | {\n type: 'runtime' | 'dev';\n name: string;\n version: string | null;\n }\n | undefined {\n if (name in this.deps)\n return {\n name,\n type: 'runtime',\n version: this.deps[name],\n };\n\n if (name in this.devDeps)\n return {\n name,\n type: 'dev',\n version: this.devDeps[name],\n };\n\n console.warn(`dep info for ${name} cannot be found`);\n }\n\n getComponentByName(name: string): Component | undefined {\n return this.compiler.raw.components.find((comp) => comp.name === name);\n }\n\n getSubComponent(file: string) {\n const relativeFile = path.relative(this.compiler.raw.dir, file);\n const comp = this.fileToComponent.get(relativeFile);\n\n if (!comp) return;\n return {\n component: comp[0],\n file: comp[1],\n };\n }\n}\n\nexport type SourceReference =\n | {\n type: 'file';\n /**\n * Absolute path\n */\n file: string;\n }\n | {\n type: 'dependency';\n dep: string;\n specifier: string;\n }\n | {\n type: 'sub-component';\n resolved:\n | {\n type: 'local';\n component: Component;\n file: ComponentFile;\n }\n | {\n type: 'remote';\n component: Component;\n file: ComponentFile;\n registryName: string;\n };\n }\n | {\n type: 'unknown-specifier';\n specifier: string;\n };\n\nexport type Reference =\n | SourceReference\n | {\n type: 'custom';\n specifier: string;\n };\n\nexport class ComponentCompiler {\n private readonly processedFiles = new Set<string>();\n private readonly registry: Registry;\n private readonly subComponents = new Map<string, string | z.input<typeof httpSubComponent>>();\n private readonly devDependencies = new Map<string, string | null>();\n private readonly dependencies = new Map<string, string | null>();\n\n constructor(\n private readonly compiler: RegistryCompiler,\n private readonly component: Component,\n ) {\n this.registry = compiler.raw;\n }\n\n // see https://github.com/shadcn-ui/ui/blob/396275e46a58333caa1fa0a991bd9bc5237d2ee3/packages/shadcn/src/utils/updaters/update-files.ts#L585\n // to hit the fast-path step, we need to import `target` path first because it's detected from `fileSet`, a set of output file paths\n private toImportPath(file: ComponentFile): string {\n let filePath = file.target ?? file.path;\n\n if (filePath.startsWith('./')) filePath = filePath.slice(2);\n\n return `@/${filePath.replaceAll(path.sep, '/')}`;\n }\n\n async build(): Promise<CompiledComponent> {\n return {\n name: this.component.name,\n title: this.component.title,\n description: this.component.description,\n files: (await Promise.all(this.component.files.map((file) => this.onBuildFile(file)))).flat(),\n subComponents: Array.from(this.subComponents.values()),\n dependencies: Object.fromEntries(this.dependencies),\n devDependencies: Object.fromEntries(this.devDependencies),\n };\n }\n\n private async onBuildFile(file: ComponentFile): Promise<CompiledFile[]> {\n if (this.processedFiles.has(file.path)) return [];\n this.processedFiles.add(file.path);\n const resolver = this.compiler.resolver;\n\n const queue: ComponentFile[] = [];\n const result = await this.buildFile(file, (reference) => {\n if (reference.type === 'unknown-specifier') {\n if (!reference.specifier.startsWith('node:')) {\n console.warn(`Unknown specifier ${reference.specifier}, skipping for now`);\n }\n\n return reference.specifier;\n }\n\n if (reference.type === 'custom') return reference.specifier;\n\n if (reference.type === 'file') {\n const refFile = this.registry.onUnknownFile?.(reference.file);\n if (refFile) {\n queue.push(refFile);\n return this.toImportPath(refFile);\n }\n\n if (refFile === false) return;\n\n throw new Error(`Unknown file ${reference.file} referenced by ${file.path}`);\n }\n\n if (reference.type === 'sub-component') {\n const resolved = reference.resolved;\n if (resolved.component.name === this.component.name)\n return this.toImportPath(resolved.file);\n\n if (resolved.type === 'remote') {\n this.subComponents.set(`${resolved.registryName}:${resolved.component.name}`, {\n type: 'http',\n baseUrl: resolved.registryName,\n component: resolved.component.name,\n });\n } else {\n this.subComponents.set(resolved.component.name, resolved.component.name);\n }\n\n return this.toImportPath(resolved.file);\n }\n\n const dep = resolver.getDepInfo(reference.dep);\n if (dep) {\n const map = dep.type === 'dev' ? this.devDependencies : this.dependencies;\n map.set(dep.name, dep.version);\n }\n\n return reference.specifier;\n });\n\n return [result, ...(await Promise.all(queue.map((file) => this.onBuildFile(file)))).flat()];\n }\n\n private async buildFile(\n file: ComponentFile,\n /**\n * write references back to import specifiers\n *\n * keep original one if `undefined`\n */\n writeReference: (reference: Reference) => string | undefined,\n ): Promise<CompiledFile> {\n const sourceFilePath = path.join(this.registry.dir, file.path);\n const astTypes: Record<string, 'js' | 'ts' | undefined> = {\n '.ts': 'ts',\n '.tsx': 'ts',\n '.js': 'js',\n '.jsx': 'js',\n };\n const astType = astTypes[path.extname(file.path)];\n const content = (await fs.readFile(sourceFilePath)).toString();\n\n if (!astType)\n return {\n content,\n path: file.path,\n type: file.type,\n target: file.target,\n };\n\n const resolver = this.compiler.resolver;\n\n const ast = await parse(sourceFilePath, content, {\n astType,\n });\n\n if (ast.errors.length > 0) {\n throw new Error(`failed to parse file ${sourceFilePath}: \\n${ast.errors.join('\\n')}`);\n }\n\n const s = new MagicString(content);\n /**\n * Process import paths\n */\n transformSpecifiers(ast.program, s, (specifier) => {\n let resolved: Reference = {\n type: 'unknown-specifier',\n specifier: specifier,\n };\n const onResolve = this.component.onResolve ?? this.registry.onResolve;\n const resolvedSpecifier = resolver.oxc.resolveFileSync(sourceFilePath, specifier);\n if (resolvedSpecifier.error || !resolvedSpecifier.path) {\n return writeReference(onResolve ? onResolve(resolved) : resolved);\n }\n\n resolved = {\n type: 'file',\n file: resolvedSpecifier.path,\n };\n\n // outside of registry dir\n if (path.relative(this.registry.dir, resolvedSpecifier.path).startsWith('../')) {\n resolved = {\n type: 'dependency',\n dep: resolver.getDepFromSpecifier(specifier),\n specifier,\n };\n } else {\n const sub = resolver.getSubComponent(resolvedSpecifier.path);\n if (sub) {\n resolved = {\n type: 'sub-component',\n resolved: {\n type: 'local',\n component: sub.component,\n file: sub.file,\n },\n };\n }\n }\n\n return writeReference(onResolve ? onResolve(resolved) : resolved);\n });\n\n return {\n content: s.toString(),\n type: file.type,\n path: file.path,\n target: file.target,\n };\n }\n}\n\nexport function resolveFromRemote(\n r: Registry,\n component: string,\n selectFile: (file: ComponentFile) => boolean,\n): Reference | undefined {\n const comp = r.components.find((comp) => comp.name === component);\n if (!comp) return;\n const file = comp.files.find(selectFile);\n if (!file) return;\n\n return {\n type: 'sub-component',\n resolved: {\n type: 'remote',\n registryName: r.name,\n component: comp,\n file,\n },\n };\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport picocolors from 'picocolors';\nimport type { CompiledRegistry } from '@/build/compiler';\n\nexport * from './compiler';\n\nexport interface MonoRegistry extends CompiledRegistry {\n registries: CompiledRegistry[];\n}\n\nexport function combineRegistry(\n root: CompiledRegistry,\n ...items: CompiledRegistry[]\n): MonoRegistry {\n return {\n ...root,\n info: {\n ...root.info,\n registries: items.map((item) => item.name),\n },\n registries: items,\n };\n}\n\nexport async function writeDocsRegistry(\n out: CompiledRegistry | MonoRegistry,\n options: {\n dir: string;\n\n /**\n * Remove previous outputs\n *\n * @defaultValue false\n */\n cleanDir?: boolean;\n\n log?: boolean;\n },\n): Promise<void> {\n const { dir, cleanDir = false, log = true } = options;\n\n if (cleanDir) {\n await fs.rm(dir, {\n recursive: true,\n force: true,\n });\n console.log(picocolors.bold(picocolors.greenBright('Cleaned directory')));\n }\n\n async function writeInfo() {\n const file = path.join(dir, '_registry.json');\n const json = JSON.stringify(out.info, null, 2);\n\n await writeFile(file, json, log);\n }\n\n const write = out.components.map(async (comp) => {\n const file = path.join(dir, `${comp.name}.json`);\n const json = JSON.stringify(comp, null, 2);\n\n await writeFile(file, json, log);\n });\n\n write.push(writeInfo());\n if ('registries' in out) {\n for (const child of out.registries) {\n write.push(\n writeDocsRegistry(child, {\n dir: path.join(dir, child.name),\n log: options.log,\n }),\n );\n }\n }\n\n await Promise.all(write);\n}\n\nasync function writeFile(file: string, content: string, log = true): Promise<void> {\n await fs.mkdir(path.dirname(file), { recursive: true });\n await fs.writeFile(file, content);\n\n if (log) {\n const size = (Buffer.byteLength(content) / 1024).toFixed(2);\n\n console.log(\n `${picocolors.greenBright('+')} ${path.relative(process.cwd(), file)} ${picocolors.dim(`${size} KB`)}`,\n );\n }\n}\n"],"mappings":"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"}