moonflower 1.4.8 → 1.5.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 +18 -3
- package/dist/openapi/analyzerModule/analyzerModule.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/analyzerModule.mjs +168 -112
- package/dist/openapi/analyzerModule/analyzerModule.mjs.map +1 -1
- package/dist/openapi/analyzerModule/analyzerWorker.cjs +2 -0
- package/dist/openapi/analyzerModule/analyzerWorker.cjs.map +1 -0
- package/dist/openapi/analyzerModule/analyzerWorker.d.ts +2 -0
- package/dist/openapi/analyzerModule/analyzerWorker.d.ts.map +1 -0
- package/dist/openapi/analyzerModule/analyzerWorker.mjs +44 -0
- package/dist/openapi/analyzerModule/analyzerWorker.mjs.map +1 -0
- package/dist/openapi/analyzerModule/nodeParsers.cjs +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.cjs.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/nodeParsers.mjs +199 -264
- package/dist/openapi/analyzerModule/nodeParsers.mjs.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.cjs +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.cjs.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.d.ts +8 -1
- package/dist/openapi/analyzerModule/parseEndpoint.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/parseEndpoint.mjs +121 -106
- package/dist/openapi/analyzerModule/parseEndpoint.mjs.map +1 -1
- package/dist/openapi/analyzerModule/test/TestCase.d.ts +1 -0
- package/dist/openapi/analyzerModule/test/TestCase.d.ts.map +1 -1
- package/dist/openapi/analyzerModule/test/workerGlobalSetup.d.ts +3 -0
- package/dist/openapi/analyzerModule/test/workerGlobalSetup.d.ts.map +1 -0
- package/dist/openapi/analyzerModule/workerPaths.d.ts +2 -0
- package/dist/openapi/analyzerModule/workerPaths.d.ts.map +1 -0
- package/dist/openapi/analyzerModule/workerPool.cjs +2 -0
- package/dist/openapi/analyzerModule/workerPool.cjs.map +1 -0
- package/dist/openapi/analyzerModule/workerPool.d.ts +33 -0
- package/dist/openapi/analyzerModule/workerPool.d.ts.map +1 -0
- package/dist/openapi/analyzerModule/workerPool.mjs +46 -0
- package/dist/openapi/analyzerModule/workerPool.mjs.map +1 -0
- package/package.json +1 -1
- package/src/openapi/analyzerModule/analyzerModule.ts +198 -25
- package/src/openapi/analyzerModule/analyzerWorker.ts +73 -0
- package/src/openapi/analyzerModule/nodeParsers.ts +4 -104
- package/src/openapi/analyzerModule/parseEndpoint.ts +31 -9
- package/src/openapi/analyzerModule/test/TestCase.ts +1 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.spec.ts +2 -2
- package/src/openapi/analyzerModule/test/openApiAnalyzer.zod.spec.data.ts +6 -0
- package/src/openapi/analyzerModule/test/openApiAnalyzer.zod.spec.ts +9 -1
- package/src/openapi/analyzerModule/test/workerGlobalSetup.ts +25 -0
- package/src/openapi/analyzerModule/workerPaths.ts +4 -0
- package/src/openapi/analyzerModule/workerPool.ts +92 -0
- package/src/test/app.spec.ts +10 -1
- package/vite.config.ts +5 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { buildSync } from 'esbuild'
|
|
2
|
+
import { existsSync, unlinkSync } from 'fs'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
const workerSrc = path.join(__dirname, '..', 'analyzerWorker.ts')
|
|
8
|
+
const workerOut = path.join(__dirname, '..', 'analyzerWorker.test.mjs')
|
|
9
|
+
|
|
10
|
+
export function setup() {
|
|
11
|
+
buildSync({
|
|
12
|
+
entryPoints: [workerSrc],
|
|
13
|
+
outfile: workerOut,
|
|
14
|
+
bundle: true,
|
|
15
|
+
format: 'esm',
|
|
16
|
+
platform: 'node',
|
|
17
|
+
external: ['ts-morph', '@ts-morph/common', 'typescript', 'worker_threads'],
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function teardown() {
|
|
22
|
+
if (existsSync(workerOut)) {
|
|
23
|
+
unlinkSync(workerOut)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import os from 'os'
|
|
2
|
+
import { Worker } from 'worker_threads'
|
|
3
|
+
|
|
4
|
+
import { EndpointData } from '../types'
|
|
5
|
+
import { SectionTiming } from './parseEndpoint'
|
|
6
|
+
|
|
7
|
+
export type WorkerTask = {
|
|
8
|
+
taskId: string
|
|
9
|
+
tsconfigPath: string
|
|
10
|
+
sourceFilePath: string
|
|
11
|
+
routerName: string
|
|
12
|
+
endpointIndex: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type WorkerResultSuccess = {
|
|
16
|
+
taskId: string
|
|
17
|
+
endpoint: EndpointData
|
|
18
|
+
sectionTimings: SectionTiming[]
|
|
19
|
+
timing: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type WorkerResultError = {
|
|
23
|
+
taskId: string
|
|
24
|
+
error: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type WorkerResult = WorkerResultSuccess | WorkerResultError
|
|
28
|
+
|
|
29
|
+
export class WorkerPool {
|
|
30
|
+
private workers: Worker[]
|
|
31
|
+
private idle: Worker[]
|
|
32
|
+
private queue: Array<{ task: WorkerTask; resolve: (r: WorkerResult) => void }> = []
|
|
33
|
+
private pending = new Map<string, (r: WorkerResult) => void>()
|
|
34
|
+
|
|
35
|
+
constructor(workerUrl: URL) {
|
|
36
|
+
const size = Math.max(1, Math.min(os.cpus().length - 1, 8))
|
|
37
|
+
this.workers = Array.from({ length: size }, () => {
|
|
38
|
+
const worker = new Worker(workerUrl)
|
|
39
|
+
worker.on('message', (result: WorkerResult) => {
|
|
40
|
+
const resolve = this.pending.get(result.taskId)
|
|
41
|
+
if (resolve) {
|
|
42
|
+
this.pending.delete(result.taskId)
|
|
43
|
+
resolve(result)
|
|
44
|
+
}
|
|
45
|
+
this.idle.push(worker)
|
|
46
|
+
this.flush()
|
|
47
|
+
})
|
|
48
|
+
worker.on('error', (err) => {
|
|
49
|
+
// Find any pending task for this worker and reject it
|
|
50
|
+
// (worker crashed — shouldn't happen, but handle gracefully)
|
|
51
|
+
for (const [taskId, resolve] of this.pending) {
|
|
52
|
+
resolve({ taskId, error: String(err) })
|
|
53
|
+
this.pending.delete(taskId)
|
|
54
|
+
break
|
|
55
|
+
}
|
|
56
|
+
this.idle.push(worker)
|
|
57
|
+
this.flush()
|
|
58
|
+
})
|
|
59
|
+
return worker
|
|
60
|
+
})
|
|
61
|
+
this.idle = [...this.workers]
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
run(task: WorkerTask): Promise<WorkerResult> {
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
if (this.idle.length > 0) {
|
|
67
|
+
const worker = this.idle.pop()!
|
|
68
|
+
this.pending.set(task.taskId, resolve)
|
|
69
|
+
worker.postMessage(task)
|
|
70
|
+
} else {
|
|
71
|
+
this.queue.push({ task, resolve })
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
runAll(tasks: WorkerTask[]): Promise<WorkerResult[]> {
|
|
77
|
+
return Promise.all(tasks.map((t) => this.run(t)))
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
terminate() {
|
|
81
|
+
this.workers.forEach((w) => w.terminate())
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private flush() {
|
|
85
|
+
while (this.queue.length > 0 && this.idle.length > 0) {
|
|
86
|
+
const { task, resolve } = this.queue.shift()!
|
|
87
|
+
const worker = this.idle.pop()!
|
|
88
|
+
this.pending.set(task.taskId, resolve)
|
|
89
|
+
worker.postMessage(task)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/test/app.spec.ts
CHANGED
|
@@ -3,13 +3,22 @@ import Koa from 'koa'
|
|
|
3
3
|
import * as os from 'os'
|
|
4
4
|
import * as path from 'path'
|
|
5
5
|
import request from 'supertest'
|
|
6
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { beforeAll, describe, expect, it, vi } from 'vitest'
|
|
7
7
|
|
|
8
8
|
import { generateOpenApiSpec } from '../openapi/generatorModule/generatorModule'
|
|
9
9
|
import { initOpenApiEngine } from '../openapi/initOpenApiEngine'
|
|
10
10
|
import { OpenApiManager } from '../openapi/manager/OpenApiManager'
|
|
11
11
|
import { app } from './app'
|
|
12
12
|
|
|
13
|
+
// The OpenAPI engine runs the TypeScript analyzer lazily on first request, and any request that
|
|
14
|
+
// reaches the initOpenApiEngine middleware awaits its readiness. Requests that match a route never
|
|
15
|
+
// reach it, but unmatched ones (e.g. the 405 test) do, so the first such request pays the full
|
|
16
|
+
// analyzer cold-start cost. That can exceed a single test's default 5s timeout in CI. Warm the
|
|
17
|
+
// engine up once here so no individual test bears that cost.
|
|
18
|
+
beforeAll(async () => {
|
|
19
|
+
await request(app.callback()).get('/api-json')
|
|
20
|
+
}, 60_000)
|
|
21
|
+
|
|
13
22
|
describe('TestAppRouter', () => {
|
|
14
23
|
it('includes content type header', async () => {
|
|
15
24
|
const response = await request(app.callback()).get('/test/hello')
|
package/vite.config.ts
CHANGED
|
@@ -24,6 +24,7 @@ const entries = {
|
|
|
24
24
|
'validators/BuiltInValidators': resolve(__dirname, 'src/validators/BuiltInValidators.ts'),
|
|
25
25
|
'validators/ParamWrappers': resolve(__dirname, 'src/validators/ParamWrappers.ts'),
|
|
26
26
|
'cli/cli': resolve(__dirname, 'src/cli/cli.ts'),
|
|
27
|
+
'openapi/analyzerModule/analyzerWorker': resolve(__dirname, 'src/openapi/analyzerModule/analyzerWorker.ts'),
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
export const baseViteConfig: ViteUserConfig = {
|
|
@@ -50,7 +51,10 @@ export const baseViteConfig: ViteUserConfig = {
|
|
|
50
51
|
'fs/promises',
|
|
51
52
|
'assert',
|
|
52
53
|
'crypto',
|
|
54
|
+
'os',
|
|
53
55
|
'perf_hooks',
|
|
56
|
+
'url',
|
|
57
|
+
'worker_threads',
|
|
54
58
|
'@ts-morph/common',
|
|
55
59
|
'typescript',
|
|
56
60
|
'ts-morph',
|
|
@@ -90,6 +94,7 @@ export const baseViteConfig: ViteUserConfig = {
|
|
|
90
94
|
},
|
|
91
95
|
test: {
|
|
92
96
|
globals: true,
|
|
97
|
+
globalSetup: 'src/openapi/analyzerModule/test/workerGlobalSetup.ts',
|
|
93
98
|
setupFiles: 'src/setupTests.ts',
|
|
94
99
|
include: ['src/**/*.spec.ts'],
|
|
95
100
|
coverage: {
|