@mxpicture/build-api 0.2.48 → 0.2.50

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.
@@ -1,5 +1,6 @@
1
1
  import { BarrelGroup, BarrelParams, BarrelResult } from "../types/types.barrel.js";
2
2
  import { Pkg } from "../pkg/Pkg.js";
3
+ import { SourceFile } from "../types/types.code.js";
3
4
  export declare const DEFAULT_EXCLUDED_PATTERNS: RegExp[];
4
5
  export declare const DEFAULT_HEADER = "// This file is auto-generated. Do not edit manually.\n";
5
6
  export declare const runBarrel: (params: BarrelParams) => Promise<void>;
@@ -9,11 +10,13 @@ export declare class Barrel {
9
10
  constructor(excludes: RegExp[], fileHeader: string);
10
11
  run(): Promise<void>;
11
12
  protected isExcluded(fileName: string): boolean;
12
- protected persistBarrel(group: BarrelGroup): Promise<BarrelGroup>;
13
- protected extractExportsFromFile(filePath: string): Promise<{
14
- exports: string[];
15
- hasDefault: boolean;
16
- }>;
13
+ protected persistBarrel(group: BarrelGroup, sourceFileMap: Map<string, SourceFile>): Promise<BarrelGroup>;
14
+ /**
15
+ * Returns true if any source file in the group is newer than the barrel
16
+ * file, or if the barrel file does not yet exist. File deletions are handled
17
+ * implicitly because the group is rebuilt from readdir on every run.
18
+ */
19
+ protected hasGroupChanged(group: BarrelGroup, barrelPath: string): Promise<boolean>;
17
20
  protected updatePackageExports(pkg: Pkg, exports: Record<string, string>): Promise<void>;
18
21
  protected hasExportsChanged(a: Record<string, string> | undefined, b: Record<string, string> | undefined): boolean;
19
22
  protected extractExports(result: BarrelResult): Record<string, string>;
@@ -1 +1 @@
1
- {"version":3,"file":"Barrel.d.ts","sourceRoot":"","sources":["../../src/barrel/Barrel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIpC,eAAO,MAAM,yBAAyB,EAAE,MAAM,EAQ7C,CAAC;AAGF,eAAO,MAAM,cAAc,4DACgC,CAAC;AAE5D,eAAO,MAAM,SAAS,GAAU,QAAQ,YAAY,kBAMnD,CAAC;AAEF,qBAAa,MAAM;IAEf,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE;IACrC,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM;gBADlB,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM;IAG1B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAkFjC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAI/B,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;cA6BvD,sBAAsB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;cAmDtC,oBAAoB,CAClC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAoBjC,SAAS,CAAC,iBAAiB,CACzB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACrC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GACpC,OAAO;IAcV,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CASvE"}
1
+ {"version":3,"file":"Barrel.d.ts","sourceRoot":"","sources":["../../src/barrel/Barrel.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACb,MAAM,0BAA0B,CAAC;AAIlC,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAIpC,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGpD,eAAO,MAAM,yBAAyB,EAAE,MAAM,EAQ7C,CAAC;AAGF,eAAO,MAAM,cAAc,4DACgC,CAAC;AAE5D,eAAO,MAAM,SAAS,GAAU,QAAQ,YAAY,kBAMnD,CAAC;AAEF,qBAAa,MAAM;IAEf,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE;IACrC,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM;gBADlB,QAAQ,EAAE,MAAM,EAAE,EAClB,UAAU,EAAE,MAAM;IAG1B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAoGjC,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAI/B,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,GACrC,OAAO,CAAC,WAAW,CAAC;IAwCvB;;;;OAIG;cACa,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,OAAO,CAAC;cAwEH,oBAAoB,CAClC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAoBjC,SAAS,CAAC,iBAAiB,CACzB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACrC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GACpC,OAAO;IAcV,SAAS,CAAC,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CASvE"}
@@ -1,8 +1,10 @@
1
1
  import { basename, dirname, join, relative } from "node:path";
2
- import { readdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { readdir, rm, stat, writeFile } from "node:fs/promises";
3
3
  import { logInfo, logSuccess } from "../logger/Logger.js";
4
4
  import { initWorkspace, workspace } from "../workspace/Workspace.js";
5
- import { formatCode } from "../format/format.code.js";
5
+ import { formatCode } from "../code/code.format.js";
6
+ import { fileExports } from "../code/code.exports.js";
7
+ import { createSourceFileMap } from "../code/code.common.js";
6
8
  // /** File patterns to exclude from barrel exports */
7
9
  export const DEFAULT_EXCLUDED_PATTERNS = [
8
10
  /\.test\.ts$/,
@@ -29,23 +31,26 @@ export class Barrel {
29
31
  async run() {
30
32
  const ws = workspace();
31
33
  await ws.read();
32
- const promises = [];
34
+ // Phase 1: collect all barrel groups, keyed by package name
35
+ const groupsByPkg = new Map();
33
36
  for (const pkg of ws.packages) {
34
37
  try {
35
38
  const items = (await readdir(pkg.srcPath, { recursive: true })).sort();
36
39
  let currentGroup;
40
+ const pushGroup = (g) => {
41
+ const key = g.pkg.content.name;
42
+ if (!groupsByPkg.has(key))
43
+ groupsByPkg.set(key, []);
44
+ groupsByPkg.get(key).push({ ...g });
45
+ };
37
46
  for (const item of items) {
38
47
  const filename = basename(item);
39
48
  const dirPath = join(pkg.srcPath, dirname(item));
40
49
  const filePath = join(dirPath, filename);
41
50
  if (dirPath !== currentGroup?.dirPath) {
42
51
  if (currentGroup)
43
- promises.push(this.persistBarrel({ ...currentGroup }));
44
- currentGroup = {
45
- dirPath,
46
- files: [],
47
- pkg,
48
- };
52
+ pushGroup(currentGroup);
53
+ currentGroup = { dirPath, files: [], pkg };
49
54
  }
50
55
  if (this.isExcluded(filePath) ||
51
56
  (!filename.endsWith(".ts") && !filename.endsWith(".mts")))
@@ -53,12 +58,23 @@ export class Barrel {
53
58
  currentGroup.files.push(filename);
54
59
  }
55
60
  if (currentGroup)
56
- promises.push(this.persistBarrel({ ...currentGroup }));
61
+ pushGroup(currentGroup);
57
62
  }
58
63
  catch {
59
64
  continue;
60
65
  }
61
66
  }
67
+ // Phase 2: build one ts.Program per package, then persist all groups in parallel
68
+ const promises = [];
69
+ for (const groups of groupsByPkg.values()) {
70
+ const allFilePaths = groups.flatMap((g) => g.files.map((f) => join(g.dirPath, f)));
71
+ const sourceFileMap = allFilePaths.length > 0
72
+ ? createSourceFileMap(allFilePaths)
73
+ : new Map();
74
+ for (const group of groups) {
75
+ promises.push(this.persistBarrel({ ...group }, sourceFileMap));
76
+ }
77
+ }
62
78
  const barrelGroups = (await Promise.all(promises)).filter((prom) => prom.files.length > 0);
63
79
  const results = [];
64
80
  for (const barrelGroup of barrelGroups) {
@@ -86,19 +102,25 @@ export class Barrel {
86
102
  isExcluded(fileName) {
87
103
  return this.excludes.some((pattern) => pattern.test(fileName));
88
104
  }
89
- async persistBarrel(group) {
105
+ async persistBarrel(group, sourceFileMap) {
90
106
  const barrelPath = join(group.dirPath, "index.ts");
91
107
  // no files --> skip/delete index.ts
92
108
  if (group.files.length === 0) {
93
109
  await rm(barrelPath, { recursive: true, force: true });
94
110
  return group;
95
111
  }
112
+ // Skip if all source files are older than the existing barrel
113
+ if (!(await this.hasGroupChanged(group, barrelPath)))
114
+ return group;
96
115
  const exportLines = [];
97
116
  for (const file of group.files.sort()) {
98
117
  const filePath = join(group.dirPath, file);
99
- const { exports, hasDefault } = await this.extractExportsFromFile(filePath);
118
+ const expResult = fileExports(filePath, undefined, sourceFileMap.get(filePath));
119
+ if (expResult.items.length === 0)
120
+ continue;
121
+ const exports = expResult.items.map((item) => item.name);
100
122
  const moduleRef = `./${basename(file, ".ts")}.js`;
101
- if (hasDefault) {
123
+ if (expResult.hasDefault) {
102
124
  exportLines.push(`export * from "${moduleRef}";`);
103
125
  }
104
126
  else if (exports.length > 0) {
@@ -110,52 +132,79 @@ export class Barrel {
110
132
  await writeFile(barrelPath, content);
111
133
  return group;
112
134
  }
113
- async extractExportsFromFile(filePath) {
135
+ /**
136
+ * Returns true if any source file in the group is newer than the barrel
137
+ * file, or if the barrel file does not yet exist. File deletions are handled
138
+ * implicitly because the group is rebuilt from readdir on every run.
139
+ */
140
+ async hasGroupChanged(group, barrelPath) {
141
+ let barrelMtime;
114
142
  try {
115
- const content = await readFile(filePath, "utf-8");
116
- const exports = new Set();
117
- let hasDefault = false;
118
- // Detect any default export
119
- if (/export\s+default\b/.test(content))
120
- hasDefault = true;
121
- // Match named exports: export const|function|class Name
122
- const namedExportPattern = /export\s+(?:const|let|var|function|class|interface|type|enum)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
123
- let match;
124
- while ((match = namedExportPattern.exec(content)) !== null) {
125
- const name = match[1];
126
- if (!name.startsWith("_") &&
127
- !name.startsWith("//") &&
128
- !name.startsWith("/*"))
129
- exports.add(name);
130
- }
131
- // Match export { a, b, c } and export { a, b, c } from '...'
132
- const exportBracePattern = /export\s*\{\s*([^}]+)\s*\}/g;
133
- while ((match = exportBracePattern.exec(content)) !== null) {
134
- const items = match[1].split(",");
135
- for (const item of items) {
136
- const trimmed = item.trim();
137
- if (!trimmed)
138
- continue;
139
- // Handle "export { name as alias }"
140
- const parts = trimmed.split(/\s+as\s+/);
141
- const name = parts[0].trim();
142
- const alias = parts[1]?.trim();
143
- // Skip default exports (e.g. "export { Foo as default }")
144
- if (alias === "default") {
145
- hasDefault = true;
146
- continue;
147
- }
148
- if (name && name !== "default" && !name.startsWith("_")) {
149
- exports.add(name);
150
- }
151
- }
152
- }
153
- return { exports: Array.from(exports).sort(), hasDefault };
143
+ barrelMtime = (await stat(barrelPath)).mtimeMs;
154
144
  }
155
145
  catch {
156
- return { exports: [], hasDefault: false };
146
+ return true; // barrel doesn't exist yet
147
+ }
148
+ for (const file of group.files) {
149
+ try {
150
+ const fileMtime = (await stat(join(group.dirPath, file))).mtimeMs;
151
+ if (fileMtime > barrelMtime)
152
+ return true;
153
+ }
154
+ catch {
155
+ return true; // file accessibility changed
156
+ }
157
157
  }
158
+ return false;
158
159
  }
160
+ // protected async extractExportsFromFile(
161
+ // filePath: string,
162
+ // ): Promise<{ exports: string[]; hasDefault: boolean }> {
163
+ // try {
164
+ // const content = await readFile(filePath, "utf-8");
165
+ // const exports: Set<string> = new Set();
166
+ // let hasDefault = false;
167
+ // // Detect any default export
168
+ // if (/export\s+default\b/.test(content)) hasDefault = true;
169
+ // // Match named exports: export const|function|class Name
170
+ // const namedExportPattern =
171
+ // /export\s+(?:const|let|var|function|class|interface|type|enum)\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;
172
+ // let match;
173
+ // while ((match = namedExportPattern.exec(content)) !== null) {
174
+ // const name = match[1];
175
+ // if (
176
+ // !name.startsWith("_") &&
177
+ // !name.startsWith("//") &&
178
+ // !name.startsWith("/*")
179
+ // )
180
+ // exports.add(name);
181
+ // }
182
+ // // Match export { a, b, c } and export { a, b, c } from '...'
183
+ // const exportBracePattern = /export\s*\{\s*([^}]+)\s*\}/g;
184
+ // while ((match = exportBracePattern.exec(content)) !== null) {
185
+ // const items = match[1].split(",");
186
+ // for (const item of items) {
187
+ // const trimmed = item.trim();
188
+ // if (!trimmed) continue;
189
+ // // Handle "export { name as alias }"
190
+ // const parts = trimmed.split(/\s+as\s+/);
191
+ // const name = parts[0].trim();
192
+ // const alias = parts[1]?.trim();
193
+ // // Skip default exports (e.g. "export { Foo as default }")
194
+ // if (alias === "default") {
195
+ // hasDefault = true;
196
+ // continue;
197
+ // }
198
+ // if (name && name !== "default" && !name.startsWith("_")) {
199
+ // exports.add(name);
200
+ // }
201
+ // }
202
+ // }
203
+ // return { exports: Array.from(exports).sort(), hasDefault };
204
+ // } catch {
205
+ // return { exports: [], hasDefault: false };
206
+ // }
207
+ // }
159
208
  async updatePackageExports(pkg, exports) {
160
209
  try {
161
210
  // const pkgName = relative(this.paths.workspacesDir, packageDir);
@@ -1 +1 @@
1
- {"version":3,"file":"Barrel.js","sourceRoot":"","sources":["../../src/barrel/Barrel.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename, dirname, join, relative } from \"node:path\";\nimport {\n BarrelGroup,\n BarrelParams,\n BarrelResult,\n} from \"../types/types.barrel.js\";\nimport { readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { logInfo, logSuccess } from \"../logger/Logger.js\";\nimport { initWorkspace, workspace } from \"../workspace/Workspace.js\";\nimport { Pkg } from \"../pkg/Pkg.js\";\nimport { formatCode } from \"../format/format.code.js\";\n\n// /** File patterns to exclude from barrel exports */\nexport const DEFAULT_EXCLUDED_PATTERNS: RegExp[] = [\n /\\.test\\.ts$/,\n /\\.spec\\.ts$/,\n /(^|\\/)__tests__(\\/|$)/,\n /\\.d\\.ts$/,\n /index\\.ts$/,\n /(.+\\/|^)src\\/(.+\\/|)scripts?\\/.+\\.m?ts$/,\n /\\/4testing(\\/|$)/,\n];\n\n// /** Header comment added to every generated barrel file */\nexport const DEFAULT_HEADER =\n \"// This file is auto-generated. Do not edit manually.\\n\";\n\nexport const runBarrel = async (params: BarrelParams) => {\n initWorkspace(params.repoRoot);\n return new Barrel(\n params.excludes ?? DEFAULT_EXCLUDED_PATTERNS,\n params.fileHeader ?? DEFAULT_HEADER,\n ).run();\n};\n\nexport class Barrel {\n public constructor(\n protected readonly excludes: RegExp[],\n protected readonly fileHeader: string,\n ) {}\n\n public async run(): Promise<void> {\n const ws = workspace();\n await ws.read();\n\n const promises: Promise<BarrelGroup>[] = [];\n\n for (const pkg of ws.packages) {\n try {\n const items = (await readdir(pkg.srcPath, { recursive: true })).sort();\n let currentGroup: BarrelGroup | undefined;\n\n for (const item of items) {\n const filename = basename(item);\n const dirPath = join(pkg.srcPath, dirname(item));\n const filePath = join(dirPath, filename);\n\n if (dirPath !== currentGroup?.dirPath) {\n if (currentGroup)\n promises.push(this.persistBarrel({ ...currentGroup }));\n currentGroup = {\n dirPath,\n files: [],\n pkg,\n };\n }\n\n if (\n this.isExcluded(filePath) ||\n (!filename.endsWith(\".ts\") && !filename.endsWith(\".mts\"))\n )\n continue;\n\n currentGroup.files.push(filename);\n }\n\n if (currentGroup)\n promises.push(this.persistBarrel({ ...currentGroup }));\n } catch {\n continue;\n }\n }\n\n const barrelGroups = (await Promise.all(promises)).filter(\n (prom) => prom.files.length > 0,\n );\n\n const results: BarrelResult[] = [];\n\n for (const barrelGroup of barrelGroups) {\n let found = results.find(\n (res) => barrelGroup.dirPath === res.pkg.dirPath,\n );\n if (!found) {\n found = {\n barrelDirs: [],\n pkg: barrelGroup.pkg,\n };\n results.push(found);\n }\n\n found.barrelDirs.push(barrelGroup.dirPath);\n }\n\n const pkgExps: Record<string, { pkg: Pkg; exps: Record<string, string> }> =\n {};\n for (const res of results) {\n if (!(res.pkg.content.name in pkgExps))\n pkgExps[res.pkg.content.name] = { pkg: res.pkg, exps: {} };\n\n pkgExps[res.pkg.content.name].exps = {\n ...pkgExps[res.pkg.content.name].exps,\n ...this.extractExports(res),\n };\n }\n\n await Promise.all(\n Object.values(pkgExps).map(async (pkgExp) =>\n this.updatePackageExports(pkgExp.pkg, pkgExp.exps),\n ),\n );\n }\n\n protected isExcluded(fileName: string): boolean {\n return this.excludes.some((pattern) => pattern.test(fileName));\n }\n\n protected async persistBarrel(group: BarrelGroup): Promise<BarrelGroup> {\n const barrelPath = join(group.dirPath, \"index.ts\");\n // no files --> skip/delete index.ts\n if (group.files.length === 0) {\n await rm(barrelPath, { recursive: true, force: true });\n return group;\n }\n\n const exportLines: string[] = [];\n for (const file of group.files.sort()) {\n const filePath = join(group.dirPath, file);\n const { exports, hasDefault } =\n await this.extractExportsFromFile(filePath);\n const moduleRef = `./${basename(file, \".ts\")}.js`;\n if (hasDefault) {\n exportLines.push(`export * from \"${moduleRef}\";`);\n } else if (exports.length > 0) {\n exportLines.push(\n `export { ${exports.join(\", \")} } from \"${moduleRef}\";`,\n );\n }\n }\n\n let content = `${this.fileHeader}${exportLines.length > 0 ? exportLines.join(\"\\n\") + \"\\n\" : \"\"}`;\n content = await formatCode(content);\n await writeFile(barrelPath, content);\n return group;\n }\n\n protected async extractExportsFromFile(\n filePath: string,\n ): Promise<{ exports: string[]; hasDefault: boolean }> {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const exports: Set<string> = new Set();\n let hasDefault = false;\n\n // Detect any default export\n if (/export\\s+default\\b/.test(content)) hasDefault = true;\n\n // Match named exports: export const|function|class Name\n const namedExportPattern =\n /export\\s+(?:const|let|var|function|class|interface|type|enum)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;\n let match;\n while ((match = namedExportPattern.exec(content)) !== null) {\n const name = match[1];\n if (\n !name.startsWith(\"_\") &&\n !name.startsWith(\"//\") &&\n !name.startsWith(\"/*\")\n )\n exports.add(name);\n }\n\n // Match export { a, b, c } and export { a, b, c } from '...'\n const exportBracePattern = /export\\s*\\{\\s*([^}]+)\\s*\\}/g;\n while ((match = exportBracePattern.exec(content)) !== null) {\n const items = match[1].split(\",\");\n for (const item of items) {\n const trimmed = item.trim();\n if (!trimmed) continue;\n // Handle \"export { name as alias }\"\n const parts = trimmed.split(/\\s+as\\s+/);\n const name = parts[0].trim();\n const alias = parts[1]?.trim();\n // Skip default exports (e.g. \"export { Foo as default }\")\n if (alias === \"default\") {\n hasDefault = true;\n continue;\n }\n if (name && name !== \"default\" && !name.startsWith(\"_\")) {\n exports.add(name);\n }\n }\n }\n\n return { exports: Array.from(exports).sort(), hasDefault };\n } catch {\n return { exports: [], hasDefault: false };\n }\n }\n\n protected async updatePackageExports(\n pkg: Pkg,\n exports: Record<string, string>,\n ) {\n try {\n // const pkgName = relative(this.paths.workspacesDir, packageDir);\n // // const pkgs = await workspace().loadPackages();\n\n logInfo(`📦 updating ${pkg.repoDirPath} package.json ...`);\n // const pkg = await readPackageJsonThrow(packageJsonPath);\n if (!this.hasExportsChanged(exports, pkg.content.exports)) {\n logInfo(`🧹 No changes in ${pkg.repoDirPath}, nothing to do`);\n return;\n }\n pkg.content.exports = { ...exports };\n await pkg.write();\n logSuccess(`✅ ${pkg.repoDirPath} update successful`);\n } catch (error) {\n logInfo(error);\n }\n }\n\n protected hasExportsChanged(\n a: Record<string, string> | undefined,\n b: Record<string, string> | undefined,\n ): boolean {\n if (!a) a = {};\n if (!b) b = {};\n\n if (Object.keys(a).length !== Object.keys(b).length) return true;\n if (!a && !b) return false;\n if (!a || !b) return true;\n\n for (const entryA of Object.entries(a)) {\n if (b[entryA[0]] !== entryA[1]) return true;\n }\n return false;\n }\n\n protected extractExports(result: BarrelResult): Record<string, string> {\n const record: Record<string, string> = {};\n for (const barrelDir of result.barrelDirs) {\n const ex = relative(result.pkg.srcPath, barrelDir);\n record[`./${ex}`] = `./dist/${ex}/index.js`;\n }\n record[\"./package.json\"] = \"./package.json\";\n return record;\n }\n}\n"]}
1
+ {"version":3,"file":"Barrel.js","sourceRoot":"","sources":["../../src/barrel/Barrel.ts"],"names":[],"mappings":"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","sourcesContent":["import { basename, dirname, join, relative } from \"node:path\";\nimport {\n BarrelGroup,\n BarrelParams,\n BarrelResult,\n} from \"../types/types.barrel.js\";\nimport { readdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { logInfo, logSuccess } from \"../logger/Logger.js\";\nimport { initWorkspace, workspace } from \"../workspace/Workspace.js\";\nimport { Pkg } from \"../pkg/Pkg.js\";\nimport { formatCode } from \"../code/code.format.js\";\nimport { fileExports } from \"../code/code.exports.js\";\nimport { createSourceFileMap } from \"../code/code.common.js\";\nimport { SourceFile } from \"../types/types.code.js\";\n\n// /** File patterns to exclude from barrel exports */\nexport const DEFAULT_EXCLUDED_PATTERNS: RegExp[] = [\n /\\.test\\.ts$/,\n /\\.spec\\.ts$/,\n /(^|\\/)__tests__(\\/|$)/,\n /\\.d\\.ts$/,\n /index\\.ts$/,\n /(.+\\/|^)src\\/(.+\\/|)scripts?\\/.+\\.m?ts$/,\n /\\/4testing(\\/|$)/,\n];\n\n// /** Header comment added to every generated barrel file */\nexport const DEFAULT_HEADER =\n \"// This file is auto-generated. Do not edit manually.\\n\";\n\nexport const runBarrel = async (params: BarrelParams) => {\n initWorkspace(params.repoRoot);\n return new Barrel(\n params.excludes ?? DEFAULT_EXCLUDED_PATTERNS,\n params.fileHeader ?? DEFAULT_HEADER,\n ).run();\n};\n\nexport class Barrel {\n public constructor(\n protected readonly excludes: RegExp[],\n protected readonly fileHeader: string,\n ) {}\n\n public async run(): Promise<void> {\n const ws = workspace();\n await ws.read();\n\n // Phase 1: collect all barrel groups, keyed by package name\n const groupsByPkg = new Map<string, BarrelGroup[]>();\n\n for (const pkg of ws.packages) {\n try {\n const items = (await readdir(pkg.srcPath, { recursive: true })).sort();\n let currentGroup: BarrelGroup | undefined;\n\n const pushGroup = (g: BarrelGroup) => {\n const key = g.pkg.content.name;\n if (!groupsByPkg.has(key)) groupsByPkg.set(key, []);\n groupsByPkg.get(key)!.push({ ...g });\n };\n\n for (const item of items) {\n const filename = basename(item);\n const dirPath = join(pkg.srcPath, dirname(item));\n const filePath = join(dirPath, filename);\n\n if (dirPath !== currentGroup?.dirPath) {\n if (currentGroup) pushGroup(currentGroup);\n currentGroup = { dirPath, files: [], pkg };\n }\n\n if (\n this.isExcluded(filePath) ||\n (!filename.endsWith(\".ts\") && !filename.endsWith(\".mts\"))\n )\n continue;\n\n currentGroup.files.push(filename);\n }\n\n if (currentGroup) pushGroup(currentGroup);\n } catch {\n continue;\n }\n }\n\n // Phase 2: build one ts.Program per package, then persist all groups in parallel\n const promises: Promise<BarrelGroup>[] = [];\n\n for (const groups of groupsByPkg.values()) {\n const allFilePaths = groups.flatMap((g) =>\n g.files.map((f) => join(g.dirPath, f)),\n );\n const sourceFileMap: Map<string, SourceFile> =\n allFilePaths.length > 0\n ? createSourceFileMap(allFilePaths)\n : new Map<string, SourceFile>();\n\n for (const group of groups) {\n promises.push(this.persistBarrel({ ...group }, sourceFileMap));\n }\n }\n\n const barrelGroups = (await Promise.all(promises)).filter(\n (prom) => prom.files.length > 0,\n );\n\n const results: BarrelResult[] = [];\n\n for (const barrelGroup of barrelGroups) {\n let found = results.find(\n (res) => barrelGroup.dirPath === res.pkg.dirPath,\n );\n if (!found) {\n found = {\n barrelDirs: [],\n pkg: barrelGroup.pkg,\n };\n results.push(found);\n }\n\n found.barrelDirs.push(barrelGroup.dirPath);\n }\n\n const pkgExps: Record<string, { pkg: Pkg; exps: Record<string, string> }> =\n {};\n for (const res of results) {\n if (!(res.pkg.content.name in pkgExps))\n pkgExps[res.pkg.content.name] = { pkg: res.pkg, exps: {} };\n\n pkgExps[res.pkg.content.name].exps = {\n ...pkgExps[res.pkg.content.name].exps,\n ...this.extractExports(res),\n };\n }\n\n await Promise.all(\n Object.values(pkgExps).map(async (pkgExp) =>\n this.updatePackageExports(pkgExp.pkg, pkgExp.exps),\n ),\n );\n }\n\n protected isExcluded(fileName: string): boolean {\n return this.excludes.some((pattern) => pattern.test(fileName));\n }\n\n protected async persistBarrel(\n group: BarrelGroup,\n sourceFileMap: Map<string, SourceFile>,\n ): Promise<BarrelGroup> {\n const barrelPath = join(group.dirPath, \"index.ts\");\n // no files --> skip/delete index.ts\n if (group.files.length === 0) {\n await rm(barrelPath, { recursive: true, force: true });\n return group;\n }\n\n // Skip if all source files are older than the existing barrel\n if (!(await this.hasGroupChanged(group, barrelPath))) return group;\n\n const exportLines: string[] = [];\n for (const file of group.files.sort()) {\n const filePath = join(group.dirPath, file);\n\n const expResult = fileExports(\n filePath,\n undefined,\n sourceFileMap.get(filePath),\n );\n if (expResult.items.length === 0) continue;\n\n const exports = expResult.items.map((item) => item.name);\n const moduleRef = `./${basename(file, \".ts\")}.js`;\n\n if (expResult.hasDefault) {\n exportLines.push(`export * from \"${moduleRef}\";`);\n } else if (exports.length > 0) {\n exportLines.push(\n `export { ${exports.join(\", \")} } from \"${moduleRef}\";`,\n );\n }\n }\n\n let content = `${this.fileHeader}${exportLines.length > 0 ? exportLines.join(\"\\n\") + \"\\n\" : \"\"}`;\n content = await formatCode(content);\n await writeFile(barrelPath, content);\n return group;\n }\n\n /**\n * Returns true if any source file in the group is newer than the barrel\n * file, or if the barrel file does not yet exist. File deletions are handled\n * implicitly because the group is rebuilt from readdir on every run.\n */\n protected async hasGroupChanged(\n group: BarrelGroup,\n barrelPath: string,\n ): Promise<boolean> {\n let barrelMtime: number;\n try {\n barrelMtime = (await stat(barrelPath)).mtimeMs;\n } catch {\n return true; // barrel doesn't exist yet\n }\n\n for (const file of group.files) {\n try {\n const fileMtime = (await stat(join(group.dirPath, file))).mtimeMs;\n if (fileMtime > barrelMtime) return true;\n } catch {\n return true; // file accessibility changed\n }\n }\n return false;\n }\n\n // protected async extractExportsFromFile(\n // filePath: string,\n // ): Promise<{ exports: string[]; hasDefault: boolean }> {\n // try {\n // const content = await readFile(filePath, \"utf-8\");\n // const exports: Set<string> = new Set();\n // let hasDefault = false;\n\n // // Detect any default export\n // if (/export\\s+default\\b/.test(content)) hasDefault = true;\n\n // // Match named exports: export const|function|class Name\n // const namedExportPattern =\n // /export\\s+(?:const|let|var|function|class|interface|type|enum)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)/g;\n // let match;\n // while ((match = namedExportPattern.exec(content)) !== null) {\n // const name = match[1];\n // if (\n // !name.startsWith(\"_\") &&\n // !name.startsWith(\"//\") &&\n // !name.startsWith(\"/*\")\n // )\n // exports.add(name);\n // }\n\n // // Match export { a, b, c } and export { a, b, c } from '...'\n // const exportBracePattern = /export\\s*\\{\\s*([^}]+)\\s*\\}/g;\n // while ((match = exportBracePattern.exec(content)) !== null) {\n // const items = match[1].split(\",\");\n // for (const item of items) {\n // const trimmed = item.trim();\n // if (!trimmed) continue;\n // // Handle \"export { name as alias }\"\n // const parts = trimmed.split(/\\s+as\\s+/);\n // const name = parts[0].trim();\n // const alias = parts[1]?.trim();\n // // Skip default exports (e.g. \"export { Foo as default }\")\n // if (alias === \"default\") {\n // hasDefault = true;\n // continue;\n // }\n // if (name && name !== \"default\" && !name.startsWith(\"_\")) {\n // exports.add(name);\n // }\n // }\n // }\n\n // return { exports: Array.from(exports).sort(), hasDefault };\n // } catch {\n // return { exports: [], hasDefault: false };\n // }\n // }\n\n protected async updatePackageExports(\n pkg: Pkg,\n exports: Record<string, string>,\n ) {\n try {\n // const pkgName = relative(this.paths.workspacesDir, packageDir);\n // // const pkgs = await workspace().loadPackages();\n\n logInfo(`📦 updating ${pkg.repoDirPath} package.json ...`);\n // const pkg = await readPackageJsonThrow(packageJsonPath);\n if (!this.hasExportsChanged(exports, pkg.content.exports)) {\n logInfo(`🧹 No changes in ${pkg.repoDirPath}, nothing to do`);\n return;\n }\n pkg.content.exports = { ...exports };\n await pkg.write();\n logSuccess(`✅ ${pkg.repoDirPath} update successful`);\n } catch (error) {\n logInfo(error);\n }\n }\n\n protected hasExportsChanged(\n a: Record<string, string> | undefined,\n b: Record<string, string> | undefined,\n ): boolean {\n if (!a) a = {};\n if (!b) b = {};\n\n if (Object.keys(a).length !== Object.keys(b).length) return true;\n if (!a && !b) return false;\n if (!a || !b) return true;\n\n for (const entryA of Object.entries(a)) {\n if (b[entryA[0]] !== entryA[1]) return true;\n }\n return false;\n }\n\n protected extractExports(result: BarrelResult): Record<string, string> {\n const record: Record<string, string> = {};\n for (const barrelDir of result.barrelDirs) {\n const ex = relative(result.pkg.srcPath, barrelDir);\n record[`./${ex}`] = `./dist/${ex}/index.js`;\n }\n record[\"./package.json\"] = \"./package.json\";\n return record;\n }\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import ts from "typescript";
2
+ import { SourceFile } from "../types/types.code.js";
3
+ export declare const createSourceFiles: (filePaths: string[]) => SourceFile[];
4
+ /**
5
+ * Creates a single ts.Program for all provided file paths and returns a map
6
+ * from filePath → SourceFile. This is much more efficient than calling
7
+ * createSourceFiles() per file because the TypeScript compiler is only
8
+ * instantiated once.
9
+ */
10
+ export declare const createSourceFileMap: (filePaths: string[]) => Map<string, SourceFile>;
11
+ export declare const declarationKindName: (d: ts.Declaration) => string;
12
+ export declare const guessKindFromFlags: (sym: ts.Symbol) => string;
13
+ //# sourceMappingURL=code.common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.common.d.ts","sourceRoot":"","sources":["../../src/code/code.common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,KAAG,UAAU,EAgBjE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAC9B,WAAW,MAAM,EAAE,KAClB,GAAG,CAAC,MAAM,EAAE,UAAU,CAcxB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,GAAG,EAAE,CAAC,WAAW,WACjB,CAAC;AAErC,eAAO,MAAM,kBAAkB,GAAI,KAAK,EAAE,CAAC,MAAM,KAAG,MAYnD,CAAC"}
@@ -0,0 +1,62 @@
1
+ import ts from "typescript";
2
+ export const createSourceFiles = (filePaths) => {
3
+ const program = ts.createProgram(filePaths, {
4
+ target: ts.ScriptTarget.ES2023,
5
+ module: ts.ModuleKind.Node20,
6
+ strict: true,
7
+ });
8
+ const checker = program.getTypeChecker();
9
+ const results = [];
10
+ for (const filePath of filePaths) {
11
+ const sourceFile = program.getSourceFile(filePath);
12
+ if (!sourceFile)
13
+ continue;
14
+ results.push({ sourceFile, filePath, checker });
15
+ }
16
+ return results;
17
+ };
18
+ /**
19
+ * Creates a single ts.Program for all provided file paths and returns a map
20
+ * from filePath → SourceFile. This is much more efficient than calling
21
+ * createSourceFiles() per file because the TypeScript compiler is only
22
+ * instantiated once.
23
+ */
24
+ export const createSourceFileMap = (filePaths) => {
25
+ const program = ts.createProgram(filePaths, {
26
+ target: ts.ScriptTarget.ES2023,
27
+ module: ts.ModuleKind.Node20,
28
+ strict: true,
29
+ });
30
+ const checker = program.getTypeChecker();
31
+ const map = new Map();
32
+ for (const filePath of filePaths) {
33
+ const sourceFile = program.getSourceFile(filePath);
34
+ if (!sourceFile)
35
+ continue;
36
+ map.set(filePath, { sourceFile, filePath, checker });
37
+ }
38
+ return map;
39
+ };
40
+ export const declarationKindName = (d) => ts.SyntaxKind[d.kind] ?? "Unknown";
41
+ export const guessKindFromFlags = (sym) => {
42
+ // Not perfect, but good enough for reporting.
43
+ const f = sym.getFlags();
44
+ if (f & ts.SymbolFlags.Function)
45
+ return "function";
46
+ if (f & ts.SymbolFlags.Class)
47
+ return "class";
48
+ if (f & ts.SymbolFlags.Enum)
49
+ return "enum";
50
+ if (f & ts.SymbolFlags.ValueModule)
51
+ return "namespace";
52
+ if (f & ts.SymbolFlags.TypeAlias)
53
+ return "type";
54
+ if (f & ts.SymbolFlags.Interface)
55
+ return "interface";
56
+ if (f & ts.SymbolFlags.Variable)
57
+ return "variable";
58
+ if (f & ts.SymbolFlags.Alias)
59
+ return "alias";
60
+ return "unknown";
61
+ };
62
+ //# sourceMappingURL=code.common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.common.js","sourceRoot":"","sources":["../../src/code/code.common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAG5B,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAmB,EAAgB,EAAE;IACrE,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE;QAC1C,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;QAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM;QAC5B,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IACzC,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,SAAmB,EACM,EAAE;IAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE;QAC1C,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;QAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM;QAC5B,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC1C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAiB,EAAE,EAAE,CACvD,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;AAErC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAc,EAAU,EAAE;IAC3D,8CAA8C;IAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IACzB,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ;QAAE,OAAO,UAAU,CAAC;IACnD,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK;QAAE,OAAO,OAAO,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI;QAAE,OAAO,MAAM,CAAC;IAC3C,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW;QAAE,OAAO,WAAW,CAAC;IACvD,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC;IAChD,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS;QAAE,OAAO,WAAW,CAAC;IACrD,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,QAAQ;QAAE,OAAO,UAAU,CAAC;IACnD,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK;QAAE,OAAO,OAAO,CAAC;IAC7C,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC","sourcesContent":["import ts from \"typescript\";\nimport { SourceFile } from \"../types/types.code.js\";\n\nexport const createSourceFiles = (filePaths: string[]): SourceFile[] => {\n const program = ts.createProgram(filePaths, {\n target: ts.ScriptTarget.ES2023,\n module: ts.ModuleKind.Node20,\n strict: true,\n });\n const checker = program.getTypeChecker();\n const results: SourceFile[] = [];\n\n for (const filePath of filePaths) {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) continue;\n results.push({ sourceFile, filePath, checker });\n }\n\n return results;\n};\n\n/**\n * Creates a single ts.Program for all provided file paths and returns a map\n * from filePath → SourceFile. This is much more efficient than calling\n * createSourceFiles() per file because the TypeScript compiler is only\n * instantiated once.\n */\nexport const createSourceFileMap = (\n filePaths: string[],\n): Map<string, SourceFile> => {\n const program = ts.createProgram(filePaths, {\n target: ts.ScriptTarget.ES2023,\n module: ts.ModuleKind.Node20,\n strict: true,\n });\n const checker = program.getTypeChecker();\n const map = new Map<string, SourceFile>();\n for (const filePath of filePaths) {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) continue;\n map.set(filePath, { sourceFile, filePath, checker });\n }\n return map;\n};\n\nexport const declarationKindName = (d: ts.Declaration) =>\n ts.SyntaxKind[d.kind] ?? \"Unknown\";\n\nexport const guessKindFromFlags = (sym: ts.Symbol): string => {\n // Not perfect, but good enough for reporting.\n const f = sym.getFlags();\n if (f & ts.SymbolFlags.Function) return \"function\";\n if (f & ts.SymbolFlags.Class) return \"class\";\n if (f & ts.SymbolFlags.Enum) return \"enum\";\n if (f & ts.SymbolFlags.ValueModule) return \"namespace\";\n if (f & ts.SymbolFlags.TypeAlias) return \"type\";\n if (f & ts.SymbolFlags.Interface) return \"interface\";\n if (f & ts.SymbolFlags.Variable) return \"variable\";\n if (f & ts.SymbolFlags.Alias) return \"alias\";\n return \"unknown\";\n};\n"]}
@@ -0,0 +1,8 @@
1
+ import { SourceExport, SourceFile } from "../types/types.code.js";
2
+ export declare const fileExports: (filePath: string, opts?: {
3
+ includeTypeOnly?: boolean;
4
+ includeReExports?: boolean;
5
+ includeDefault?: boolean;
6
+ includePrivate?: boolean;
7
+ }, preBuiltSource?: SourceFile) => SourceExport;
8
+ //# sourceMappingURL=code.exports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.exports.d.ts","sourceRoot":"","sources":["../../src/code/code.exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAQlE,eAAO,MAAM,WAAW,GACtB,UAAU,MAAM,EAChB,OAAO;IACL,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,EACD,iBAAiB,UAAU,KAC1B,YA2EF,CAAC"}
@@ -0,0 +1,72 @@
1
+ import ts from "typescript";
2
+ import { resolve } from "node:path";
3
+ import { createSourceFiles, declarationKindName, guessKindFromFlags, } from "./code.common.js";
4
+ export const fileExports = (filePath, opts, preBuiltSource) => {
5
+ const includeTypeOnly = opts?.includeTypeOnly ?? true;
6
+ const includeReExports = opts?.includeReExports ?? true;
7
+ const abs = resolve(filePath);
8
+ const files = preBuiltSource
9
+ ? [preBuiltSource]
10
+ : createSourceFiles([filePath]);
11
+ if (files.length === 0)
12
+ throw new Error(`Could not load source file: ${abs}`);
13
+ const { checker, sourceFile } = files[0];
14
+ const result = {
15
+ items: [],
16
+ hasDefault: false,
17
+ };
18
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
19
+ if (!moduleSymbol)
20
+ return result;
21
+ // This gives the "export surface" of the module (including re-exports).
22
+ const exports = checker.getExportsOfModule(moduleSymbol);
23
+ for (const sym of exports) {
24
+ const name = sym.getName();
25
+ if (name === "default") {
26
+ result.hasDefault = true;
27
+ if (!opts?.includeDefault)
28
+ continue;
29
+ }
30
+ else if (name.startsWith("_")) {
31
+ if (!opts?.includePrivate)
32
+ continue;
33
+ }
34
+ // Determine if it's type-only (TypeScript 5.x provides isTypeOnlySymbol).
35
+ // Fallback: approximate using flags.
36
+ const isTypeOnly =
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ typeof checker.isTypeOnlySymbol === "function"
39
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ checker.isTypeOnlySymbol(sym)
41
+ : !!(sym.getFlags() &
42
+ (ts.SymbolFlags.Type |
43
+ ts.SymbolFlags.Interface |
44
+ ts.SymbolFlags.TypeAlias));
45
+ if (!includeTypeOnly && isTypeOnly)
46
+ continue;
47
+ // Re-export detection: if symbol is an alias and resolves elsewhere
48
+ let isReExport = false;
49
+ let resolved = sym;
50
+ if (sym.getFlags() & ts.SymbolFlags.Alias) {
51
+ const aliased = checker.getAliasedSymbol(sym);
52
+ if (aliased && aliased !== sym) {
53
+ isReExport = true;
54
+ resolved = aliased;
55
+ }
56
+ }
57
+ if (!includeReExports && isReExport)
58
+ continue;
59
+ const decls = (resolved.getDeclarations() ?? []).map(declarationKindName);
60
+ result.items.push({
61
+ name,
62
+ kind: guessKindFromFlags(resolved),
63
+ isTypeOnly,
64
+ isReExport,
65
+ declarations: decls,
66
+ });
67
+ }
68
+ // stable-ish output
69
+ result.items.sort((a, b) => a.name.localeCompare(b.name));
70
+ return result;
71
+ };
72
+ //# sourceMappingURL=code.exports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.exports.js","sourceRoot":"","sources":["../../src/code/code.exports.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from \"typescript\";\nimport { SourceExport, SourceFile } from \"../types/types.code.js\";\nimport { resolve } from \"node:path\";\nimport {\n createSourceFiles,\n declarationKindName,\n guessKindFromFlags,\n} from \"./code.common.js\";\n\nexport const fileExports = (\n filePath: string,\n opts?: {\n includeTypeOnly?: boolean;\n includeReExports?: boolean;\n includeDefault?: boolean;\n includePrivate?: boolean;\n },\n preBuiltSource?: SourceFile,\n): SourceExport => {\n const includeTypeOnly = opts?.includeTypeOnly ?? true;\n const includeReExports = opts?.includeReExports ?? true;\n const abs = resolve(filePath);\n\n const files = preBuiltSource\n ? [preBuiltSource]\n : createSourceFiles([filePath]);\n if (files.length === 0) throw new Error(`Could not load source file: ${abs}`);\n\n const { checker, sourceFile } = files[0];\n\n const result: SourceExport = {\n items: [],\n hasDefault: false,\n };\n\n const moduleSymbol = checker.getSymbolAtLocation(sourceFile);\n if (!moduleSymbol) return result;\n\n // This gives the \"export surface\" of the module (including re-exports).\n const exports = checker.getExportsOfModule(moduleSymbol);\n\n for (const sym of exports) {\n const name = sym.getName();\n if (name === \"default\") {\n result.hasDefault = true;\n if (!opts?.includeDefault) continue;\n } else if (name.startsWith(\"_\")) {\n if (!opts?.includePrivate) continue;\n }\n\n // Determine if it's type-only (TypeScript 5.x provides isTypeOnlySymbol).\n // Fallback: approximate using flags.\n const isTypeOnly =\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n typeof (checker as any).isTypeOnlySymbol === \"function\"\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ((checker as any).isTypeOnlySymbol(sym) as boolean)\n : !!(\n sym.getFlags() &\n (ts.SymbolFlags.Type |\n ts.SymbolFlags.Interface |\n ts.SymbolFlags.TypeAlias)\n );\n\n if (!includeTypeOnly && isTypeOnly) continue;\n\n // Re-export detection: if symbol is an alias and resolves elsewhere\n let isReExport = false;\n let resolved = sym;\n if (sym.getFlags() & ts.SymbolFlags.Alias) {\n const aliased = checker.getAliasedSymbol(sym);\n if (aliased && aliased !== sym) {\n isReExport = true;\n resolved = aliased;\n }\n }\n\n if (!includeReExports && isReExport) continue;\n\n const decls = (resolved.getDeclarations() ?? []).map(declarationKindName);\n\n result.items.push({\n name,\n kind: guessKindFromFlags(resolved),\n isTypeOnly,\n isReExport,\n declarations: decls,\n });\n }\n\n // stable-ish output\n result.items.sort((a, b) => a.name.localeCompare(b.name));\n return result;\n};\n"]}
@@ -1,6 +1,4 @@
1
- import { SourceFile } from "../types/types.code.js";
2
1
  export declare const formatCode: (...lines: string[]) => Promise<string>;
3
2
  export declare const formatJson: (...lines: string[]) => Promise<string>;
4
3
  export declare const formatJsonStringify: (...lines: string[]) => Promise<string>;
5
- export declare const createSourceFiles: (filePaths: string[]) => SourceFile[];
6
- //# sourceMappingURL=format.code.d.ts.map
4
+ //# sourceMappingURL=code.format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.format.d.ts","sourceRoot":"","sources":["../../src/code/code.format.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,GAAU,GAAG,OAAO,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAChB,CAAC;AAErD,eAAO,MAAM,UAAU,GAAU,GAAG,OAAO,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CACtB,CAAC;AAE/C,eAAO,MAAM,mBAAmB,GAC9B,GAAG,OAAO,MAAM,EAAE,KACjB,OAAO,CAAC,MAAM,CAA2D,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { format } from "prettier";
2
+ export const formatCode = async (...lines) => format(lines.join("\n"), { parser: "typescript" });
3
+ export const formatJson = async (...lines) => format(lines.join("\n"), { parser: "json" });
4
+ export const formatJsonStringify = async (...lines) => format(lines.join("\n"), { parser: "json-stringify" });
5
+ //# sourceMappingURL=code.format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code.format.js","sourceRoot":"","sources":["../../src/code/code.format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAG,KAAe,EAAmB,EAAE,CACtE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAErD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAG,KAAe,EAAmB,EAAE,CACtE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,GAAG,KAAe,EACD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC","sourcesContent":["import { format } from \"prettier\";\n\nexport const formatCode = async (...lines: string[]): Promise<string> =>\n format(lines.join(\"\\n\"), { parser: \"typescript\" });\n\nexport const formatJson = async (...lines: string[]): Promise<string> =>\n format(lines.join(\"\\n\"), { parser: \"json\" });\n\nexport const formatJsonStringify = async (\n ...lines: string[]\n): Promise<string> => format(lines.join(\"\\n\"), { parser: \"json-stringify\" });\n"]}
@@ -0,0 +1,4 @@
1
+ export * from "./code.common.js";
2
+ export * from "./code.exports.js";
3
+ export * from "./code.format.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/code/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // This file is auto-generated. Do not edit manually.
2
+ export * from "./code.common.js";
3
+ export * from "./code.exports.js";
4
+ export * from "./code.format.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/code/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC","sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport * from \"./code.common.js\";\nexport * from \"./code.exports.js\";\nexport * from \"./code.format.js\";\n"]}
@@ -1,7 +1,7 @@
1
1
  import json5 from "json5";
2
2
  import { readFile, writeFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
- import { formatJsonStringify } from "../format/format.code.js";
4
+ import { formatJsonStringify } from "../code/code.format.js";
5
5
  import { readFileSync } from "node:fs";
6
6
  export const readPackageJson = async (dirOrFilepath) => json5.parse(await readFile(ensurePkgJsonPath(dirOrFilepath), "utf8"));
7
7
  export const readPackageJsonSync = (dirOrFilepath) => json5.parse(readFileSync(ensurePkgJsonPath(dirOrFilepath), "utf8"));
@@ -1 +1 @@
1
- {"version":3,"file":"pkg.fs.js","sourceRoot":"","sources":["../../src/pkg/pkg.fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,aAAqB,EACC,EAAE,CACxB,KAAK,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,aAAqB,EAAe,EAAE,CACxE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,QAAgB,EAChB,OAAoB,EACL,EAAE,CACjB,SAAS,CAAC,QAAQ,EAAE,MAAM,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,aAAqB,EAAU,EAAE,CACjE,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;IACrC,CAAC,CAAC,aAAa;IACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC","sourcesContent":["import json5 from \"json5\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { PackageJson } from \"../types/types.package.js\";\nimport { join } from \"node:path\";\nimport { formatJsonStringify } from \"../format/format.code.js\";\nimport { readFileSync } from \"node:fs\";\n\nexport const readPackageJson = async (\n dirOrFilepath: string,\n): Promise<PackageJson> =>\n json5.parse(await readFile(ensurePkgJsonPath(dirOrFilepath), \"utf8\"));\n\nexport const readPackageJsonSync = (dirOrFilepath: string): PackageJson =>\n json5.parse(readFileSync(ensurePkgJsonPath(dirOrFilepath), \"utf8\"));\n\nexport const writePackageJson = async (\n jsonPath: string,\n content: PackageJson,\n): Promise<void> =>\n writeFile(jsonPath, await formatJsonStringify(json5.stringify(content)));\n\nexport const ensurePkgJsonPath = (dirOrFilepath: string): string =>\n dirOrFilepath.endsWith(\"/package.json\")\n ? dirOrFilepath\n : join(dirOrFilepath, \"package.json\");\n"]}
1
+ {"version":3,"file":"pkg.fs.js","sourceRoot":"","sources":["../../src/pkg/pkg.fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,aAAqB,EACC,EAAE,CACxB,KAAK,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,aAAqB,EAAe,EAAE,CACxE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,iBAAiB,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,QAAgB,EAChB,OAAoB,EACL,EAAE,CACjB,SAAS,CAAC,QAAQ,EAAE,MAAM,mBAAmB,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAE3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,aAAqB,EAAU,EAAE,CACjE,aAAa,CAAC,QAAQ,CAAC,eAAe,CAAC;IACrC,CAAC,CAAC,aAAa;IACf,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC","sourcesContent":["import json5 from \"json5\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { PackageJson } from \"../types/types.package.js\";\nimport { join } from \"node:path\";\nimport { formatJsonStringify } from \"../code/code.format.js\";\nimport { readFileSync } from \"node:fs\";\n\nexport const readPackageJson = async (\n dirOrFilepath: string,\n): Promise<PackageJson> =>\n json5.parse(await readFile(ensurePkgJsonPath(dirOrFilepath), \"utf8\"));\n\nexport const readPackageJsonSync = (dirOrFilepath: string): PackageJson =>\n json5.parse(readFileSync(ensurePkgJsonPath(dirOrFilepath), \"utf8\"));\n\nexport const writePackageJson = async (\n jsonPath: string,\n content: PackageJson,\n): Promise<void> =>\n writeFile(jsonPath, await formatJsonStringify(json5.stringify(content)));\n\nexport const ensurePkgJsonPath = (dirOrFilepath: string): string =>\n dirOrFilepath.endsWith(\"/package.json\")\n ? dirOrFilepath\n : join(dirOrFilepath, \"package.json\");\n"]}
@@ -4,4 +4,15 @@ export interface SourceFile {
4
4
  checker: ts.TypeChecker;
5
5
  sourceFile: ts.SourceFile;
6
6
  }
7
+ export interface SourceExportItem {
8
+ name: string;
9
+ kind: string;
10
+ isTypeOnly: boolean;
11
+ isReExport: boolean;
12
+ declarations: string[];
13
+ }
14
+ export interface SourceExport {
15
+ items: SourceExportItem[];
16
+ hasDefault: boolean;
17
+ }
7
18
  //# sourceMappingURL=types.code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.code.d.ts","sourceRoot":"","sources":["../../src/types/types.code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;CAC3B"}
1
+ {"version":3,"file":"types.code.d.ts","sourceRoot":"","sources":["../../src/types/types.code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC;IACxB,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,UAAU,EAAE,OAAO,CAAC;CACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.code.js","sourceRoot":"","sources":["../../src/types/types.code.ts"],"names":[],"mappings":"","sourcesContent":["import ts from \"typescript\";\n\nexport interface SourceFile {\n filePath: string;\n checker: ts.TypeChecker;\n sourceFile: ts.SourceFile;\n}\n"]}
1
+ {"version":3,"file":"types.code.js","sourceRoot":"","sources":["../../src/types/types.code.ts"],"names":[],"mappings":"","sourcesContent":["import ts from \"typescript\";\n\nexport interface SourceFile {\n filePath: string;\n checker: ts.TypeChecker;\n sourceFile: ts.SourceFile;\n}\n\nexport interface SourceExportItem {\n name: string; // export name (e.g. \"foo\", \"default\")\n kind: string; // human-ish kind (e.g. \"function\", \"class\", \"type\", \"namespace\", \"unknown\")\n isTypeOnly: boolean; // true if TS considers it type-only\n isReExport: boolean; // true if it comes from another module via export-from / export *\n declarations: string[]; // declaration kinds for debugging (e.g. [\"FunctionDeclaration\"])\n}\n\nexport interface SourceExport {\n items: SourceExportItem[];\n hasDefault: boolean;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mxpicture/build-api",
3
- "version": "0.2.48",
3
+ "version": "0.2.50",
4
4
  "description": "Build utilities API",
5
5
  "type": "module",
6
6
  "author": "MXPicture",
@@ -12,9 +12,9 @@
12
12
  "exports": {
13
13
  "./barrel": "./dist/barrel/index.js",
14
14
  "./cleanup": "./dist/cleanup/index.js",
15
+ "./code": "./dist/code/index.js",
15
16
  "./common": "./dist/common/index.js",
16
17
  "./deps": "./dist/deps/index.js",
17
- "./format": "./dist/format/index.js",
18
18
  "./git": "./dist/git/index.js",
19
19
  "./logger": "./dist/logger/index.js",
20
20
  "./npmPublish": "./dist/npmPublish/index.js",
@@ -39,9 +39,6 @@
39
39
  "publishConfig": {
40
40
  "access": "public"
41
41
  },
42
- "devDependencies": {
43
- "typescript": "^5.9.3"
44
- },
45
42
  "dependencies": {
46
43
  "@mxpicture/dep-analyzer": "^0.1.0",
47
44
  "@types/micromatch": "^4.0.10",
@@ -49,6 +46,7 @@
49
46
  "micromatch": "^4.0.8",
50
47
  "prettier": "^3.8.1",
51
48
  "simple-git": "^3.32.3",
49
+ "typescript": "^5.9.3",
52
50
  "yaml": "^2.8.2"
53
51
  }
54
52
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.code.d.ts","sourceRoot":"","sources":["../../src/format/format.code.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,eAAO,MAAM,UAAU,GAAU,GAAG,OAAO,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CAChB,CAAC;AAErD,eAAO,MAAM,UAAU,GAAU,GAAG,OAAO,MAAM,EAAE,KAAG,OAAO,CAAC,MAAM,CACtB,CAAC;AAE/C,eAAO,MAAM,mBAAmB,GAC9B,GAAG,OAAO,MAAM,EAAE,KACjB,OAAO,CAAC,MAAM,CAA2D,CAAC;AAE7E,eAAO,MAAM,iBAAiB,GAAI,WAAW,MAAM,EAAE,KAAG,UAAU,EAgBjE,CAAC"}
@@ -1,22 +0,0 @@
1
- import ts from "typescript";
2
- import { format } from "prettier";
3
- export const formatCode = async (...lines) => format(lines.join("\n"), { parser: "typescript" });
4
- export const formatJson = async (...lines) => format(lines.join("\n"), { parser: "json" });
5
- export const formatJsonStringify = async (...lines) => format(lines.join("\n"), { parser: "json-stringify" });
6
- export const createSourceFiles = (filePaths) => {
7
- const program = ts.createProgram(filePaths, {
8
- target: ts.ScriptTarget.ES2023,
9
- module: ts.ModuleKind.Node20,
10
- strict: true,
11
- });
12
- const checker = program.getTypeChecker();
13
- const results = [];
14
- for (const filePath of filePaths) {
15
- const sourceFile = program.getSourceFile(filePath);
16
- if (!sourceFile)
17
- continue;
18
- results.push({ sourceFile, filePath, checker });
19
- }
20
- return results;
21
- };
22
- //# sourceMappingURL=format.code.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.code.js","sourceRoot":"","sources":["../../src/format/format.code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAG,KAAe,EAAmB,EAAE,CACtE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAErD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,GAAG,KAAe,EAAmB,EAAE,CACtE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,EACtC,GAAG,KAAe,EACD,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAE7E,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAmB,EAAgB,EAAE;IACrE,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE;QAC1C,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM;QAC9B,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM;QAC5B,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IACzC,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC","sourcesContent":["import ts from \"typescript\";\nimport { format } from \"prettier\";\nimport { SourceFile } from \"../types/types.code.js\";\n\nexport const formatCode = async (...lines: string[]): Promise<string> =>\n format(lines.join(\"\\n\"), { parser: \"typescript\" });\n\nexport const formatJson = async (...lines: string[]): Promise<string> =>\n format(lines.join(\"\\n\"), { parser: \"json\" });\n\nexport const formatJsonStringify = async (\n ...lines: string[]\n): Promise<string> => format(lines.join(\"\\n\"), { parser: \"json-stringify\" });\n\nexport const createSourceFiles = (filePaths: string[]): SourceFile[] => {\n const program = ts.createProgram(filePaths, {\n target: ts.ScriptTarget.ES2023,\n module: ts.ModuleKind.Node20,\n strict: true,\n });\n const checker = program.getTypeChecker();\n const results: SourceFile[] = [];\n\n for (const filePath of filePaths) {\n const sourceFile = program.getSourceFile(filePath);\n if (!sourceFile) continue;\n results.push({ sourceFile, filePath, checker });\n }\n\n return results;\n};\n"]}
@@ -1,2 +0,0 @@
1
- export * from "./format.code.js";
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/format/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC"}
@@ -1,3 +0,0 @@
1
- // This file is auto-generated. Do not edit manually.
2
- export * from "./format.code.js";
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/format/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,cAAc,kBAAkB,CAAC","sourcesContent":["// This file is auto-generated. Do not edit manually.\nexport * from \"./format.code.js\";\n"]}