@kubb/fabric-core 0.5.5 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -13
- package/dist/{Fabric-DlBN6CDR.d.cts → Fabric-BXYWK9V4.d.cts} +93 -49
- package/dist/{Fabric-CtqeUUFU.d.ts → Fabric-CDFwTDyP.d.ts} +93 -49
- package/dist/index.cjs +11 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -19
- package/dist/index.js.map +1 -1
- package/dist/parsers/typescript.d.cts +2 -2
- package/dist/parsers/typescript.d.ts +2 -2
- package/dist/parsers.d.cts +2 -2
- package/dist/parsers.d.ts +2 -2
- package/dist/plugins.cjs +16 -16
- package/dist/plugins.cjs.map +1 -1
- package/dist/plugins.d.cts +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +16 -16
- package/dist/plugins.js.map +1 -1
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/{typescriptParser-BAlwCe3a.d.ts → typescriptParser-CPUUUA9z.d.ts} +2 -2
- package/dist/{typescriptParser-CnzxSeDN.d.cts → typescriptParser-H0FvAP4t.d.cts} +2 -2
- package/package.json +1 -1
- package/src/Fabric.ts +92 -24
- package/src/FileManager.ts +6 -6
- package/src/FileProcessor.ts +5 -5
- package/src/plugins/barrelPlugin.ts +2 -2
- package/src/plugins/fsPlugin.ts +1 -1
- package/src/plugins/graphPlugin.ts +1 -1
- package/src/plugins/loggerPlugin.ts +13 -13
package/dist/plugins.js
CHANGED
|
@@ -207,7 +207,7 @@ const barrelPlugin = definePlugin({
|
|
|
207
207
|
install(ctx, options) {
|
|
208
208
|
if (!options) throw new Error("Barrel plugin requires options.root and options.mode");
|
|
209
209
|
if (!options.mode) return;
|
|
210
|
-
ctx.on("files:writing:start", async (
|
|
210
|
+
ctx.on("files:writing:start", async (files) => {
|
|
211
211
|
const root = options.root;
|
|
212
212
|
const barrelFiles = getBarrelFiles({
|
|
213
213
|
files,
|
|
@@ -288,7 +288,7 @@ const fsPlugin = definePlugin({
|
|
|
288
288
|
name: "fs",
|
|
289
289
|
install(ctx, options = {}) {
|
|
290
290
|
if (options.clean) fs.removeSync(options.clean.path);
|
|
291
|
-
ctx.on("
|
|
291
|
+
ctx.on("file:processing:update", async ({ file, source }) => {
|
|
292
292
|
if (options.onBeforeWrite) await options.onBeforeWrite(file.path, source);
|
|
293
293
|
await write(file.path, source, { sanity: false });
|
|
294
294
|
});
|
|
@@ -396,7 +396,7 @@ const graphPlugin = definePlugin({
|
|
|
396
396
|
name: "graph",
|
|
397
397
|
install(ctx, options) {
|
|
398
398
|
if (!options) throw new Error("Graph plugin requires options.root and options.mode");
|
|
399
|
-
ctx.on("files:writing:start", async (
|
|
399
|
+
ctx.on("files:writing:start", async (files) => {
|
|
400
400
|
const root = options.root;
|
|
401
401
|
const graph = getGraph({
|
|
402
402
|
files,
|
|
@@ -504,20 +504,20 @@ const loggerPlugin = definePlugin({
|
|
|
504
504
|
logger.info("Rendering application graph");
|
|
505
505
|
broadcast("lifecycle:render", { timestamp: Date.now() });
|
|
506
506
|
});
|
|
507
|
-
ctx.on("files:added", async (
|
|
507
|
+
ctx.on("files:added", async (files) => {
|
|
508
508
|
if (!files.length) return;
|
|
509
509
|
logger.info(`Queued ${pluralize("file", files.length)}`);
|
|
510
510
|
broadcast("files:added", { files: files.map(serializeFile) });
|
|
511
511
|
});
|
|
512
|
-
ctx.on("file:path
|
|
512
|
+
ctx.on("file:resolve:path", async (file) => {
|
|
513
513
|
logger.info(`Resolving path for ${formatPath(file.path)}`);
|
|
514
|
-
broadcast("file:path
|
|
514
|
+
broadcast("file:resolve:path", { file: serializeFile(file) });
|
|
515
515
|
});
|
|
516
|
-
ctx.on("file:name
|
|
516
|
+
ctx.on("file:resolve:name", async (file) => {
|
|
517
517
|
logger.info(`Resolving name for ${formatPath(file.path)}`);
|
|
518
|
-
broadcast("file:name
|
|
518
|
+
broadcast("file:resolve:name", { file: serializeFile(file) });
|
|
519
519
|
});
|
|
520
|
-
ctx.on("files:processing:start", async (
|
|
520
|
+
ctx.on("files:processing:start", async (files) => {
|
|
521
521
|
logger.start(`Processing ${pluralize("file", files.length)}`);
|
|
522
522
|
broadcast("files:processing:start", {
|
|
523
523
|
total: files.length,
|
|
@@ -528,7 +528,7 @@ const loggerPlugin = definePlugin({
|
|
|
528
528
|
progressBar.start(files.length, 0, { message: "Starting..." });
|
|
529
529
|
}
|
|
530
530
|
});
|
|
531
|
-
ctx.on("file:processing:start", async (
|
|
531
|
+
ctx.on("file:processing:start", async (file, index, total) => {
|
|
532
532
|
logger.info(`Processing [${index + 1}/${total}] ${formatPath(file.path)}`);
|
|
533
533
|
broadcast("file:processing:start", {
|
|
534
534
|
index,
|
|
@@ -536,10 +536,10 @@ const loggerPlugin = definePlugin({
|
|
|
536
536
|
file: serializeFile(file)
|
|
537
537
|
});
|
|
538
538
|
});
|
|
539
|
-
ctx.on("
|
|
539
|
+
ctx.on("file:processing:update", async ({ processed, total, percentage, file }) => {
|
|
540
540
|
const formattedPercentage = Number.isFinite(percentage) ? percentage.toFixed(1) : "0.0";
|
|
541
541
|
logger.info(`Progress ${formattedPercentage}% (${processed}/${total}) → ${formatPath(file.path)}`);
|
|
542
|
-
broadcast("
|
|
542
|
+
broadcast("file:processing:update", {
|
|
543
543
|
processed,
|
|
544
544
|
total,
|
|
545
545
|
percentage,
|
|
@@ -547,7 +547,7 @@ const loggerPlugin = definePlugin({
|
|
|
547
547
|
});
|
|
548
548
|
if (progressBar) progressBar.increment(1, { message: `Writing ${formatPath(file.path)}` });
|
|
549
549
|
});
|
|
550
|
-
ctx.on("file:processing:end", async (
|
|
550
|
+
ctx.on("file:processing:end", async (file, index, total) => {
|
|
551
551
|
logger.success(`Finished [${index + 1}/${total}] ${formatPath(file.path)}`);
|
|
552
552
|
broadcast("file:processing:end", {
|
|
553
553
|
index,
|
|
@@ -555,15 +555,15 @@ const loggerPlugin = definePlugin({
|
|
|
555
555
|
file: serializeFile(file)
|
|
556
556
|
});
|
|
557
557
|
});
|
|
558
|
-
ctx.on("files:writing:start", async (
|
|
558
|
+
ctx.on("files:writing:start", async (files) => {
|
|
559
559
|
logger.start(`Writing ${pluralize("file", files.length)} to disk`);
|
|
560
560
|
broadcast("files:writing:start", { files: files.map(serializeFile) });
|
|
561
561
|
});
|
|
562
|
-
ctx.on("files:writing:end", async (
|
|
562
|
+
ctx.on("files:writing:end", async (files) => {
|
|
563
563
|
logger.success(`Written ${pluralize("file", files.length)} to disk`);
|
|
564
564
|
broadcast("files:writing:end", { files: files.map(serializeFile) });
|
|
565
565
|
});
|
|
566
|
-
ctx.on("files:processing:end", async (
|
|
566
|
+
ctx.on("files:processing:end", async (files) => {
|
|
567
567
|
logger.success(`Processed ${pluralize("file", files.length)}`);
|
|
568
568
|
broadcast("files:processing:end", {
|
|
569
569
|
total: files.length,
|
package/dist/plugins.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugins.js","names":["result: Array<TreeNode<TData>>","stack: Array<TreeNode<TData>>","nodes: Array<{ id: string; label: string }>","edges: Array<{ from: string; to: string }>","stack: Array<TreeNode<BarrelData>>","filteredFiles: Array<KubbFile.File>","indexableSources: Array<KubbFile.Source>","barrelFiles: Array<KubbFile.ResolvedFile>","exports: Array<KubbFile.Export>","path","path","server: http.Server | undefined","wss: WebSocketServer | undefined","broadcast: Broadcast","path","closures: Array<Promise<void>>","resolve"],"sources":["../src/utils/TreeNode.ts","../src/plugins/definePlugin.ts","../src/plugins/barrelPlugin.ts","../src/plugins/fsPlugin.ts","../src/utils/open.ts","../src/plugins/graphPlugin.ts","../src/plugins/loggerPlugin.ts"],"sourcesContent":["import type * as KubbFile from '../KubbFile.ts'\n\ntype BarrelData = {\n file?: KubbFile.File\n path: string\n name: string\n}\n\nexport type Graph = {\n nodes: Array<{ id: string; label: string }>\n edges: Array<{ from: string; to: string }>\n}\n\nexport class TreeNode<TData = unknown> {\n data: TData\n parent?: TreeNode<TData>\n children: Array<TreeNode<TData>> = []\n #childrenMap = new Map<string, TreeNode<TData>>()\n #cachedLeaves?: Array<TreeNode<TData>>\n\n constructor(data: TData, parent?: TreeNode<TData>) {\n this.data = data\n this.parent = parent\n }\n\n addChild(data: TData): TreeNode<TData> {\n const child = new TreeNode(data, this)\n this.children.push(child)\n // Update Map if data has a name property (for BarrelData)\n if (typeof data === 'object' && data !== null && 'name' in data) {\n this.#childrenMap.set((data as { name: string }).name, child)\n }\n this.#cachedLeaves = undefined // invalidate cached leaves\n return child\n }\n\n getChildByName(name: string): TreeNode<TData> | undefined {\n return this.#childrenMap.get(name)\n }\n\n get leaves(): Array<TreeNode<TData>> {\n if (this.#cachedLeaves) return this.#cachedLeaves\n if (this.children.length === 0) return [this]\n\n const result: Array<TreeNode<TData>> = []\n const stack: Array<TreeNode<TData>> = [...this.children]\n const visited = new Set<TreeNode<TData>>()\n\n while (stack.length > 0) {\n const node = stack.pop()!\n if (visited.has(node)) {\n continue\n }\n visited.add(node)\n\n if (node.children.length > 0) {\n stack.push(...node.children)\n } else {\n result.push(node)\n }\n }\n\n this.#cachedLeaves = result\n return result\n }\n\n forEach(callback: (node: TreeNode<TData>) => void): this {\n const stack: Array<TreeNode<TData>> = [this]\n\n for (let i = 0; i < stack.length; i++) {\n const node = stack[i]!\n callback(node)\n\n if (node.children.length > 0) {\n stack.push(...node.children)\n }\n }\n\n return this\n }\n\n findDeep(predicate: (node: TreeNode<TData>) => boolean): TreeNode<TData> | undefined {\n for (const leaf of this.leaves) {\n if (predicate(leaf)) return leaf\n }\n return undefined\n }\n\n static toGraph(root: TreeNode<BarrelData>): Graph {\n const nodes: Array<{ id: string; label: string }> = []\n const edges: Array<{ from: string; to: string }> = []\n\n const stack: Array<TreeNode<BarrelData>> = [root]\n\n for (let i = 0; i < stack.length; i++) {\n const node = stack[i]!\n\n nodes.push({\n id: node.data.path,\n label: node.data.name,\n })\n\n const children = node.children\n if (children.length > 0) {\n for (let j = 0, len = children.length; j < len; j++) {\n const child = children[j]!\n edges.push({\n from: node.data.path,\n to: child.data.path,\n })\n stack.push(child)\n }\n }\n }\n\n return { nodes, edges }\n }\n\n static fromFiles(files: Array<KubbFile.File>, rootFolder = ''): TreeNode<BarrelData> | null {\n const normalizePath = (p: string): string => p.replace(/\\\\/g, '/')\n const normalizedRoot = normalizePath(rootFolder)\n const rootPrefix = normalizedRoot.endsWith('/') ? normalizedRoot : `${normalizedRoot}/`\n\n const normalizedPaths = new Map<KubbFile.File, string>()\n const filteredFiles: Array<KubbFile.File> = []\n for (const file of files) {\n const filePath = normalizedPaths.get(file) ?? normalizePath(file.path)\n normalizedPaths.set(file, filePath)\n if (!filePath.endsWith('.json') && (!rootFolder || filePath.startsWith(rootPrefix))) {\n filteredFiles.push(file)\n }\n }\n\n if (filteredFiles.length === 0) {\n return null\n }\n\n const treeNode = new TreeNode<BarrelData>({\n name: rootFolder || '',\n path: rootFolder || '',\n file: undefined,\n })\n\n for (const file of filteredFiles) {\n const filePath = normalizedPaths.get(file)!\n const relPath = filePath.slice(rootPrefix.length)\n const parts = relPath.split('/')\n\n let current = treeNode\n let currentPath = rootFolder\n\n for (const [index, part] of parts.entries()) {\n const isLast = index === parts.length - 1\n currentPath += (currentPath.endsWith('/') ? '' : '/') + part\n\n let next = current.getChildByName(part)\n\n if (!next) {\n next = current.addChild({\n name: part,\n path: currentPath,\n file: isLast ? file : undefined,\n })\n }\n\n current = next\n }\n }\n\n return treeNode\n }\n}\n","import type { Plugin, UserPlugin } from './types.ts'\n\nexport function definePlugin<Options = unknown, TAppExtension extends Record<string, any> = {}>(\n plugin: UserPlugin<Options, TAppExtension>,\n): Plugin<Options, TAppExtension> {\n return {\n type: 'plugin',\n ...plugin,\n }\n}\n","/** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */\n\nimport path from 'node:path'\nimport { createFile } from '../createFile.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { getRelativePath } from '../utils/getRelativePath.ts'\nimport { TreeNode } from '../utils/TreeNode.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Mode = 'all' | 'named' | 'propagate' | false\n\ntype Options = {\n root: string\n mode: Mode\n dryRun?: boolean\n}\n\ntype WriteEntryOptions = {\n root: string\n mode: Mode\n}\n\ntype ExtendOptions = {\n /**\n * `fabric.writeEntry` should be called before `fabric.write`\n */\n writeEntry(options: WriteEntryOptions): Promise<void>\n}\n\ndeclare global {\n namespace Kubb {\n interface Fabric {\n /**\n * `fabric.writeEntry` should be called before `fabric.write`\n */\n writeEntry(options: WriteEntryOptions): Promise<void>\n }\n }\n}\n\ntype GetBarrelFilesOptions = {\n files: KubbFile.File[]\n root: string\n mode: Mode\n}\n\nexport function getBarrelFiles({ files, root, mode }: GetBarrelFilesOptions): Array<KubbFile.File> {\n // Do not generate when propagating or disabled\n if (mode === 'propagate' || mode === false) {\n return []\n }\n\n const indexableSourcesMap = new Map<KubbFile.File, Array<KubbFile.Source>>()\n\n for (const file of files) {\n const indexableSources: Array<KubbFile.Source> = []\n for (const source of file.sources || []) {\n if (source.isIndexable && source.name) {\n indexableSources.push(source)\n }\n }\n if (indexableSources.length > 0) {\n indexableSourcesMap.set(file, indexableSources)\n }\n }\n\n const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()\n const dedupe = new Map<KubbFile.Path, Set<string>>()\n\n const treeNode = TreeNode.fromFiles(files, root)\n\n if (!treeNode) {\n return []\n }\n\n treeNode.forEach((node) => {\n // Only create a barrel for directory-like nodes that have a parent with a path\n if (!node?.children || !node.parent?.data.path) {\n return\n }\n\n const parentPath = node.parent.data.path as KubbFile.Path\n const barrelPath = path.join(parentPath, 'index.ts') as KubbFile.Path\n\n let barrelFile = cachedFiles.get(barrelPath)\n if (!barrelFile) {\n barrelFile = createFile({\n path: barrelPath,\n baseName: 'index.ts',\n exports: [],\n sources: [],\n })\n cachedFiles.set(barrelPath, barrelFile)\n dedupe.set(barrelPath, new Set<string>())\n }\n\n const seen = dedupe.get(barrelPath)!\n\n for (const leaf of node.leaves) {\n const file = leaf.data.file\n if (!file || !file.path) {\n continue\n }\n\n const indexableSources = indexableSourcesMap.get(file)\n if (!indexableSources) {\n continue\n }\n\n for (const source of indexableSources) {\n const key = `${source.name}|${source.isTypeOnly ? '1' : '0'}`\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n\n // Always compute relative path from the parent directory to the file path\n barrelFile!.exports!.push({\n name: [source.name!],\n path: getRelativePath(parentPath, file.path),\n isTypeOnly: source.isTypeOnly,\n })\n\n barrelFile!.sources.push({\n name: source.name!,\n isTypeOnly: source.isTypeOnly,\n value: '', // TODO use parser to generate import\n isExportable: mode === 'all' || mode === 'named',\n isIndexable: mode === 'all' || mode === 'named',\n })\n }\n }\n })\n\n const result = [...cachedFiles.values()]\n\n if (mode === 'all') {\n return result.map((file) => ({\n ...file,\n exports: file.exports?.map((e) => ({ ...e, name: undefined })),\n }))\n }\n\n return result\n}\n\nexport const barrelPlugin = definePlugin<Options, ExtendOptions>({\n name: 'barrel',\n install(ctx, options) {\n if (!options) {\n throw new Error('Barrel plugin requires options.root and options.mode')\n }\n\n if (!options.mode) {\n return undefined\n }\n\n ctx.on('files:writing:start', async ({ files }) => {\n const root = options.root\n const barrelFiles = getBarrelFiles({ files, root, mode: options.mode })\n\n await ctx.fileManager.add(...barrelFiles)\n })\n },\n inject(ctx, options) {\n if (!options) {\n throw new Error('Barrel plugin requires options.root and options.mode')\n }\n\n return {\n async writeEntry({ root, mode }) {\n if (!mode || mode === 'propagate') {\n return undefined\n }\n\n const rootPath = path.resolve(root, 'index.ts')\n\n const barrelFiles: Array<KubbFile.ResolvedFile> = []\n for (const file of ctx.files) {\n for (const source of file.sources) {\n if (source.isIndexable) {\n barrelFiles.push(file)\n\n break\n }\n }\n }\n\n const fileTypeCache = new Map<KubbFile.ResolvedFile, boolean>()\n for (const file of barrelFiles) {\n fileTypeCache.set(\n file,\n file.sources.every((source) => source.isTypeOnly),\n )\n }\n\n const exports: Array<KubbFile.Export> = []\n for (const file of barrelFiles) {\n const containsOnlyTypes = fileTypeCache.get(file) ?? false\n\n for (const source of file.sources) {\n if (!file.path || !source.isIndexable) {\n continue\n }\n\n exports.push({\n name: mode === 'all' ? undefined : [source.name],\n path: getRelativePath(rootPath, file.path),\n isTypeOnly: mode === 'all' ? containsOnlyTypes : source.isTypeOnly,\n } as KubbFile.Export)\n }\n }\n\n const entryFile = createFile({\n path: rootPath,\n baseName: 'index.ts',\n exports,\n sources: [],\n })\n\n await ctx.addFile(entryFile)\n\n await ctx.fileManager.write({\n mode: ctx.config.mode,\n dryRun: options.dryRun,\n parsers: ctx.installedParsers,\n })\n },\n }\n },\n})\n","import { resolve } from 'node:path'\nimport fs from 'fs-extra'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype WriteOptions = {\n extension?: Record<KubbFile.Extname, KubbFile.Extname | ''>\n}\n\ntype Options = {\n dryRun?: boolean\n /**\n * Optional callback that is invoked whenever a file is written by the plugin.\n * Useful for tests to observe write operations without spying on internal functions.\n */\n onBeforeWrite?: (path: string, data: string | undefined) => void | Promise<void>\n clean?: {\n path: string\n }\n}\n\ntype ExtendOptions = {\n write(options?: WriteOptions): Promise<void>\n}\n\nexport async function write(path: string, data: string | undefined, options: { sanity?: boolean } = {}): Promise<string | undefined> {\n if (typeof Bun !== 'undefined') {\n if (!data || data?.trim() === '') {\n return undefined\n }\n\n await Bun.write(resolve(path), data.trim())\n\n if (options?.sanity) {\n const file = Bun.file(resolve(path))\n const savedData = await file.text()\n\n if (savedData?.toString() !== data?.toString()) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n\n return savedData\n }\n\n return data\n }\n\n if (!data || data?.trim() === '') {\n return undefined\n }\n\n try {\n const oldContent = await fs.readFile(resolve(path), {\n encoding: 'utf-8',\n })\n if (oldContent?.toString() === data?.toString()) {\n return\n }\n } catch (_err) {\n /* empty */\n }\n\n await fs.outputFile(resolve(path), data.trim(), { encoding: 'utf-8' })\n\n if (options?.sanity) {\n const savedData = await fs.readFile(resolve(path), {\n encoding: 'utf-8',\n })\n\n if (savedData?.toString() !== data?.toString()) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n\n return savedData\n }\n\n return data\n}\n\ndeclare global {\n namespace Kubb {\n interface Fabric {\n write(options?: WriteOptions): Promise<void>\n }\n }\n}\n\nexport const fsPlugin = definePlugin<Options, ExtendOptions>({\n name: 'fs',\n install(ctx, options = {}) {\n if (options.clean) {\n fs.removeSync(options.clean.path)\n }\n\n ctx.on('files:processing:update', async ({ file, source }) => {\n if (options.onBeforeWrite) {\n await options.onBeforeWrite(file.path, source)\n }\n await write(file.path, source, { sanity: false })\n })\n },\n inject(ctx, { dryRun } = {}) {\n return {\n async write(\n options = {\n extension: { '.ts': '.ts' },\n },\n ) {\n await ctx.fileManager.write({\n mode: ctx.config.mode,\n extension: options.extension,\n dryRun,\n parsers: ctx.installedParsers,\n })\n },\n }\n },\n})\n","import { spawn } from 'node:child_process'\n\nconst spawnBin = (bin: string, args: string[]): Promise<boolean> => {\n return new Promise((resolve) => {\n const process = spawn(bin, args, {\n detached: true,\n shell: false,\n windowsHide: true,\n })\n\n process.on('close', (code) => {\n resolve(!code)\n })\n })\n}\n\ntype Options = {\n app?: string\n}\n\nexport async function open(path: string, options?: Options): Promise<boolean> {\n const app = options?.app\n\n if (process.platform === 'win32') {\n return spawnBin('cmd.exe', ['/c', 'start', app || '', path.replace(/[&^]/g, '^$&')])\n }\n\n if (process.platform === 'linux') {\n return spawnBin(app || 'xdg-open', [path])\n }\n if (process.platform === 'darwin') {\n return spawnBin('open', app ? ['-a', app, path] : [path])\n }\n\n throw new Error(`Unsupported platform, could not open \"${path}\"`)\n}\n","import http from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport path from 'node:path'\nimport handler from 'serve-handler'\nimport { createFile } from '../createFile.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { open } from '../utils/open.ts'\nimport { type Graph, TreeNode } from '../utils/TreeNode.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Options = {\n root: string\n /**\n * @default false\n */\n open?: boolean\n}\n\ntype GetGraphOptions = {\n files: KubbFile.File[]\n root: string\n}\n\nexport function getGraph({ files, root }: GetGraphOptions): Graph | undefined {\n const treeNode = TreeNode.fromFiles(files, root)\n\n if (!treeNode) {\n return undefined\n }\n\n return TreeNode.toGraph(treeNode)\n}\nconst html = `\n <!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>File Graph</title>\n <script type=\"module\">\n import { Network } from 'https://cdn.jsdelivr.net/npm/vis-network/standalone/esm/vis-network.min.js'\n\n async function main() {\n const res = await fetch('./graph.json')\n const { nodes, edges } = await res.json()\n const container = document.getElementById('graph')\n\n const network = new Network(\n container,\n { nodes, edges },\n {\n layout: { hierarchical: { direction: 'UD', sortMethod: 'directed' } },\n nodes: { shape: 'box', font: { face: 'monospace' } },\n edges: { arrows: 'to' },\n physics: false,\n },\n )\n }\n\n main()\n </script>\n <style>\n html, body, #graph { height: 100%; margin: 0; }\n </style>\n </head>\n <body>\n <div id=\"graph\"></div>\n </body>\n</html>\n`\n\nasync function serve(root: string) {\n const server = http.createServer((req, res) => {\n return handler(req, res, {\n public: root,\n cleanUrls: true,\n })\n })\n\n server.listen(0, async () => {\n const { port } = server.address() as AddressInfo\n console.log(`Running on http://localhost:${port}/graph.html`)\n\n await open(`http://localhost:${port}/graph.html`)\n })\n}\n\nexport const graphPlugin = definePlugin<Options>({\n name: 'graph',\n install(ctx, options) {\n if (!options) {\n throw new Error('Graph plugin requires options.root and options.mode')\n }\n\n ctx.on('files:writing:start', async ({ files }) => {\n const root = options.root\n\n const graph = getGraph({ files, root })\n\n if (!graph) {\n return undefined\n }\n\n const graphFile = createFile({\n baseName: 'graph.json',\n path: path.join(root, 'graph.json'),\n sources: [\n {\n name: 'graph',\n value: JSON.stringify(graph, null, 2),\n },\n ],\n })\n\n const graphHtmlFile = createFile({\n baseName: 'graph.html',\n path: path.join(root, 'graph.html'),\n sources: [\n {\n name: 'graph',\n value: html,\n },\n ],\n })\n\n await ctx.addFile(graphFile, graphHtmlFile)\n\n if (options.open) {\n await serve(root)\n }\n })\n },\n})\n","import http from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport { relative } from 'node:path'\nimport { Presets, SingleBar } from 'cli-progress'\nimport { createConsola, type LogLevel } from 'consola'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport type { FabricEvents } from '../Fabric.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Broadcast = <T = unknown>(event: keyof FabricEvents | string, payload: T) => void\ntype WebSocketOptions = {\n /**\n * Hostname to bind the websocket server to.\n * @default '127.0.0.1'\n */\n host?: string\n /**\n * Port to bind the websocket server to.\n * @default 0 (random available port)\n */\n port?: number\n}\n\ntype Options = {\n /**\n * Explicit consola log level.\n */\n level?: LogLevel\n /**\n * Toggle progress bar output.\n * @default true\n */\n progress?: boolean\n /**\n * Toggle or configure the websocket broadcast server.\n * When `true`, a websocket server is started on an ephemeral port.\n * When `false`, websocket support is disabled.\n * When providing an object, the server uses the supplied host and port.\n * @default true\n */\n websocket?: boolean | WebSocketOptions\n}\n\nfunction normalizeAddress(address: AddressInfo): {\n host: string\n port: number\n} {\n const host = address.address === '::' ? '127.0.0.1' : address.address\n\n return { host, port: address.port }\n}\n\nfunction serializeFile(file: KubbFile.File | KubbFile.ResolvedFile) {\n return {\n path: file.path,\n baseName: file.baseName,\n name: 'name' in file ? file.name : undefined,\n extname: 'extname' in file ? file.extname : undefined,\n }\n}\n\nfunction pluralize(word: string, count: number) {\n return `${count} ${word}${count === 1 ? '' : 's'}`\n}\n\nconst defaultTag = 'Fabric'\n\nconst createProgressBar = () =>\n new SingleBar(\n {\n format: '{bar} {percentage}% | {value}/{total} | {message}',\n barCompleteChar: '█',\n barIncompleteChar: '░',\n hideCursor: true,\n clearOnComplete: true,\n },\n Presets.shades_grey,\n )\n\nexport const loggerPlugin = definePlugin<Options>({\n name: 'logger',\n install(ctx, options = {}) {\n const { level, websocket = true, progress = true } = options\n\n const logger = createConsola(level !== undefined ? { level } : {}).withTag(defaultTag)\n\n const progressBar = progress ? createProgressBar() : undefined\n\n let server: http.Server | undefined\n let wss: WebSocketServer | undefined\n\n const broadcast: Broadcast = (event, payload) => {\n if (!wss) {\n return\n }\n\n const message = JSON.stringify({ event, payload })\n\n for (const client of wss.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(message)\n }\n }\n }\n\n if (websocket) {\n const { host = '127.0.0.1', port = 0 } = typeof websocket === 'boolean' ? {} : websocket\n\n server = http.createServer()\n wss = new WebSocketServer({ server })\n\n server.listen(port, host, () => {\n const addressInfo = server?.address()\n\n if (addressInfo && typeof addressInfo === 'object') {\n const { host: resolvedHost, port: resolvedPort } = normalizeAddress(addressInfo)\n const url = `ws://${resolvedHost}:${resolvedPort}`\n\n logger.info(`Logger websocket listening on ${url}`)\n broadcast('websocket:ready', { url })\n }\n })\n\n wss.on('connection', (socket) => {\n logger.info('Logger websocket client connected')\n socket.send(\n JSON.stringify({\n event: 'welcome',\n payload: {\n message: 'Connected to Fabric log stream',\n timestamp: Date.now(),\n },\n }),\n )\n })\n\n wss.on('error', (error) => {\n logger.error('Logger websocket error', error)\n })\n }\n\n const formatPath = (path: string) => relative(process.cwd(), path)\n\n ctx.on('lifecycle:start', async () => {\n logger.start('Starting Fabric run')\n broadcast('lifecycle:start', { timestamp: Date.now() })\n })\n\n ctx.on('lifecycle:render', async () => {\n logger.info('Rendering application graph')\n broadcast('lifecycle:render', { timestamp: Date.now() })\n })\n\n ctx.on('files:added', async ({ files }) => {\n if (!files.length) {\n return\n }\n\n logger.info(`Queued ${pluralize('file', files.length)}`)\n broadcast('files:added', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('file:path:resolving', async ({ file }) => {\n logger.info(`Resolving path for ${formatPath(file.path)}`)\n broadcast('file:path:resolving', { file: serializeFile(file) })\n })\n\n ctx.on('file:name:resolving', async ({ file }) => {\n logger.info(`Resolving name for ${formatPath(file.path)}`)\n broadcast('file:name:resolving', { file: serializeFile(file) })\n })\n\n ctx.on('files:processing:start', async ({ files }) => {\n logger.start(`Processing ${pluralize('file', files.length)}`)\n broadcast('files:processing:start', {\n total: files.length,\n timestamp: Date.now(),\n })\n\n if (progressBar) {\n logger.pauseLogs()\n progressBar.start(files.length, 0, { message: 'Starting...' })\n }\n })\n\n ctx.on('file:processing:start', async ({ file, index, total }) => {\n logger.info(`Processing [${index + 1}/${total}] ${formatPath(file.path)}`)\n broadcast('file:processing:start', {\n index,\n total,\n file: serializeFile(file),\n })\n })\n\n ctx.on('files:processing:update', async ({ processed, total, percentage, file }) => {\n const formattedPercentage = Number.isFinite(percentage) ? percentage.toFixed(1) : '0.0'\n\n logger.info(`Progress ${formattedPercentage}% (${processed}/${total}) → ${formatPath(file.path)}`)\n broadcast('files:processing:update', {\n processed,\n total,\n percentage,\n file: serializeFile(file),\n })\n\n if (progressBar) {\n progressBar.increment(1, {\n message: `Writing ${formatPath(file.path)}`,\n })\n }\n })\n\n ctx.on('file:processing:end', async ({ file, index, total }) => {\n logger.success(`Finished [${index + 1}/${total}] ${formatPath(file.path)}`)\n broadcast('file:processing:end', {\n index,\n total,\n file: serializeFile(file),\n })\n })\n\n ctx.on('files:writing:start', async ({ files }) => {\n logger.start(`Writing ${pluralize('file', files.length)} to disk`)\n broadcast('files:writing:start', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('files:writing:end', async ({ files }) => {\n logger.success(`Written ${pluralize('file', files.length)} to disk`)\n broadcast('files:writing:end', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('files:processing:end', async ({ files }) => {\n logger.success(`Processed ${pluralize('file', files.length)}`)\n broadcast('files:processing:end', {\n total: files.length,\n timestamp: Date.now(),\n })\n\n if (progressBar) {\n progressBar.update(files.length, { message: 'Done ✅' })\n progressBar.stop()\n\n logger.resumeLogs()\n }\n })\n\n ctx.on('lifecycle:end', async () => {\n logger.success('Fabric run completed')\n broadcast('lifecycle:end', { timestamp: Date.now() })\n\n if (progressBar) {\n progressBar.stop()\n logger.resumeLogs()\n }\n\n const closures: Array<Promise<void>> = []\n\n if (wss) {\n const wsServer = wss\n\n closures.push(\n new Promise((resolve) => {\n for (const client of wsServer.clients) {\n client.close()\n }\n wsServer.close(() => resolve())\n }),\n )\n }\n\n if (server) {\n const httpServer = server\n\n closures.push(\n new Promise((resolve) => {\n httpServer.close(() => resolve())\n }),\n )\n }\n\n if (closures.length) {\n await Promise.allSettled(closures)\n logger.info('Logger websocket closed')\n }\n })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"plugins.js","names":["result: Array<TreeNode<TData>>","stack: Array<TreeNode<TData>>","nodes: Array<{ id: string; label: string }>","edges: Array<{ from: string; to: string }>","stack: Array<TreeNode<BarrelData>>","filteredFiles: Array<KubbFile.File>","indexableSources: Array<KubbFile.Source>","barrelFiles: Array<KubbFile.ResolvedFile>","exports: Array<KubbFile.Export>","path","path","server: http.Server | undefined","wss: WebSocketServer | undefined","broadcast: Broadcast","path","closures: Array<Promise<void>>","resolve"],"sources":["../src/utils/TreeNode.ts","../src/plugins/definePlugin.ts","../src/plugins/barrelPlugin.ts","../src/plugins/fsPlugin.ts","../src/utils/open.ts","../src/plugins/graphPlugin.ts","../src/plugins/loggerPlugin.ts"],"sourcesContent":["import type * as KubbFile from '../KubbFile.ts'\n\ntype BarrelData = {\n file?: KubbFile.File\n path: string\n name: string\n}\n\nexport type Graph = {\n nodes: Array<{ id: string; label: string }>\n edges: Array<{ from: string; to: string }>\n}\n\nexport class TreeNode<TData = unknown> {\n data: TData\n parent?: TreeNode<TData>\n children: Array<TreeNode<TData>> = []\n #childrenMap = new Map<string, TreeNode<TData>>()\n #cachedLeaves?: Array<TreeNode<TData>>\n\n constructor(data: TData, parent?: TreeNode<TData>) {\n this.data = data\n this.parent = parent\n }\n\n addChild(data: TData): TreeNode<TData> {\n const child = new TreeNode(data, this)\n this.children.push(child)\n // Update Map if data has a name property (for BarrelData)\n if (typeof data === 'object' && data !== null && 'name' in data) {\n this.#childrenMap.set((data as { name: string }).name, child)\n }\n this.#cachedLeaves = undefined // invalidate cached leaves\n return child\n }\n\n getChildByName(name: string): TreeNode<TData> | undefined {\n return this.#childrenMap.get(name)\n }\n\n get leaves(): Array<TreeNode<TData>> {\n if (this.#cachedLeaves) return this.#cachedLeaves\n if (this.children.length === 0) return [this]\n\n const result: Array<TreeNode<TData>> = []\n const stack: Array<TreeNode<TData>> = [...this.children]\n const visited = new Set<TreeNode<TData>>()\n\n while (stack.length > 0) {\n const node = stack.pop()!\n if (visited.has(node)) {\n continue\n }\n visited.add(node)\n\n if (node.children.length > 0) {\n stack.push(...node.children)\n } else {\n result.push(node)\n }\n }\n\n this.#cachedLeaves = result\n return result\n }\n\n forEach(callback: (node: TreeNode<TData>) => void): this {\n const stack: Array<TreeNode<TData>> = [this]\n\n for (let i = 0; i < stack.length; i++) {\n const node = stack[i]!\n callback(node)\n\n if (node.children.length > 0) {\n stack.push(...node.children)\n }\n }\n\n return this\n }\n\n findDeep(predicate: (node: TreeNode<TData>) => boolean): TreeNode<TData> | undefined {\n for (const leaf of this.leaves) {\n if (predicate(leaf)) return leaf\n }\n return undefined\n }\n\n static toGraph(root: TreeNode<BarrelData>): Graph {\n const nodes: Array<{ id: string; label: string }> = []\n const edges: Array<{ from: string; to: string }> = []\n\n const stack: Array<TreeNode<BarrelData>> = [root]\n\n for (let i = 0; i < stack.length; i++) {\n const node = stack[i]!\n\n nodes.push({\n id: node.data.path,\n label: node.data.name,\n })\n\n const children = node.children\n if (children.length > 0) {\n for (let j = 0, len = children.length; j < len; j++) {\n const child = children[j]!\n edges.push({\n from: node.data.path,\n to: child.data.path,\n })\n stack.push(child)\n }\n }\n }\n\n return { nodes, edges }\n }\n\n static fromFiles(files: Array<KubbFile.File>, rootFolder = ''): TreeNode<BarrelData> | null {\n const normalizePath = (p: string): string => p.replace(/\\\\/g, '/')\n const normalizedRoot = normalizePath(rootFolder)\n const rootPrefix = normalizedRoot.endsWith('/') ? normalizedRoot : `${normalizedRoot}/`\n\n const normalizedPaths = new Map<KubbFile.File, string>()\n const filteredFiles: Array<KubbFile.File> = []\n for (const file of files) {\n const filePath = normalizedPaths.get(file) ?? normalizePath(file.path)\n normalizedPaths.set(file, filePath)\n if (!filePath.endsWith('.json') && (!rootFolder || filePath.startsWith(rootPrefix))) {\n filteredFiles.push(file)\n }\n }\n\n if (filteredFiles.length === 0) {\n return null\n }\n\n const treeNode = new TreeNode<BarrelData>({\n name: rootFolder || '',\n path: rootFolder || '',\n file: undefined,\n })\n\n for (const file of filteredFiles) {\n const filePath = normalizedPaths.get(file)!\n const relPath = filePath.slice(rootPrefix.length)\n const parts = relPath.split('/')\n\n let current = treeNode\n let currentPath = rootFolder\n\n for (const [index, part] of parts.entries()) {\n const isLast = index === parts.length - 1\n currentPath += (currentPath.endsWith('/') ? '' : '/') + part\n\n let next = current.getChildByName(part)\n\n if (!next) {\n next = current.addChild({\n name: part,\n path: currentPath,\n file: isLast ? file : undefined,\n })\n }\n\n current = next\n }\n }\n\n return treeNode\n }\n}\n","import type { Plugin, UserPlugin } from './types.ts'\n\nexport function definePlugin<Options = unknown, TAppExtension extends Record<string, any> = {}>(\n plugin: UserPlugin<Options, TAppExtension>,\n): Plugin<Options, TAppExtension> {\n return {\n type: 'plugin',\n ...plugin,\n }\n}\n","/** biome-ignore-all lint/suspicious/useIterableCallbackReturn: not needed */\n\nimport path from 'node:path'\nimport { createFile } from '../createFile.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { getRelativePath } from '../utils/getRelativePath.ts'\nimport { TreeNode } from '../utils/TreeNode.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Mode = 'all' | 'named' | 'propagate' | false\n\ntype Options = {\n root: string\n mode: Mode\n dryRun?: boolean\n}\n\ntype WriteEntryOptions = {\n root: string\n mode: Mode\n}\n\ntype ExtendOptions = {\n /**\n * `fabric.writeEntry` should be called before `fabric.write`\n */\n writeEntry(options: WriteEntryOptions): Promise<void>\n}\n\ndeclare global {\n namespace Kubb {\n interface Fabric {\n /**\n * `fabric.writeEntry` should be called before `fabric.write`\n */\n writeEntry(options: WriteEntryOptions): Promise<void>\n }\n }\n}\n\ntype GetBarrelFilesOptions = {\n files: KubbFile.File[]\n root: string\n mode: Mode\n}\n\nexport function getBarrelFiles({ files, root, mode }: GetBarrelFilesOptions): Array<KubbFile.File> {\n // Do not generate when propagating or disabled\n if (mode === 'propagate' || mode === false) {\n return []\n }\n\n const indexableSourcesMap = new Map<KubbFile.File, Array<KubbFile.Source>>()\n\n for (const file of files) {\n const indexableSources: Array<KubbFile.Source> = []\n for (const source of file.sources || []) {\n if (source.isIndexable && source.name) {\n indexableSources.push(source)\n }\n }\n if (indexableSources.length > 0) {\n indexableSourcesMap.set(file, indexableSources)\n }\n }\n\n const cachedFiles = new Map<KubbFile.Path, KubbFile.File>()\n const dedupe = new Map<KubbFile.Path, Set<string>>()\n\n const treeNode = TreeNode.fromFiles(files, root)\n\n if (!treeNode) {\n return []\n }\n\n treeNode.forEach((node) => {\n // Only create a barrel for directory-like nodes that have a parent with a path\n if (!node?.children || !node.parent?.data.path) {\n return\n }\n\n const parentPath = node.parent.data.path as KubbFile.Path\n const barrelPath = path.join(parentPath, 'index.ts') as KubbFile.Path\n\n let barrelFile = cachedFiles.get(barrelPath)\n if (!barrelFile) {\n barrelFile = createFile({\n path: barrelPath,\n baseName: 'index.ts',\n exports: [],\n sources: [],\n })\n cachedFiles.set(barrelPath, barrelFile)\n dedupe.set(barrelPath, new Set<string>())\n }\n\n const seen = dedupe.get(barrelPath)!\n\n for (const leaf of node.leaves) {\n const file = leaf.data.file\n if (!file || !file.path) {\n continue\n }\n\n const indexableSources = indexableSourcesMap.get(file)\n if (!indexableSources) {\n continue\n }\n\n for (const source of indexableSources) {\n const key = `${source.name}|${source.isTypeOnly ? '1' : '0'}`\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n\n // Always compute relative path from the parent directory to the file path\n barrelFile.exports!.push({\n name: [source.name!],\n path: getRelativePath(parentPath, file.path),\n isTypeOnly: source.isTypeOnly,\n })\n\n barrelFile!.sources.push({\n name: source.name!,\n isTypeOnly: source.isTypeOnly,\n value: '', // TODO use parser to generate import\n isExportable: mode === 'all' || mode === 'named',\n isIndexable: mode === 'all' || mode === 'named',\n })\n }\n }\n })\n\n const result = [...cachedFiles.values()]\n\n if (mode === 'all') {\n return result.map((file) => ({\n ...file,\n exports: file.exports?.map((e) => ({ ...e, name: undefined })),\n }))\n }\n\n return result\n}\n\nexport const barrelPlugin = definePlugin<Options, ExtendOptions>({\n name: 'barrel',\n install(ctx, options) {\n if (!options) {\n throw new Error('Barrel plugin requires options.root and options.mode')\n }\n\n if (!options.mode) {\n return undefined\n }\n\n ctx.on('files:writing:start', async (files) => {\n const root = options.root\n const barrelFiles = getBarrelFiles({ files, root, mode: options.mode })\n\n await ctx.fileManager.add(...barrelFiles)\n })\n },\n inject(ctx, options) {\n if (!options) {\n throw new Error('Barrel plugin requires options.root and options.mode')\n }\n\n return {\n async writeEntry({ root, mode }) {\n if (!mode || mode === 'propagate') {\n return undefined\n }\n\n const rootPath = path.resolve(root, 'index.ts')\n\n const barrelFiles: Array<KubbFile.ResolvedFile> = []\n for (const file of ctx.files) {\n for (const source of file.sources) {\n if (source.isIndexable) {\n barrelFiles.push(file)\n\n break\n }\n }\n }\n\n const fileTypeCache = new Map<KubbFile.ResolvedFile, boolean>()\n for (const file of barrelFiles) {\n fileTypeCache.set(\n file,\n file.sources.every((source) => source.isTypeOnly),\n )\n }\n\n const exports: Array<KubbFile.Export> = []\n for (const file of barrelFiles) {\n const containsOnlyTypes = fileTypeCache.get(file) ?? false\n\n for (const source of file.sources) {\n if (!file.path || !source.isIndexable) {\n continue\n }\n\n exports.push({\n name: mode === 'all' ? undefined : [source.name],\n path: getRelativePath(rootPath, file.path),\n isTypeOnly: mode === 'all' ? containsOnlyTypes : source.isTypeOnly,\n } as KubbFile.Export)\n }\n }\n\n const entryFile = createFile({\n path: rootPath,\n baseName: 'index.ts',\n exports,\n sources: [],\n })\n\n await ctx.addFile(entryFile)\n\n await ctx.fileManager.write({\n mode: ctx.config.mode,\n dryRun: options.dryRun,\n parsers: ctx.installedParsers,\n })\n },\n }\n },\n})\n","import { resolve } from 'node:path'\nimport fs from 'fs-extra'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype WriteOptions = {\n extension?: Record<KubbFile.Extname, KubbFile.Extname | ''>\n}\n\ntype Options = {\n dryRun?: boolean\n /**\n * Optional callback that is invoked whenever a file is written by the plugin.\n * Useful for tests to observe write operations without spying on internal functions.\n */\n onBeforeWrite?: (path: string, data: string | undefined) => void | Promise<void>\n clean?: {\n path: string\n }\n}\n\ntype ExtendOptions = {\n write(options?: WriteOptions): Promise<void>\n}\n\nexport async function write(path: string, data: string | undefined, options: { sanity?: boolean } = {}): Promise<string | undefined> {\n if (typeof Bun !== 'undefined') {\n if (!data || data?.trim() === '') {\n return undefined\n }\n\n await Bun.write(resolve(path), data.trim())\n\n if (options?.sanity) {\n const file = Bun.file(resolve(path))\n const savedData = await file.text()\n\n if (savedData?.toString() !== data?.toString()) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n\n return savedData\n }\n\n return data\n }\n\n if (!data || data?.trim() === '') {\n return undefined\n }\n\n try {\n const oldContent = await fs.readFile(resolve(path), {\n encoding: 'utf-8',\n })\n if (oldContent?.toString() === data?.toString()) {\n return\n }\n } catch (_err) {\n /* empty */\n }\n\n await fs.outputFile(resolve(path), data.trim(), { encoding: 'utf-8' })\n\n if (options?.sanity) {\n const savedData = await fs.readFile(resolve(path), {\n encoding: 'utf-8',\n })\n\n if (savedData?.toString() !== data?.toString()) {\n throw new Error(`Sanity check failed for ${path}\\n\\nData[${data.length}]:\\n${data}\\n\\nSaved[${savedData.length}]:\\n${savedData}\\n`)\n }\n\n return savedData\n }\n\n return data\n}\n\ndeclare global {\n namespace Kubb {\n interface Fabric {\n write(options?: WriteOptions): Promise<void>\n }\n }\n}\n\nexport const fsPlugin = definePlugin<Options, ExtendOptions>({\n name: 'fs',\n install(ctx, options = {}) {\n if (options.clean) {\n fs.removeSync(options.clean.path)\n }\n\n ctx.on('file:processing:update', async ({ file, source }) => {\n if (options.onBeforeWrite) {\n await options.onBeforeWrite(file.path, source)\n }\n await write(file.path, source, { sanity: false })\n })\n },\n inject(ctx, { dryRun } = {}) {\n return {\n async write(\n options = {\n extension: { '.ts': '.ts' },\n },\n ) {\n await ctx.fileManager.write({\n mode: ctx.config.mode,\n extension: options.extension,\n dryRun,\n parsers: ctx.installedParsers,\n })\n },\n }\n },\n})\n","import { spawn } from 'node:child_process'\n\nconst spawnBin = (bin: string, args: string[]): Promise<boolean> => {\n return new Promise((resolve) => {\n const process = spawn(bin, args, {\n detached: true,\n shell: false,\n windowsHide: true,\n })\n\n process.on('close', (code) => {\n resolve(!code)\n })\n })\n}\n\ntype Options = {\n app?: string\n}\n\nexport async function open(path: string, options?: Options): Promise<boolean> {\n const app = options?.app\n\n if (process.platform === 'win32') {\n return spawnBin('cmd.exe', ['/c', 'start', app || '', path.replace(/[&^]/g, '^$&')])\n }\n\n if (process.platform === 'linux') {\n return spawnBin(app || 'xdg-open', [path])\n }\n if (process.platform === 'darwin') {\n return spawnBin('open', app ? ['-a', app, path] : [path])\n }\n\n throw new Error(`Unsupported platform, could not open \"${path}\"`)\n}\n","import http from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport path from 'node:path'\nimport handler from 'serve-handler'\nimport { createFile } from '../createFile.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { open } from '../utils/open.ts'\nimport { type Graph, TreeNode } from '../utils/TreeNode.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Options = {\n root: string\n /**\n * @default false\n */\n open?: boolean\n}\n\ntype GetGraphOptions = {\n files: KubbFile.File[]\n root: string\n}\n\nexport function getGraph({ files, root }: GetGraphOptions): Graph | undefined {\n const treeNode = TreeNode.fromFiles(files, root)\n\n if (!treeNode) {\n return undefined\n }\n\n return TreeNode.toGraph(treeNode)\n}\nconst html = `\n <!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\" />\n <title>File Graph</title>\n <script type=\"module\">\n import { Network } from 'https://cdn.jsdelivr.net/npm/vis-network/standalone/esm/vis-network.min.js'\n\n async function main() {\n const res = await fetch('./graph.json')\n const { nodes, edges } = await res.json()\n const container = document.getElementById('graph')\n\n const network = new Network(\n container,\n { nodes, edges },\n {\n layout: { hierarchical: { direction: 'UD', sortMethod: 'directed' } },\n nodes: { shape: 'box', font: { face: 'monospace' } },\n edges: { arrows: 'to' },\n physics: false,\n },\n )\n }\n\n main()\n </script>\n <style>\n html, body, #graph { height: 100%; margin: 0; }\n </style>\n </head>\n <body>\n <div id=\"graph\"></div>\n </body>\n</html>\n`\n\nasync function serve(root: string) {\n const server = http.createServer((req, res) => {\n return handler(req, res, {\n public: root,\n cleanUrls: true,\n })\n })\n\n server.listen(0, async () => {\n const { port } = server.address() as AddressInfo\n console.log(`Running on http://localhost:${port}/graph.html`)\n\n await open(`http://localhost:${port}/graph.html`)\n })\n}\n\nexport const graphPlugin = definePlugin<Options>({\n name: 'graph',\n install(ctx, options) {\n if (!options) {\n throw new Error('Graph plugin requires options.root and options.mode')\n }\n\n ctx.on('files:writing:start', async (files) => {\n const root = options.root\n\n const graph = getGraph({ files, root })\n\n if (!graph) {\n return undefined\n }\n\n const graphFile = createFile({\n baseName: 'graph.json',\n path: path.join(root, 'graph.json'),\n sources: [\n {\n name: 'graph',\n value: JSON.stringify(graph, null, 2),\n },\n ],\n })\n\n const graphHtmlFile = createFile({\n baseName: 'graph.html',\n path: path.join(root, 'graph.html'),\n sources: [\n {\n name: 'graph',\n value: html,\n },\n ],\n })\n\n await ctx.addFile(graphFile, graphHtmlFile)\n\n if (options.open) {\n await serve(root)\n }\n })\n },\n})\n","import http from 'node:http'\nimport type { AddressInfo } from 'node:net'\nimport { relative } from 'node:path'\nimport { Presets, SingleBar } from 'cli-progress'\nimport { createConsola, type LogLevel } from 'consola'\nimport { WebSocket, WebSocketServer } from 'ws'\nimport type { FabricEvents } from '../Fabric.ts'\nimport type * as KubbFile from '../KubbFile.ts'\nimport { definePlugin } from './definePlugin.ts'\n\ntype Broadcast = <T = unknown>(event: keyof FabricEvents | string, payload: T) => void\ntype WebSocketOptions = {\n /**\n * Hostname to bind the websocket server to.\n * @default '127.0.0.1'\n */\n host?: string\n /**\n * Port to bind the websocket server to.\n * @default 0 (random available port)\n */\n port?: number\n}\n\ntype Options = {\n /**\n * Explicit consola log level.\n */\n level?: LogLevel\n /**\n * Toggle progress bar output.\n * @default true\n */\n progress?: boolean\n /**\n * Toggle or configure the websocket broadcast server.\n * When `true`, a websocket server is started on an ephemeral port.\n * When `false`, websocket support is disabled.\n * When providing an object, the server uses the supplied host and port.\n * @default true\n */\n websocket?: boolean | WebSocketOptions\n}\n\nfunction normalizeAddress(address: AddressInfo): {\n host: string\n port: number\n} {\n const host = address.address === '::' ? '127.0.0.1' : address.address\n\n return { host, port: address.port }\n}\n\nfunction serializeFile(file: KubbFile.File | KubbFile.ResolvedFile) {\n return {\n path: file.path,\n baseName: file.baseName,\n name: 'name' in file ? file.name : undefined,\n extname: 'extname' in file ? file.extname : undefined,\n }\n}\n\nfunction pluralize(word: string, count: number) {\n return `${count} ${word}${count === 1 ? '' : 's'}`\n}\n\nconst defaultTag = 'Fabric'\n\nconst createProgressBar = () =>\n new SingleBar(\n {\n format: '{bar} {percentage}% | {value}/{total} | {message}',\n barCompleteChar: '█',\n barIncompleteChar: '░',\n hideCursor: true,\n clearOnComplete: true,\n },\n Presets.shades_grey,\n )\n\nexport const loggerPlugin = definePlugin<Options>({\n name: 'logger',\n install(ctx, options = {}) {\n const { level, websocket = true, progress = true } = options\n\n const logger = createConsola(level !== undefined ? { level } : {}).withTag(defaultTag)\n\n const progressBar = progress ? createProgressBar() : undefined\n\n let server: http.Server | undefined\n let wss: WebSocketServer | undefined\n\n const broadcast: Broadcast = (event, payload) => {\n if (!wss) {\n return\n }\n\n const message = JSON.stringify({ event, payload })\n\n for (const client of wss.clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.send(message)\n }\n }\n }\n\n if (websocket) {\n const { host = '127.0.0.1', port = 0 } = typeof websocket === 'boolean' ? {} : websocket\n\n server = http.createServer()\n wss = new WebSocketServer({ server })\n\n server.listen(port, host, () => {\n const addressInfo = server?.address()\n\n if (addressInfo && typeof addressInfo === 'object') {\n const { host: resolvedHost, port: resolvedPort } = normalizeAddress(addressInfo)\n const url = `ws://${resolvedHost}:${resolvedPort}`\n\n logger.info(`Logger websocket listening on ${url}`)\n broadcast('websocket:ready', { url })\n }\n })\n\n wss.on('connection', (socket) => {\n logger.info('Logger websocket client connected')\n socket.send(\n JSON.stringify({\n event: 'welcome',\n payload: {\n message: 'Connected to Fabric log stream',\n timestamp: Date.now(),\n },\n }),\n )\n })\n\n wss.on('error', (error) => {\n logger.error('Logger websocket error', error)\n })\n }\n\n const formatPath = (path: string) => relative(process.cwd(), path)\n\n ctx.on('lifecycle:start', async () => {\n logger.start('Starting Fabric run')\n broadcast('lifecycle:start', { timestamp: Date.now() })\n })\n\n ctx.on('lifecycle:render', async () => {\n logger.info('Rendering application graph')\n broadcast('lifecycle:render', { timestamp: Date.now() })\n })\n\n ctx.on('files:added', async (files) => {\n if (!files.length) {\n return\n }\n\n logger.info(`Queued ${pluralize('file', files.length)}`)\n broadcast('files:added', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('file:resolve:path', async (file) => {\n logger.info(`Resolving path for ${formatPath(file.path)}`)\n broadcast('file:resolve:path', { file: serializeFile(file) })\n })\n\n ctx.on('file:resolve:name', async (file) => {\n logger.info(`Resolving name for ${formatPath(file.path)}`)\n broadcast('file:resolve:name', { file: serializeFile(file) })\n })\n\n ctx.on('files:processing:start', async (files) => {\n logger.start(`Processing ${pluralize('file', files.length)}`)\n broadcast('files:processing:start', {\n total: files.length,\n timestamp: Date.now(),\n })\n\n if (progressBar) {\n logger.pauseLogs()\n progressBar.start(files.length, 0, { message: 'Starting...' })\n }\n })\n\n ctx.on('file:processing:start', async (file, index, total) => {\n logger.info(`Processing [${index + 1}/${total}] ${formatPath(file.path)}`)\n broadcast('file:processing:start', {\n index,\n total,\n file: serializeFile(file),\n })\n })\n\n ctx.on('file:processing:update', async ({ processed, total, percentage, file }) => {\n const formattedPercentage = Number.isFinite(percentage) ? percentage.toFixed(1) : '0.0'\n\n logger.info(`Progress ${formattedPercentage}% (${processed}/${total}) → ${formatPath(file.path)}`)\n broadcast('file:processing:update', {\n processed,\n total,\n percentage,\n file: serializeFile(file),\n })\n\n if (progressBar) {\n progressBar.increment(1, {\n message: `Writing ${formatPath(file.path)}`,\n })\n }\n })\n\n ctx.on('file:processing:end', async (file, index, total) => {\n logger.success(`Finished [${index + 1}/${total}] ${formatPath(file.path)}`)\n broadcast('file:processing:end', {\n index,\n total,\n file: serializeFile(file),\n })\n })\n\n ctx.on('files:writing:start', async (files) => {\n logger.start(`Writing ${pluralize('file', files.length)} to disk`)\n broadcast('files:writing:start', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('files:writing:end', async (files) => {\n logger.success(`Written ${pluralize('file', files.length)} to disk`)\n broadcast('files:writing:end', {\n files: files.map(serializeFile),\n })\n })\n\n ctx.on('files:processing:end', async (files) => {\n logger.success(`Processed ${pluralize('file', files.length)}`)\n broadcast('files:processing:end', {\n total: files.length,\n timestamp: Date.now(),\n })\n\n if (progressBar) {\n progressBar.update(files.length, { message: 'Done ✅' })\n progressBar.stop()\n\n logger.resumeLogs()\n }\n })\n\n ctx.on('lifecycle:end', async () => {\n logger.success('Fabric run completed')\n broadcast('lifecycle:end', { timestamp: Date.now() })\n\n if (progressBar) {\n progressBar.stop()\n logger.resumeLogs()\n }\n\n const closures: Array<Promise<void>> = []\n\n if (wss) {\n const wsServer = wss\n\n closures.push(\n new Promise((resolve) => {\n for (const client of wsServer.clients) {\n client.close()\n }\n wsServer.close(() => resolve())\n }),\n )\n }\n\n if (server) {\n const httpServer = server\n\n closures.push(\n new Promise((resolve) => {\n httpServer.close(() => resolve())\n }),\n )\n }\n\n if (closures.length) {\n await Promise.allSettled(closures)\n logger.info('Logger websocket closed')\n }\n })\n },\n})\n"],"mappings":"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"}
|
package/dist/types.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as FabricOptions, i as FabricMode, m as KubbFile_d_exports, n as FabricConfig, r as FabricContext } from "./Fabric-
|
|
1
|
+
import { a as FabricOptions, i as FabricMode, m as KubbFile_d_exports, n as FabricConfig, r as FabricContext } from "./Fabric-BXYWK9V4.cjs";
|
|
2
2
|
export { type FabricConfig, type FabricContext, type FabricMode, type FabricOptions, KubbFile_d_exports as KubbFile };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as FabricOptions, i as FabricMode, m as KubbFile_d_exports, n as FabricConfig, r as FabricContext } from "./Fabric-
|
|
1
|
+
import { a as FabricOptions, i as FabricMode, m as KubbFile_d_exports, n as FabricConfig, r as FabricContext } from "./Fabric-CDFwTDyP.js";
|
|
2
2
|
export { type FabricConfig, type FabricContext, type FabricMode, type FabricOptions, KubbFile_d_exports as KubbFile };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as Parser } from "./Fabric-
|
|
1
|
+
import { u as Parser } from "./Fabric-CDFwTDyP.js";
|
|
2
2
|
import ts from "typescript";
|
|
3
3
|
|
|
4
4
|
//#region src/parsers/typescriptParser.d.ts
|
|
@@ -36,4 +36,4 @@ declare function createExport({
|
|
|
36
36
|
declare const typescriptParser: Parser<[], any>;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { typescriptParser as i, createImport as n, print as r, createExport as t };
|
|
39
|
-
//# sourceMappingURL=typescriptParser-
|
|
39
|
+
//# sourceMappingURL=typescriptParser-CPUUUA9z.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { u as Parser } from "./Fabric-
|
|
1
|
+
import { u as Parser } from "./Fabric-BXYWK9V4.cjs";
|
|
2
2
|
import ts from "typescript";
|
|
3
3
|
|
|
4
4
|
//#region src/parsers/typescriptParser.d.ts
|
|
@@ -36,4 +36,4 @@ declare function createExport({
|
|
|
36
36
|
declare const typescriptParser: Parser<[], any>;
|
|
37
37
|
//#endregion
|
|
38
38
|
export { typescriptParser as i, createImport as n, print as r, createExport as t };
|
|
39
|
-
//# sourceMappingURL=typescriptParser-
|
|
39
|
+
//# sourceMappingURL=typescriptParser-H0FvAP4t.d.cts.map
|
package/package.json
CHANGED
package/src/Fabric.ts
CHANGED
|
@@ -37,43 +37,107 @@ export type FabricMode = 'sequential' | 'parallel'
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Event definitions emitted during the Fabric lifecycle.
|
|
40
|
+
*
|
|
41
|
+
* These events allow plugins and external code to hook into different stages
|
|
42
|
+
* of the file generation process. All events are asynchronous and can be
|
|
43
|
+
* listened to using `fabric.context.on()` or `fabric.context.onOnce()`.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* fabric.context.on('lifecycle:start', async () => {
|
|
48
|
+
* console.log('Fabric started!')
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
40
51
|
*/
|
|
41
52
|
export interface FabricEvents {
|
|
42
|
-
/**
|
|
53
|
+
/**
|
|
54
|
+
* Emitted when the Fabric application lifecycle begins.
|
|
55
|
+
* This is typically the first event fired when starting a Fabric run.
|
|
56
|
+
* Use this to perform initial setup or logging.
|
|
57
|
+
*/
|
|
43
58
|
'lifecycle:start': []
|
|
44
59
|
|
|
45
|
-
/**
|
|
60
|
+
/**
|
|
61
|
+
* Emitted when the Fabric application lifecycle completes.
|
|
62
|
+
* This is typically the last event fired after all processing is done.
|
|
63
|
+
* Use this for cleanup tasks or final reporting.
|
|
64
|
+
*/
|
|
46
65
|
'lifecycle:end': []
|
|
47
66
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Emitted when Fabric starts rendering (used with reactPlugin).
|
|
69
|
+
* Provides access to the Fabric instance for render-time operations.
|
|
70
|
+
*/
|
|
71
|
+
'lifecycle:render': [fabric: Fabric]
|
|
50
72
|
|
|
51
|
-
/**
|
|
52
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Emitted once before file processing begins.
|
|
75
|
+
* Provides the complete list of files that will be processed.
|
|
76
|
+
* Use this to prepare for batch operations or display initial file counts.
|
|
77
|
+
*/
|
|
78
|
+
'files:processing:start': [files: Array<KubbFile.ResolvedFile>]
|
|
53
79
|
|
|
54
|
-
/**
|
|
55
|
-
|
|
80
|
+
/**
|
|
81
|
+
* Emitted when files are successfully added to the FileManager's internal cache.
|
|
82
|
+
* This happens after files pass through path and name resolution.
|
|
83
|
+
* Use this to track which files have been registered.
|
|
84
|
+
*/
|
|
85
|
+
'files:added': [files: Array<KubbFile.ResolvedFile>]
|
|
56
86
|
|
|
57
|
-
/**
|
|
58
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Emitted during file path resolution, before a file is cached.
|
|
89
|
+
* Listeners can modify the file's path property to customize output location.
|
|
90
|
+
* This is called for each file being added via `addFile()` or `upsertFile()`.
|
|
91
|
+
*/
|
|
92
|
+
'file:resolve:path': [file: KubbFile.File]
|
|
59
93
|
|
|
60
|
-
/**
|
|
61
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Emitted during file name resolution, before a file is cached.
|
|
96
|
+
* Listeners can modify the file's name-related properties to customize naming.
|
|
97
|
+
* This is called for each file being added via `addFile()` or `upsertFile()`.
|
|
98
|
+
*/
|
|
99
|
+
'file:resolve:name': [file: KubbFile.File]
|
|
62
100
|
|
|
63
|
-
/**
|
|
64
|
-
|
|
101
|
+
/**
|
|
102
|
+
* Emitted just before files are written to disk.
|
|
103
|
+
* Provides all files that will be written in this batch.
|
|
104
|
+
* Use this to perform pre-write operations like creating directories.
|
|
105
|
+
*/
|
|
106
|
+
'files:writing:start': [files: Array<KubbFile.ResolvedFile>]
|
|
65
107
|
|
|
66
|
-
/**
|
|
67
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Emitted after all files have been successfully written to disk.
|
|
110
|
+
* Provides all files that were written in this batch.
|
|
111
|
+
* Use this for post-write operations like running formatters or reporting.
|
|
112
|
+
*/
|
|
113
|
+
'files:writing:end': [files: Array<KubbFile.ResolvedFile>]
|
|
68
114
|
|
|
69
|
-
/**
|
|
70
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Emitted when an individual file starts being processed.
|
|
117
|
+
* This happens for each file in the queue, before parsing.
|
|
118
|
+
* Use this for per-file setup or detailed logging.
|
|
119
|
+
*/
|
|
120
|
+
'file:processing:start': [file: KubbFile.ResolvedFile, index: number, total: number]
|
|
71
121
|
|
|
72
|
-
/**
|
|
73
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Emitted when an individual file completes processing.
|
|
124
|
+
* This happens after the file has been parsed and handled.
|
|
125
|
+
* Use this for per-file cleanup or progress tracking.
|
|
126
|
+
*/
|
|
127
|
+
'file:processing:end': [file: KubbFile.ResolvedFile, index: number, total: number]
|
|
74
128
|
|
|
75
|
-
/**
|
|
76
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Emitted after each file is processed, providing progress metrics.
|
|
131
|
+
* This is the primary event for implementing progress bars or tracking.
|
|
132
|
+
* Plugins like fsPlugin use this to write files to disk.
|
|
133
|
+
*
|
|
134
|
+
* @property processed - Number of files processed so far
|
|
135
|
+
* @property total - Total number of files to process
|
|
136
|
+
* @property percentage - Completion percentage (0-100)
|
|
137
|
+
* @property source - Optional parsed source code of the file
|
|
138
|
+
* @property file - The file that was just processed
|
|
139
|
+
*/
|
|
140
|
+
'file:processing:update': [
|
|
77
141
|
{
|
|
78
142
|
processed: number
|
|
79
143
|
total: number
|
|
@@ -83,8 +147,12 @@ export interface FabricEvents {
|
|
|
83
147
|
},
|
|
84
148
|
]
|
|
85
149
|
|
|
86
|
-
/**
|
|
87
|
-
|
|
150
|
+
/**
|
|
151
|
+
* Emitted once all files have been successfully processed.
|
|
152
|
+
* This marks the completion of the processing phase.
|
|
153
|
+
* Use this to perform batch operations on all processed files.
|
|
154
|
+
*/
|
|
155
|
+
'files:processing:end': [files: Array<KubbFile.ResolvedFile>]
|
|
88
156
|
}
|
|
89
157
|
|
|
90
158
|
/**
|
package/src/FileManager.ts
CHANGED
|
@@ -34,13 +34,13 @@ export class FileManager {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
#resolvePath(file: KubbFile.File): KubbFile.File {
|
|
37
|
-
this.events.emit('file:path
|
|
37
|
+
this.events.emit('file:resolve:path', file)
|
|
38
38
|
|
|
39
39
|
return file
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
#resolveName(file: KubbFile.File): KubbFile.File {
|
|
43
|
-
this.events.emit('file:name
|
|
43
|
+
this.events.emit('file:resolve:name', file)
|
|
44
44
|
|
|
45
45
|
return file
|
|
46
46
|
}
|
|
@@ -71,7 +71,7 @@ export class FileManager {
|
|
|
71
71
|
resolvedFiles.push(resolvedFile)
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
await this.events.emit('files:added',
|
|
74
|
+
await this.events.emit('files:added', resolvedFiles)
|
|
75
75
|
|
|
76
76
|
return resolvedFiles
|
|
77
77
|
}
|
|
@@ -105,7 +105,7 @@ export class FileManager {
|
|
|
105
105
|
resolvedFiles.push(resolvedFile)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
await this.events.emit('files:added',
|
|
108
|
+
await this.events.emit('files:added', resolvedFiles)
|
|
109
109
|
|
|
110
110
|
return resolvedFiles
|
|
111
111
|
}
|
|
@@ -155,13 +155,13 @@ export class FileManager {
|
|
|
155
155
|
|
|
156
156
|
//TODO add test and check if write of FileManager contains the newly added file
|
|
157
157
|
async write(options: ProcessFilesProps): Promise<KubbFile.ResolvedFile[]> {
|
|
158
|
-
await this.events.emit('files:writing:start',
|
|
158
|
+
await this.events.emit('files:writing:start', this.files)
|
|
159
159
|
|
|
160
160
|
const resolvedFiles = await this.processor.run(this.files, options)
|
|
161
161
|
|
|
162
162
|
this.clear()
|
|
163
163
|
|
|
164
|
-
await this.events.emit('files:writing:end',
|
|
164
|
+
await this.events.emit('files:writing:end', resolvedFiles)
|
|
165
165
|
|
|
166
166
|
return resolvedFiles
|
|
167
167
|
}
|
package/src/FileProcessor.ts
CHANGED
|
@@ -60,20 +60,20 @@ export class FileProcessor {
|
|
|
60
60
|
files: Array<KubbFile.ResolvedFile>,
|
|
61
61
|
{ parsers, mode = 'sequential', dryRun, extension }: ProcessFilesProps = {},
|
|
62
62
|
): Promise<KubbFile.ResolvedFile[]> {
|
|
63
|
-
await this.events.emit('files:processing:start',
|
|
63
|
+
await this.events.emit('files:processing:start', files)
|
|
64
64
|
|
|
65
65
|
const total = files.length
|
|
66
66
|
let processed = 0
|
|
67
67
|
|
|
68
68
|
const processOne = async (resolvedFile: KubbFile.ResolvedFile, index: number) => {
|
|
69
|
-
await this.events.emit('file:processing:start',
|
|
69
|
+
await this.events.emit('file:processing:start', resolvedFile, index, total)
|
|
70
70
|
|
|
71
71
|
const source = dryRun ? undefined : await this.parse(resolvedFile, { extension, parsers })
|
|
72
72
|
|
|
73
73
|
const currentProcessed = ++processed
|
|
74
74
|
const percentage = (currentProcessed / total) * 100
|
|
75
75
|
|
|
76
|
-
await this.events.emit('
|
|
76
|
+
await this.events.emit('file:processing:update', {
|
|
77
77
|
file: resolvedFile,
|
|
78
78
|
source,
|
|
79
79
|
processed: currentProcessed,
|
|
@@ -81,7 +81,7 @@ export class FileProcessor {
|
|
|
81
81
|
total,
|
|
82
82
|
})
|
|
83
83
|
|
|
84
|
-
await this.events.emit('file:processing:end',
|
|
84
|
+
await this.events.emit('file:processing:end', resolvedFile, index, total)
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
if (mode === 'sequential') {
|
|
@@ -101,7 +101,7 @@ export class FileProcessor {
|
|
|
101
101
|
await Promise.all(promises)
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
await this.events.emit('files:processing:end',
|
|
104
|
+
await this.events.emit('files:processing:end', files)
|
|
105
105
|
|
|
106
106
|
return files
|
|
107
107
|
}
|
|
@@ -115,7 +115,7 @@ export function getBarrelFiles({ files, root, mode }: GetBarrelFilesOptions): Ar
|
|
|
115
115
|
seen.add(key)
|
|
116
116
|
|
|
117
117
|
// Always compute relative path from the parent directory to the file path
|
|
118
|
-
barrelFile
|
|
118
|
+
barrelFile.exports!.push({
|
|
119
119
|
name: [source.name!],
|
|
120
120
|
path: getRelativePath(parentPath, file.path),
|
|
121
121
|
isTypeOnly: source.isTypeOnly,
|
|
@@ -155,7 +155,7 @@ export const barrelPlugin = definePlugin<Options, ExtendOptions>({
|
|
|
155
155
|
return undefined
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
ctx.on('files:writing:start', async (
|
|
158
|
+
ctx.on('files:writing:start', async (files) => {
|
|
159
159
|
const root = options.root
|
|
160
160
|
const barrelFiles = getBarrelFiles({ files, root, mode: options.mode })
|
|
161
161
|
|
package/src/plugins/fsPlugin.ts
CHANGED
|
@@ -92,7 +92,7 @@ export const fsPlugin = definePlugin<Options, ExtendOptions>({
|
|
|
92
92
|
fs.removeSync(options.clean.path)
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
ctx.on('
|
|
95
|
+
ctx.on('file:processing:update', async ({ file, source }) => {
|
|
96
96
|
if (options.onBeforeWrite) {
|
|
97
97
|
await options.onBeforeWrite(file.path, source)
|
|
98
98
|
}
|
|
@@ -91,7 +91,7 @@ export const graphPlugin = definePlugin<Options>({
|
|
|
91
91
|
throw new Error('Graph plugin requires options.root and options.mode')
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
ctx.on('files:writing:start', async (
|
|
94
|
+
ctx.on('files:writing:start', async (files) => {
|
|
95
95
|
const root = options.root
|
|
96
96
|
|
|
97
97
|
const graph = getGraph({ files, root })
|