moonflower 1.5.0 → 1.5.2

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 +1 @@
1
- {"version":3,"file":"analyzerModule.mjs","sources":["../../../src/openapi/analyzerModule/analyzerModule.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { existsSync } from 'fs'\nimport * as path from 'path'\nimport { fileURLToPath } from 'url'\n\nfunction resolveWorkerUrl(): URL {\n\tconst candidates = ['./analyzerWorker.mjs', './analyzerWorker.test.mjs']\n\tfor (const candidate of candidates) {\n\t\tconst url = new URL(candidate, import.meta.url)\n\t\tif (existsSync(fileURLToPath(url))) {\n\t\t\treturn url\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'analyzerWorker.mjs not found. Run yarn build, or run tests via yarn test (which compiles the worker first).',\n\t)\n}\nimport { SourceFile, SyntaxKind } from 'ts-morph'\nimport { Project } from 'ts-morph'\n\nimport { Logger } from '../../utils/logger'\nimport { discoverImportedName } from '../discoveryModule/discoverImports/discoverImports'\nimport {\n\tDiscoveredSourceFile,\n\tdiscoverRouterFiles,\n} from '../discoveryModule/discoverRouterFiles/discoverRouterFiles'\nimport { discoverRouters } from '../discoveryModule/discoverRouters/discoverRouters'\nimport { ApiDocsHeader, OpenApiManager } from '../manager/OpenApiManager'\nimport { EndpointData, ExposedModelData } from '../types'\nimport { getSourceFileTimestamp, TimestampCache } from './getSourceFileTimestamp'\nimport { getValuesOfObjectLiteral, resolveEndpointPath } from './nodeParsers'\nimport { parseEndpoint, SectionTiming } from './parseEndpoint'\nimport { parseExposedModel, parseNamedExposedModels } from './parseExposedModels'\nimport { SourceFileCache } from './sourceFileCache'\nimport { WorkerPool, WorkerResult, WorkerTask } from './workerPool'\n\ntype Props = {\n\tlogLevel?: Parameters<(typeof Logger)['setLevel']>[0]\n\ttsconfigPath: string\n\tsourceFilePaths?: string[]\n\tsourceFileDiscovery?: boolean | FileDiscoveryConfig\n\tincremental?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tcachePath: string\n\t\t }\n\tprofiling?: 'stats' | 'off' | 'debug'\n}\n\ntype FileDiscoveryConfig = {\n\trootPath: string\n}\n\ntype EndpointTiming = { method: string; path: string; timing: number; sectionTimings: SectionTiming[] }\n\n/**\n * @param tsconfigPath Path to tsconfig file relative to project root\n * @param sourceFilePaths Array of router source files relative to project root\n */\nexport const prepareOpenApiSpec = async ({\n\tlogLevel,\n\ttsconfigPath,\n\tsourceFilePaths,\n\tsourceFileDiscovery,\n\tincremental,\n\tprofiling = 'stats',\n}: Props): Promise<void> => {\n\tconst openApiManager = OpenApiManager.getInstance()\n\n\tif (openApiManager.isReady()) {\n\t\treturn\n\t}\n\n\tif (logLevel) {\n\t\tLogger.setLevel(logLevel)\n\t}\n\n\tLogger.info('Preparing OpenAPI spec')\n\n\tconst project = new Project({\n\t\ttsConfigFilePath: path.resolve(tsconfigPath),\n\t\tskipFileDependencyResolution: true,\n\t})\n\n\tconst { explicitRouters, discoveredRouterFiles, allSourceFiles } = (() => {\n\t\tconst sourceFilesToAdd = sourceFilePaths ?? []\n\t\tconst resolvedSourceFilePaths = sourceFilesToAdd.map((filepath) => path.resolve(filepath))\n\t\tconst sourceFiles = resolvedSourceFilePaths.map((filePath) => project.getSourceFileOrThrow(filePath))\n\t\tconst explicitRouters = sourceFiles.flatMap((file) => ({\n\t\t\tfileName: file.getFilePath(),\n\t\t\tsourceFile: file,\n\t\t\trouters: discoverRouters(file),\n\t\t}))\n\n\t\tconst { discoveredRouterFiles, discoveredSourceFiles } = (() => {\n\t\t\tif (sourceFileDiscovery === false) {\n\t\t\t\treturn { discoveredRouterFiles: [], discoveredSourceFiles: [] }\n\t\t\t}\n\n\t\t\tconst startTime = performance.now()\n\t\t\tconst files = discoverRouterFiles({\n\t\t\t\ttargetPath: typeof sourceFileDiscovery === 'object' ? sourceFileDiscovery.rootPath : '.',\n\t\t\t\ttsConfigPath: tsconfigPath,\n\t\t\t})\n\t\t\tif (profiling !== 'off') {\n\t\t\t\tLogger.info(`File discovery took ${Math.round(performance.now() - startTime)}ms`)\n\t\t\t}\n\t\t\treturn files\n\t\t})()\n\n\t\tconst allSourceFiles = sourceFiles.reduce(\n\t\t\t(acc, current) =>\n\t\t\t\tacc.some((r) => r.getFilePath() === current.getFilePath()) ? acc : acc.concat(current),\n\t\t\tdiscoveredSourceFiles,\n\t\t)\n\n\t\treturn { explicitRouters, discoveredRouterFiles, allSourceFiles }\n\t})()\n\n\tconst filesToAnalyze = explicitRouters.reduce(\n\t\t(acc, current) => (acc.some((r) => r.fileName === current.fileName) ? acc : acc.concat(current)),\n\t\tdiscoveredRouterFiles,\n\t)\n\n\tconst apiHeaders = allSourceFiles\n\t\t.flatMap((file) => analyzeSourceFileApiHeader(file))\n\t\t.filter((headers) => !!headers)\n\tif (apiHeaders.length > 0 && apiHeaders[0]) {\n\t\topenApiManager.setHeader(apiHeaders[0])\n\t}\n\n\tconst exposedModels = allSourceFiles.flatMap((file) => analyzeSourceFileExposedModels(file))\n\n\topenApiManager.setExposedModels(exposedModels)\n\n\tconst cachePath = (() => {\n\t\tif (typeof incremental === 'object' && incremental.cachePath) {\n\t\t\treturn incremental.cachePath\n\t\t}\n\t\treturn path.resolve(process.cwd(), 'node_modules', '.cache', 'moonflower')\n\t})()\n\tconst endpoints = await analyzeMultipleSourceFiles(filesToAnalyze, {\n\t\tincremental: incremental !== false,\n\t\tcachePath,\n\t\ttimestampCache: {},\n\t\tprofiling,\n\t\ttsconfigPath: path.resolve(tsconfigPath),\n\t})\n\n\topenApiManager.setStats({\n\t\tdiscoveredRouterFiles: discoveredRouterFiles.map((file) => ({\n\t\t\tpath: file.fileName,\n\t\t\trouters: file.routers.named.map((r) => ({\n\t\t\t\tname: r,\n\t\t\t\tendpoints: endpoints\n\t\t\t\t\t.filter((e) => e.sourceFilePath === file.fileName)\n\t\t\t\t\t.map((e) => `${e.method.toUpperCase()} ${e.path}`),\n\t\t\t})),\n\t\t})),\n\t\texplicitRouterFiles: explicitRouters.map((file) => ({\n\t\t\tpath: file.fileName,\n\t\t\trouters: file.routers.named.map((r) => ({\n\t\t\t\tname: r,\n\t\t\t\tendpoints: endpoints\n\t\t\t\t\t.filter((e) => e.sourceFilePath === file.fileName)\n\t\t\t\t\t.map((e) => `${e.method.toUpperCase()} ${e.path}`),\n\t\t\t})),\n\t\t})),\n\t})\n\n\topenApiManager.setEndpoints(endpoints)\n\topenApiManager.markAsReady()\n}\n\nexport const analyzeMultipleSourceFiles = async (\n\tfiles: DiscoveredSourceFile[],\n\tconfig: {\n\t\tincremental: boolean\n\t\tcachePath: string\n\t\ttimestampCache: TimestampCache\n\t\tprofiling?: 'stats' | 'off' | 'debug'\n\t\ttsconfigPath: string\n\t},\n\tfilterEndpointPaths?: string[],\n): Promise<EndpointData[]> => {\n\tconst profiling = config.profiling ?? 'stats'\n\tconst startTime = performance.now()\n\n\t// Separate cached files from those needing analysis\n\ttype CachedFile = { endpoints: EndpointData[]; fileName: string; timing: 0; endpointTimings: [] }\n\ttype UncachedFile = { file: DiscoveredSourceFile; timestamp: number }\n\n\tconst cached: CachedFile[] = []\n\tconst uncached: UncachedFile[] = []\n\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache)\n\t\tconst hit = config.incremental\n\t\t\t? SourceFileCache.getCachedResults(file.sourceFile, timestamp, config.cachePath)\n\t\t\t: null\n\t\tif (hit) {\n\t\t\tLogger.debug(`[${file.fileName}] Found cached results`)\n\t\t\tcached.push({ endpoints: hit.endpoints, fileName: file.fileName, timing: 0, endpointTimings: [] })\n\t\t} else {\n\t\t\tuncached.push({ file, timestamp })\n\t\t}\n\t}\n\n\tif (uncached.length === 0) {\n\t\tif (profiling !== 'off') {\n\t\t\tLogger.info(`Router analysis took ${Math.round(performance.now() - startTime)}ms`)\n\t\t}\n\t\treturn cached.flatMap((f) => f.endpoints)\n\t}\n\n\t// Build one task per endpoint across all uncached files\n\tconst OPERATIONS = ['get', 'post', 'put', 'delete', 'del', 'patch']\n\tconst operationsPattern = OPERATIONS.join('|')\n\n\ttype FileTask = { task: WorkerTask; fileName: string }\n\tconst allTasks: FileTask[] = []\n\n\tfor (const { file } of uncached) {\n\t\tfor (const routerName of file.routers.named) {\n\t\t\tconst routerPattern = new RegExp(`${routerName}\\\\.(?:${operationsPattern})`)\n\t\t\tlet endpointIndex = 0\n\t\t\tfile.sourceFile.forEachChild((node) => {\n\t\t\t\tconst nodeText = node.getText()\n\t\t\t\tif (routerPattern.test(nodeText)) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!filterEndpointPaths ||\n\t\t\t\t\t\tfilterEndpointPaths.some((p) => resolveEndpointPath(node)?.includes(p))\n\t\t\t\t\t) {\n\t\t\t\t\t\tallTasks.push({\n\t\t\t\t\t\t\tfileName: file.fileName,\n\t\t\t\t\t\t\ttask: {\n\t\t\t\t\t\t\t\ttaskId: crypto.randomUUID(),\n\t\t\t\t\t\t\t\ttsconfigPath: config.tsconfigPath,\n\t\t\t\t\t\t\t\tsourceFilePath: file.sourceFile.getFilePath(),\n\t\t\t\t\t\t\t\trouterName,\n\t\t\t\t\t\t\t\tendpointIndex,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tendpointIndex++\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\t}\n\n\t// Dispatch all tasks to the worker pool\n\tconst pool = new WorkerPool(resolveWorkerUrl())\n\n\ttype EndpointTiming = { method: string; path: string; timing: number; sectionTimings: SectionTiming[] }\n\ttype FileResult = {\n\t\tendpoints: EndpointData[]\n\t\tfileName: string\n\t\ttiming: number\n\t\tendpointTimings: EndpointTiming[]\n\t}\n\n\tlet results: WorkerResult[]\n\ttry {\n\t\tresults = await pool.runAll(allTasks.map((ft) => ft.task))\n\t} finally {\n\t\tpool.terminate()\n\t}\n\n\t// Group results by file\n\tconst byFile = new Map<string, FileResult>()\n\tfor (const { file } of uncached) {\n\t\tbyFile.set(file.fileName, { endpoints: [], fileName: file.fileName, timing: 0, endpointTimings: [] })\n\t}\n\n\tfor (let i = 0; i < results.length; i++) {\n\t\tconst result = results[i]\n\t\tconst fileName = allTasks[i].fileName\n\t\tconst fileResult = byFile.get(fileName)!\n\n\t\tif ('error' in result) {\n\t\t\tLogger.error(`[${fileName}] Worker error: ${result.error}`)\n\t\t\tcontinue\n\t\t}\n\n\t\tfileResult.endpoints.push(result.endpoint)\n\t\tfileResult.timing += result.timing\n\t\tfileResult.endpointTimings.push({\n\t\t\tmethod: result.endpoint.method,\n\t\t\tpath: result.endpoint.path,\n\t\t\ttiming: result.timing,\n\t\t\tsectionTimings: result.sectionTimings,\n\t\t})\n\t}\n\n\t// Write cache for each uncached file\n\tfor (const { file, timestamp } of uncached) {\n\t\tconst fileResult = byFile.get(file.fileName)!\n\t\tif (fileResult.endpoints.length > 0) {\n\t\t\tSourceFileCache.cacheResults(file.sourceFile, timestamp, config.cachePath, fileResult.endpoints)\n\t\t}\n\t}\n\n\tconst analyzedFiles = [...cached, ...Array.from(byFile.values())]\n\n\tif (profiling !== 'off') {\n\t\tLogger.info(`Router analysis took ${Math.round(performance.now() - startTime)}ms`)\n\t}\n\n\tif (profiling === 'stats') {\n\t\tanalyzedFiles\n\t\t\t.map((f) => ({ fileName: f.fileName, timeTaken: f.timing }))\n\t\t\t.sort((a, b) => b.timeTaken - a.timeTaken)\n\t\t\t.filter((t) => t.timeTaken > 500)\n\t\t\t.forEach((t) => {\n\t\t\t\tLogger.info(`- [${t.fileName}] Took ${Math.round(t.timeTaken)}ms to analyze`)\n\t\t\t})\n\t} else if (profiling === 'debug') {\n\t\tanalyzedFiles\n\t\t\t.map((f) => ({ fileName: f.fileName, timeTaken: f.timing, endpointTimings: f.endpointTimings }))\n\t\t\t.sort((a, b) => b.timeTaken - a.timeTaken)\n\t\t\t.forEach((t) => {\n\t\t\t\tLogger.info(`- [${t.fileName}] Took ${Math.round(t.timeTaken)}ms to analyze`)\n\t\t\t\tt.endpointTimings\n\t\t\t\t\t.sort((a, b) => b.timing - a.timing)\n\t\t\t\t\t.forEach((ep) => {\n\t\t\t\t\t\tLogger.info(` - ${ep.method} ${ep.path} (${Math.round(ep.timing)}ms)`)\n\t\t\t\t\t\tep.sectionTimings\n\t\t\t\t\t\t\t.filter((s) => s.timing >= 1)\n\t\t\t\t\t\t\t.sort((a, b) => b.timing - a.timing)\n\t\t\t\t\t\t\t.forEach((s) => {\n\t\t\t\t\t\t\t\tLogger.info(` - ${s.section}: ${Math.round(s.timing)}ms`)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t})\n\t}\n\n\treturn analyzedFiles.flatMap((f) => f.endpoints)\n}\n\nexport const analyzeSourceFileWithCache = (\n\tfile: DiscoveredSourceFile,\n\tconfig: {\n\t\tincremental: boolean\n\t\tcachePath: string\n\t\ttimestampCache: TimestampCache\n\t\tprofiling?: 'stats' | 'off' | 'debug'\n\t},\n\tfilterEndpointPaths?: string[],\n): { endpoints: EndpointData[]; timing: number; endpointTimings: EndpointTiming[] } => {\n\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache)\n\tconst cachedResults = SourceFileCache.getCachedResults(file.sourceFile, timestamp, config.cachePath)\n\n\tif (cachedResults) {\n\t\tLogger.debug(`[${file.fileName}] Found cached results`)\n\t\treturn { endpoints: cachedResults.endpoints, timing: 0, endpointTimings: [] }\n\t}\n\tLogger.debug(`[${file.fileName}] Analyzing...`)\n\n\tconst t1 = performance.now()\n\tconst { endpoints, endpointTimings } = analyzeSourceFileEndpoints(file, filterEndpointPaths)\n\tconst t2 = performance.now()\n\tLogger.debug(`[${file.fileName}] Analyzed in ${t2 - t1}ms`)\n\tSourceFileCache.cacheResults(file.sourceFile, timestamp, config.cachePath, endpoints)\n\treturn { endpoints, timing: t2 - t1, endpointTimings }\n}\n\nexport const analyzeSourceFileEndpoints = (\n\tfile: DiscoveredSourceFile,\n\tfilterEndpointPaths?: string[],\n): { endpoints: EndpointData[]; endpointTimings: EndpointTiming[] } => {\n\tconst endpoints: EndpointData[] = []\n\tconst endpointTimings: EndpointTiming[] = []\n\tconst operations = ['get', 'post', 'put', 'delete', 'del', 'patch']\n\tconst joinedOperations = operations.join('|')\n\n\tfile.routers.named.forEach((routerName) => {\n\t\tconst routerPattern = new RegExp(`${routerName}\\\\.(?:${joinedOperations})`)\n\t\tfile.sourceFile.forEachChild((node) => {\n\t\t\tconst nodeText = node.getText()\n\n\t\t\tif (routerPattern.test(nodeText)) {\n\t\t\t\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\n\t\t\t\tif (filterEndpointPaths && !filterEndpointPaths.some((path) => endpointPath.includes(path))) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst t1 = performance.now()\n\t\t\t\tconst { endpoint, sectionTimings } = parseEndpoint(node, file.fileName)\n\t\t\t\tendpointTimings.push({\n\t\t\t\t\tmethod: endpoint.method,\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\ttiming: performance.now() - t1,\n\t\t\t\t\tsectionTimings,\n\t\t\t\t})\n\t\t\t\tendpoints.push(endpoint)\n\t\t\t}\n\t\t})\n\t})\n\n\treturn { endpoints, endpointTimings }\n}\n\nexport const analyzeSourceFileApiHeader = (sourceFile: SourceFile): ApiDocsHeader | null => {\n\tconst nameOfUseApiHeader = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useApiHeader',\n\t})\n\n\tif (!nameOfUseApiHeader) {\n\t\treturn null\n\t}\n\n\tconst node = sourceFile\n\t\t.forEachChildAsArray()\n\t\t.filter((node) => node.isKind(SyntaxKind.ExpressionStatement))\n\t\t.find((node) => nameOfUseApiHeader && node.getText().startsWith(nameOfUseApiHeader))\n\n\tif (!node) {\n\t\treturn null\n\t}\n\n\tconst targetNode = node.getFirstDescendantByKindOrThrow(SyntaxKind.ObjectLiteralExpression)\n\tconst values = getValuesOfObjectLiteral(targetNode)\n\n\tconst collapseObject = (v: string | string[] | typeof values): any => {\n\t\tif (typeof v === 'string') {\n\t\t\treturn v\n\t\t}\n\t\tif (Array.isArray(v) && v.every((value) => typeof value === 'string')) {\n\t\t\treturn v\n\t\t}\n\n\t\treturn v.reduce((acc, current) => {\n\t\t\tif (typeof current === 'string') {\n\t\t\t\treturn acc\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t[current.identifier]: collapseObject(current.value as string[]),\n\t\t\t}\n\t\t}, {})\n\t}\n\treturn collapseObject(values)\n}\n\nexport const analyzeSourceFileExposedModels = (sourceFile: SourceFile): ExposedModelData[] => {\n\tconst models: ExposedModelData[] = []\n\n\tconst nameOfUseExposeApiModel = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useExposeApiModel',\n\t})\n\n\tconst nameOfUseExposeNamedApiModels = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useExposeNamedApiModels',\n\t})\n\n\tsourceFile\n\t\t.forEachChildAsArray()\n\t\t.filter((node) => node.isKind(SyntaxKind.ExpressionStatement))\n\t\t.map((node) => {\n\t\t\tif (nameOfUseExposeApiModel && node.getText().startsWith(nameOfUseExposeApiModel)) {\n\t\t\t\tconst callExpressionNode = node.getFirstChild()\n\t\t\t\tconst syntaxListChildren = callExpressionNode?.getChildrenOfKind(SyntaxKind.SyntaxList) || []\n\n\t\t\t\tconst firstChild = syntaxListChildren[0].getFirstChild()\n\t\t\t\tif (!firstChild) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tmodels.push(parseExposedModel(firstChild))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (nameOfUseExposeNamedApiModels && node.getText().startsWith(nameOfUseExposeNamedApiModels)) {\n\t\t\t\tconst callExpressionNode = node.getFirstChild()\n\t\t\t\tconst syntaxListChildren = callExpressionNode?.getChildrenOfKind(SyntaxKind.SyntaxList) || []\n\n\t\t\t\tconst firstChild = syntaxListChildren[0].getFirstChild()\n\t\t\t\tif (!firstChild) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst parsedModels = parseNamedExposedModels(firstChild)\n\t\t\t\tparsedModels.forEach((model) => models.push(model))\n\t\t\t}\n\t\t})\n\treturn models\n}\n"],"names":["resolveWorkerUrl","candidates","candidate","url","existsSync","fileURLToPath","prepareOpenApiSpec","logLevel","tsconfigPath","sourceFilePaths","sourceFileDiscovery","incremental","profiling","openApiManager","OpenApiManager","Logger","project","Project","path","explicitRouters","discoveredRouterFiles","allSourceFiles","sourceFiles","filepath","filePath","file","discoverRouters","discoveredSourceFiles","startTime","files","discoverRouterFiles","acc","current","r","filesToAnalyze","apiHeaders","analyzeSourceFileApiHeader","headers","exposedModels","analyzeSourceFileExposedModels","cachePath","endpoints","analyzeMultipleSourceFiles","e","config","filterEndpointPaths","cached","uncached","timestamp","getSourceFileTimestamp","hit","SourceFileCache","f","operationsPattern","allTasks","routerName","routerPattern","endpointIndex","node","nodeText","crypto","pool","WorkerPool","results","ft","byFile","i","result","fileName","fileResult","analyzedFiles","a","b","t","ep","s","sourceFile","nameOfUseApiHeader","discoverImportedName","SyntaxKind","targetNode","values","getValuesOfObjectLiteral","collapseObject","v","value","models","nameOfUseExposeApiModel","nameOfUseExposeNamedApiModels","firstChild","parseExposedModel","parseNamedExposedModels","model"],"mappings":"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"}
1
+ {"version":3,"file":"analyzerModule.mjs","sources":["../../../src/openapi/analyzerModule/analyzerModule.ts"],"sourcesContent":["import crypto from 'crypto'\nimport { existsSync } from 'fs'\nimport * as path from 'path'\nimport { fileURLToPath } from 'url'\n\nfunction resolveWorkerUrl(): URL {\n\tconst candidates = ['./analyzerWorker.mjs', './analyzerWorker.test.mjs']\n\tfor (const candidate of candidates) {\n\t\tconst url = new URL(candidate, import.meta.url)\n\t\tif (existsSync(fileURLToPath(url))) {\n\t\t\treturn url\n\t\t}\n\t}\n\tthrow new Error(\n\t\t'analyzerWorker.mjs not found. Run yarn build, or run tests via yarn test (which compiles the worker first).',\n\t)\n}\nimport { SourceFile, SyntaxKind } from 'ts-morph'\nimport { Project } from 'ts-morph'\n\nimport { Logger } from '../../utils/logger'\nimport { discoverImportedName } from '../discoveryModule/discoverImports/discoverImports'\nimport {\n\tDiscoveredSourceFile,\n\tdiscoverRouterFiles,\n} from '../discoveryModule/discoverRouterFiles/discoverRouterFiles'\nimport { discoverRouters } from '../discoveryModule/discoverRouters/discoverRouters'\nimport { ApiDocsHeader, OpenApiManager } from '../manager/OpenApiManager'\nimport { EndpointData, ExposedModelData } from '../types'\nimport { getSourceFileTimestamp, TimestampCache } from './getSourceFileTimestamp'\nimport { getValuesOfObjectLiteral, resolveEndpointPath } from './nodeParsers'\nimport { parseEndpoint, SectionTiming } from './parseEndpoint'\nimport { parseExposedModel, parseNamedExposedModels } from './parseExposedModels'\nimport { SourceFileCache } from './sourceFileCache'\nimport { WorkerPool, WorkerResult, WorkerTask } from './workerPool'\n\ntype Props = {\n\tlogLevel?: Parameters<(typeof Logger)['setLevel']>[0]\n\ttsconfigPath: string\n\tsourceFilePaths?: string[]\n\tsourceFileDiscovery?: boolean | FileDiscoveryConfig\n\tincremental?:\n\t\t| boolean\n\t\t| {\n\t\t\t\tcachePath: string\n\t\t }\n\tprofiling?: 'stats' | 'off' | 'debug'\n}\n\ntype FileDiscoveryConfig = {\n\trootPath: string\n}\n\ntype EndpointTiming = { method: string; path: string; timing: number; sectionTimings: SectionTiming[] }\n\n/**\n * Number of uncached files at or below which analysis runs inline on the (already-warm) main-thread\n * Project instead of fanning out to worker threads. Each worker pays a multi-second cold-start to\n * build its own Project, so parallelism only wins once there are several files to share that cost.\n */\nconst INLINE_ANALYSIS_FILE_THRESHOLD = 2\n\n/**\n * @param tsconfigPath Path to tsconfig file relative to project root\n * @param sourceFilePaths Array of router source files relative to project root\n */\nexport const prepareOpenApiSpec = async ({\n\tlogLevel,\n\ttsconfigPath,\n\tsourceFilePaths,\n\tsourceFileDiscovery,\n\tincremental,\n\tprofiling = 'stats',\n}: Props): Promise<void> => {\n\tconst openApiManager = OpenApiManager.getInstance()\n\n\tif (openApiManager.isReady()) {\n\t\treturn\n\t}\n\n\tif (logLevel) {\n\t\tLogger.setLevel(logLevel)\n\t}\n\n\tLogger.info('Preparing OpenAPI spec')\n\n\tconst project = new Project({\n\t\ttsConfigFilePath: path.resolve(tsconfigPath),\n\t\tskipFileDependencyResolution: true,\n\t})\n\n\tconst { explicitRouters, discoveredRouterFiles, allSourceFiles } = (() => {\n\t\tconst sourceFilesToAdd = sourceFilePaths ?? []\n\t\tconst resolvedSourceFilePaths = sourceFilesToAdd.map((filepath) => path.resolve(filepath))\n\t\tconst sourceFiles = resolvedSourceFilePaths.map((filePath) => project.getSourceFileOrThrow(filePath))\n\t\tconst explicitRouters = sourceFiles.flatMap((file) => ({\n\t\t\tfileName: file.getFilePath(),\n\t\t\tsourceFile: file,\n\t\t\trouters: discoverRouters(file),\n\t\t}))\n\n\t\tconst { discoveredRouterFiles, discoveredSourceFiles } = (() => {\n\t\t\tif (sourceFileDiscovery === false) {\n\t\t\t\treturn { discoveredRouterFiles: [], discoveredSourceFiles: [] }\n\t\t\t}\n\n\t\t\tconst startTime = performance.now()\n\t\t\tconst files = discoverRouterFiles({\n\t\t\t\ttargetPath: typeof sourceFileDiscovery === 'object' ? sourceFileDiscovery.rootPath : '.',\n\t\t\t\ttsConfigPath: tsconfigPath,\n\t\t\t})\n\t\t\tif (profiling !== 'off') {\n\t\t\t\tLogger.info(`File discovery took ${Math.round(performance.now() - startTime)}ms`)\n\t\t\t}\n\t\t\treturn files\n\t\t})()\n\n\t\tconst allSourceFiles = sourceFiles.reduce(\n\t\t\t(acc, current) =>\n\t\t\t\tacc.some((r) => r.getFilePath() === current.getFilePath()) ? acc : acc.concat(current),\n\t\t\tdiscoveredSourceFiles,\n\t\t)\n\n\t\treturn { explicitRouters, discoveredRouterFiles, allSourceFiles }\n\t})()\n\n\tconst filesToAnalyze = explicitRouters.reduce(\n\t\t(acc, current) => (acc.some((r) => r.fileName === current.fileName) ? acc : acc.concat(current)),\n\t\tdiscoveredRouterFiles,\n\t)\n\n\tconst apiHeaders = allSourceFiles\n\t\t.flatMap((file) => analyzeSourceFileApiHeader(file))\n\t\t.filter((headers) => !!headers)\n\tif (apiHeaders.length > 0 && apiHeaders[0]) {\n\t\topenApiManager.setHeader(apiHeaders[0])\n\t}\n\n\tconst exposedModels = allSourceFiles.flatMap((file) => analyzeSourceFileExposedModels(file))\n\n\topenApiManager.setExposedModels(exposedModels)\n\n\tconst cachePath = (() => {\n\t\tif (typeof incremental === 'object' && incremental.cachePath) {\n\t\t\treturn incremental.cachePath\n\t\t}\n\t\treturn path.resolve(process.cwd(), 'node_modules', '.cache', 'moonflower')\n\t})()\n\tconst endpoints = await analyzeMultipleSourceFiles(filesToAnalyze, {\n\t\tincremental: incremental !== false,\n\t\tcachePath,\n\t\ttimestampCache: {},\n\t\tprofiling,\n\t\ttsconfigPath: path.resolve(tsconfigPath),\n\t})\n\n\topenApiManager.setStats({\n\t\tdiscoveredRouterFiles: discoveredRouterFiles.map((file) => ({\n\t\t\tpath: file.fileName,\n\t\t\trouters: file.routers.named.map((r) => ({\n\t\t\t\tname: r,\n\t\t\t\tendpoints: endpoints\n\t\t\t\t\t.filter((e) => e.sourceFilePath === file.fileName)\n\t\t\t\t\t.map((e) => `${e.method.toUpperCase()} ${e.path}`),\n\t\t\t})),\n\t\t})),\n\t\texplicitRouterFiles: explicitRouters.map((file) => ({\n\t\t\tpath: file.fileName,\n\t\t\trouters: file.routers.named.map((r) => ({\n\t\t\t\tname: r,\n\t\t\t\tendpoints: endpoints\n\t\t\t\t\t.filter((e) => e.sourceFilePath === file.fileName)\n\t\t\t\t\t.map((e) => `${e.method.toUpperCase()} ${e.path}`),\n\t\t\t})),\n\t\t})),\n\t})\n\n\topenApiManager.setEndpoints(endpoints)\n\topenApiManager.markAsReady()\n}\n\nexport const analyzeMultipleSourceFiles = async (\n\tfiles: DiscoveredSourceFile[],\n\tconfig: {\n\t\tincremental: boolean\n\t\tcachePath: string\n\t\ttimestampCache: TimestampCache\n\t\tprofiling?: 'stats' | 'off' | 'debug'\n\t\ttsconfigPath: string\n\t},\n\tfilterEndpointPaths?: string[],\n): Promise<EndpointData[]> => {\n\tconst profiling = config.profiling ?? 'stats'\n\tconst startTime = performance.now()\n\n\t// Separate cached files from those needing analysis\n\ttype CachedFile = { endpoints: EndpointData[]; fileName: string; timing: 0; endpointTimings: [] }\n\ttype UncachedFile = { file: DiscoveredSourceFile; timestamp: number }\n\n\tconst cached: CachedFile[] = []\n\tconst uncached: UncachedFile[] = []\n\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache)\n\t\tconst hit = config.incremental\n\t\t\t? SourceFileCache.getCachedResults(file.sourceFile, timestamp, config.cachePath)\n\t\t\t: null\n\t\tif (hit) {\n\t\t\tLogger.debug(`[${file.fileName}] Found cached results`)\n\t\t\tcached.push({ endpoints: hit.endpoints, fileName: file.fileName, timing: 0, endpointTimings: [] })\n\t\t} else {\n\t\t\tuncached.push({ file, timestamp })\n\t\t}\n\t}\n\n\tif (uncached.length === 0) {\n\t\tif (profiling !== 'off') {\n\t\t\tLogger.info(`Router analysis took ${Math.round(performance.now() - startTime)}ms`)\n\t\t}\n\t\treturn cached.flatMap((f) => f.endpoints)\n\t}\n\n\ttype FileResult = {\n\t\tendpoints: EndpointData[]\n\t\tfileName: string\n\t\ttiming: number\n\t\tendpointTimings: EndpointTiming[]\n\t}\n\n\tconst byFile = new Map<string, FileResult>()\n\tfor (const { file } of uncached) {\n\t\tbyFile.set(file.fileName, { endpoints: [], fileName: file.fileName, timing: 0, endpointTimings: [] })\n\t}\n\n\t// The caller (prepareOpenApiSpec) already built and warmed a ts-morph Project on this thread, so\n\t// inline analysis runs against a hot type-checker. A worker, by contrast, must spawn a thread and\n\t// build its own Project from scratch — a multi-second cold-start. That cold-start only pays off\n\t// when there are enough uncached files that spreading the parse work across workers beats it; below\n\t// the threshold (e.g. the common single-file incremental rebuild), inline is strictly faster.\n\tif (uncached.length <= INLINE_ANALYSIS_FILE_THRESHOLD) {\n\t\tfor (const { file } of uncached) {\n\t\t\tconst { endpoints, endpointTimings } = analyzeSourceFileEndpoints(file, filterEndpointPaths)\n\t\t\tconst fileResult = byFile.get(file.fileName)!\n\t\t\tfileResult.endpoints = endpoints\n\t\t\tfileResult.endpointTimings = endpointTimings\n\t\t\tfileResult.timing = endpointTimings.reduce((sum, t) => sum + t.timing, 0)\n\t\t}\n\t} else {\n\t\t// One task per file: each worker analyzes a whole file in a single pass, paying its Project\n\t\t// cold-start once and reusing the warmed-up checker for every endpoint in that file. Cap the\n\t\t// pool at one worker per file so we never spin up a worker with nothing to do.\n\t\ttype FileTask = { task: WorkerTask; fileName: string }\n\t\tconst allTasks: FileTask[] = uncached.map(({ file }) => ({\n\t\t\tfileName: file.fileName,\n\t\t\ttask: {\n\t\t\t\ttaskId: crypto.randomUUID(),\n\t\t\t\ttsconfigPath: config.tsconfigPath,\n\t\t\t\tsourceFilePath: file.sourceFile.getFilePath(),\n\t\t\t\trouterNames: file.routers.named,\n\t\t\t\tfilterEndpointPaths,\n\t\t\t},\n\t\t}))\n\n\t\tconst pool = new WorkerPool(resolveWorkerUrl(), allTasks.length)\n\t\tlet results: WorkerResult[]\n\t\ttry {\n\t\t\tresults = await pool.runAll(allTasks.map((ft) => ft.task))\n\t\t} finally {\n\t\t\tpool.terminate()\n\t\t}\n\n\t\t// Each result maps 1:1 to a file task.\n\t\tfor (let i = 0; i < results.length; i++) {\n\t\t\tconst result = results[i]\n\t\t\tconst fileName = allTasks[i].fileName\n\t\t\tconst fileResult = byFile.get(fileName)!\n\n\t\t\tif ('error' in result) {\n\t\t\t\tLogger.error(`[${fileName}] Worker error: ${result.error}`)\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tfileResult.endpoints = result.endpoints\n\t\t\tfileResult.endpointTimings = result.endpointTimings\n\t\t\tfileResult.timing = result.endpointTimings.reduce((sum, t) => sum + t.timing, 0)\n\t\t}\n\t}\n\n\t// Write cache for each uncached file\n\tfor (const { file, timestamp } of uncached) {\n\t\tconst fileResult = byFile.get(file.fileName)!\n\t\tif (fileResult.endpoints.length > 0) {\n\t\t\tSourceFileCache.cacheResults(file.sourceFile, timestamp, config.cachePath, fileResult.endpoints)\n\t\t}\n\t}\n\n\tconst analyzedFiles = [...cached, ...Array.from(byFile.values())]\n\n\tif (profiling !== 'off') {\n\t\tLogger.info(`Router analysis took ${Math.round(performance.now() - startTime)}ms`)\n\t}\n\n\tif (profiling === 'stats') {\n\t\tanalyzedFiles\n\t\t\t.map((f) => ({ fileName: f.fileName, timeTaken: f.timing }))\n\t\t\t.sort((a, b) => b.timeTaken - a.timeTaken)\n\t\t\t.filter((t) => t.timeTaken > 500)\n\t\t\t.forEach((t) => {\n\t\t\t\tLogger.info(`- [${t.fileName}] Took ${Math.round(t.timeTaken)}ms to analyze`)\n\t\t\t})\n\t} else if (profiling === 'debug') {\n\t\tanalyzedFiles\n\t\t\t.map((f) => ({ fileName: f.fileName, timeTaken: f.timing, endpointTimings: f.endpointTimings }))\n\t\t\t.sort((a, b) => b.timeTaken - a.timeTaken)\n\t\t\t.forEach((t) => {\n\t\t\t\tLogger.info(`- [${t.fileName}] Took ${Math.round(t.timeTaken)}ms to analyze`)\n\t\t\t\tt.endpointTimings\n\t\t\t\t\t.sort((a, b) => b.timing - a.timing)\n\t\t\t\t\t.forEach((ep) => {\n\t\t\t\t\t\tLogger.info(` - ${ep.method} ${ep.path} (${Math.round(ep.timing)}ms)`)\n\t\t\t\t\t\tep.sectionTimings\n\t\t\t\t\t\t\t.filter((s) => s.timing >= 1)\n\t\t\t\t\t\t\t.sort((a, b) => b.timing - a.timing)\n\t\t\t\t\t\t\t.forEach((s) => {\n\t\t\t\t\t\t\t\tLogger.info(` - ${s.section}: ${Math.round(s.timing)}ms`)\n\t\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t})\n\t}\n\n\treturn analyzedFiles.flatMap((f) => f.endpoints)\n}\n\nexport const analyzeSourceFileWithCache = (\n\tfile: DiscoveredSourceFile,\n\tconfig: {\n\t\tincremental: boolean\n\t\tcachePath: string\n\t\ttimestampCache: TimestampCache\n\t\tprofiling?: 'stats' | 'off' | 'debug'\n\t},\n\tfilterEndpointPaths?: string[],\n): { endpoints: EndpointData[]; timing: number; endpointTimings: EndpointTiming[] } => {\n\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache)\n\tconst cachedResults = SourceFileCache.getCachedResults(file.sourceFile, timestamp, config.cachePath)\n\n\tif (cachedResults) {\n\t\tLogger.debug(`[${file.fileName}] Found cached results`)\n\t\treturn { endpoints: cachedResults.endpoints, timing: 0, endpointTimings: [] }\n\t}\n\tLogger.debug(`[${file.fileName}] Analyzing...`)\n\n\tconst t1 = performance.now()\n\tconst { endpoints, endpointTimings } = analyzeSourceFileEndpoints(file, filterEndpointPaths)\n\tconst t2 = performance.now()\n\tLogger.debug(`[${file.fileName}] Analyzed in ${t2 - t1}ms`)\n\tSourceFileCache.cacheResults(file.sourceFile, timestamp, config.cachePath, endpoints)\n\treturn { endpoints, timing: t2 - t1, endpointTimings }\n}\n\nexport const analyzeSourceFileEndpoints = (\n\tfile: DiscoveredSourceFile,\n\tfilterEndpointPaths?: string[],\n): { endpoints: EndpointData[]; endpointTimings: EndpointTiming[] } => {\n\tconst endpoints: EndpointData[] = []\n\tconst endpointTimings: EndpointTiming[] = []\n\tconst operations = ['get', 'post', 'put', 'delete', 'del', 'patch']\n\tconst joinedOperations = operations.join('|')\n\n\tfile.routers.named.forEach((routerName) => {\n\t\tconst routerPattern = new RegExp(`${routerName}\\\\.(?:${joinedOperations})`)\n\t\tfile.sourceFile.forEachChild((node) => {\n\t\t\tconst nodeText = node.getText()\n\n\t\t\tif (routerPattern.test(nodeText)) {\n\t\t\t\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\n\t\t\t\tif (filterEndpointPaths && !filterEndpointPaths.some((path) => endpointPath.includes(path))) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst t1 = performance.now()\n\t\t\t\tconst { endpoint, sectionTimings } = parseEndpoint(node, file.fileName)\n\t\t\t\tendpointTimings.push({\n\t\t\t\t\tmethod: endpoint.method,\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\ttiming: performance.now() - t1,\n\t\t\t\t\tsectionTimings,\n\t\t\t\t})\n\t\t\t\tendpoints.push(endpoint)\n\t\t\t}\n\t\t})\n\t})\n\n\treturn { endpoints, endpointTimings }\n}\n\nexport const analyzeSourceFileApiHeader = (sourceFile: SourceFile): ApiDocsHeader | null => {\n\tconst nameOfUseApiHeader = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useApiHeader',\n\t})\n\n\tif (!nameOfUseApiHeader) {\n\t\treturn null\n\t}\n\n\tconst node = sourceFile\n\t\t.forEachChildAsArray()\n\t\t.filter((node) => node.isKind(SyntaxKind.ExpressionStatement))\n\t\t.find((node) => nameOfUseApiHeader && node.getText().startsWith(nameOfUseApiHeader))\n\n\tif (!node) {\n\t\treturn null\n\t}\n\n\tconst targetNode = node.getFirstDescendantByKindOrThrow(SyntaxKind.ObjectLiteralExpression)\n\tconst values = getValuesOfObjectLiteral(targetNode)\n\n\tconst collapseObject = (v: string | string[] | typeof values): any => {\n\t\tif (typeof v === 'string') {\n\t\t\treturn v\n\t\t}\n\t\tif (Array.isArray(v) && v.every((value) => typeof value === 'string')) {\n\t\t\treturn v\n\t\t}\n\n\t\treturn v.reduce((acc, current) => {\n\t\t\tif (typeof current === 'string') {\n\t\t\t\treturn acc\n\t\t\t}\n\t\t\treturn {\n\t\t\t\t...acc,\n\t\t\t\t[current.identifier]: collapseObject(current.value as string[]),\n\t\t\t}\n\t\t}, {})\n\t}\n\treturn collapseObject(values)\n}\n\nexport const analyzeSourceFileExposedModels = (sourceFile: SourceFile): ExposedModelData[] => {\n\tconst models: ExposedModelData[] = []\n\n\tconst nameOfUseExposeApiModel = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useExposeApiModel',\n\t})\n\n\tconst nameOfUseExposeNamedApiModels = discoverImportedName({\n\t\tsourceFile,\n\t\toriginalName: 'useExposeNamedApiModels',\n\t})\n\n\tsourceFile\n\t\t.forEachChildAsArray()\n\t\t.filter((node) => node.isKind(SyntaxKind.ExpressionStatement))\n\t\t.map((node) => {\n\t\t\tif (nameOfUseExposeApiModel && node.getText().startsWith(nameOfUseExposeApiModel)) {\n\t\t\t\tconst callExpressionNode = node.getFirstChild()\n\t\t\t\tconst syntaxListChildren = callExpressionNode?.getChildrenOfKind(SyntaxKind.SyntaxList) || []\n\n\t\t\t\tconst firstChild = syntaxListChildren[0].getFirstChild()\n\t\t\t\tif (!firstChild) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tmodels.push(parseExposedModel(firstChild))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (nameOfUseExposeNamedApiModels && node.getText().startsWith(nameOfUseExposeNamedApiModels)) {\n\t\t\t\tconst callExpressionNode = node.getFirstChild()\n\t\t\t\tconst syntaxListChildren = callExpressionNode?.getChildrenOfKind(SyntaxKind.SyntaxList) || []\n\n\t\t\t\tconst firstChild = syntaxListChildren[0].getFirstChild()\n\t\t\t\tif (!firstChild) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst parsedModels = parseNamedExposedModels(firstChild)\n\t\t\t\tparsedModels.forEach((model) => models.push(model))\n\t\t\t}\n\t\t})\n\treturn models\n}\n"],"names":["resolveWorkerUrl","candidates","candidate","url","existsSync","fileURLToPath","INLINE_ANALYSIS_FILE_THRESHOLD","prepareOpenApiSpec","logLevel","tsconfigPath","sourceFilePaths","sourceFileDiscovery","incremental","profiling","openApiManager","OpenApiManager","Logger","project","Project","path","explicitRouters","discoveredRouterFiles","allSourceFiles","sourceFiles","filepath","filePath","file","discoverRouters","discoveredSourceFiles","startTime","files","discoverRouterFiles","acc","current","r","filesToAnalyze","apiHeaders","analyzeSourceFileApiHeader","headers","exposedModels","analyzeSourceFileExposedModels","cachePath","endpoints","analyzeMultipleSourceFiles","e","config","filterEndpointPaths","cached","uncached","timestamp","getSourceFileTimestamp","hit","SourceFileCache","f","byFile","endpointTimings","analyzeSourceFileEndpoints","fileResult","sum","t","allTasks","crypto","pool","WorkerPool","results","ft","i","result","fileName","analyzedFiles","a","b","ep","s","joinedOperations","routerName","routerPattern","node","nodeText","resolveEndpointPath","t1","endpoint","sectionTimings","parseEndpoint","sourceFile","nameOfUseApiHeader","discoverImportedName","SyntaxKind","targetNode","values","getValuesOfObjectLiteral","collapseObject","v","value","models","nameOfUseExposeApiModel","nameOfUseExposeNamedApiModels","firstChild","parseExposedModel","parseNamedExposedModels","model"],"mappings":";;;;;;;;;;;;;;;;AAKA,SAASA,IAAwB;AAC1B,QAAAC,IAAa,CAAC,wBAAwB,2BAA2B;AACvE,aAAWC,KAAaD,GAAY;AACnC,UAAME,IAAM,IAAI,IAAID,GAAW,YAAY,GAAG;AAC9C,QAAIE,EAAWC,EAAcF,CAAG,CAAC;AACzB,aAAAA;AAAA,EACR;AAED,QAAM,IAAI;AAAA,IACT;AAAA,EACD;AACD;AA4CA,MAAMG,IAAiC,GAM1BC,KAAqB,OAAO;AAAA,EACxC,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,WAAAC,IAAY;AACb,MAA4B;AACrB,QAAAC,IAAiBC,EAAe,YAAY;AAE9C,MAAAD,EAAe;AAClB;AAGD,EAAIN,KACHQ,EAAO,SAASR,CAAQ,GAGzBQ,EAAO,KAAK,wBAAwB;AAE9B,QAAAC,IAAU,IAAIC,EAAQ;AAAA,IAC3B,kBAAkBC,EAAK,QAAQV,CAAY;AAAA,IAC3C,8BAA8B;AAAA,EAAA,CAC9B,GAEK,EAAE,iBAAAW,GAAiB,uBAAAC,GAAuB,gBAAAC,EAAA,KAAoB,MAAM;AAGnE,UAAAC,KAFmBb,KAAmB,CAAC,GACI,IAAI,CAACc,MAAaL,EAAK,QAAQK,CAAQ,CAAC,EAC7C,IAAI,CAACC,MAAaR,EAAQ,qBAAqBQ,CAAQ,CAAC,GAC9FL,IAAkBG,EAAY,QAAQ,CAACG,OAAU;AAAA,MACtD,UAAUA,EAAK,YAAY;AAAA,MAC3B,YAAYA;AAAA,MACZ,SAASC,EAAgBD,CAAI;AAAA,IAAA,EAC5B,GAEI,EAAE,uBAAAL,GAAuB,uBAAAO,EAAA,KAA2B,MAAM;AAC/D,UAAIjB,MAAwB;AAC3B,eAAO,EAAE,uBAAuB,IAAI,uBAAuB,CAAA,EAAG;AAGzD,YAAAkB,IAAY,YAAY,IAAI,GAC5BC,IAAQC,EAAoB;AAAA,QACjC,YAAY,OAAOpB,KAAwB,WAAWA,EAAoB,WAAW;AAAA,QACrF,cAAcF;AAAA,MAAA,CACd;AACD,aAAII,MAAc,SACVG,EAAA,KAAK,uBAAuB,KAAK,MAAM,YAAY,IAAI,IAAIa,CAAS,CAAC,IAAI,GAE1EC;AAAA,IAAA,GACL,GAEGR,IAAiBC,EAAY;AAAA,MAClC,CAACS,GAAKC,MACLD,EAAI,KAAK,CAACE,MAAMA,EAAE,YAAY,MAAMD,EAAQ,YAAY,CAAC,IAAID,IAAMA,EAAI,OAAOC,CAAO;AAAA,MACtFL;AAAA,IACD;AAEA,WAAO,EAAE,iBAAAR,GAAiB,uBAAAC,GAAuB,gBAAAC,EAAe;AAAA,EAAA,GAC9D,GAEGa,IAAiBf,EAAgB;AAAA,IACtC,CAACY,GAAKC,MAAaD,EAAI,KAAK,CAACE,MAAMA,EAAE,aAAaD,EAAQ,QAAQ,IAAID,IAAMA,EAAI,OAAOC,CAAO;AAAA,IAC9FZ;AAAA,EACD,GAEMe,IAAad,EACjB,QAAQ,CAACI,MAASW,EAA2BX,CAAI,CAAC,EAClD,OAAO,CAACY,MAAY,CAAC,CAACA,CAAO;AAC/B,EAAIF,EAAW,SAAS,KAAKA,EAAW,CAAC,KACzBtB,EAAA,UAAUsB,EAAW,CAAC,CAAC;AAGvC,QAAMG,IAAgBjB,EAAe,QAAQ,CAACI,MAASc,EAA+Bd,CAAI,CAAC;AAE3F,EAAAZ,EAAe,iBAAiByB,CAAa;AAE7C,QAAME,IACD,OAAO7B,KAAgB,YAAYA,EAAY,YAC3CA,EAAY,YAEbO,EAAK,QAAQ,QAAQ,OAAO,gBAAgB,UAAU,YAAY,GAEpEuB,IAAY,MAAMC,EAA2BR,GAAgB;AAAA,IAClE,aAAavB,MAAgB;AAAA,IAC7B,WAAA6B;AAAA,IACA,gBAAgB,CAAC;AAAA,IACjB,WAAA5B;AAAA,IACA,cAAcM,EAAK,QAAQV,CAAY;AAAA,EAAA,CACvC;AAED,EAAAK,EAAe,SAAS;AAAA,IACvB,uBAAuBO,EAAsB,IAAI,CAACK,OAAU;AAAA,MAC3D,MAAMA,EAAK;AAAA,MACX,SAASA,EAAK,QAAQ,MAAM,IAAI,CAACQ,OAAO;AAAA,QACvC,MAAMA;AAAA,QACN,WAAWQ,EACT,OAAO,CAACE,MAAMA,EAAE,mBAAmBlB,EAAK,QAAQ,EAChD,IAAI,CAACkB,MAAM,GAAGA,EAAE,OAAO,aAAa,IAAIA,EAAE,IAAI,EAAE;AAAA,MAAA,EACjD;AAAA,IAAA,EACD;AAAA,IACF,qBAAqBxB,EAAgB,IAAI,CAACM,OAAU;AAAA,MACnD,MAAMA,EAAK;AAAA,MACX,SAASA,EAAK,QAAQ,MAAM,IAAI,CAACQ,OAAO;AAAA,QACvC,MAAMA;AAAA,QACN,WAAWQ,EACT,OAAO,CAACE,MAAMA,EAAE,mBAAmBlB,EAAK,QAAQ,EAChD,IAAI,CAACkB,MAAM,GAAGA,EAAE,OAAO,aAAa,IAAIA,EAAE,IAAI,EAAE;AAAA,MAAA,EACjD;AAAA,IAAA,EACD;AAAA,EAAA,CACF,GAED9B,EAAe,aAAa4B,CAAS,GACrC5B,EAAe,YAAY;AAC5B,GAEa6B,IAA6B,OACzCb,GACAe,GAOAC,MAC6B;AACvB,QAAAjC,IAAYgC,EAAO,aAAa,SAChChB,IAAY,YAAY,IAAI,GAM5BkB,IAAuB,CAAC,GACxBC,IAA2B,CAAC;AAElC,aAAWtB,KAAQI,GAAO;AACzB,UAAMmB,IAAYC,EAAuBxB,EAAK,YAAYmB,EAAO,cAAc,GACzEM,IAAMN,EAAO,cAChBO,EAAgB,iBAAiB1B,EAAK,YAAYuB,GAAWJ,EAAO,SAAS,IAC7E;AACH,IAAIM,KACHnC,EAAO,MAAM,IAAIU,EAAK,QAAQ,wBAAwB,GACtDqB,EAAO,KAAK,EAAE,WAAWI,EAAI,WAAW,UAAUzB,EAAK,UAAU,QAAQ,GAAG,iBAAiB,IAAI,KAEjGsB,EAAS,KAAK,EAAE,MAAAtB,GAAM,WAAAuB,EAAA,CAAW;AAAA,EAClC;AAGG,MAAAD,EAAS,WAAW;AACvB,WAAInC,MAAc,SACVG,EAAA,KAAK,wBAAwB,KAAK,MAAM,YAAY,IAAI,IAAIa,CAAS,CAAC,IAAI,GAE3EkB,EAAO,QAAQ,CAACM,MAAMA,EAAE,SAAS;AAUnC,QAAAC,wBAAa,IAAwB;AAChC,aAAA,EAAE,MAAA5B,EAAK,KAAKsB;AACtB,IAAAM,EAAO,IAAI5B,EAAK,UAAU,EAAE,WAAW,CAAC,GAAG,UAAUA,EAAK,UAAU,QAAQ,GAAG,iBAAiB,IAAI;AAQjG,MAAAsB,EAAS,UAAU1C;AACX,eAAA,EAAE,MAAAoB,EAAK,KAAKsB,GAAU;AAChC,YAAM,EAAE,WAAAN,GAAW,iBAAAa,MAAoBC,EAA2B9B,CAAyB,GACrF+B,IAAaH,EAAO,IAAI5B,EAAK,QAAQ;AAC3C,MAAA+B,EAAW,YAAYf,GACvBe,EAAW,kBAAkBF,GAClBE,EAAA,SAASF,EAAgB,OAAO,CAACG,GAAKC,MAAMD,IAAMC,EAAE,QAAQ,CAAC;AAAA,IAAA;AAAA,OAEnE;AAKN,UAAMC,IAAuBZ,EAAS,IAAI,CAAC,EAAE,MAAAtB,SAAY;AAAA,MACxD,UAAUA,EAAK;AAAA,MACf,MAAM;AAAA,QACL,QAAQmC,EAAO,WAAW;AAAA,QAC1B,cAAchB,EAAO;AAAA,QACrB,gBAAgBnB,EAAK,WAAW,YAAY;AAAA,QAC5C,aAAaA,EAAK,QAAQ;AAAA,QAC1B,qBAAAoB;AAAA,MAAA;AAAA,IACD,EACC,GAEIgB,IAAO,IAAIC,EAAW/D,EAAiB,GAAG4D,EAAS,MAAM;AAC3D,QAAAI;AACA,QAAA;AACO,MAAAA,IAAA,MAAMF,EAAK,OAAOF,EAAS,IAAI,CAACK,MAAOA,EAAG,IAAI,CAAC;AAAA,IAAA,UACxD;AACD,MAAAH,EAAK,UAAU;AAAA,IAAA;AAIhB,aAASI,IAAI,GAAGA,IAAIF,EAAQ,QAAQE,KAAK;AAClC,YAAAC,IAASH,EAAQE,CAAC,GAClBE,IAAWR,EAASM,CAAC,EAAE,UACvBT,IAAaH,EAAO,IAAIc,CAAQ;AAEtC,UAAI,WAAWD,GAAQ;AACtB,QAAAnD,EAAO,MAAM,IAAIoD,CAAQ,mBAAmBD,EAAO,KAAK,EAAE;AAC1D;AAAA,MAAA;AAGD,MAAAV,EAAW,YAAYU,EAAO,WAC9BV,EAAW,kBAAkBU,EAAO,iBACzBV,EAAA,SAASU,EAAO,gBAAgB,OAAO,CAACT,GAAKC,MAAMD,IAAMC,EAAE,QAAQ,CAAC;AAAA,IAAA;AAAA,EAChF;AAID,aAAW,EAAE,MAAAjC,GAAM,WAAAuB,EAAU,KAAKD,GAAU;AAC3C,UAAMS,IAAaH,EAAO,IAAI5B,EAAK,QAAQ;AACvC,IAAA+B,EAAW,UAAU,SAAS,KACjCL,EAAgB,aAAa1B,EAAK,YAAYuB,GAAWJ,EAAO,WAAWY,EAAW,SAAS;AAAA,EAChG;AAGK,QAAAY,IAAgB,CAAC,GAAGtB,GAAQ,GAAG,MAAM,KAAKO,EAAO,OAAO,CAAC,CAAC;AAEhE,SAAIzC,MAAc,SACVG,EAAA,KAAK,wBAAwB,KAAK,MAAM,YAAY,IAAI,IAAIa,CAAS,CAAC,IAAI,GAG9EhB,MAAc,UACjBwD,EACE,IAAI,CAAChB,OAAO,EAAE,UAAUA,EAAE,UAAU,WAAWA,EAAE,OAAS,EAAA,EAC1D,KAAK,CAACiB,GAAGC,MAAMA,EAAE,YAAYD,EAAE,SAAS,EACxC,OAAO,CAACX,MAAMA,EAAE,YAAY,GAAG,EAC/B,QAAQ,CAACA,MAAM;AACR,IAAA3C,EAAA,KAAK,MAAM2C,EAAE,QAAQ,UAAU,KAAK,MAAMA,EAAE,SAAS,CAAC,eAAe;AAAA,EAAA,CAC5E,IACQ9C,MAAc,WAEtBwD,EAAA,IAAI,CAAChB,OAAO,EAAE,UAAUA,EAAE,UAAU,WAAWA,EAAE,QAAQ,iBAAiBA,EAAE,kBAAkB,EAC9F,KAAK,CAACiB,GAAGC,MAAMA,EAAE,YAAYD,EAAE,SAAS,EACxC,QAAQ,CAACX,MAAM;AACR,IAAA3C,EAAA,KAAK,MAAM2C,EAAE,QAAQ,UAAU,KAAK,MAAMA,EAAE,SAAS,CAAC,eAAe,GAC5EA,EAAE,gBACA,KAAK,CAACW,GAAGC,MAAMA,EAAE,SAASD,EAAE,MAAM,EAClC,QAAQ,CAACE,MAAO;AAChB,MAAAxD,EAAO,KAAK,OAAOwD,EAAG,MAAM,IAAIA,EAAG,IAAI,KAAK,KAAK,MAAMA,EAAG,MAAM,CAAC,KAAK,GACtEA,EAAG,eACD,OAAO,CAACC,MAAMA,EAAE,UAAU,CAAC,EAC3B,KAAK,CAACH,GAAGC,MAAMA,EAAE,SAASD,EAAE,MAAM,EAClC,QAAQ,CAACG,MAAM;AACR,QAAAzD,EAAA,KAAK,SAASyD,EAAE,OAAO,KAAK,KAAK,MAAMA,EAAE,MAAM,CAAC,IAAI;AAAA,MAAA,CAC3D;AAAA,IAAA,CACF;AAAA,EAAA,CACF,GAGIJ,EAAc,QAAQ,CAAChB,MAAMA,EAAE,SAAS;AAChD,GA6BaG,IAA6B,CACzC9B,GACAoB,MACsE;AACtE,QAAMJ,IAA4B,CAAC,GAC7Ba,IAAoC,CAAC,GAErCmB,IADa,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,OAAO,EAC9B,KAAK,GAAG;AAE5C,SAAAhD,EAAK,QAAQ,MAAM,QAAQ,CAACiD,MAAe;AAC1C,UAAMC,IAAgB,IAAI,OAAO,GAAGD,CAAU,SAASD,CAAgB,GAAG;AACrE,IAAAhD,EAAA,WAAW,aAAa,CAACmD,MAAS;AAChC,YAAAC,IAAWD,EAAK,QAAQ;AAE1B,UAAAD,EAAc,KAAKE,CAAQ,GAAG;AACZ,QAAAC,EAAoBF,CAAI;AAMvC,cAAAG,IAAK,YAAY,IAAI,GACrB,EAAE,UAAAC,GAAU,gBAAAC,MAAmBC,EAAcN,GAAMnD,EAAK,QAAQ;AACtE,QAAA6B,EAAgB,KAAK;AAAA,UACpB,QAAQ0B,EAAS;AAAA,UACjB,MAAMA,EAAS;AAAA,UACf,QAAQ,YAAY,IAAA,IAAQD;AAAA,UAC5B,gBAAAE;AAAA,QAAA,CACA,GACDxC,EAAU,KAAKuC,CAAQ;AAAA,MAAA;AAAA,IACxB,CACA;AAAA,EAAA,CACD,GAEM,EAAE,WAAAvC,GAAW,iBAAAa,EAAgB;AACrC,GAEalB,IAA6B,CAAC+C,MAAiD;AAC3F,QAAMC,IAAqBC,EAAqB;AAAA,IAC/C,YAAAF;AAAA,IACA,cAAc;AAAA,EAAA,CACd;AAED,MAAI,CAACC;AACG,WAAA;AAGF,QAAAR,IAAOO,EACX,oBAAoB,EACpB,OAAO,CAACP,MAASA,EAAK,OAAOU,EAAW,mBAAmB,CAAC,EAC5D,KAAK,CAACV,MAASQ,KAAsBR,EAAK,QAAQ,EAAE,WAAWQ,CAAkB,CAAC;AAEpF,MAAI,CAACR;AACG,WAAA;AAGR,QAAMW,IAAaX,EAAK,gCAAgCU,EAAW,uBAAuB,GACpFE,IAASC,EAAyBF,CAAU,GAE5CG,IAAiB,CAACC,MACnB,OAAOA,KAAM,YAGb,MAAM,QAAQA,CAAC,KAAKA,EAAE,MAAM,CAACC,MAAU,OAAOA,KAAU,QAAQ,IAC5DD,IAGDA,EAAE,OAAO,CAAC5D,GAAKC,MACjB,OAAOA,KAAY,WACfD,IAED;AAAA,IACN,GAAGA;AAAA,IACH,CAACC,EAAQ,UAAU,GAAG0D,EAAe1D,EAAQ,KAAiB;AAAA,EAC/D,GACE,EAAE;AAEN,SAAO0D,EAAeF,CAAM;AAC7B,GAEajD,IAAiC,CAAC4C,MAA+C;AAC7F,QAAMU,IAA6B,CAAC,GAE9BC,IAA0BT,EAAqB;AAAA,IACpD,YAAAF;AAAA,IACA,cAAc;AAAA,EAAA,CACd,GAEKY,IAAgCV,EAAqB;AAAA,IAC1D,YAAAF;AAAA,IACA,cAAc;AAAA,EAAA,CACd;AAED,SAAAA,EACE,oBAAoB,EACpB,OAAO,CAACP,MAASA,EAAK,OAAOU,EAAW,mBAAmB,CAAC,EAC5D,IAAI,CAACV,MAAS;AACd,QAAIkB,KAA2BlB,EAAK,QAAU,EAAA,WAAWkB,CAAuB,GAAG;AAIlF,YAAME,KAHqBpB,EAAK,cAAc,GACC,kBAAkBU,EAAW,UAAU,KAAK,CAAC,GAEtD,CAAC,EAAE,cAAc;AACvD,UAAI,CAACU;AACJ;AAGM,MAAAH,EAAA,KAAKI,EAAkBD,CAAU,CAAC;AACzC;AAAA,IAAA;AAGD,QAAID,KAAiCnB,EAAK,QAAU,EAAA,WAAWmB,CAA6B,GAAG;AAI9F,YAAMC,KAHqBpB,EAAK,cAAc,GACC,kBAAkBU,EAAW,UAAU,KAAK,CAAC,GAEtD,CAAC,EAAE,cAAc;AACvD,UAAI,CAACU;AACJ;AAID,MADqBE,EAAwBF,CAAU,EAC1C,QAAQ,CAACG,MAAUN,EAAO,KAAKM,CAAK,CAAC;AAAA,IAAA;AAAA,EACnD,CACA,GACKN;AACR;"}
@@ -1,2 +1,2 @@
1
- "use strict";const g=require("ts-morph"),i=require("worker_threads"),f=require("./parseEndpoint.cjs"),h=["get","post","put","delete","del","patch"],I=h.join("|");let s=null,u=null;function F(e){return(!s||u!==e)&&(s=new g.Project({tsConfigFilePath:e,skipFileDependencyResolution:!0}),u=e),s}i.parentPort.on("message",e=>{try{const r=F(e.tsconfigPath);let t=r.getSourceFile(e.sourceFilePath);t||(t=r.addSourceFileAtPath(e.sourceFilePath));const p=new RegExp(`${e.routerName}\\.(?:${I})`);let c=0,n;if(t.forEachChild(o=>{n||p.test(o.getText())&&(c===e.endpointIndex&&(n=o),c++)}),!n){const o={taskId:e.taskId,error:`Endpoint not found: routerName=${e.routerName} index=${e.endpointIndex} in ${e.sourceFilePath}`};i.parentPort.postMessage(o);return}const l=performance.now(),{endpoint:d,sectionTimings:a}=f.parseEndpoint(n,e.sourceFilePath),P={taskId:e.taskId,endpoint:d,sectionTimings:a,timing:performance.now()-l};i.parentPort.postMessage(P)}catch(r){const t={taskId:e.taskId,error:String(r)};i.parentPort.postMessage(t)}});
1
+ "use strict";const E=require("ts-morph"),s=require("worker_threads"),m=require("./nodeParsers.cjs"),F=require("./parseEndpoint.cjs"),T=["get","post","put","delete","del","patch"],I=T.join("|");let i=null,u=null;function j(e){return(!i||u!==e)&&(i=new E.Project({tsConfigFilePath:e,skipFileDependencyResolution:!0}),u=e),i}s.parentPort.on("message",e=>{try{const r=j(e.tsconfigPath);let t=r.getSourceFile(e.sourceFilePath);t||(t=r.addSourceFileAtPath(e.sourceFilePath));const c=[],p=[];e.routerNames.forEach(l=>{const d=new RegExp(`${l}\\.(?:${I})`);t.forEachChild(n=>{if(!d.test(n.getText()))return;if(e.filterEndpointPaths){const f=m.resolveEndpointPath(n)??"";if(!e.filterEndpointPaths.some(g=>f.includes(g)))return}const h=performance.now(),{endpoint:o,sectionTimings:P}=F.parseEndpoint(n,e.sourceFilePath);p.push({method:o.method,path:o.path,timing:performance.now()-h,sectionTimings:P}),c.push(o)})});const a={taskId:e.taskId,endpoints:c,endpointTimings:p};s.parentPort.postMessage(a)}catch(r){const t={taskId:e.taskId,error:String(r)};s.parentPort.postMessage(t)}});
2
2
  //# sourceMappingURL=analyzerWorker.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyzerWorker.cjs","sources":["../../../src/openapi/analyzerModule/analyzerWorker.ts"],"sourcesContent":["import { Node, Project, ts } from 'ts-morph'\nimport { parentPort } from 'worker_threads'\n\nimport { parseEndpoint } from './parseEndpoint'\nimport { WorkerResult, WorkerTask } from './workerPool'\n\nconst OPERATIONS = ['get', 'post', 'put', 'delete', 'del', 'patch']\nconst OPERATIONS_PATTERN = OPERATIONS.join('|')\n\nlet project: Project | null = null\nlet currentTsconfigPath: string | null = null\n\nfunction getProject(tsconfigPath: string): Project {\n\tif (!project || currentTsconfigPath !== tsconfigPath) {\n\t\tproject = new Project({\n\t\t\ttsConfigFilePath: tsconfigPath,\n\t\t\tskipFileDependencyResolution: true,\n\t\t})\n\t\tcurrentTsconfigPath = tsconfigPath\n\t}\n\treturn project\n}\n\nparentPort!.on('message', (task: WorkerTask) => {\n\ttry {\n\t\tconst proj = getProject(task.tsconfigPath)\n\n\t\tlet sourceFile = proj.getSourceFile(task.sourceFilePath)\n\t\tif (!sourceFile) {\n\t\t\tsourceFile = proj.addSourceFileAtPath(task.sourceFilePath)\n\t\t}\n\n\t\tconst routerPattern = new RegExp(`${task.routerName}\\\\.(?:${OPERATIONS_PATTERN})`)\n\t\tlet index = 0\n\t\tlet targetNode: Node<ts.Node> | undefined\n\n\t\tsourceFile.forEachChild((node) => {\n\t\t\tif (targetNode) return\n\t\t\tif (routerPattern.test(node.getText())) {\n\t\t\t\tif (index === task.endpointIndex) {\n\t\t\t\t\ttargetNode = node\n\t\t\t\t}\n\t\t\t\tindex++\n\t\t\t}\n\t\t})\n\n\t\tif (!targetNode) {\n\t\t\tconst result: WorkerResult = {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\terror: `Endpoint not found: routerName=${task.routerName} index=${task.endpointIndex} in ${task.sourceFilePath}`,\n\t\t\t}\n\t\t\tparentPort!.postMessage(result)\n\t\t\treturn\n\t\t}\n\n\t\tconst t1 = performance.now()\n\t\tconst { endpoint, sectionTimings } = parseEndpoint(targetNode, task.sourceFilePath)\n\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\tendpoint,\n\t\t\tsectionTimings,\n\t\t\ttiming: performance.now() - t1,\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t} catch (err) {\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\terror: String(err),\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t}\n})\n"],"names":["OPERATIONS","OPERATIONS_PATTERN","project","currentTsconfigPath","getProject","tsconfigPath","Project","parentPort","task","proj","sourceFile","routerPattern","index","targetNode","node","result","t1","endpoint","sectionTimings","parseEndpoint","err"],"mappings":"sGAMMA,EAAa,CAAC,MAAO,OAAQ,MAAO,SAAU,MAAO,OAAO,EAC5DC,EAAqBD,EAAW,KAAK,GAAG,EAE9C,IAAIE,EAA0B,KAC1BC,EAAqC,KAEzC,SAASC,EAAWC,EAA+B,CAC9C,OAAA,CAACH,GAAWC,IAAwBE,KACvCH,EAAU,IAAII,EAAAA,QAAQ,CACrB,iBAAkBD,EAClB,6BAA8B,EAAA,CAC9B,EACqBF,EAAAE,GAEhBH,CACR,CAEAK,EAAAA,WAAY,GAAG,UAAYC,GAAqB,CAC3C,GAAA,CACG,MAAAC,EAAOL,EAAWI,EAAK,YAAY,EAEzC,IAAIE,EAAaD,EAAK,cAAcD,EAAK,cAAc,EAClDE,IACSA,EAAAD,EAAK,oBAAoBD,EAAK,cAAc,GAGpD,MAAAG,EAAgB,IAAI,OAAO,GAAGH,EAAK,UAAU,SAASP,CAAkB,GAAG,EACjF,IAAIW,EAAQ,EACRC,EAYJ,GAVWH,EAAA,aAAcI,GAAS,CAC7BD,GACAF,EAAc,KAAKG,EAAK,QAAS,CAAA,IAChCF,IAAUJ,EAAK,gBACLK,EAAAC,GAEdF,IACD,CACA,EAEG,CAACC,EAAY,CAChB,MAAME,EAAuB,CAC5B,OAAQP,EAAK,OACb,MAAO,kCAAkCA,EAAK,UAAU,UAAUA,EAAK,aAAa,OAAOA,EAAK,cAAc,EAC/G,EACAD,EAAA,WAAY,YAAYQ,CAAM,EAC9B,MAAA,CAGK,MAAAC,EAAK,YAAY,IAAI,EACrB,CAAE,SAAAC,EAAU,eAAAC,GAAmBC,EAAc,cAAAN,EAAYL,EAAK,cAAc,EAE5EO,EAAuB,CAC5B,OAAQP,EAAK,OACb,SAAAS,EACA,eAAAC,EACA,OAAQ,YAAY,MAAQF,CAC7B,EACAT,EAAA,WAAY,YAAYQ,CAAM,QACtBK,EAAK,CACb,MAAML,EAAuB,CAC5B,OAAQP,EAAK,OACb,MAAO,OAAOY,CAAG,CAClB,EACAb,EAAA,WAAY,YAAYQ,CAAM,CAAA,CAEhC,CAAC"}
