moonflower 1.5.3 → 1.6.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/dist/openapi/analyzerModule/analyzerModule.cjs +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.cjs.map +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.d.ts +3 -1
- package/dist/openapi/analyzerModule/analyzerModule.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.mjs +134 -132
- package/dist/openapi/analyzerModule/analyzerModule.mjs.map +1 -1
- package/dist/router/Router.cjs.map +1 -1
- package/dist/router/Router.d.ts +17 -10
- package/dist/router/Router.d.ts.map +1 -1
- package/dist/router/Router.mjs.map +1 -1
- package/package.json +9 -13
- package/src/openapi/analyzerModule/analyzerModule.ts +6 -9
- package/src/router/Router.ts +11 -14
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("crypto"),U=require("fs"),W=require("path"),K=require("url"),S=require("ts-morph"),y=require("../../utils/logger.cjs"),R=require("../discoveryModule/discoverImports/discoverImports.cjs"),_=require("../discoveryModule/discoverRouterFiles/discoverRouterFiles.cjs"),H=require("../discoveryModule/discoverRouters/discoverRouters.cjs"),D=require("../manager/OpenApiManager.cjs"),B=require("./getSourceFileTimestamp.cjs"),A=require("./nodeParsers.cjs"),V=require("./parseEndpoint.cjs"),C=require("./parseExposedModels.cjs"),w=require("./sourceFileCache.cjs"),Y=require("./workerPool.cjs");var P=typeof document<"u"?document.currentScript:null;function G(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const l in r)if(l!=="default"){const c=Object.getOwnPropertyDescriptor(r,l);Object.defineProperty(t,l,c.get?c:{enumerable:!0,get:()=>r[l]})}}return t.default=r,Object.freeze(t)}const M=G(W);function J(){const r=["./analyzerWorker.mjs","./analyzerWorker.test.mjs"];for(const t of r){const l=new URL(t,typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.tagName.toUpperCase()==="SCRIPT"&&P.src||new URL("openapi/analyzerModule/analyzerModule.cjs",document.baseURI).href);if(U.existsSync(K.fileURLToPath(l)))return l}throw new Error("analyzerWorker.mjs not found. Run yarn build, or run tests via yarn test (which compiles the worker first).")}const Q=2,X=async({logLevel:r,tsconfigPath:t,sourceFilePaths:l,sourceFileDiscovery:c,incremental:p,profiling:m="stats",workers:o=!1})=>{const a=D.OpenApiManager.getInstance();if(a.isReady())return;r&&y.Logger.setLevel(r),y.Logger.info("Preparing OpenAPI spec");const h=new S.Project({tsConfigFilePath:M.resolve(t),skipFileDependencyResolution:!0}),{explicitRouters:g,discoveredRouterFiles:x,allSourceFiles:T}=(()=>{const u=(l??[]).map(f=>M.resolve(f)).map(f=>h.getSourceFileOrThrow(f)),k=u.flatMap(f=>({fileName:f.getFilePath(),sourceFile:f,routers:H.discoverRouters(f)})),{discoveredRouterFiles:b,discoveredSourceFiles:j}=(()=>{if(c===!1)return{discoveredRouterFiles:[],discoveredSourceFiles:[]};const f=performance.now(),E=_.discoverRouterFiles({targetPath:typeof c=="object"?c.rootPath:".",tsConfigPath:t});return m!=="off"&&y.Logger.info(`File discovery took ${Math.round(performance.now()-f)}ms`),E})(),z=u.reduce((f,E)=>f.some(q=>q.getFilePath()===E.getFilePath())?f:f.concat(E),j);return{explicitRouters:k,discoveredRouterFiles:b,allSourceFiles:z}})(),e=g.reduce((i,N)=>i.some(u=>u.fileName===N.fileName)?i:i.concat(N),x),n=T.flatMap(i=>O(i)).filter(i=>!!i);n.length>0&&n[0]&&a.setHeader(n[0]);const s=T.flatMap(i=>$(i));a.setExposedModels(s);const d=typeof p=="object"&&p.cachePath?p.cachePath:M.resolve(process.cwd(),"node_modules",".cache","moonflower"),F=await L(e,{incremental:p!==!1,cachePath:d,timestampCache:{},profiling:m,tsconfigPath:M.resolve(t),workers:o});a.setStats({discoveredRouterFiles:x.map(i=>({path:i.fileName,routers:i.routers.named.map(N=>({name:N,endpoints:F.filter(u=>u.sourceFilePath===i.fileName).map(u=>`${u.method.toUpperCase()} ${u.path}`)}))})),explicitRouterFiles:g.map(i=>({path:i.fileName,routers:i.routers.named.map(N=>({name:N,endpoints:F.filter(u=>u.sourceFilePath===i.fileName).map(u=>`${u.method.toUpperCase()} ${u.path}`)}))}))}),a.setEndpoints(F),a.markAsReady()},L=async(r,t,l)=>{const c=t.profiling??"stats",p=performance.now(),m=[],o=[],a=performance.now(),h=new Map;for(const e of r){const n=B.getSourceFileTimestamp(e.sourceFile,t.timestampCache,h),s=t.incremental?w.SourceFileCache.getCachedResults(e.sourceFile,n,t.cachePath):null;s?(y.Logger.debug(`[${e.fileName}] Found cached results`),m.push({endpoints:s.endpoints,fileName:e.fileName,timing:0,endpointTimings:[]})):o.push({file:e,timestamp:n})}if(c!=="off"&&y.Logger.info(`Cache freshness check took ${Math.round(performance.now()-a)}ms`),o.length===0)return c!=="off"&&y.Logger.info(`Router analysis took ${Math.round(performance.now()-p)}ms`),m.flatMap(e=>e.endpoints);const g=new Map;for(const{file:e}of o)g.set(e.fileName,{endpoints:[],fileName:e.fileName,timing:0,endpointTimings:[]});if(!(t.workers!==!1)||o.length<=Q)for(const{file:e}of o){const{endpoints:n,endpointTimings:s}=v(e),d=g.get(e.fileName);d.endpoints=n,d.endpointTimings=s,d.timing=s.reduce((F,i)=>F+i.timing,0)}else{const e=o.map(({file:d})=>({fileName:d.fileName,task:{taskId:I.randomUUID(),tsconfigPath:t.tsconfigPath,sourceFilePath:d.sourceFile.getFilePath(),routerNames:d.routers.named,filterEndpointPaths:l}})),n=new Y.WorkerPool(J(),e.length);let s;try{s=await n.runAll(e.map(d=>d.task))}finally{n.terminate()}for(let d=0;d<s.length;d++){const F=s[d],i=e[d].fileName,N=g.get(i);if("error"in F){y.Logger.error(`[${i}] Worker error: ${F.error}`);continue}N.endpoints=F.endpoints,N.endpointTimings=F.endpointTimings,N.timing=F.endpointTimings.reduce((u,k)=>u+k.timing,0)}}for(const{file:e,timestamp:n}of o){const s=g.get(e.fileName);s.endpoints.length>0&&w.SourceFileCache.cacheResults(e.sourceFile,n,t.cachePath,s.endpoints)}const T=[...m,...Array.from(g.values())];return c!=="off"&&y.Logger.info(`Router analysis took ${Math.round(performance.now()-p)}ms`),c==="stats"?T.map(e=>({fileName:e.fileName,timeTaken:e.timing})).sort((e,n)=>n.timeTaken-e.timeTaken).filter(e=>e.timeTaken>500).forEach(e=>{y.Logger.info(`- [${e.fileName}] Took ${Math.round(e.timeTaken)}ms to analyze`)}):c==="debug"&&T.map(e=>({fileName:e.fileName,timeTaken:e.timing,endpointTimings:e.endpointTimings})).sort((e,n)=>n.timeTaken-e.timeTaken).forEach(e=>{y.Logger.info(`- [${e.fileName}] Took ${Math.round(e.timeTaken)}ms to analyze`),e.endpointTimings.sort((n,s)=>s.timing-n.timing).forEach(n=>{y.Logger.info(` - ${n.method} ${n.path} (${Math.round(n.timing)}ms)`),n.sectionTimings.filter(s=>s.timing>=1).sort((s,d)=>d.timing-s.timing).forEach(s=>{y.Logger.info(` - ${s.section}: ${Math.round(s.timing)}ms`)})})}),T.flatMap(e=>e.endpoints)},v=(r,t)=>{const l=[],c=[],m=["get","post","put","delete","del","patch"].join("|");return r.routers.named.forEach(o=>{const a=new RegExp(`${o}\\.(?:${m})`);r.sourceFile.forEachChild(h=>{const g=h.getText();if(a.test(g)){A.resolveEndpointPath(h);const x=performance.now(),{endpoint:T,sectionTimings:e}=V.parseEndpoint(h,r.fileName);c.push({method:T.method,path:T.path,timing:performance.now()-x,sectionTimings:e}),l.push(T)}})}),{endpoints:l,endpointTimings:c}},O=r=>{const t=R.discoverImportedName({sourceFile:r,originalName:"useApiHeader"});if(!t)return null;const l=r.forEachChildAsArray().filter(o=>o.isKind(S.SyntaxKind.ExpressionStatement)).find(o=>t&&o.getText().startsWith(t));if(!l)return null;const c=l.getFirstDescendantByKindOrThrow(S.SyntaxKind.ObjectLiteralExpression),p=A.getValuesOfObjectLiteral(c),m=o=>typeof o=="string"||Array.isArray(o)&&o.every(a=>typeof a=="string")?o:o.reduce((a,h)=>typeof h=="string"?a:{...a,[h.identifier]:m(h.value)},{});return m(p)},$=r=>{const t=[],l=R.discoverImportedName({sourceFile:r,originalName:"useExposeApiModel"}),c=R.discoverImportedName({sourceFile:r,originalName:"useExposeNamedApiModels"});return r.forEachChildAsArray().filter(p=>p.isKind(S.SyntaxKind.ExpressionStatement)).map(p=>{if(l&&p.getText().startsWith(l)){const a=(p.getFirstChild()?.getChildrenOfKind(S.SyntaxKind.SyntaxList)||[])[0].getFirstChild();if(!a)return;t.push(C.parseExposedModel(a));return}if(c&&p.getText().startsWith(c)){const a=(p.getFirstChild()?.getChildrenOfKind(S.SyntaxKind.SyntaxList)||[])[0].getFirstChild();if(!a)return;C.parseNamedExposedModels(a).forEach(g=>t.push(g))}}),t};exports.analyzeMultipleSourceFiles=L;exports.analyzeSourceFileApiHeader=O;exports.analyzeSourceFileEndpoints=v;exports.analyzeSourceFileExposedModels=$;exports.prepareOpenApiSpec=X;
|
|
2
2
|
//# sourceMappingURL=analyzerModule.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzerModule.cjs","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, MtimeCache, 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\tconst freshnessCheckStart = performance.now()\n\tconst mtimeCache: MtimeCache = new Map()\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache, mtimeCache)\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\tif (profiling !== 'off') {\n\t\tLogger.info(`Cache freshness check took ${Math.round(performance.now() - freshnessCheckStart)}ms`)\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","_documentCurrentScript","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","freshnessCheckStart","mtimeCache","timestamp","getSourceFileTimestamp","hit","SourceFileCache","f","byFile","endpointTimings","analyzeSourceFileEndpoints","fileResult","sum","t","allTasks","crypto","pool","WorkerPool","results","ft","i","result","fileName","analyzedFiles","a","b","ep","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":"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"}
|
|
1
|
+
{"version":3,"file":"analyzerModule.cjs","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, MtimeCache, 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\tworkers?: boolean\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\tworkers = false,\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\tworkers,\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\tworkers?: boolean\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\tconst freshnessCheckStart = performance.now()\n\tconst mtimeCache: MtimeCache = new Map()\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache, mtimeCache)\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\tif (profiling !== 'off') {\n\t\tLogger.info(`Cache freshness check took ${Math.round(performance.now() - freshnessCheckStart)}ms`)\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\tconst useWorkers = config.workers !== false\n\tif (!useWorkers || 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\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","_documentCurrentScript","existsSync","fileURLToPath","INLINE_ANALYSIS_FILE_THRESHOLD","prepareOpenApiSpec","logLevel","tsconfigPath","sourceFilePaths","sourceFileDiscovery","incremental","profiling","workers","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","freshnessCheckStart","mtimeCache","timestamp","getSourceFileTimestamp","hit","SourceFileCache","f","byFile","endpointTimings","analyzeSourceFileEndpoints","fileResult","sum","t","allTasks","crypto","pool","WorkerPool","results","ft","i","result","fileName","analyzedFiles","a","b","ep","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":"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"}
|
|
@@ -15,6 +15,7 @@ type Props = {
|
|
|
15
15
|
cachePath: string;
|
|
16
16
|
};
|
|
17
17
|
profiling?: 'stats' | 'off' | 'debug';
|
|
18
|
+
workers?: boolean;
|
|
18
19
|
};
|
|
19
20
|
type FileDiscoveryConfig = {
|
|
20
21
|
rootPath: string;
|
|
@@ -25,13 +26,14 @@ type EndpointTiming = {
|
|
|
25
26
|
timing: number;
|
|
26
27
|
sectionTimings: SectionTiming[];
|
|
27
28
|
};
|
|
28
|
-
export declare const prepareOpenApiSpec: ({ logLevel, tsconfigPath, sourceFilePaths, sourceFileDiscovery, incremental, profiling, }: Props) => Promise<void>;
|
|
29
|
+
export declare const prepareOpenApiSpec: ({ logLevel, tsconfigPath, sourceFilePaths, sourceFileDiscovery, incremental, profiling, workers, }: Props) => Promise<void>;
|
|
29
30
|
export declare const analyzeMultipleSourceFiles: (files: DiscoveredSourceFile[], config: {
|
|
30
31
|
incremental: boolean;
|
|
31
32
|
cachePath: string;
|
|
32
33
|
timestampCache: TimestampCache;
|
|
33
34
|
profiling?: "stats" | "off" | "debug";
|
|
34
35
|
tsconfigPath: string;
|
|
36
|
+
workers?: boolean;
|
|
35
37
|
}, filterEndpointPaths?: string[]) => Promise<EndpointData[]>;
|
|
36
38
|
export declare const analyzeSourceFileWithCache: (file: DiscoveredSourceFile, config: {
|
|
37
39
|
incremental: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzerModule.d.ts","sourceRoot":"","sources":["../../../src/openapi/analyzerModule/analyzerModule.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAc,MAAM,UAAU,CAAA;AAGjD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,OAAO,EACN,oBAAoB,EAEpB,MAAM,4DAA4D,CAAA;AAEnE,OAAO,EAAE,aAAa,EAAkB,MAAM,2BAA2B,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAsC,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE7F,OAAO,EAAiB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAK9D,KAAK,KAAK,GAAG;IACZ,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,mBAAmB,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAA;IACnD,WAAW,CAAC,EACT,OAAO,GACP;QACA,SAAS,EAAE,MAAM,CAAA;KAChB,CAAA;IACJ,SAAS,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"analyzerModule.d.ts","sourceRoot":"","sources":["../../../src/openapi/analyzerModule/analyzerModule.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,UAAU,EAAc,MAAM,UAAU,CAAA;AAGjD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAA;AAE3C,OAAO,EACN,oBAAoB,EAEpB,MAAM,4DAA4D,CAAA;AAEnE,OAAO,EAAE,aAAa,EAAkB,MAAM,2BAA2B,CAAA;AACzE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AACzD,OAAO,EAAsC,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE7F,OAAO,EAAiB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAK9D,KAAK,KAAK,GAAG;IACZ,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,mBAAmB,CAAC,EAAE,OAAO,GAAG,mBAAmB,CAAA;IACnD,WAAW,CAAC,EACT,OAAO,GACP;QACA,SAAS,EAAE,MAAM,CAAA;KAChB,CAAA;IACJ,SAAS,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAA;IACrC,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,KAAK,mBAAmB,GAAG;IAC1B,QAAQ,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,cAAc,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,aAAa,EAAE,CAAA;CAAE,CAAA;AAavG,eAAO,MAAM,kBAAkB,uGAQ5B,KAAK,KAAG,OAAO,CAAC,IAAI,CA2GtB,CAAA;AAED,eAAO,MAAM,0BAA0B,UAC/B,oBAAoB,EAAE,UACrB;IACP,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAA;IACrC,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB,wBACqB,MAAM,EAAE,KAC5B,OAAO,CAAC,YAAY,EAAE,CA0IxB,CAAA;AAED,eAAO,MAAM,0BAA0B,SAChC,oBAAoB,UAClB;IACP,WAAW,EAAE,OAAO,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,EAAE,cAAc,CAAA;IAC9B,SAAS,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,OAAO,CAAA;CACrC,wBACqB,MAAM,EAAE,KAC5B;IAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,cAAc,EAAE,CAAA;CAgBhF,CAAA;AAED,eAAO,MAAM,0BAA0B,SAChC,oBAAoB,wBACJ,MAAM,EAAE,KAC5B;IAAE,SAAS,EAAE,YAAY,EAAE,CAAC;IAAC,eAAe,EAAE,cAAc,EAAE,CAAA;CAgChE,CAAA;AAED,eAAO,MAAM,0BAA0B,eAAgB,UAAU,KAAG,aAAa,GAAG,IAyCnF,CAAA;AAED,eAAO,MAAM,8BAA8B,eAAgB,UAAU,KAAG,gBAAgB,EA4CvF,CAAA"}
|
|
@@ -1,211 +1,213 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { existsSync as
|
|
3
|
-
import * as
|
|
4
|
-
import { fileURLToPath as
|
|
5
|
-
import { Project as
|
|
1
|
+
import v from "crypto";
|
|
2
|
+
import { existsSync as O } from "fs";
|
|
3
|
+
import * as M from "path";
|
|
4
|
+
import { fileURLToPath as L } from "url";
|
|
5
|
+
import { Project as j, SyntaxKind as E } from "ts-morph";
|
|
6
6
|
import { Logger as F } from "../../utils/logger.mjs";
|
|
7
|
-
import { discoverImportedName as
|
|
8
|
-
import { discoverRouterFiles as
|
|
9
|
-
import { discoverRouters as
|
|
7
|
+
import { discoverImportedName as R } from "../discoveryModule/discoverImports/discoverImports.mjs";
|
|
8
|
+
import { discoverRouterFiles as z } from "../discoveryModule/discoverRouterFiles/discoverRouterFiles.mjs";
|
|
9
|
+
import { discoverRouters as W } from "../discoveryModule/discoverRouters/discoverRouters.mjs";
|
|
10
10
|
import { OpenApiManager as U } from "../manager/OpenApiManager.mjs";
|
|
11
11
|
import { getSourceFileTimestamp as b } from "./getSourceFileTimestamp.mjs";
|
|
12
|
-
import { getValuesOfObjectLiteral as I, resolveEndpointPath as
|
|
13
|
-
import { parseEndpoint as
|
|
14
|
-
import { parseExposedModel as
|
|
15
|
-
import { SourceFileCache as
|
|
16
|
-
import { WorkerPool as
|
|
17
|
-
function
|
|
18
|
-
const
|
|
19
|
-
for (const n of
|
|
12
|
+
import { getValuesOfObjectLiteral as I, resolveEndpointPath as H } from "./nodeParsers.mjs";
|
|
13
|
+
import { parseEndpoint as K } from "./parseEndpoint.mjs";
|
|
14
|
+
import { parseExposedModel as _, parseNamedExposedModels as D } from "./parseExposedModels.mjs";
|
|
15
|
+
import { SourceFileCache as w } from "./sourceFileCache.mjs";
|
|
16
|
+
import { WorkerPool as B } from "./workerPool.mjs";
|
|
17
|
+
function V() {
|
|
18
|
+
const l = ["./analyzerWorker.mjs", "./analyzerWorker.test.mjs"];
|
|
19
|
+
for (const n of l) {
|
|
20
20
|
const d = new URL(n, import.meta.url);
|
|
21
|
-
if (
|
|
21
|
+
if (O(L(d)))
|
|
22
22
|
return d;
|
|
23
23
|
}
|
|
24
24
|
throw new Error(
|
|
25
25
|
"analyzerWorker.mjs not found. Run yarn build, or run tests via yarn test (which compiles the worker first)."
|
|
26
26
|
);
|
|
27
27
|
}
|
|
28
|
-
const
|
|
29
|
-
logLevel:
|
|
28
|
+
const Y = 2, fe = async ({
|
|
29
|
+
logLevel: l,
|
|
30
30
|
tsconfigPath: n,
|
|
31
31
|
sourceFilePaths: d,
|
|
32
|
-
sourceFileDiscovery:
|
|
33
|
-
incremental:
|
|
34
|
-
profiling: f = "stats"
|
|
32
|
+
sourceFileDiscovery: m,
|
|
33
|
+
incremental: c,
|
|
34
|
+
profiling: f = "stats",
|
|
35
|
+
workers: t = !1
|
|
35
36
|
}) => {
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
37
|
+
const r = U.getInstance();
|
|
38
|
+
if (r.isReady())
|
|
38
39
|
return;
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
tsConfigFilePath:
|
|
40
|
+
l && F.setLevel(l), F.info("Preparing OpenAPI spec");
|
|
41
|
+
const h = new j({
|
|
42
|
+
tsConfigFilePath: M.resolve(n),
|
|
42
43
|
skipFileDependencyResolution: !0
|
|
43
|
-
}), { explicitRouters:
|
|
44
|
-
const p = (d ?? []).map((
|
|
45
|
-
fileName:
|
|
46
|
-
sourceFile:
|
|
47
|
-
routers:
|
|
44
|
+
}), { explicitRouters: g, discoveredRouterFiles: x, allSourceFiles: T } = (() => {
|
|
45
|
+
const p = (d ?? []).map((u) => M.resolve(u)).map((u) => h.getSourceFileOrThrow(u)), P = p.flatMap((u) => ({
|
|
46
|
+
fileName: u.getFilePath(),
|
|
47
|
+
sourceFile: u,
|
|
48
|
+
routers: W(u)
|
|
48
49
|
})), { discoveredRouterFiles: C, discoveredSourceFiles: S } = (() => {
|
|
49
|
-
if (
|
|
50
|
+
if (m === !1)
|
|
50
51
|
return { discoveredRouterFiles: [], discoveredSourceFiles: [] };
|
|
51
|
-
const
|
|
52
|
-
targetPath: typeof
|
|
52
|
+
const u = performance.now(), k = z({
|
|
53
|
+
targetPath: typeof m == "object" ? m.rootPath : ".",
|
|
53
54
|
tsConfigPath: n
|
|
54
55
|
});
|
|
55
|
-
return f !== "off" && F.info(`File discovery took ${Math.round(performance.now() -
|
|
56
|
-
})(),
|
|
57
|
-
(
|
|
56
|
+
return f !== "off" && F.info(`File discovery took ${Math.round(performance.now() - u)}ms`), k;
|
|
57
|
+
})(), A = p.reduce(
|
|
58
|
+
(u, k) => u.some(($) => $.getFilePath() === k.getFilePath()) ? u : u.concat(k),
|
|
58
59
|
S
|
|
59
60
|
);
|
|
60
|
-
return { explicitRouters:
|
|
61
|
-
})(), e =
|
|
62
|
-
(
|
|
63
|
-
|
|
64
|
-
), o = T.flatMap((
|
|
65
|
-
o.length > 0 && o[0] &&
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
incremental:
|
|
70
|
-
cachePath:
|
|
61
|
+
return { explicitRouters: P, discoveredRouterFiles: C, allSourceFiles: A };
|
|
62
|
+
})(), e = g.reduce(
|
|
63
|
+
(i, N) => i.some((p) => p.fileName === N.fileName) ? i : i.concat(N),
|
|
64
|
+
x
|
|
65
|
+
), o = T.flatMap((i) => J(i)).filter((i) => !!i);
|
|
66
|
+
o.length > 0 && o[0] && r.setHeader(o[0]);
|
|
67
|
+
const s = T.flatMap((i) => Q(i));
|
|
68
|
+
r.setExposedModels(s);
|
|
69
|
+
const a = typeof c == "object" && c.cachePath ? c.cachePath : M.resolve(process.cwd(), "node_modules", ".cache", "moonflower"), y = await q(e, {
|
|
70
|
+
incremental: c !== !1,
|
|
71
|
+
cachePath: a,
|
|
71
72
|
timestampCache: {},
|
|
72
73
|
profiling: f,
|
|
73
|
-
tsconfigPath:
|
|
74
|
+
tsconfigPath: M.resolve(n),
|
|
75
|
+
workers: t
|
|
74
76
|
});
|
|
75
|
-
|
|
76
|
-
discoveredRouterFiles:
|
|
77
|
-
path:
|
|
78
|
-
routers:
|
|
77
|
+
r.setStats({
|
|
78
|
+
discoveredRouterFiles: x.map((i) => ({
|
|
79
|
+
path: i.fileName,
|
|
80
|
+
routers: i.routers.named.map((N) => ({
|
|
79
81
|
name: N,
|
|
80
|
-
endpoints: y.filter((p) => p.sourceFilePath ===
|
|
82
|
+
endpoints: y.filter((p) => p.sourceFilePath === i.fileName).map((p) => `${p.method.toUpperCase()} ${p.path}`)
|
|
81
83
|
}))
|
|
82
84
|
})),
|
|
83
|
-
explicitRouterFiles:
|
|
84
|
-
path:
|
|
85
|
-
routers:
|
|
85
|
+
explicitRouterFiles: g.map((i) => ({
|
|
86
|
+
path: i.fileName,
|
|
87
|
+
routers: i.routers.named.map((N) => ({
|
|
86
88
|
name: N,
|
|
87
|
-
endpoints: y.filter((p) => p.sourceFilePath ===
|
|
89
|
+
endpoints: y.filter((p) => p.sourceFilePath === i.fileName).map((p) => `${p.method.toUpperCase()} ${p.path}`)
|
|
88
90
|
}))
|
|
89
91
|
}))
|
|
90
|
-
}),
|
|
91
|
-
},
|
|
92
|
-
const
|
|
93
|
-
for (const e of
|
|
94
|
-
const o = b(e.sourceFile, n.timestampCache,
|
|
95
|
-
|
|
92
|
+
}), r.setEndpoints(y), r.markAsReady();
|
|
93
|
+
}, q = async (l, n, d) => {
|
|
94
|
+
const m = n.profiling ?? "stats", c = performance.now(), f = [], t = [], r = performance.now(), h = /* @__PURE__ */ new Map();
|
|
95
|
+
for (const e of l) {
|
|
96
|
+
const o = b(e.sourceFile, n.timestampCache, h), s = n.incremental ? w.getCachedResults(e.sourceFile, o, n.cachePath) : null;
|
|
97
|
+
s ? (F.debug(`[${e.fileName}] Found cached results`), f.push({ endpoints: s.endpoints, fileName: e.fileName, timing: 0, endpointTimings: [] })) : t.push({ file: e, timestamp: o });
|
|
96
98
|
}
|
|
97
|
-
if (
|
|
98
|
-
return
|
|
99
|
+
if (m !== "off" && F.info(`Cache freshness check took ${Math.round(performance.now() - r)}ms`), t.length === 0)
|
|
100
|
+
return m !== "off" && F.info(`Router analysis took ${Math.round(performance.now() - c)}ms`), f.flatMap((e) => e.endpoints);
|
|
99
101
|
const g = /* @__PURE__ */ new Map();
|
|
100
102
|
for (const { file: e } of t)
|
|
101
103
|
g.set(e.fileName, { endpoints: [], fileName: e.fileName, timing: 0, endpointTimings: [] });
|
|
102
|
-
if (t.length <=
|
|
104
|
+
if (!(n.workers !== !1) || t.length <= Y)
|
|
103
105
|
for (const { file: e } of t) {
|
|
104
|
-
const { endpoints: o, endpointTimings:
|
|
105
|
-
|
|
106
|
+
const { endpoints: o, endpointTimings: s } = G(e), a = g.get(e.fileName);
|
|
107
|
+
a.endpoints = o, a.endpointTimings = s, a.timing = s.reduce((y, i) => y + i.timing, 0);
|
|
106
108
|
}
|
|
107
109
|
else {
|
|
108
|
-
const e = t.map(({ file:
|
|
109
|
-
fileName:
|
|
110
|
+
const e = t.map(({ file: a }) => ({
|
|
111
|
+
fileName: a.fileName,
|
|
110
112
|
task: {
|
|
111
|
-
taskId:
|
|
113
|
+
taskId: v.randomUUID(),
|
|
112
114
|
tsconfigPath: n.tsconfigPath,
|
|
113
|
-
sourceFilePath:
|
|
114
|
-
routerNames:
|
|
115
|
+
sourceFilePath: a.sourceFile.getFilePath(),
|
|
116
|
+
routerNames: a.routers.named,
|
|
115
117
|
filterEndpointPaths: d
|
|
116
118
|
}
|
|
117
|
-
})), o = new
|
|
118
|
-
let
|
|
119
|
+
})), o = new B(V(), e.length);
|
|
120
|
+
let s;
|
|
119
121
|
try {
|
|
120
|
-
|
|
122
|
+
s = await o.runAll(e.map((a) => a.task));
|
|
121
123
|
} finally {
|
|
122
124
|
o.terminate();
|
|
123
125
|
}
|
|
124
|
-
for (let
|
|
125
|
-
const y =
|
|
126
|
+
for (let a = 0; a < s.length; a++) {
|
|
127
|
+
const y = s[a], i = e[a].fileName, N = g.get(i);
|
|
126
128
|
if ("error" in y) {
|
|
127
|
-
F.error(`[${
|
|
129
|
+
F.error(`[${i}] Worker error: ${y.error}`);
|
|
128
130
|
continue;
|
|
129
131
|
}
|
|
130
|
-
N.endpoints = y.endpoints, N.endpointTimings = y.endpointTimings, N.timing = y.endpointTimings.reduce((p,
|
|
132
|
+
N.endpoints = y.endpoints, N.endpointTimings = y.endpointTimings, N.timing = y.endpointTimings.reduce((p, P) => p + P.timing, 0);
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
for (const { file: e, timestamp: o } of t) {
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
+
const s = g.get(e.fileName);
|
|
137
|
+
s.endpoints.length > 0 && w.cacheResults(e.sourceFile, o, n.cachePath, s.endpoints);
|
|
136
138
|
}
|
|
137
139
|
const T = [...f, ...Array.from(g.values())];
|
|
138
|
-
return
|
|
140
|
+
return m !== "off" && F.info(`Router analysis took ${Math.round(performance.now() - c)}ms`), m === "stats" ? T.map((e) => ({ fileName: e.fileName, timeTaken: e.timing })).sort((e, o) => o.timeTaken - e.timeTaken).filter((e) => e.timeTaken > 500).forEach((e) => {
|
|
139
141
|
F.info(`- [${e.fileName}] Took ${Math.round(e.timeTaken)}ms to analyze`);
|
|
140
|
-
}) :
|
|
141
|
-
F.info(`- [${e.fileName}] Took ${Math.round(e.timeTaken)}ms to analyze`), e.endpointTimings.sort((o,
|
|
142
|
-
F.info(` - ${o.method} ${o.path} (${Math.round(o.timing)}ms)`), o.sectionTimings.filter((
|
|
143
|
-
F.info(` - ${
|
|
142
|
+
}) : m === "debug" && T.map((e) => ({ fileName: e.fileName, timeTaken: e.timing, endpointTimings: e.endpointTimings })).sort((e, o) => o.timeTaken - e.timeTaken).forEach((e) => {
|
|
143
|
+
F.info(`- [${e.fileName}] Took ${Math.round(e.timeTaken)}ms to analyze`), e.endpointTimings.sort((o, s) => s.timing - o.timing).forEach((o) => {
|
|
144
|
+
F.info(` - ${o.method} ${o.path} (${Math.round(o.timing)}ms)`), o.sectionTimings.filter((s) => s.timing >= 1).sort((s, a) => a.timing - s.timing).forEach((s) => {
|
|
145
|
+
F.info(` - ${s.section}: ${Math.round(s.timing)}ms`);
|
|
144
146
|
});
|
|
145
147
|
});
|
|
146
148
|
}), T.flatMap((e) => e.endpoints);
|
|
147
|
-
},
|
|
148
|
-
const d = [],
|
|
149
|
-
return
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
const g =
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
method:
|
|
158
|
-
path:
|
|
159
|
-
timing: performance.now() -
|
|
160
|
-
sectionTimings:
|
|
161
|
-
}), d.push(
|
|
149
|
+
}, G = (l, n) => {
|
|
150
|
+
const d = [], m = [], f = ["get", "post", "put", "delete", "del", "patch"].join("|");
|
|
151
|
+
return l.routers.named.forEach((t) => {
|
|
152
|
+
const r = new RegExp(`${t}\\.(?:${f})`);
|
|
153
|
+
l.sourceFile.forEachChild((h) => {
|
|
154
|
+
const g = h.getText();
|
|
155
|
+
if (r.test(g)) {
|
|
156
|
+
H(h);
|
|
157
|
+
const x = performance.now(), { endpoint: T, sectionTimings: e } = K(h, l.fileName);
|
|
158
|
+
m.push({
|
|
159
|
+
method: T.method,
|
|
160
|
+
path: T.path,
|
|
161
|
+
timing: performance.now() - x,
|
|
162
|
+
sectionTimings: e
|
|
163
|
+
}), d.push(T);
|
|
162
164
|
}
|
|
163
165
|
});
|
|
164
|
-
}), { endpoints: d, endpointTimings:
|
|
165
|
-
},
|
|
166
|
-
const n =
|
|
167
|
-
sourceFile:
|
|
166
|
+
}), { endpoints: d, endpointTimings: m };
|
|
167
|
+
}, J = (l) => {
|
|
168
|
+
const n = R({
|
|
169
|
+
sourceFile: l,
|
|
168
170
|
originalName: "useApiHeader"
|
|
169
171
|
});
|
|
170
172
|
if (!n)
|
|
171
173
|
return null;
|
|
172
|
-
const d =
|
|
174
|
+
const d = l.forEachChildAsArray().filter((t) => t.isKind(E.ExpressionStatement)).find((t) => n && t.getText().startsWith(n));
|
|
173
175
|
if (!d)
|
|
174
176
|
return null;
|
|
175
|
-
const
|
|
176
|
-
...
|
|
177
|
-
[
|
|
177
|
+
const m = d.getFirstDescendantByKindOrThrow(E.ObjectLiteralExpression), c = I(m), f = (t) => typeof t == "string" || Array.isArray(t) && t.every((r) => typeof r == "string") ? t : t.reduce((r, h) => typeof h == "string" ? r : {
|
|
178
|
+
...r,
|
|
179
|
+
[h.identifier]: f(h.value)
|
|
178
180
|
}, {});
|
|
179
|
-
return f(
|
|
180
|
-
},
|
|
181
|
-
const n = [], d =
|
|
182
|
-
sourceFile:
|
|
181
|
+
return f(c);
|
|
182
|
+
}, Q = (l) => {
|
|
183
|
+
const n = [], d = R({
|
|
184
|
+
sourceFile: l,
|
|
183
185
|
originalName: "useExposeApiModel"
|
|
184
|
-
}),
|
|
185
|
-
sourceFile:
|
|
186
|
+
}), m = R({
|
|
187
|
+
sourceFile: l,
|
|
186
188
|
originalName: "useExposeNamedApiModels"
|
|
187
189
|
});
|
|
188
|
-
return
|
|
189
|
-
if (d &&
|
|
190
|
-
const
|
|
191
|
-
if (!
|
|
190
|
+
return l.forEachChildAsArray().filter((c) => c.isKind(E.ExpressionStatement)).map((c) => {
|
|
191
|
+
if (d && c.getText().startsWith(d)) {
|
|
192
|
+
const r = (c.getFirstChild()?.getChildrenOfKind(E.SyntaxList) || [])[0].getFirstChild();
|
|
193
|
+
if (!r)
|
|
192
194
|
return;
|
|
193
|
-
n.push(
|
|
195
|
+
n.push(_(r));
|
|
194
196
|
return;
|
|
195
197
|
}
|
|
196
|
-
if (
|
|
197
|
-
const
|
|
198
|
-
if (!
|
|
198
|
+
if (m && c.getText().startsWith(m)) {
|
|
199
|
+
const r = (c.getFirstChild()?.getChildrenOfKind(E.SyntaxList) || [])[0].getFirstChild();
|
|
200
|
+
if (!r)
|
|
199
201
|
return;
|
|
200
|
-
|
|
202
|
+
D(r).forEach((g) => n.push(g));
|
|
201
203
|
}
|
|
202
204
|
}), n;
|
|
203
205
|
};
|
|
204
206
|
export {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
q as analyzeMultipleSourceFiles,
|
|
208
|
+
J as analyzeSourceFileApiHeader,
|
|
209
|
+
G as analyzeSourceFileEndpoints,
|
|
210
|
+
Q as analyzeSourceFileExposedModels,
|
|
211
|
+
fe as prepareOpenApiSpec
|
|
210
212
|
};
|
|
211
213
|
//# sourceMappingURL=analyzerModule.mjs.map
|
|
@@ -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, MtimeCache, 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\tconst freshnessCheckStart = performance.now()\n\tconst mtimeCache: MtimeCache = new Map()\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache, mtimeCache)\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\tif (profiling !== 'off') {\n\t\tLogger.info(`Cache freshness check took ${Math.round(performance.now() - freshnessCheckStart)}ms`)\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","freshnessCheckStart","mtimeCache","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":"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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, MtimeCache, 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\tworkers?: boolean\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\tworkers = false,\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\tworkers,\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\tworkers?: boolean\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\tconst freshnessCheckStart = performance.now()\n\tconst mtimeCache: MtimeCache = new Map()\n\tfor (const file of files) {\n\t\tconst timestamp = getSourceFileTimestamp(file.sourceFile, config.timestampCache, mtimeCache)\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\tif (profiling !== 'off') {\n\t\tLogger.info(`Cache freshness check took ${Math.round(performance.now() - freshnessCheckStart)}ms`)\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\tconst useWorkers = config.workers !== false\n\tif (!useWorkers || 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\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","workers","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","freshnessCheckStart","mtimeCache","timestamp","getSourceFileTimestamp","hit","SourceFileCache","f","byFile","endpointTimings","analyzeSourceFileEndpoints","fileResult","sum","t","allTasks","crypto","pool","WorkerPool","results","ft","i","result","fileName","analyzedFiles","a","b","ep","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;AA6CA,MAAMG,IAAiC,GAM1BC,KAAqB,OAAO;AAAA,EACxC,UAAAC;AAAA,EACA,cAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,qBAAAC;AAAA,EACA,aAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,SAAAC,IAAU;AACX,MAA4B;AACrB,QAAAC,IAAiBC,EAAe,YAAY;AAE9C,MAAAD,EAAe;AAClB;AAGD,EAAIP,KACHS,EAAO,SAAST,CAAQ,GAGzBS,EAAO,KAAK,wBAAwB;AAE9B,QAAAC,IAAU,IAAIC,EAAQ;AAAA,IAC3B,kBAAkBC,EAAK,QAAQX,CAAY;AAAA,IAC3C,8BAA8B;AAAA,EAAA,CAC9B,GAEK,EAAE,iBAAAY,GAAiB,uBAAAC,GAAuB,gBAAAC,EAAA,KAAoB,MAAM;AAGnE,UAAAC,KAFmBd,KAAmB,CAAC,GACI,IAAI,CAACe,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,UAAIlB,MAAwB;AAC3B,eAAO,EAAE,uBAAuB,IAAI,uBAAuB,CAAA,EAAG;AAGzD,YAAAmB,IAAY,YAAY,IAAI,GAC5BC,IAAQC,EAAoB;AAAA,QACjC,YAAY,OAAOrB,KAAwB,WAAWA,EAAoB,WAAW;AAAA,QACrF,cAAcF;AAAA,MAAA,CACd;AACD,aAAII,MAAc,SACVI,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,OAAO9B,KAAgB,YAAYA,EAAY,YAC3CA,EAAY,YAEbQ,EAAK,QAAQ,QAAQ,OAAO,gBAAgB,UAAU,YAAY,GAEpEuB,IAAY,MAAMC,EAA2BR,GAAgB;AAAA,IAClE,aAAaxB,MAAgB;AAAA,IAC7B,WAAA8B;AAAA,IACA,gBAAgB,CAAC;AAAA,IACjB,WAAA7B;AAAA,IACA,cAAcO,EAAK,QAAQX,CAAY;AAAA,IACvC,SAAAK;AAAA,EAAA,CACA;AAED,EAAAC,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,GAQAC,MAC6B;AACvB,QAAAlC,IAAYiC,EAAO,aAAa,SAChChB,IAAY,YAAY,IAAI,GAM5BkB,IAAuB,CAAC,GACxBC,IAA2B,CAAC,GAE5BC,IAAsB,YAAY,IAAI,GACtCC,wBAA6B,IAAI;AACvC,aAAWxB,KAAQI,GAAO;AACzB,UAAMqB,IAAYC,EAAuB1B,EAAK,YAAYmB,EAAO,gBAAgBK,CAAU,GACrFG,IAAMR,EAAO,cAChBS,EAAgB,iBAAiB5B,EAAK,YAAYyB,GAAWN,EAAO,SAAS,IAC7E;AACH,IAAIQ,KACHrC,EAAO,MAAM,IAAIU,EAAK,QAAQ,wBAAwB,GACtDqB,EAAO,KAAK,EAAE,WAAWM,EAAI,WAAW,UAAU3B,EAAK,UAAU,QAAQ,GAAG,iBAAiB,IAAI,KAEjGsB,EAAS,KAAK,EAAE,MAAAtB,GAAM,WAAAyB,EAAA,CAAW;AAAA,EAClC;AAMG,MAJAvC,MAAc,SACVI,EAAA,KAAK,8BAA8B,KAAK,MAAM,YAAY,IAAI,IAAIiC,CAAmB,CAAC,IAAI,GAG9FD,EAAS,WAAW;AACvB,WAAIpC,MAAc,SACVI,EAAA,KAAK,wBAAwB,KAAK,MAAM,YAAY,IAAI,IAAIa,CAAS,CAAC,IAAI,GAE3EkB,EAAO,QAAQ,CAACQ,MAAMA,EAAE,SAAS;AAUnC,QAAAC,wBAAa,IAAwB;AAChC,aAAA,EAAE,MAAA9B,EAAK,KAAKsB;AACtB,IAAAQ,EAAO,IAAI9B,EAAK,UAAU,EAAE,WAAW,CAAC,GAAG,UAAUA,EAAK,UAAU,QAAQ,GAAG,iBAAiB,IAAI;AAIrG,MAAI,EADemB,EAAO,YAAY,OACnBG,EAAS,UAAU3C;AAC1B,eAAA,EAAE,MAAAqB,EAAK,KAAKsB,GAAU;AAChC,YAAM,EAAE,WAAAN,GAAW,iBAAAe,MAAoBC,EAA2BhC,CAAyB,GACrFiC,IAAaH,EAAO,IAAI9B,EAAK,QAAQ;AAC3C,MAAAiC,EAAW,YAAYjB,GACvBiB,EAAW,kBAAkBF,GAClBE,EAAA,SAASF,EAAgB,OAAO,CAACG,GAAKC,MAAMD,IAAMC,EAAE,QAAQ,CAAC;AAAA,IAAA;AAAA,OAEnE;AAEN,UAAMC,IAAuBd,EAAS,IAAI,CAAC,EAAE,MAAAtB,SAAY;AAAA,MACxD,UAAUA,EAAK;AAAA,MACf,MAAM;AAAA,QACL,QAAQqC,EAAO,WAAW;AAAA,QAC1B,cAAclB,EAAO;AAAA,QACrB,gBAAgBnB,EAAK,WAAW,YAAY;AAAA,QAC5C,aAAaA,EAAK,QAAQ;AAAA,QAC1B,qBAAAoB;AAAA,MAAA;AAAA,IACD,EACC,GAEIkB,IAAO,IAAIC,EAAWlE,EAAiB,GAAG+D,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,QAAArD,EAAO,MAAM,IAAIsD,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,MAAAnC,GAAM,WAAAyB,EAAU,KAAKH,GAAU;AAC3C,UAAMW,IAAaH,EAAO,IAAI9B,EAAK,QAAQ;AACvC,IAAAiC,EAAW,UAAU,SAAS,KACjCL,EAAgB,aAAa5B,EAAK,YAAYyB,GAAWN,EAAO,WAAWc,EAAW,SAAS;AAAA,EAChG;AAGK,QAAAY,IAAgB,CAAC,GAAGxB,GAAQ,GAAG,MAAM,KAAKS,EAAO,OAAO,CAAC,CAAC;AAEhE,SAAI5C,MAAc,SACVI,EAAA,KAAK,wBAAwB,KAAK,MAAM,YAAY,IAAI,IAAIa,CAAS,CAAC,IAAI,GAG9EjB,MAAc,UACjB2D,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,IAAA7C,EAAA,KAAK,MAAM6C,EAAE,QAAQ,UAAU,KAAK,MAAMA,EAAE,SAAS,CAAC,eAAe;AAAA,EAAA,CAC5E,IACQjD,MAAc,WAEtB2D,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,IAAA7C,EAAA,KAAK,MAAM6C,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,MAAA1D,EAAO,KAAK,OAAO0D,EAAG,MAAM,IAAIA,EAAG,IAAI,KAAK,KAAK,MAAMA,EAAG,MAAM,CAAC,KAAK,GACtEA,EAAG,eACD,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,EAC3B,KAAK,CAACF,GAAGC,MAAMA,EAAE,SAASD,EAAE,MAAM,EAClC,QAAQ,CAAC,MAAM;AACR,QAAAxD,EAAA,KAAK,SAAS,EAAE,OAAO,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC,IAAI;AAAA,MAAA,CAC3D;AAAA,IAAA,CACF;AAAA,EAAA,CACF,GAGIuD,EAAc,QAAQ,CAAChB,MAAMA,EAAE,SAAS;AAChD,GA6BaG,IAA6B,CACzChC,GACAoB,MACsE;AACtE,QAAMJ,IAA4B,CAAC,GAC7Be,IAAoC,CAAC,GAErCkB,IADa,CAAC,OAAO,QAAQ,OAAO,UAAU,OAAO,OAAO,EAC9B,KAAK,GAAG;AAE5C,SAAAjD,EAAK,QAAQ,MAAM,QAAQ,CAACkD,MAAe;AAC1C,UAAMC,IAAgB,IAAI,OAAO,GAAGD,CAAU,SAASD,CAAgB,GAAG;AACrE,IAAAjD,EAAA,WAAW,aAAa,CAACoD,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,GAAMpD,EAAK,QAAQ;AACtE,QAAA+B,EAAgB,KAAK;AAAA,UACpB,QAAQyB,EAAS;AAAA,UACjB,MAAMA,EAAS;AAAA,UACf,QAAQ,YAAY,IAAA,IAAQD;AAAA,UAC5B,gBAAAE;AAAA,QAAA,CACA,GACDzC,EAAU,KAAKwC,CAAQ;AAAA,MAAA;AAAA,IACxB,CACA;AAAA,EAAA,CACD,GAEM,EAAE,WAAAxC,GAAW,iBAAAe,EAAgB;AACrC,GAEapB,IAA6B,CAACgD,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,CAAC7D,GAAKC,MACjB,OAAOA,KAAY,WACfD,IAED;AAAA,IACN,GAAGA;AAAA,IACH,CAACC,EAAQ,UAAU,GAAG2D,EAAe3D,EAAQ,KAAiB;AAAA,EAC/D,GACE,EAAE;AAEN,SAAO2D,EAAeF,CAAM;AAC7B,GAEalD,IAAiC,CAAC6C,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.cjs","sources":["../../src/router/Router.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"Router.cjs","sources":["../../src/router/Router.ts"],"sourcesContent":["import KoaRouter, { RouterContext, RouterMiddleware } from '@koa/router'\nimport Koa from 'koa'\n\nimport { OpenApiManager } from '../openapi/manager/OpenApiManager'\nimport { ExtractedRequestParams } from '../utils/TypeUtils'\nimport { parseEndpointReturnValue } from './parseEndpointReturnValue'\n\ntype Props = {\n\tskipOpenApiAnalysis: boolean\n}\n\nexport class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {\n\tpublic koaRouter: KoaRouter = new KoaRouter()\n\n\tpublic constructor(props: Props = { skipOpenApiAnalysis: false }) {\n\t\tif (!props.skipOpenApiAnalysis) {\n\t\t\tconst openApiManager = OpenApiManager.getInstance()\n\t\t\topenApiManager.registerRouters([this])\n\t\t}\n\t}\n\n\tprivate async sendResponseValue<P extends string>(\n\t\tctx: RouterContext,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\t// @ts-expect-error - Context is valid\n\t\tconst responseValue = await callback(ctx, undefined)\n\t\tconst { value, status, contentType } = parseEndpointReturnValue(responseValue)\n\t\tctx.body = value\n\t\tif (status !== 'unset') {\n\t\t\tctx.status = status\n\t\t}\n\t\tctx.set('Content-Type', contentType)\n\t}\n\n\tpublic use(...middleware: Array<RouterMiddleware<StateT, ContextT>>) {\n\t\tthis.koaRouter.use(...middleware)\n\t\treturn this\n\t}\n\n\tpublic with<ResponseTypeT extends Record<string, any>>(\n\t\tmiddleware: (ctx: Koa.ParameterizedContext<ContextT>) => ResponseTypeT,\n\t) {\n\t\ttype AugmentedData = ResponseTypeT extends Promise<any> ? Awaited<ResponseTypeT> : ResponseTypeT\n\t\tthis.koaRouter.use(async (ctx, next) => {\n\t\t\tconst userData = await Promise.resolve(middleware(ctx))\n\t\t\tObject.keys(userData).forEach((key) => {\n\t\t\t\tctx[key] = userData[key]\n\t\t\t})\n\t\t\tawait next()\n\t\t})\n\t\treturn this as Router<StateT, ContextT & AugmentedData>\n\t}\n\n\tpublic get<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.get(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic post<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.post(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic put<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.put(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic delete<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.delete(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic del<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.del(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic patch<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.patch(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic routes() {\n\t\treturn this.koaRouter.routes()\n\t}\n\n\tpublic allowedMethods() {\n\t\treturn this.koaRouter.allowedMethods()\n\t}\n}\n"],"names":["Router","props","KoaRouter","OpenApiManager","ctx","callback","responseValue","value","status","contentType","parseEndpointReturnValue","middleware","next","userData","key","path"],"mappings":"8MAWO,MAAMA,CAAiE,CAGtE,YAAYC,EAAe,CAAE,oBAAqB,IAAS,CAF3D,KAAA,UAAuB,IAAIC,EAG5BD,EAAM,qBACaE,iBAAe,YAAY,EACnC,gBAAgB,CAAC,IAAI,CAAC,CACtC,CAGD,MAAc,kBACbC,EACAC,EACC,CAED,MAAMC,EAAgB,MAAMD,EAASD,EAAK,MAAS,EAC7C,CAAE,MAAAG,EAAO,OAAAC,EAAQ,YAAAC,CAAY,EAAIC,EAAAA,yBAAyBJ,CAAa,EAC7EF,EAAI,KAAOG,EACPC,IAAW,UACdJ,EAAI,OAASI,GAEVJ,EAAA,IAAI,eAAgBK,CAAW,CAAA,CAG7B,OAAOE,EAAuD,CAC/D,YAAA,UAAU,IAAI,GAAGA,CAAU,EACzB,IAAA,CAGD,KACNA,EACC,CAED,YAAK,UAAU,IAAI,MAAOP,EAAKQ,IAAS,CACvC,MAAMC,EAAW,MAAM,QAAQ,QAAQF,EAAWP,CAAG,CAAC,EACtD,OAAO,KAAKS,CAAQ,EAAE,QAASC,GAAQ,CAClCV,EAAAU,CAAG,EAAID,EAASC,CAAG,CAAA,CACvB,EACD,MAAMF,EAAK,CAAA,CACX,EACM,IAAA,CAGD,IACNG,EACAV,EACC,CACD,YAAK,UAAU,IAAIU,EAAM,MAAOX,GAAQ,CACjC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,KACNU,EACAV,EACC,CACD,YAAK,UAAU,KAAKU,EAAM,MAAOX,GAAQ,CAClC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,IACNU,EACAV,EACC,CACD,YAAK,UAAU,IAAIU,EAAM,MAAOX,GAAQ,CACjC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,OACNU,EACAV,EACC,CACD,YAAK,UAAU,OAAOU,EAAM,MAAOX,GAAQ,CACpC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,IACNU,EACAV,EACC,CACD,YAAK,UAAU,IAAIU,EAAM,MAAOX,GAAQ,CACjC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,MACNU,EACAV,EACC,CACD,YAAK,UAAU,MAAMU,EAAM,MAAOX,GAAQ,CACnC,MAAA,KAAK,kBAAkBA,EAAKC,CAAQ,CAAA,CAC1C,EACM,IAAA,CAGD,QAAS,CACR,OAAA,KAAK,UAAU,OAAO,CAAA,CAGvB,gBAAiB,CAChB,OAAA,KAAK,UAAU,eAAe,CAAA,CAEvC"}
|
package/dist/router/Router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { default as KoaRouter } from '@koa/router';
|
|
1
|
+
import { default as KoaRouter, RouterMiddleware } from '@koa/router';
|
|
2
2
|
import { default as Koa } from 'koa';
|
|
3
3
|
import { ExtractedRequestParams } from '../utils/TypeUtils';
|
|
4
4
|
|
|
@@ -9,16 +9,23 @@ export declare class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultCon
|
|
|
9
9
|
koaRouter: KoaRouter;
|
|
10
10
|
constructor(props?: Props);
|
|
11
11
|
private sendResponseValue;
|
|
12
|
-
use(...middleware: Array<
|
|
12
|
+
use(...middleware: Array<RouterMiddleware<StateT, ContextT>>): this;
|
|
13
13
|
with<ResponseTypeT extends Record<string, any>>(middleware: (ctx: Koa.ParameterizedContext<ContextT>) => ResponseTypeT): Router<StateT, ContextT & (ResponseTypeT extends Promise<any> ? Awaited<ResponseTypeT> : ResponseTypeT)>;
|
|
14
|
-
get<P extends string>(path: P, callback:
|
|
15
|
-
post<P extends string>(path: P, callback:
|
|
16
|
-
put<P extends string>(path: P, callback:
|
|
17
|
-
delete<P extends string>(path: P, callback:
|
|
18
|
-
del<P extends string>(path: P, callback:
|
|
19
|
-
patch<P extends string>(path: P, callback:
|
|
20
|
-
routes():
|
|
21
|
-
|
|
14
|
+
get<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
15
|
+
post<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
16
|
+
put<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
17
|
+
delete<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
18
|
+
del<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
19
|
+
patch<P extends string>(path: P, callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>): this;
|
|
20
|
+
routes(): Koa.Middleware<Koa.DefaultState, Koa.DefaultContext & {
|
|
21
|
+
params: Record<string, string>;
|
|
22
|
+
router: import('@koa/router').RouterInstance<Koa.DefaultState, Koa.DefaultContext>;
|
|
23
|
+
_matchedRoute?: string | RegExp;
|
|
24
|
+
_matchedRouteName?: string;
|
|
25
|
+
}> & {
|
|
26
|
+
router?: KoaRouter<Koa.DefaultState, Koa.DefaultContext> | undefined;
|
|
27
|
+
};
|
|
28
|
+
allowedMethods(): RouterMiddleware<Koa.DefaultState, Koa.DefaultContext, unknown>;
|
|
22
29
|
}
|
|
23
30
|
export {};
|
|
24
31
|
//# sourceMappingURL=Router.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/router/Router.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Router.d.ts","sourceRoot":"","sources":["../../src/router/Router.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAAiB,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACxE,OAAO,GAAG,MAAM,KAAK,CAAA;AAGrB,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAG3D,KAAK,KAAK,GAAG;IACZ,mBAAmB,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED,qBAAa,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,QAAQ,GAAG,GAAG,CAAC,cAAc;IACpE,SAAS,EAAE,SAAS,CAAkB;gBAE1B,KAAK,GAAE,KAAsC;YAOlD,iBAAiB;IAcxB,GAAG,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAK5D,IAAI,CAAC,aAAa,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACpD,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,KAAK,aAAa,GAUvD,MAAM,CAAC,MAAM,EAAE,QAAQ,gFAAgB,CAAC;IAGjD,GAAG,CAAC,CAAC,SAAS,MAAM,EAC1B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,IAAI,CAAC,CAAC,SAAS,MAAM,EAC3B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,GAAG,CAAC,CAAC,SAAS,MAAM,EAC1B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,MAAM,CAAC,CAAC,SAAS,MAAM,EAC7B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,GAAG,CAAC,CAAC,SAAS,MAAM,EAC1B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,KAAK,CAAC,CAAC,SAAS,MAAM,EAC5B,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,sBAAsB,CAAC,CAAC,CAAC,CAAC;IAQlE,MAAM;;;;;;;;IAIN,cAAc;CAGrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Router.mjs","sources":["../../src/router/Router.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"Router.mjs","sources":["../../src/router/Router.ts"],"sourcesContent":["import KoaRouter, { RouterContext, RouterMiddleware } from '@koa/router'\nimport Koa from 'koa'\n\nimport { OpenApiManager } from '../openapi/manager/OpenApiManager'\nimport { ExtractedRequestParams } from '../utils/TypeUtils'\nimport { parseEndpointReturnValue } from './parseEndpointReturnValue'\n\ntype Props = {\n\tskipOpenApiAnalysis: boolean\n}\n\nexport class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {\n\tpublic koaRouter: KoaRouter = new KoaRouter()\n\n\tpublic constructor(props: Props = { skipOpenApiAnalysis: false }) {\n\t\tif (!props.skipOpenApiAnalysis) {\n\t\t\tconst openApiManager = OpenApiManager.getInstance()\n\t\t\topenApiManager.registerRouters([this])\n\t\t}\n\t}\n\n\tprivate async sendResponseValue<P extends string>(\n\t\tctx: RouterContext,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\t// @ts-expect-error - Context is valid\n\t\tconst responseValue = await callback(ctx, undefined)\n\t\tconst { value, status, contentType } = parseEndpointReturnValue(responseValue)\n\t\tctx.body = value\n\t\tif (status !== 'unset') {\n\t\t\tctx.status = status\n\t\t}\n\t\tctx.set('Content-Type', contentType)\n\t}\n\n\tpublic use(...middleware: Array<RouterMiddleware<StateT, ContextT>>) {\n\t\tthis.koaRouter.use(...middleware)\n\t\treturn this\n\t}\n\n\tpublic with<ResponseTypeT extends Record<string, any>>(\n\t\tmiddleware: (ctx: Koa.ParameterizedContext<ContextT>) => ResponseTypeT,\n\t) {\n\t\ttype AugmentedData = ResponseTypeT extends Promise<any> ? Awaited<ResponseTypeT> : ResponseTypeT\n\t\tthis.koaRouter.use(async (ctx, next) => {\n\t\t\tconst userData = await Promise.resolve(middleware(ctx))\n\t\t\tObject.keys(userData).forEach((key) => {\n\t\t\t\tctx[key] = userData[key]\n\t\t\t})\n\t\t\tawait next()\n\t\t})\n\t\treturn this as Router<StateT, ContextT & AugmentedData>\n\t}\n\n\tpublic get<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.get(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic post<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.post(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic put<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.put(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic delete<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.delete(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic del<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.del(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic patch<P extends string>(\n\t\tpath: P,\n\t\tcallback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,\n\t) {\n\t\tthis.koaRouter.patch(path, async (ctx) => {\n\t\t\tawait this.sendResponseValue(ctx, callback)\n\t\t})\n\t\treturn this\n\t}\n\n\tpublic routes() {\n\t\treturn this.koaRouter.routes()\n\t}\n\n\tpublic allowedMethods() {\n\t\treturn this.koaRouter.allowedMethods()\n\t}\n}\n"],"names":["Router","props","KoaRouter","OpenApiManager","ctx","callback","responseValue","value","status","contentType","parseEndpointReturnValue","middleware","next","userData","key","path"],"mappings":";;;AAWO,MAAMA,EAAiE;AAAA,EAGtE,YAAYC,IAAe,EAAE,qBAAqB,MAAS;AAF3D,SAAA,YAAuB,IAAIC,EAAU,GAGtCD,EAAM,uBACaE,EAAe,YAAY,EACnC,gBAAgB,CAAC,IAAI,CAAC;AAAA,EACtC;AAAA,EAGD,MAAc,kBACbC,GACAC,GACC;AAED,UAAMC,IAAgB,MAAMD,EAASD,GAAK,MAAS,GAC7C,EAAE,OAAAG,GAAO,QAAAC,GAAQ,aAAAC,EAAY,IAAIC,EAAyBJ,CAAa;AAC7E,IAAAF,EAAI,OAAOG,GACPC,MAAW,YACdJ,EAAI,SAASI,IAEVJ,EAAA,IAAI,gBAAgBK,CAAW;AAAA,EAAA;AAAA,EAG7B,OAAOE,GAAuD;AAC/D,gBAAA,UAAU,IAAI,GAAGA,CAAU,GACzB;AAAA,EAAA;AAAA,EAGD,KACNA,GACC;AAED,gBAAK,UAAU,IAAI,OAAOP,GAAKQ,MAAS;AACvC,YAAMC,IAAW,MAAM,QAAQ,QAAQF,EAAWP,CAAG,CAAC;AACtD,aAAO,KAAKS,CAAQ,EAAE,QAAQ,CAACC,MAAQ;AAClC,QAAAV,EAAAU,CAAG,IAAID,EAASC,CAAG;AAAA,MAAA,CACvB,GACD,MAAMF,EAAK;AAAA,IAAA,CACX,GACM;AAAA,EAAA;AAAA,EAGD,IACNG,GACAV,GACC;AACD,gBAAK,UAAU,IAAIU,GAAM,OAAOX,MAAQ;AACjC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,KACNU,GACAV,GACC;AACD,gBAAK,UAAU,KAAKU,GAAM,OAAOX,MAAQ;AAClC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,IACNU,GACAV,GACC;AACD,gBAAK,UAAU,IAAIU,GAAM,OAAOX,MAAQ;AACjC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,OACNU,GACAV,GACC;AACD,gBAAK,UAAU,OAAOU,GAAM,OAAOX,MAAQ;AACpC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,IACNU,GACAV,GACC;AACD,gBAAK,UAAU,IAAIU,GAAM,OAAOX,MAAQ;AACjC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,MACNU,GACAV,GACC;AACD,gBAAK,UAAU,MAAMU,GAAM,OAAOX,MAAQ;AACnC,YAAA,KAAK,kBAAkBA,GAAKC,CAAQ;AAAA,IAAA,CAC1C,GACM;AAAA,EAAA;AAAA,EAGD,SAAS;AACR,WAAA,KAAK,UAAU,OAAO;AAAA,EAAA;AAAA,EAGvB,iBAAiB;AAChB,WAAA,KAAK,UAAU,eAAe;AAAA,EAAA;AAEvC;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "moonflower",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "tenebrie",
|
|
6
6
|
"license": "MIT",
|
|
@@ -131,27 +131,23 @@
|
|
|
131
131
|
"yargs": "^17.7.2"
|
|
132
132
|
},
|
|
133
133
|
"peerDependencies": {
|
|
134
|
-
"@koa/router": "^
|
|
135
|
-
"koa": "^3.
|
|
134
|
+
"@koa/router": "^15.0.0",
|
|
135
|
+
"koa": "^3.0.0",
|
|
136
136
|
"koa-bodyparser": "^4.4.1",
|
|
137
137
|
"ts-morph": "^28.0.0",
|
|
138
|
-
"zod": "4.
|
|
138
|
+
"zod": "^4.0.0"
|
|
139
139
|
},
|
|
140
140
|
"peerDependenciesMeta": {
|
|
141
141
|
"ts-morph": {
|
|
142
142
|
"optional": true
|
|
143
|
-
},
|
|
144
|
-
"zod": {
|
|
145
|
-
"optional": true
|
|
146
143
|
}
|
|
147
144
|
},
|
|
148
145
|
"devDependencies": {
|
|
149
|
-
"@koa/router": "^
|
|
146
|
+
"@koa/router": "^15.0.0",
|
|
150
147
|
"@types/jest": "29.5.14",
|
|
151
148
|
"@types/jsonwebtoken": "^9.0.7",
|
|
152
|
-
"@types/koa": "^
|
|
149
|
+
"@types/koa": "^3.0.0",
|
|
153
150
|
"@types/koa-bodyparser": "^4.3.12",
|
|
154
|
-
"@types/koa__router": "^12.0.4",
|
|
155
151
|
"@types/node": "^22.10.2",
|
|
156
152
|
"@types/supertest": "^6.0.2",
|
|
157
153
|
"@typescript-eslint/eslint-plugin": "^8.18.0",
|
|
@@ -162,15 +158,15 @@
|
|
|
162
158
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
163
159
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
164
160
|
"jest": "29.7.0",
|
|
165
|
-
"zod": "4.
|
|
166
|
-
"koa": "^
|
|
161
|
+
"zod": "^4.0.0",
|
|
162
|
+
"koa": "^3.0.0",
|
|
167
163
|
"koa-bodyparser": "^4.4.1",
|
|
168
164
|
"node-mocks-http": "^1.16.2",
|
|
169
165
|
"prettier": "^3.4.2",
|
|
170
166
|
"source-map-support": "^0.5.20",
|
|
171
167
|
"supertest": "^7.0.0",
|
|
172
168
|
"ts-jest": "29.2.5",
|
|
173
|
-
"ts-morph": "^
|
|
169
|
+
"ts-morph": "^28.0.0",
|
|
174
170
|
"ts-node": "^10.9.2",
|
|
175
171
|
"tsconfig-paths": "4.2.0",
|
|
176
172
|
"typescript": "^5.7.2",
|
|
@@ -45,6 +45,7 @@ type Props = {
|
|
|
45
45
|
cachePath: string
|
|
46
46
|
}
|
|
47
47
|
profiling?: 'stats' | 'off' | 'debug'
|
|
48
|
+
workers?: boolean
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
type FileDiscoveryConfig = {
|
|
@@ -71,6 +72,7 @@ export const prepareOpenApiSpec = async ({
|
|
|
71
72
|
sourceFileDiscovery,
|
|
72
73
|
incremental,
|
|
73
74
|
profiling = 'stats',
|
|
75
|
+
workers = false,
|
|
74
76
|
}: Props): Promise<void> => {
|
|
75
77
|
const openApiManager = OpenApiManager.getInstance()
|
|
76
78
|
|
|
@@ -152,6 +154,7 @@ export const prepareOpenApiSpec = async ({
|
|
|
152
154
|
timestampCache: {},
|
|
153
155
|
profiling,
|
|
154
156
|
tsconfigPath: path.resolve(tsconfigPath),
|
|
157
|
+
workers,
|
|
155
158
|
})
|
|
156
159
|
|
|
157
160
|
openApiManager.setStats({
|
|
@@ -187,6 +190,7 @@ export const analyzeMultipleSourceFiles = async (
|
|
|
187
190
|
timestampCache: TimestampCache
|
|
188
191
|
profiling?: 'stats' | 'off' | 'debug'
|
|
189
192
|
tsconfigPath: string
|
|
193
|
+
workers?: boolean
|
|
190
194
|
},
|
|
191
195
|
filterEndpointPaths?: string[],
|
|
192
196
|
): Promise<EndpointData[]> => {
|
|
@@ -237,12 +241,8 @@ export const analyzeMultipleSourceFiles = async (
|
|
|
237
241
|
byFile.set(file.fileName, { endpoints: [], fileName: file.fileName, timing: 0, endpointTimings: [] })
|
|
238
242
|
}
|
|
239
243
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
// build its own Project from scratch — a multi-second cold-start. That cold-start only pays off
|
|
243
|
-
// when there are enough uncached files that spreading the parse work across workers beats it; below
|
|
244
|
-
// the threshold (e.g. the common single-file incremental rebuild), inline is strictly faster.
|
|
245
|
-
if (uncached.length <= INLINE_ANALYSIS_FILE_THRESHOLD) {
|
|
244
|
+
const useWorkers = config.workers !== false
|
|
245
|
+
if (!useWorkers || uncached.length <= INLINE_ANALYSIS_FILE_THRESHOLD) {
|
|
246
246
|
for (const { file } of uncached) {
|
|
247
247
|
const { endpoints, endpointTimings } = analyzeSourceFileEndpoints(file, filterEndpointPaths)
|
|
248
248
|
const fileResult = byFile.get(file.fileName)!
|
|
@@ -251,9 +251,6 @@ export const analyzeMultipleSourceFiles = async (
|
|
|
251
251
|
fileResult.timing = endpointTimings.reduce((sum, t) => sum + t.timing, 0)
|
|
252
252
|
}
|
|
253
253
|
} else {
|
|
254
|
-
// One task per file: each worker analyzes a whole file in a single pass, paying its Project
|
|
255
|
-
// cold-start once and reusing the warmed-up checker for every endpoint in that file. Cap the
|
|
256
|
-
// pool at one worker per file so we never spin up a worker with nothing to do.
|
|
257
254
|
type FileTask = { task: WorkerTask; fileName: string }
|
|
258
255
|
const allTasks: FileTask[] = uncached.map(({ file }) => ({
|
|
259
256
|
fileName: file.fileName,
|
package/src/router/Router.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import KoaRouter from '@koa/router'
|
|
1
|
+
import KoaRouter, { RouterContext, RouterMiddleware } from '@koa/router'
|
|
3
2
|
import Koa from 'koa'
|
|
4
3
|
|
|
5
4
|
import { OpenApiManager } from '../openapi/manager/OpenApiManager'
|
|
@@ -21,10 +20,10 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
private async sendResponseValue<P extends string>(
|
|
24
|
-
ctx:
|
|
25
|
-
callback:
|
|
23
|
+
ctx: RouterContext,
|
|
24
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
26
25
|
) {
|
|
27
|
-
// @ts-
|
|
26
|
+
// @ts-expect-error - Context is valid
|
|
28
27
|
const responseValue = await callback(ctx, undefined)
|
|
29
28
|
const { value, status, contentType } = parseEndpointReturnValue(responseValue)
|
|
30
29
|
ctx.body = value
|
|
@@ -34,8 +33,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
34
33
|
ctx.set('Content-Type', contentType)
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
public use(...middleware: Array<
|
|
38
|
-
// @ts-ignore
|
|
36
|
+
public use(...middleware: Array<RouterMiddleware<StateT, ContextT>>) {
|
|
39
37
|
this.koaRouter.use(...middleware)
|
|
40
38
|
return this
|
|
41
39
|
}
|
|
@@ -45,7 +43,6 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
45
43
|
) {
|
|
46
44
|
type AugmentedData = ResponseTypeT extends Promise<any> ? Awaited<ResponseTypeT> : ResponseTypeT
|
|
47
45
|
this.koaRouter.use(async (ctx, next) => {
|
|
48
|
-
// @ts-ignore
|
|
49
46
|
const userData = await Promise.resolve(middleware(ctx))
|
|
50
47
|
Object.keys(userData).forEach((key) => {
|
|
51
48
|
ctx[key] = userData[key]
|
|
@@ -57,7 +54,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
57
54
|
|
|
58
55
|
public get<P extends string>(
|
|
59
56
|
path: P,
|
|
60
|
-
callback:
|
|
57
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
61
58
|
) {
|
|
62
59
|
this.koaRouter.get(path, async (ctx) => {
|
|
63
60
|
await this.sendResponseValue(ctx, callback)
|
|
@@ -67,7 +64,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
67
64
|
|
|
68
65
|
public post<P extends string>(
|
|
69
66
|
path: P,
|
|
70
|
-
callback:
|
|
67
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
71
68
|
) {
|
|
72
69
|
this.koaRouter.post(path, async (ctx) => {
|
|
73
70
|
await this.sendResponseValue(ctx, callback)
|
|
@@ -77,7 +74,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
77
74
|
|
|
78
75
|
public put<P extends string>(
|
|
79
76
|
path: P,
|
|
80
|
-
callback:
|
|
77
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
81
78
|
) {
|
|
82
79
|
this.koaRouter.put(path, async (ctx) => {
|
|
83
80
|
await this.sendResponseValue(ctx, callback)
|
|
@@ -87,7 +84,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
87
84
|
|
|
88
85
|
public delete<P extends string>(
|
|
89
86
|
path: P,
|
|
90
|
-
callback:
|
|
87
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
91
88
|
) {
|
|
92
89
|
this.koaRouter.delete(path, async (ctx) => {
|
|
93
90
|
await this.sendResponseValue(ctx, callback)
|
|
@@ -97,7 +94,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
97
94
|
|
|
98
95
|
public del<P extends string>(
|
|
99
96
|
path: P,
|
|
100
|
-
callback:
|
|
97
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
101
98
|
) {
|
|
102
99
|
this.koaRouter.del(path, async (ctx) => {
|
|
103
100
|
await this.sendResponseValue(ctx, callback)
|
|
@@ -107,7 +104,7 @@ export class Router<StateT = Koa.DefaultState, ContextT = Koa.DefaultContext> {
|
|
|
107
104
|
|
|
108
105
|
public patch<P extends string>(
|
|
109
106
|
path: P,
|
|
110
|
-
callback:
|
|
107
|
+
callback: RouterMiddleware<StateT, ContextT & ExtractedRequestParams<P>>,
|
|
111
108
|
) {
|
|
112
109
|
this.koaRouter.patch(path, async (ctx) => {
|
|
113
110
|
await this.sendResponseValue(ctx, callback)
|