From 0e201bde7b1bd4628814492db40c13b5ef9691c7 Mon Sep 17 00:00:00 2001 From: Roberto Bianchi Date: Fri, 6 Nov 2026 09:17:11 +0100 Subject: [PATCH] perf(cli): cache schema names Signed-off-by: Roberto Bianchi --- packages/massimo-cli/lib/schema-names.js | 9 +++---- .../test/cli-openapi-named-schemas.test.js | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/massimo-cli/lib/schema-names.js b/packages/massimo-cli/lib/schema-names.js index f206c853..9208cdd5 100644 --- a/packages/massimo-cli/lib/schema-names.js +++ b/packages/massimo-cli/lib/schema-names.js @@ -50,20 +50,21 @@ export function buildSchemaNames (spec, takenNames = []) { if (!schemas) return schemaNames const keys = Object.keys(schemas) + const typeNames = new Map(keys.map(key => [key, toTypeName(key)])) const taken = new Set([...RESERVED_TYPE_NAMES, ...takenNames]) const assigned = new Map() const claim = key => { - const name = toTypeName(key) + const name = typeNames.get(key) if (!taken.has(name)) { taken.add(name) assigned.set(key, name) } } - keys.filter(key => toTypeName(key) === key).forEach(claim) - keys.filter(key => toTypeName(key) !== key).forEach(claim) + keys.filter(key => typeNames.get(key) === key).forEach(claim) + keys.filter(key => typeNames.get(key) !== key).forEach(claim) for (const key of keys) { if (assigned.has(key)) continue - const base = `${toTypeName(key)}Schema` + const base = `${typeNames.get(key)}Schema` let name = base for (let i = 2; taken.has(name); i++) { name = `${base}${i}` diff --git a/packages/massimo-cli/test/cli-openapi-named-schemas.test.js b/packages/massimo-cli/test/cli-openapi-named-schemas.test.js index 961c954e..c2fd78e6 100644 --- a/packages/massimo-cli/test/cli-openapi-named-schemas.test.js +++ b/packages/massimo-cli/test/cli-openapi-named-schemas.test.js @@ -92,6 +92,30 @@ test('buildSchemaNames is deterministic and maps refs with JSON pointer escaping equal(buildSchemaNames({}).size, 0) }) +test('buildSchemaNames preserves collision priority for normalized names', () => { + const spec = { + components: { + schemas: { + 'foo-bar': {}, + foo_bar: {}, + 'foo/bar': {}, + FooBar: {}, + FooBarSchema: {}, + Array: {} + } + } + } + + deepEqual([...buildSchemaNames(spec).entries()], [ + ['#/components/schemas/foo_bar', 'foo_bar'], + ['#/components/schemas/FooBar', 'FooBar'], + ['#/components/schemas/FooBarSchema', 'FooBarSchema'], + ['#/components/schemas/foo-bar', 'FooBarSchema2'], + ['#/components/schemas/foo~1bar', 'FooBarSchema3'], + ['#/components/schemas/Array', 'ArraySchema'] + ]) +}) + test('--named-schemas works with --frontend', async () => { const dir = await moveToTmpdir(after) await execa('node', [join(import.meta.dirname, '..', 'index.js'), openAPIfile, '--name', 'movies', '--frontend', '--language', 'ts', '--named-schemas'])