1
+ {"version":3,"file":"analyzerWorker.cjs","sources":["../../../src/openapi/analyzerModule/analyzerWorker.ts"],"sourcesContent":["import { Project } from 'ts-morph'\nimport { parentPort } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { resolveEndpointPath } from './nodeParsers'\nimport { parseEndpoint } from './parseEndpoint'\nimport { EndpointTiming, WorkerResult, WorkerTask } from './workerPool'\n\nconst OPERATIONS = ['get', 'post', 'put', 'delete', 'del', 'patch']\nconst OPERATIONS_PATTERN = OPERATIONS.join('|')\n\nlet project: Project | null = null\nlet currentTsconfigPath: string | null = null\n\nfunction getProject(tsconfigPath: string): Project {\n\tif (!project || currentTsconfigPath !== tsconfigPath) {\n\t\tproject = new Project({\n\t\t\ttsConfigFilePath: tsconfigPath,\n\t\t\tskipFileDependencyResolution: true,\n\t\t})\n\t\tcurrentTsconfigPath = tsconfigPath\n\t}\n\treturn project\n}\n\nparentPort!.on('message', (task: WorkerTask) => {\n\ttry {\n\t\tconst proj = getProject(task.tsconfigPath)\n\n\t\tlet sourceFile = proj.getSourceFile(task.sourceFilePath)\n\t\tif (!sourceFile) {\n\t\t\tsourceFile = proj.addSourceFileAtPath(task.sourceFilePath)\n\t\t}\n\n\t\tconst endpoints: EndpointData[] = []\n\t\tconst endpointTimings: EndpointTiming[] = []\n\n\t\ttask.routerNames.forEach((routerName) => {\n\t\t\tconst routerPattern = new RegExp(`${routerName}\\\\.(?:${OPERATIONS_PATTERN})`)\n\t\t\tsourceFile!.forEachChild((node) => {\n\t\t\t\tif (!routerPattern.test(node.getText())) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (task.filterEndpointPaths) {\n\t\t\t\t\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\t\t\t\t\tif (!task.filterEndpointPaths.some((p) => endpointPath.includes(p))) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst t1 = performance.now()\n\t\t\t\tconst { endpoint, sectionTimings } = parseEndpoint(node, task.sourceFilePath)\n\t\t\t\tendpointTimings.push({\n\t\t\t\t\tmethod: endpoint.method,\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\ttiming: performance.now() - t1,\n\t\t\t\t\tsectionTimings,\n\t\t\t\t})\n\t\t\t\tendpoints.push(endpoint)\n\t\t\t})\n\t\t})\n\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\tendpoints,\n\t\t\tendpointTimings,\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t} catch (err) {\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\terror: String(err),\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t}\n})\n"],"names":["OPERATIONS","OPERATIONS_PATTERN","project","currentTsconfigPath","getProject","tsconfigPath","Project","parentPort","task","proj","sourceFile","endpoints","endpointTimings","routerName","routerPattern","node","endpointPath","resolveEndpointPath","p","t1","endpoint","sectionTimings","parseEndpoint","result","err"],"mappings":"qIAQMA,EAAa,CAAC,MAAO,OAAQ,MAAO,SAAU,MAAO,OAAO,EAC5DC,EAAqBD,EAAW,KAAK,GAAG,EAE9C,IAAIE,EAA0B,KAC1BC,EAAqC,KAEzC,SAASC,EAAWC,EAA+B,CAC9C,OAAA,CAACH,GAAWC,IAAwBE,KACvCH,EAAU,IAAII,EAAAA,QAAQ,CACrB,iBAAkBD,EAClB,6BAA8B,EAAA,CAC9B,EACqBF,EAAAE,GAEhBH,CACR,CAEAK,EAAAA,WAAY,GAAG,UAAYC,GAAqB,CAC3C,GAAA,CACG,MAAAC,EAAOL,EAAWI,EAAK,YAAY,EAEzC,IAAIE,EAAaD,EAAK,cAAcD,EAAK,cAAc,EAClDE,IACSA,EAAAD,EAAK,oBAAoBD,EAAK,cAAc,GAG1D,MAAMG,EAA4B,CAAC,EAC7BC,EAAoC,CAAC,EAEtCJ,EAAA,YAAY,QAASK,GAAe,CACxC,MAAMC,EAAgB,IAAI,OAAO,GAAGD,CAAU,SAASZ,CAAkB,GAAG,EAChES,EAAA,aAAcK,GAAS,CAClC,GAAI,CAACD,EAAc,KAAKC,EAAK,QAAS,CAAA,EACrC,OAGD,GAAIP,EAAK,oBAAqB,CACvB,MAAAQ,EAAeC,EAAAA,oBAAoBF,CAAI,GAAK,GAC9C,GAAA,CAACP,EAAK,oBAAoB,KAAMU,GAAMF,EAAa,SAASE,CAAC,CAAC,EACjE,MACD,CAGK,MAAAC,EAAK,YAAY,IAAI,EACrB,CAAE,SAAAC,EAAU,eAAAC,GAAmBC,EAAc,cAAAP,EAAMP,EAAK,cAAc,EAC5EI,EAAgB,KAAK,CACpB,OAAQQ,EAAS,OACjB,KAAMA,EAAS,KACf,OAAQ,YAAY,IAAA,EAAQD,EAC5B,eAAAE,CAAA,CACA,EACDV,EAAU,KAAKS,CAAQ,CAAA,CACvB,CAAA,CACD,EAED,MAAMG,EAAuB,CAC5B,OAAQf,EAAK,OACb,UAAAG,EACA,gBAAAC,CACD,EACAL,EAAA,WAAY,YAAYgB,CAAM,QACtBC,EAAK,CACb,MAAMD,EAAuB,CAC5B,OAAQf,EAAK,OACb,MAAO,OAAOgB,CAAG,CAClB,EACAjB,EAAA,WAAY,YAAYgB,CAAM,CAAA,CAEhC,CAAC"}
@@ -1,44 +1,52 @@
1
1
  import { Project as g } from "ts-morph";
2
2
  import { parentPort as i } from "worker_threads";
3
- import { parseEndpoint as m } from "./parseEndpoint.mjs";
4
- const P = ["get", "post", "put", "delete", "del", "patch"], h = P.join("|");
3
+ import { resolveEndpointPath as E } from "./nodeParsers.mjs";
4
+ import { parseEndpoint as F } from "./parseEndpoint.mjs";
5
+ const T = ["get", "post", "put", "delete", "del", "patch"], I = T.join("|");
5
6
  let s = null, l = null;
6
- function I(e) {
7
- return (!s || l !== e) && (s = new g({
8
- tsConfigFilePath: e,
7
+ function j(t) {
8
+ return (!s || l !== t) && (s = new g({
9
+ tsConfigFilePath: t,
9
10
  skipFileDependencyResolution: !0
10
- }), l = e), s;
11
+ }), l = t), s;
11
12
  }
12
- i.on("message", (e) => {
13
+ i.on("message", (t) => {
13
14
  try {
14
- const r = I(e.tsconfigPath);
15
- let t = r.getSourceFile(e.sourceFilePath);
16
- t || (t = r.addSourceFileAtPath(e.sourceFilePath));
17
- const u = new RegExp(`${e.routerName}\\.(?:${h})`);
18
- let c = 0, o;
19
- if (t.forEachChild((n) => {
20
- o || u.test(n.getText()) && (c === e.endpointIndex && (o = n), c++);
21
- }), !o) {
22
- const n = {
23
- taskId: e.taskId,
24
- error: `Endpoint not found: routerName=${e.routerName} index=${e.endpointIndex} in ${e.sourceFilePath}`
25
- };
26
- i.postMessage(n);
27
- return;
28
- }
29
- const p = performance.now(), { endpoint: d, sectionTimings: a } = m(o, e.sourceFilePath), f = {
30
- taskId: e.taskId,
31
- endpoint: d,
32
- sectionTimings: a,
33
- timing: performance.now() - p
15
+ const o = j(t.tsconfigPath);
16
+ let e = o.getSourceFile(t.sourceFilePath);
17
+ e || (e = o.addSourceFileAtPath(t.sourceFilePath));
18
+ const c = [], p = [];
19
+ t.routerNames.forEach((a) => {
20
+ const h = new RegExp(`${a}\\.(?:${I})`);
21
+ e.forEachChild((n) => {
22
+ if (!h.test(n.getText()))
23
+ return;
24
+ if (t.filterEndpointPaths) {
25
+ const f = E(n) ?? "";
26
+ if (!t.filterEndpointPaths.some((P) => f.includes(P)))
27
+ return;
28
+ }
29
+ const d = performance.now(), { endpoint: r, sectionTimings: m } = F(n, t.sourceFilePath);
30
+ p.push({
31
+ method: r.method,
32
+ path: r.path,
33
+ timing: performance.now() - d,
34
+ sectionTimings: m
35
+ }), c.push(r);
36
+ });
37
+ });
38
+ const u = {
39
+ taskId: t.taskId,
40
+ endpoints: c,
41
+ endpointTimings: p
34
42
  };
35
- i.postMessage(f);
36
- } catch (r) {
37
- const t = {
38
- taskId: e.taskId,
39
- error: String(r)
43
+ i.postMessage(u);
44
+ } catch (o) {
45
+ const e = {
46
+ taskId: t.taskId,
47
+ error: String(o)
40
48
  };
41
- i.postMessage(t);
49
+ i.postMessage(e);
42
50
  }
43
51
  });
44
52
  //# sourceMappingURL=analyzerWorker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyzerWorker.mjs","sources":["../../../src/openapi/analyzerModule/analyzerWorker.ts"],"sourcesContent":["import { Node, Project, ts } from 'ts-morph'\nimport { parentPort } from 'worker_threads'\n\nimport { parseEndpoint } from './parseEndpoint'\nimport { WorkerResult, WorkerTask } from './workerPool'\n\nconst OPERATIONS = ['get', 'post', 'put', 'delete', 'del', 'patch']\nconst OPERATIONS_PATTERN = OPERATIONS.join('|')\n\nlet project: Project | null = null\nlet currentTsconfigPath: string | null = null\n\nfunction getProject(tsconfigPath: string): Project {\n\tif (!project || currentTsconfigPath !== tsconfigPath) {\n\t\tproject = new Project({\n\t\t\ttsConfigFilePath: tsconfigPath,\n\t\t\tskipFileDependencyResolution: true,\n\t\t})\n\t\tcurrentTsconfigPath = tsconfigPath\n\t}\n\treturn project\n}\n\nparentPort!.on('message', (task: WorkerTask) => {\n\ttry {\n\t\tconst proj = getProject(task.tsconfigPath)\n\n\t\tlet sourceFile = proj.getSourceFile(task.sourceFilePath)\n\t\tif (!sourceFile) {\n\t\t\tsourceFile = proj.addSourceFileAtPath(task.sourceFilePath)\n\t\t}\n\n\t\tconst routerPattern = new RegExp(`${task.routerName}\\\\.(?:${OPERATIONS_PATTERN})`)\n\t\tlet index = 0\n\t\tlet targetNode: Node<ts.Node> | undefined\n\n\t\tsourceFile.forEachChild((node) => {\n\t\t\tif (targetNode) return\n\t\t\tif (routerPattern.test(node.getText())) {\n\t\t\t\tif (index === task.endpointIndex) {\n\t\t\t\t\ttargetNode = node\n\t\t\t\t}\n\t\t\t\tindex++\n\t\t\t}\n\t\t})\n\n\t\tif (!targetNode) {\n\t\t\tconst result: WorkerResult = {\n\t\t\t\ttaskId: task.taskId,\n\t\t\t\terror: `Endpoint not found: routerName=${task.routerName} index=${task.endpointIndex} in ${task.sourceFilePath}`,\n\t\t\t}\n\t\t\tparentPort!.postMessage(result)\n\t\t\treturn\n\t\t}\n\n\t\tconst t1 = performance.now()\n\t\tconst { endpoint, sectionTimings } = parseEndpoint(targetNode, task.sourceFilePath)\n\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\tendpoint,\n\t\t\tsectionTimings,\n\t\t\ttiming: performance.now() - t1,\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t} catch (err) {\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\terror: String(err),\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t}\n})\n"],"names":["OPERATIONS","OPERATIONS_PATTERN","project","currentTsconfigPath","getProject","tsconfigPath","Project","parentPort","task","proj","sourceFile","routerPattern","index","targetNode","node","result","t1","endpoint","sectionTimings","parseEndpoint","err"],"mappings":";;;AAMA,MAAMA,IAAa,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,OAAO,GAC5DC,IAAqBD,EAAW,KAAK,GAAG;AAE9C,IAAIE,IAA0B,MAC1BC,IAAqC;AAEzC,SAASC,EAAWC,GAA+B;AAC9C,UAAA,CAACH,KAAWC,MAAwBE,OACvCH,IAAU,IAAII,EAAQ;AAAA,IACrB,kBAAkBD;AAAA,IAClB,8BAA8B;AAAA,EAAA,CAC9B,GACqBF,IAAAE,IAEhBH;AACR;AAEAK,EAAY,GAAG,WAAW,CAACC,MAAqB;AAC3C,MAAA;AACG,UAAAC,IAAOL,EAAWI,EAAK,YAAY;AAEzC,QAAIE,IAAaD,EAAK,cAAcD,EAAK,cAAc;AACvD,IAAKE,MACSA,IAAAD,EAAK,oBAAoBD,EAAK,cAAc;AAGpD,UAAAG,IAAgB,IAAI,OAAO,GAAGH,EAAK,UAAU,SAASP,CAAkB,GAAG;AACjF,QAAIW,IAAQ,GACRC;AAYJ,QAVWH,EAAA,aAAa,CAACI,MAAS;AACjC,MAAID,KACAF,EAAc,KAAKG,EAAK,QAAS,CAAA,MAChCF,MAAUJ,EAAK,kBACLK,IAAAC,IAEdF;AAAA,IACD,CACA,GAEG,CAACC,GAAY;AAChB,YAAME,IAAuB;AAAA,QAC5B,QAAQP,EAAK;AAAA,QACb,OAAO,kCAAkCA,EAAK,UAAU,UAAUA,EAAK,aAAa,OAAOA,EAAK,cAAc;AAAA,MAC/G;AACA,MAAAD,EAAY,YAAYQ,CAAM;AAC9B;AAAA,IAAA;AAGK,UAAAC,IAAK,YAAY,IAAI,GACrB,EAAE,UAAAC,GAAU,gBAAAC,MAAmBC,EAAcN,GAAYL,EAAK,cAAc,GAE5EO,IAAuB;AAAA,MAC5B,QAAQP,EAAK;AAAA,MACb,UAAAS;AAAA,MACA,gBAAAC;AAAA,MACA,QAAQ,YAAY,QAAQF;AAAA,IAC7B;AACA,IAAAT,EAAY,YAAYQ,CAAM;AAAA,WACtBK,GAAK;AACb,UAAML,IAAuB;AAAA,MAC5B,QAAQP,EAAK;AAAA,MACb,OAAO,OAAOY,CAAG;AAAA,IAClB;AACA,IAAAb,EAAY,YAAYQ,CAAM;AAAA,EAAA;AAEhC,CAAC;"}
1
+ {"version":3,"file":"analyzerWorker.mjs","sources":["../../../src/openapi/analyzerModule/analyzerWorker.ts"],"sourcesContent":["import { Project } from 'ts-morph'\nimport { parentPort } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { resolveEndpointPath } from './nodeParsers'\nimport { parseEndpoint } from './parseEndpoint'\nimport { EndpointTiming, WorkerResult, WorkerTask } from './workerPool'\n\nconst OPERATIONS = ['get', 'post', 'put', 'delete', 'del', 'patch']\nconst OPERATIONS_PATTERN = OPERATIONS.join('|')\n\nlet project: Project | null = null\nlet currentTsconfigPath: string | null = null\n\nfunction getProject(tsconfigPath: string): Project {\n\tif (!project || currentTsconfigPath !== tsconfigPath) {\n\t\tproject = new Project({\n\t\t\ttsConfigFilePath: tsconfigPath,\n\t\t\tskipFileDependencyResolution: true,\n\t\t})\n\t\tcurrentTsconfigPath = tsconfigPath\n\t}\n\treturn project\n}\n\nparentPort!.on('message', (task: WorkerTask) => {\n\ttry {\n\t\tconst proj = getProject(task.tsconfigPath)\n\n\t\tlet sourceFile = proj.getSourceFile(task.sourceFilePath)\n\t\tif (!sourceFile) {\n\t\t\tsourceFile = proj.addSourceFileAtPath(task.sourceFilePath)\n\t\t}\n\n\t\tconst endpoints: EndpointData[] = []\n\t\tconst endpointTimings: EndpointTiming[] = []\n\n\t\ttask.routerNames.forEach((routerName) => {\n\t\t\tconst routerPattern = new RegExp(`${routerName}\\\\.(?:${OPERATIONS_PATTERN})`)\n\t\t\tsourceFile!.forEachChild((node) => {\n\t\t\t\tif (!routerPattern.test(node.getText())) {\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (task.filterEndpointPaths) {\n\t\t\t\t\tconst endpointPath = resolveEndpointPath(node) ?? ''\n\t\t\t\t\tif (!task.filterEndpointPaths.some((p) => endpointPath.includes(p))) {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst t1 = performance.now()\n\t\t\t\tconst { endpoint, sectionTimings } = parseEndpoint(node, task.sourceFilePath)\n\t\t\t\tendpointTimings.push({\n\t\t\t\t\tmethod: endpoint.method,\n\t\t\t\t\tpath: endpoint.path,\n\t\t\t\t\ttiming: performance.now() - t1,\n\t\t\t\t\tsectionTimings,\n\t\t\t\t})\n\t\t\t\tendpoints.push(endpoint)\n\t\t\t})\n\t\t})\n\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\tendpoints,\n\t\t\tendpointTimings,\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t} catch (err) {\n\t\tconst result: WorkerResult = {\n\t\t\ttaskId: task.taskId,\n\t\t\terror: String(err),\n\t\t}\n\t\tparentPort!.postMessage(result)\n\t}\n})\n"],"names":["OPERATIONS","OPERATIONS_PATTERN","project","currentTsconfigPath","getProject","tsconfigPath","Project","parentPort","task","proj","sourceFile","endpoints","endpointTimings","routerName","routerPattern","node","endpointPath","resolveEndpointPath","p","t1","endpoint","sectionTimings","parseEndpoint","result","err"],"mappings":";;;;AAQA,MAAMA,IAAa,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,OAAO,GAC5DC,IAAqBD,EAAW,KAAK,GAAG;AAE9C,IAAIE,IAA0B,MAC1BC,IAAqC;AAEzC,SAASC,EAAWC,GAA+B;AAC9C,UAAA,CAACH,KAAWC,MAAwBE,OACvCH,IAAU,IAAII,EAAQ;AAAA,IACrB,kBAAkBD;AAAA,IAClB,8BAA8B;AAAA,EAAA,CAC9B,GACqBF,IAAAE,IAEhBH;AACR;AAEAK,EAAY,GAAG,WAAW,CAACC,MAAqB;AAC3C,MAAA;AACG,UAAAC,IAAOL,EAAWI,EAAK,YAAY;AAEzC,QAAIE,IAAaD,EAAK,cAAcD,EAAK,cAAc;AACvD,IAAKE,MACSA,IAAAD,EAAK,oBAAoBD,EAAK,cAAc;AAG1D,UAAMG,IAA4B,CAAC,GAC7BC,IAAoC,CAAC;AAEtC,IAAAJ,EAAA,YAAY,QAAQ,CAACK,MAAe;AACxC,YAAMC,IAAgB,IAAI,OAAO,GAAGD,CAAU,SAASZ,CAAkB,GAAG;AAChE,MAAAS,EAAA,aAAa,CAACK,MAAS;AAClC,YAAI,CAACD,EAAc,KAAKC,EAAK,QAAS,CAAA;AACrC;AAGD,YAAIP,EAAK,qBAAqB;AACvB,gBAAAQ,IAAeC,EAAoBF,CAAI,KAAK;AAC9C,cAAA,CAACP,EAAK,oBAAoB,KAAK,CAACU,MAAMF,EAAa,SAASE,CAAC,CAAC;AACjE;AAAA,QACD;AAGK,cAAAC,IAAK,YAAY,IAAI,GACrB,EAAE,UAAAC,GAAU,gBAAAC,MAAmBC,EAAcP,GAAMP,EAAK,cAAc;AAC5E,QAAAI,EAAgB,KAAK;AAAA,UACpB,QAAQQ,EAAS;AAAA,UACjB,MAAMA,EAAS;AAAA,UACf,QAAQ,YAAY,IAAA,IAAQD;AAAA,UAC5B,gBAAAE;AAAA,QAAA,CACA,GACDV,EAAU,KAAKS,CAAQ;AAAA,MAAA,CACvB;AAAA,IAAA,CACD;AAED,UAAMG,IAAuB;AAAA,MAC5B,QAAQf,EAAK;AAAA,MACb,WAAAG;AAAA,MACA,iBAAAC;AAAA,IACD;AACA,IAAAL,EAAY,YAAYgB,CAAM;AAAA,WACtBC,GAAK;AACb,UAAMD,IAAuB;AAAA,MAC5B,QAAQf,EAAK;AAAA,MACb,OAAO,OAAOgB,CAAG;AAAA,IAClB;AACA,IAAAjB,EAAY,YAAYgB,CAAM;AAAA,EAAA;AAEhC,CAAC;"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("os"),h=require("worker_threads");class l{constructor(e){this.queue=[],this.pending=new Map;const t=Math.max(1,Math.min(o.cpus().length-1,8));this.workers=Array.from({length:t},()=>{const s=new h.Worker(e);return s.on("message",r=>{const i=this.pending.get(r.taskId);i&&(this.pending.delete(r.taskId),i(r)),this.idle.push(s),this.flush()}),s.on("error",r=>{for(const[i,n]of this.pending){n({taskId:i,error:String(r)}),this.pending.delete(i);break}this.idle.push(s),this.flush()}),s}),this.idle=[...this.workers]}run(e){return new Promise(t=>{if(this.idle.length>0){const s=this.idle.pop();this.pending.set(e.taskId,t),s.postMessage(e)}else this.queue.push({task:e,resolve:t})})}runAll(e){return Promise.all(e.map(t=>this.run(t)))}terminate(){this.workers.forEach(e=>e.terminate())}flush(){for(;this.queue.length>0&&this.idle.length>0;){const{task:e,resolve:t}=this.queue.shift(),s=this.idle.pop();this.pending.set(e.taskId,t),s.postMessage(e)}}}exports.WorkerPool=l;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("os"),u=require("worker_threads");class d{constructor(e,t){this.queue=[],this.pending=new Map;const s=Math.max(1,Math.min(l.cpus().length-1,8)),o=t===void 0?s:Math.max(1,Math.min(s,t));this.workers=Array.from({length:o},()=>{const i=new u.Worker(e);return i.on("message",r=>{const n=this.pending.get(r.taskId);n&&(this.pending.delete(r.taskId),n(r)),this.idle.push(i),this.flush()}),i.on("error",r=>{for(const[n,h]of this.pending){h({taskId:n,error:String(r)}),this.pending.delete(n);break}this.idle.push(i),this.flush()}),i}),this.idle=[...this.workers]}run(e){return new Promise(t=>{if(this.idle.length>0){const s=this.idle.pop();this.pending.set(e.taskId,t),s.postMessage(e)}else this.queue.push({task:e,resolve:t})})}runAll(e){return Promise.all(e.map(t=>this.run(t)))}terminate(){this.workers.forEach(e=>e.terminate())}flush(){for(;this.queue.length>0&&this.idle.length>0;){const{task:e,resolve:t}=this.queue.shift(),s=this.idle.pop();this.pending.set(e.taskId,t),s.postMessage(e)}}}exports.WorkerPool=d;
2
2
  //# sourceMappingURL=workerPool.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"workerPool.cjs","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"sourcesContent":["import os from 'os'\nimport { Worker } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { SectionTiming } from './parseEndpoint'\n\nexport type WorkerTask = {\n\ttaskId: string\n\ttsconfigPath: string\n\tsourceFilePath: string\n\trouterName: string\n\tendpointIndex: number\n}\n\nexport type WorkerResultSuccess = {\n\ttaskId: string\n\tendpoint: EndpointData\n\tsectionTimings: SectionTiming[]\n\ttiming: number\n}\n\nexport type WorkerResultError = {\n\ttaskId: string\n\terror: string\n}\n\nexport type WorkerResult = WorkerResultSuccess | WorkerResultError\n\nexport class WorkerPool {\n\tprivate workers: Worker[]\n\tprivate idle: Worker[]\n\tprivate queue: Array<{ task: WorkerTask; resolve: (r: WorkerResult) => void }> = []\n\tprivate pending = new Map<string, (r: WorkerResult) => void>()\n\n\tconstructor(workerUrl: URL) {\n\t\tconst size = Math.max(1, Math.min(os.cpus().length - 1, 8))\n\t\tthis.workers = Array.from({ length: size }, () => {\n\t\t\tconst worker = new Worker(workerUrl)\n\t\t\tworker.on('message', (result: WorkerResult) => {\n\t\t\t\tconst resolve = this.pending.get(result.taskId)\n\t\t\t\tif (resolve) {\n\t\t\t\t\tthis.pending.delete(result.taskId)\n\t\t\t\t\tresolve(result)\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\tworker.on('error', (err) => {\n\t\t\t\t// Find any pending task for this worker and reject it\n\t\t\t\t// (worker crashed — shouldn't happen, but handle gracefully)\n\t\t\t\tfor (const [taskId, resolve] of this.pending) {\n\t\t\t\t\tresolve({ taskId, error: String(err) })\n\t\t\t\t\tthis.pending.delete(taskId)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\treturn worker\n\t\t})\n\t\tthis.idle = [...this.workers]\n\t}\n\n\trun(task: WorkerTask): Promise<WorkerResult> {\n\t\treturn new Promise((resolve) => {\n\t\t\tif (this.idle.length > 0) {\n\t\t\t\tconst worker = this.idle.pop()!\n\t\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\t\tworker.postMessage(task)\n\t\t\t} else {\n\t\t\t\tthis.queue.push({ task, resolve })\n\t\t\t}\n\t\t})\n\t}\n\n\trunAll(tasks: WorkerTask[]): Promise<WorkerResult[]> {\n\t\treturn Promise.all(tasks.map((t) => this.run(t)))\n\t}\n\n\tterminate() {\n\t\tthis.workers.forEach((w) => w.terminate())\n\t}\n\n\tprivate flush() {\n\t\twhile (this.queue.length > 0 && this.idle.length > 0) {\n\t\t\tconst { task, resolve } = this.queue.shift()!\n\t\t\tconst worker = this.idle.pop()!\n\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\tworker.postMessage(task)\n\t\t}\n\t}\n}\n"],"names":["WorkerPool","workerUrl","size","os","worker","Worker","result","resolve","err","taskId","task","tasks","w"],"mappings":"kIA4BO,MAAMA,CAAW,CAMvB,YAAYC,EAAgB,CAH5B,KAAQ,MAAyE,CAAC,EAC1E,KAAA,YAAc,IAGrB,MAAMC,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIC,EAAG,KAAA,EAAO,OAAS,EAAG,CAAC,CAAC,EAC1D,KAAK,QAAU,MAAM,KAAK,CAAE,OAAQD,CAAA,EAAQ,IAAM,CAC3C,MAAAE,EAAS,IAAIC,EAAA,OAAOJ,CAAS,EAC5B,OAAAG,EAAA,GAAG,UAAYE,GAAyB,CAC9C,MAAMC,EAAU,KAAK,QAAQ,IAAID,EAAO,MAAM,EAC1CC,IACE,KAAA,QAAQ,OAAOD,EAAO,MAAM,EACjCC,EAAQD,CAAM,GAEV,KAAA,KAAK,KAAKF,CAAM,EACrB,KAAK,MAAM,CAAA,CACX,EACMA,EAAA,GAAG,QAAUI,GAAQ,CAG3B,SAAW,CAACC,EAAQF,CAAO,IAAK,KAAK,QAAS,CAC7CA,EAAQ,CAAE,OAAAE,EAAQ,MAAO,OAAOD,CAAG,EAAG,EACjC,KAAA,QAAQ,OAAOC,CAAM,EAC1B,KAAA,CAEI,KAAA,KAAK,KAAKL,CAAM,EACrB,KAAK,MAAM,CAAA,CACX,EACMA,CAAA,CACP,EACD,KAAK,KAAO,CAAC,GAAG,KAAK,OAAO,CAAA,CAG7B,IAAIM,EAAyC,CACrC,OAAA,IAAI,QAASH,GAAY,CAC3B,GAAA,KAAK,KAAK,OAAS,EAAG,CACnB,MAAAH,EAAS,KAAK,KAAK,IAAI,EAC7B,KAAK,QAAQ,IAAIM,EAAK,OAAQH,CAAO,EACrCH,EAAO,YAAYM,CAAI,CAAA,MAEvB,KAAK,MAAM,KAAK,CAAE,KAAAA,EAAM,QAAAH,EAAS,CAClC,CACA,CAAA,CAGF,OAAOI,EAA8C,CAC7C,OAAA,QAAQ,IAAIA,EAAM,IAAK,GAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAA,CAGjD,WAAY,CACX,KAAK,QAAQ,QAASC,GAAMA,EAAE,WAAW,CAAA,CAGlC,OAAQ,CACf,KAAO,KAAK,MAAM,OAAS,GAAK,KAAK,KAAK,OAAS,GAAG,CACrD,KAAM,CAAE,KAAAF,EAAM,QAAAH,CAAA,EAAY,KAAK,MAAM,MAAM,EACrCH,EAAS,KAAK,KAAK,IAAI,EAC7B,KAAK,QAAQ,IAAIM,EAAK,OAAQH,CAAO,EACrCH,EAAO,YAAYM,CAAI,CAAA,CACxB,CAEF"}
1
+ {"version":3,"file":"workerPool.cjs","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"sourcesContent":["import os from 'os'\nimport { Worker } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { SectionTiming } from './parseEndpoint'\n\nexport type WorkerTask = {\n\ttaskId: string\n\ttsconfigPath: string\n\tsourceFilePath: string\n\trouterNames: string[]\n\tfilterEndpointPaths?: string[]\n}\n\nexport type EndpointTiming = {\n\tmethod: string\n\tpath: string\n\ttiming: number\n\tsectionTimings: SectionTiming[]\n}\n\nexport type WorkerResultSuccess = {\n\ttaskId: string\n\tendpoints: EndpointData[]\n\tendpointTimings: EndpointTiming[]\n}\n\nexport type WorkerResultError = {\n\ttaskId: string\n\terror: string\n}\n\nexport type WorkerResult = WorkerResultSuccess | WorkerResultError\n\nexport class WorkerPool {\n\tprivate workers: Worker[]\n\tprivate idle: Worker[]\n\tprivate queue: Array<{ task: WorkerTask; resolve: (r: WorkerResult) => void }> = []\n\tprivate pending = new Map<string, (r: WorkerResult) => void>()\n\n\tconstructor(workerUrl: URL, maxWorkers?: number) {\n\t\tconst cpuBound = Math.max(1, Math.min(os.cpus().length - 1, 8))\n\t\t// Never spin up more workers than there are files to analyze: each extra worker would\n\t\t// just pay the ts-morph Project cold-start (full TS program load + type-checker warmup)\n\t\t// for nothing while contending for CPU with the workers that actually have work.\n\t\tconst size = maxWorkers === undefined ? cpuBound : Math.max(1, Math.min(cpuBound, maxWorkers))\n\t\tthis.workers = Array.from({ length: size }, () => {\n\t\t\tconst worker = new Worker(workerUrl)\n\t\t\tworker.on('message', (result: WorkerResult) => {\n\t\t\t\tconst resolve = this.pending.get(result.taskId)\n\t\t\t\tif (resolve) {\n\t\t\t\t\tthis.pending.delete(result.taskId)\n\t\t\t\t\tresolve(result)\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\tworker.on('error', (err) => {\n\t\t\t\t// Find any pending task for this worker and reject it\n\t\t\t\t// (worker crashed — shouldn't happen, but handle gracefully)\n\t\t\t\tfor (const [taskId, resolve] of this.pending) {\n\t\t\t\t\tresolve({ taskId, error: String(err) })\n\t\t\t\t\tthis.pending.delete(taskId)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\treturn worker\n\t\t})\n\t\tthis.idle = [...this.workers]\n\t}\n\n\trun(task: WorkerTask): Promise<WorkerResult> {\n\t\treturn new Promise((resolve) => {\n\t\t\tif (this.idle.length > 0) {\n\t\t\t\tconst worker = this.idle.pop()!\n\t\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\t\tworker.postMessage(task)\n\t\t\t} else {\n\t\t\t\tthis.queue.push({ task, resolve })\n\t\t\t}\n\t\t})\n\t}\n\n\trunAll(tasks: WorkerTask[]): Promise<WorkerResult[]> {\n\t\treturn Promise.all(tasks.map((t) => this.run(t)))\n\t}\n\n\tterminate() {\n\t\tthis.workers.forEach((w) => w.terminate())\n\t}\n\n\tprivate flush() {\n\t\twhile (this.queue.length > 0 && this.idle.length > 0) {\n\t\t\tconst { task, resolve } = this.queue.shift()!\n\t\t\tconst worker = this.idle.pop()!\n\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\tworker.postMessage(task)\n\t\t}\n\t}\n}\n"],"names":["WorkerPool","workerUrl","maxWorkers","cpuBound","os","size","worker","Worker","result","resolve","err","taskId","task","tasks","w"],"mappings":"kIAkCO,MAAMA,CAAW,CAMvB,YAAYC,EAAgBC,EAAqB,CAHjD,KAAQ,MAAyE,CAAC,EAC1E,KAAA,YAAc,IAGrB,MAAMC,EAAW,KAAK,IAAI,EAAG,KAAK,IAAIC,EAAG,KAAA,EAAO,OAAS,EAAG,CAAC,CAAC,EAIxDC,EAAOH,IAAe,OAAYC,EAAW,KAAK,IAAI,EAAG,KAAK,IAAIA,EAAUD,CAAU,CAAC,EAC7F,KAAK,QAAU,MAAM,KAAK,CAAE,OAAQG,CAAA,EAAQ,IAAM,CAC3C,MAAAC,EAAS,IAAIC,EAAA,OAAON,CAAS,EAC5B,OAAAK,EAAA,GAAG,UAAYE,GAAyB,CAC9C,MAAMC,EAAU,KAAK,QAAQ,IAAID,EAAO,MAAM,EAC1CC,IACE,KAAA,QAAQ,OAAOD,EAAO,MAAM,EACjCC,EAAQD,CAAM,GAEV,KAAA,KAAK,KAAKF,CAAM,EACrB,KAAK,MAAM,CAAA,CACX,EACMA,EAAA,GAAG,QAAUI,GAAQ,CAG3B,SAAW,CAACC,EAAQF,CAAO,IAAK,KAAK,QAAS,CAC7CA,EAAQ,CAAE,OAAAE,EAAQ,MAAO,OAAOD,CAAG,EAAG,EACjC,KAAA,QAAQ,OAAOC,CAAM,EAC1B,KAAA,CAEI,KAAA,KAAK,KAAKL,CAAM,EACrB,KAAK,MAAM,CAAA,CACX,EACMA,CAAA,CACP,EACD,KAAK,KAAO,CAAC,GAAG,KAAK,OAAO,CAAA,CAG7B,IAAIM,EAAyC,CACrC,OAAA,IAAI,QAASH,GAAY,CAC3B,GAAA,KAAK,KAAK,OAAS,EAAG,CACnB,MAAAH,EAAS,KAAK,KAAK,IAAI,EAC7B,KAAK,QAAQ,IAAIM,EAAK,OAAQH,CAAO,EACrCH,EAAO,YAAYM,CAAI,CAAA,MAEvB,KAAK,MAAM,KAAK,CAAE,KAAAA,EAAM,QAAAH,EAAS,CAClC,CACA,CAAA,CAGF,OAAOI,EAA8C,CAC7C,OAAA,QAAQ,IAAIA,EAAM,IAAK,GAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAA,CAGjD,WAAY,CACX,KAAK,QAAQ,QAASC,GAAMA,EAAE,WAAW,CAAA,CAGlC,OAAQ,CACf,KAAO,KAAK,MAAM,OAAS,GAAK,KAAK,KAAK,OAAS,GAAG,CACrD,KAAM,CAAE,KAAAF,EAAM,QAAAH,CAAA,EAAY,KAAK,MAAM,MAAM,EACrCH,EAAS,KAAK,KAAK,IAAI,EAC7B,KAAK,QAAQ,IAAIM,EAAK,OAAQH,CAAO,EACrCH,EAAO,YAAYM,CAAI,CAAA,CACxB,CAEF"}
@@ -5,14 +5,19 @@ export type WorkerTask = {
5
5
  taskId: string;
6
6
  tsconfigPath: string;
7
7
  sourceFilePath: string;
8
- routerName: string;
9
- endpointIndex: number;
8
+ routerNames: string[];
9
+ filterEndpointPaths?: string[];
10
+ };
11
+ export type EndpointTiming = {
12
+ method: string;
13
+ path: string;
14
+ timing: number;
15
+ sectionTimings: SectionTiming[];
10
16
  };
11
17
  export type WorkerResultSuccess = {
12
18
  taskId: string;
13
- endpoint: EndpointData;
14
- sectionTimings: SectionTiming[];
15
- timing: number;
19
+ endpoints: EndpointData[];
20
+ endpointTimings: EndpointTiming[];
16
21
  };
17
22
  export type WorkerResultError = {
18
23
  taskId: string;
@@ -24,7 +29,7 @@ export declare class WorkerPool {
24
29
  private idle;
25
30
  private queue;
26
31
  private pending;
27
- constructor(workerUrl: URL);
32
+ constructor(workerUrl: URL, maxWorkers?: number);
28
33
  run(task: WorkerTask): Promise<WorkerResult>;
29
34
  runAll(tasks: WorkerTask[]): Promise<WorkerResult[]>;
30
35
  terminate(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"workerPool.d.ts","sourceRoot":"","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,MAAM,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,YAAY,CAAA;IACtB,cAAc,EAAE,aAAa,EAAE,CAAA;IAC/B,MAAM,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAA;AAElE,qBAAa,UAAU;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,KAAK,CAAsE;IACnF,OAAO,CAAC,OAAO,CAA+C;gBAElD,SAAS,EAAE,GAAG;IA6B1B,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAY5C,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIpD,SAAS;IAIT,OAAO,CAAC,KAAK;CAQb"}
1
+ {"version":3,"file":"workerPool.d.ts","sourceRoot":"","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,MAAM,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,aAAa,EAAE,CAAA;CAC/B,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,YAAY,EAAE,CAAA;IACzB,eAAe,EAAE,cAAc,EAAE,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,iBAAiB,CAAA;AAElE,qBAAa,UAAU;IACtB,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,IAAI,CAAU;IACtB,OAAO,CAAC,KAAK,CAAsE;IACnF,OAAO,CAAC,OAAO,CAA+C;gBAElD,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM;IAiC/C,GAAG,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC;IAY5C,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAIpD,SAAS;IAIT,OAAO,CAAC,KAAK;CAQb"}
@@ -1,46 +1,46 @@
1
- import o from "os";
2
- import { Worker as h } from "worker_threads";
3
- class u {
4
- constructor(e) {
1
+ import l from "os";
2
+ import { Worker as d } from "worker_threads";
3
+ class g {
4
+ constructor(e, s) {
5
5
  this.queue = [], this.pending = /* @__PURE__ */ new Map();
6
- const t = Math.max(1, Math.min(o.cpus().length - 1, 8));
7
- this.workers = Array.from({ length: t }, () => {
8
- const s = new h(e);
9
- return s.on("message", (i) => {
10
- const r = this.pending.get(i.taskId);
11
- r && (this.pending.delete(i.taskId), r(i)), this.idle.push(s), this.flush();
12
- }), s.on("error", (i) => {
13
- for (const [r, n] of this.pending) {
14
- n({ taskId: r, error: String(i) }), this.pending.delete(r);
6
+ const t = Math.max(1, Math.min(l.cpus().length - 1, 8)), o = s === void 0 ? t : Math.max(1, Math.min(t, s));
7
+ this.workers = Array.from({ length: o }, () => {
8
+ const i = new d(e);
9
+ return i.on("message", (r) => {
10
+ const n = this.pending.get(r.taskId);
11
+ n && (this.pending.delete(r.taskId), n(r)), this.idle.push(i), this.flush();
12
+ }), i.on("error", (r) => {
13
+ for (const [n, h] of this.pending) {
14
+ h({ taskId: n, error: String(r) }), this.pending.delete(n);
15
15
  break;
16
16
  }
17
- this.idle.push(s), this.flush();
18
- }), s;
17
+ this.idle.push(i), this.flush();
18
+ }), i;
19
19
  }), this.idle = [...this.workers];
20
20
  }
21
21
  run(e) {
22
- return new Promise((t) => {
22
+ return new Promise((s) => {
23
23
  if (this.idle.length > 0) {
24
- const s = this.idle.pop();
25
- this.pending.set(e.taskId, t), s.postMessage(e);
24
+ const t = this.idle.pop();
25
+ this.pending.set(e.taskId, s), t.postMessage(e);
26
26
  } else
27
- this.queue.push({ task: e, resolve: t });
27
+ this.queue.push({ task: e, resolve: s });
28
28
  });
29
29
  }
30
30
  runAll(e) {
31
- return Promise.all(e.map((t) => this.run(t)));
31
+ return Promise.all(e.map((s) => this.run(s)));
32
32
  }
33
33
  terminate() {
34
34
  this.workers.forEach((e) => e.terminate());
35
35
  }
36
36
  flush() {
37
37
  for (; this.queue.length > 0 && this.idle.length > 0; ) {
38
- const { task: e, resolve: t } = this.queue.shift(), s = this.idle.pop();
39
- this.pending.set(e.taskId, t), s.postMessage(e);
38
+ const { task: e, resolve: s } = this.queue.shift(), t = this.idle.pop();
39
+ this.pending.set(e.taskId, s), t.postMessage(e);
40
40
  }
41
41
  }
42
42
  }
43
43
  export {
44
- u as WorkerPool
44
+ g as WorkerPool
45
45
  };
46
46
  //# sourceMappingURL=workerPool.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"workerPool.mjs","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"sourcesContent":["import os from 'os'\nimport { Worker } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { SectionTiming } from './parseEndpoint'\n\nexport type WorkerTask = {\n\ttaskId: string\n\ttsconfigPath: string\n\tsourceFilePath: string\n\trouterName: string\n\tendpointIndex: number\n}\n\nexport type WorkerResultSuccess = {\n\ttaskId: string\n\tendpoint: EndpointData\n\tsectionTimings: SectionTiming[]\n\ttiming: number\n}\n\nexport type WorkerResultError = {\n\ttaskId: string\n\terror: string\n}\n\nexport type WorkerResult = WorkerResultSuccess | WorkerResultError\n\nexport class WorkerPool {\n\tprivate workers: Worker[]\n\tprivate idle: Worker[]\n\tprivate queue: Array<{ task: WorkerTask; resolve: (r: WorkerResult) => void }> = []\n\tprivate pending = new Map<string, (r: WorkerResult) => void>()\n\n\tconstructor(workerUrl: URL) {\n\t\tconst size = Math.max(1, Math.min(os.cpus().length - 1, 8))\n\t\tthis.workers = Array.from({ length: size }, () => {\n\t\t\tconst worker = new Worker(workerUrl)\n\t\t\tworker.on('message', (result: WorkerResult) => {\n\t\t\t\tconst resolve = this.pending.get(result.taskId)\n\t\t\t\tif (resolve) {\n\t\t\t\t\tthis.pending.delete(result.taskId)\n\t\t\t\t\tresolve(result)\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\tworker.on('error', (err) => {\n\t\t\t\t// Find any pending task for this worker and reject it\n\t\t\t\t// (worker crashed — shouldn't happen, but handle gracefully)\n\t\t\t\tfor (const [taskId, resolve] of this.pending) {\n\t\t\t\t\tresolve({ taskId, error: String(err) })\n\t\t\t\t\tthis.pending.delete(taskId)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\treturn worker\n\t\t})\n\t\tthis.idle = [...this.workers]\n\t}\n\n\trun(task: WorkerTask): Promise<WorkerResult> {\n\t\treturn new Promise((resolve) => {\n\t\t\tif (this.idle.length > 0) {\n\t\t\t\tconst worker = this.idle.pop()!\n\t\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\t\tworker.postMessage(task)\n\t\t\t} else {\n\t\t\t\tthis.queue.push({ task, resolve })\n\t\t\t}\n\t\t})\n\t}\n\n\trunAll(tasks: WorkerTask[]): Promise<WorkerResult[]> {\n\t\treturn Promise.all(tasks.map((t) => this.run(t)))\n\t}\n\n\tterminate() {\n\t\tthis.workers.forEach((w) => w.terminate())\n\t}\n\n\tprivate flush() {\n\t\twhile (this.queue.length > 0 && this.idle.length > 0) {\n\t\t\tconst { task, resolve } = this.queue.shift()!\n\t\t\tconst worker = this.idle.pop()!\n\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\tworker.postMessage(task)\n\t\t}\n\t}\n}\n"],"names":["WorkerPool","workerUrl","size","os","worker","Worker","result","resolve","err","taskId","task","tasks","w"],"mappings":";;AA4BO,MAAMA,EAAW;AAAA,EAMvB,YAAYC,GAAgB;AAH5B,SAAQ,QAAyE,CAAC,GAC1E,KAAA,8BAAc,IAAuC;AAG5D,UAAMC,IAAO,KAAK,IAAI,GAAG,KAAK,IAAIC,EAAG,KAAA,EAAO,SAAS,GAAG,CAAC,CAAC;AAC1D,SAAK,UAAU,MAAM,KAAK,EAAE,QAAQD,EAAA,GAAQ,MAAM;AAC3C,YAAAE,IAAS,IAAIC,EAAOJ,CAAS;AAC5B,aAAAG,EAAA,GAAG,WAAW,CAACE,MAAyB;AAC9C,cAAMC,IAAU,KAAK,QAAQ,IAAID,EAAO,MAAM;AAC9C,QAAIC,MACE,KAAA,QAAQ,OAAOD,EAAO,MAAM,GACjCC,EAAQD,CAAM,IAEV,KAAA,KAAK,KAAKF,CAAM,GACrB,KAAK,MAAM;AAAA,MAAA,CACX,GACMA,EAAA,GAAG,SAAS,CAACI,MAAQ;AAG3B,mBAAW,CAACC,GAAQF,CAAO,KAAK,KAAK,SAAS;AAC7C,UAAAA,EAAQ,EAAE,QAAAE,GAAQ,OAAO,OAAOD,CAAG,GAAG,GACjC,KAAA,QAAQ,OAAOC,CAAM;AAC1B;AAAA,QAAA;AAEI,aAAA,KAAK,KAAKL,CAAM,GACrB,KAAK,MAAM;AAAA,MAAA,CACX,GACMA;AAAA,IAAA,CACP,GACD,KAAK,OAAO,CAAC,GAAG,KAAK,OAAO;AAAA,EAAA;AAAA,EAG7B,IAAIM,GAAyC;AACrC,WAAA,IAAI,QAAQ,CAACH,MAAY;AAC3B,UAAA,KAAK,KAAK,SAAS,GAAG;AACnB,cAAAH,IAAS,KAAK,KAAK,IAAI;AAC7B,aAAK,QAAQ,IAAIM,EAAK,QAAQH,CAAO,GACrCH,EAAO,YAAYM,CAAI;AAAA,MAAA;AAEvB,aAAK,MAAM,KAAK,EAAE,MAAAA,GAAM,SAAAH,GAAS;AAAA,IAClC,CACA;AAAA,EAAA;AAAA,EAGF,OAAOI,GAA8C;AAC7C,WAAA,QAAQ,IAAIA,EAAM,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;AAAA,EAAA;AAAA,EAGjD,YAAY;AACX,SAAK,QAAQ,QAAQ,CAACC,MAAMA,EAAE,WAAW;AAAA,EAAA;AAAA,EAGlC,QAAQ;AACf,WAAO,KAAK,MAAM,SAAS,KAAK,KAAK,KAAK,SAAS,KAAG;AACrD,YAAM,EAAE,MAAAF,GAAM,SAAAH,EAAA,IAAY,KAAK,MAAM,MAAM,GACrCH,IAAS,KAAK,KAAK,IAAI;AAC7B,WAAK,QAAQ,IAAIM,EAAK,QAAQH,CAAO,GACrCH,EAAO,YAAYM,CAAI;AAAA,IAAA;AAAA,EACxB;AAEF;"}
1
+ {"version":3,"file":"workerPool.mjs","sources":["../../../src/openapi/analyzerModule/workerPool.ts"],"sourcesContent":["import os from 'os'\nimport { Worker } from 'worker_threads'\n\nimport { EndpointData } from '../types'\nimport { SectionTiming } from './parseEndpoint'\n\nexport type WorkerTask = {\n\ttaskId: string\n\ttsconfigPath: string\n\tsourceFilePath: string\n\trouterNames: string[]\n\tfilterEndpointPaths?: string[]\n}\n\nexport type EndpointTiming = {\n\tmethod: string\n\tpath: string\n\ttiming: number\n\tsectionTimings: SectionTiming[]\n}\n\nexport type WorkerResultSuccess = {\n\ttaskId: string\n\tendpoints: EndpointData[]\n\tendpointTimings: EndpointTiming[]\n}\n\nexport type WorkerResultError = {\n\ttaskId: string\n\terror: string\n}\n\nexport type WorkerResult = WorkerResultSuccess | WorkerResultError\n\nexport class WorkerPool {\n\tprivate workers: Worker[]\n\tprivate idle: Worker[]\n\tprivate queue: Array<{ task: WorkerTask; resolve: (r: WorkerResult) => void }> = []\n\tprivate pending = new Map<string, (r: WorkerResult) => void>()\n\n\tconstructor(workerUrl: URL, maxWorkers?: number) {\n\t\tconst cpuBound = Math.max(1, Math.min(os.cpus().length - 1, 8))\n\t\t// Never spin up more workers than there are files to analyze: each extra worker would\n\t\t// just pay the ts-morph Project cold-start (full TS program load + type-checker warmup)\n\t\t// for nothing while contending for CPU with the workers that actually have work.\n\t\tconst size = maxWorkers === undefined ? cpuBound : Math.max(1, Math.min(cpuBound, maxWorkers))\n\t\tthis.workers = Array.from({ length: size }, () => {\n\t\t\tconst worker = new Worker(workerUrl)\n\t\t\tworker.on('message', (result: WorkerResult) => {\n\t\t\t\tconst resolve = this.pending.get(result.taskId)\n\t\t\t\tif (resolve) {\n\t\t\t\t\tthis.pending.delete(result.taskId)\n\t\t\t\t\tresolve(result)\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\tworker.on('error', (err) => {\n\t\t\t\t// Find any pending task for this worker and reject it\n\t\t\t\t// (worker crashed — shouldn't happen, but handle gracefully)\n\t\t\t\tfor (const [taskId, resolve] of this.pending) {\n\t\t\t\t\tresolve({ taskId, error: String(err) })\n\t\t\t\t\tthis.pending.delete(taskId)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tthis.idle.push(worker)\n\t\t\t\tthis.flush()\n\t\t\t})\n\t\t\treturn worker\n\t\t})\n\t\tthis.idle = [...this.workers]\n\t}\n\n\trun(task: WorkerTask): Promise<WorkerResult> {\n\t\treturn new Promise((resolve) => {\n\t\t\tif (this.idle.length > 0) {\n\t\t\t\tconst worker = this.idle.pop()!\n\t\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\t\tworker.postMessage(task)\n\t\t\t} else {\n\t\t\t\tthis.queue.push({ task, resolve })\n\t\t\t}\n\t\t})\n\t}\n\n\trunAll(tasks: WorkerTask[]): Promise<WorkerResult[]> {\n\t\treturn Promise.all(tasks.map((t) => this.run(t)))\n\t}\n\n\tterminate() {\n\t\tthis.workers.forEach((w) => w.terminate())\n\t}\n\n\tprivate flush() {\n\t\twhile (this.queue.length > 0 && this.idle.length > 0) {\n\t\t\tconst { task, resolve } = this.queue.shift()!\n\t\t\tconst worker = this.idle.pop()!\n\t\t\tthis.pending.set(task.taskId, resolve)\n\t\t\tworker.postMessage(task)\n\t\t}\n\t}\n}\n"],"names":["WorkerPool","workerUrl","maxWorkers","cpuBound","os","size","worker","Worker","result","resolve","err","taskId","task","tasks","t","w"],"mappings":";;AAkCO,MAAMA,EAAW;AAAA,EAMvB,YAAYC,GAAgBC,GAAqB;AAHjD,SAAQ,QAAyE,CAAC,GAC1E,KAAA,8BAAc,IAAuC;AAG5D,UAAMC,IAAW,KAAK,IAAI,GAAG,KAAK,IAAIC,EAAG,KAAA,EAAO,SAAS,GAAG,CAAC,CAAC,GAIxDC,IAAOH,MAAe,SAAYC,IAAW,KAAK,IAAI,GAAG,KAAK,IAAIA,GAAUD,CAAU,CAAC;AAC7F,SAAK,UAAU,MAAM,KAAK,EAAE,QAAQG,EAAA,GAAQ,MAAM;AAC3C,YAAAC,IAAS,IAAIC,EAAON,CAAS;AAC5B,aAAAK,EAAA,GAAG,WAAW,CAACE,MAAyB;AAC9C,cAAMC,IAAU,KAAK,QAAQ,IAAID,EAAO,MAAM;AAC9C,QAAIC,MACE,KAAA,QAAQ,OAAOD,EAAO,MAAM,GACjCC,EAAQD,CAAM,IAEV,KAAA,KAAK,KAAKF,CAAM,GACrB,KAAK,MAAM;AAAA,MAAA,CACX,GACMA,EAAA,GAAG,SAAS,CAACI,MAAQ;AAG3B,mBAAW,CAACC,GAAQF,CAAO,KAAK,KAAK,SAAS;AAC7C,UAAAA,EAAQ,EAAE,QAAAE,GAAQ,OAAO,OAAOD,CAAG,GAAG,GACjC,KAAA,QAAQ,OAAOC,CAAM;AAC1B;AAAA,QAAA;AAEI,aAAA,KAAK,KAAKL,CAAM,GACrB,KAAK,MAAM;AAAA,MAAA,CACX,GACMA;AAAA,IAAA,CACP,GACD,KAAK,OAAO,CAAC,GAAG,KAAK,OAAO;AAAA,EAAA;AAAA,EAG7B,IAAIM,GAAyC;AACrC,WAAA,IAAI,QAAQ,CAACH,MAAY;AAC3B,UAAA,KAAK,KAAK,SAAS,GAAG;AACnB,cAAAH,IAAS,KAAK,KAAK,IAAI;AAC7B,aAAK,QAAQ,IAAIM,EAAK,QAAQH,CAAO,GACrCH,EAAO,YAAYM,CAAI;AAAA,MAAA;AAEvB,aAAK,MAAM,KAAK,EAAE,MAAAA,GAAM,SAAAH,GAAS;AAAA,IAClC,CACA;AAAA,EAAA;AAAA,EAGF,OAAOI,GAA8C;AAC7C,WAAA,QAAQ,IAAIA,EAAM,IAAI,CAACC,MAAM,KAAK,IAAIA,CAAC,CAAC,CAAC;AAAA,EAAA;AAAA,EAGjD,YAAY;AACX,SAAK,QAAQ,QAAQ,CAACC,MAAMA,EAAE,WAAW;AAAA,EAAA;AAAA,EAGlC,QAAQ;AACf,WAAO,KAAK,MAAM,SAAS,KAAK,KAAK,KAAK,SAAS,KAAG;AACrD,YAAM,EAAE,MAAAH,GAAM,SAAAH,EAAA,IAAY,KAAK,MAAM,MAAM,GACrCH,IAAS,KAAK,KAAK,IAAI;AAC7B,WAAK,QAAQ,IAAIM,EAAK,QAAQH,CAAO,GACrCH,EAAO,YAAYM,CAAI;AAAA,IAAA;AAAA,EACxB;AAEF;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moonflower",
3
- "version": "1.5.0",
3
+ "version": "1.5.2",
4
4
  "description": "",
5
5
  "author": "tenebrie",
6
6
  "license": "MIT",