From 2a08339528b837efd2f5b0304d22d73becf463a3 Mon Sep 17 00:00:00 2001 From: bzp2010 Date: Thu, 17 Jul 2025 12:17:54 +0800 Subject: [PATCH] feat(core): faster yaml and json parser --- apps/cli/src/command/convert.command.ts | 4 +-- apps/cli/src/command/diff.command.ts | 10 ++++-- apps/cli/src/command/dump.command.ts | 31 +++---------------- apps/cli/src/tasks/experimental.ts | 4 +-- apps/cli/src/tasks/load_local.ts | 10 ++++-- libs/converter-openapi/test/basic.spec.ts | 8 ++--- libs/converter-openapi/test/extension.spec.ts | 5 ++- package.json | 1 + pnpm-lock.yaml | 3 ++ 9 files changed, 35 insertions(+), 41 deletions(-) diff --git a/apps/cli/src/command/convert.command.ts b/apps/cli/src/command/convert.command.ts index 4dd94c9f..8a6f895a 100644 --- a/apps/cli/src/command/convert.command.ts +++ b/apps/cli/src/command/convert.command.ts @@ -1,12 +1,12 @@ import { OpenAPIConverter } from '@api7/adc-converter-openapi'; import * as ADCSDK from '@api7/adc-sdk'; import OpenAPIParser from '@readme/openapi-parser'; +import { dump } from 'js-yaml'; import { Listr } from 'listr2'; import { cloneDeep } from 'lodash'; import { existsSync, writeFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { OpenAPIV3 } from 'openapi-types'; -import { stringify } from 'yaml'; import { SignaleRenderer } from '../utils/listr'; import { TaskContext } from './diff.command'; @@ -103,7 +103,7 @@ const OpenAPICommand = new BaseConvertCommand('openapi') title: 'Write converted OpenAPI file', task: (ctx, task) => { ctx.local.services = ctx.buffer.flatMap((item) => item.services); - const yamlStr = stringify(ctx.local, {}); + const yamlStr = dump(ctx.local, { noRefs: true, sortKeys: true }); writeFileSync(opts.output, yamlStr); task.title = `Converted OpenAPI file to "${resolve( opts.output, diff --git a/apps/cli/src/command/diff.command.ts b/apps/cli/src/command/diff.command.ts index ad0de92a..53776545 100644 --- a/apps/cli/src/command/diff.command.ts +++ b/apps/cli/src/command/diff.command.ts @@ -1,7 +1,7 @@ import * as ADCSDK from '@api7/adc-sdk'; +import YAML from 'js-yaml'; import { Listr } from 'listr2'; -import { readFile, writeFile } from 'node:fs/promises'; -import YAML from 'yaml'; +import { writeFile } from 'node:fs/promises'; import { DiffResourceTask, @@ -82,7 +82,11 @@ export const DiffCommand = new BackendCommand( { title: 'Write detail diff result to file', task: async (ctx, task) => { - await writeFile('./diff.yaml', YAML.stringify(ctx.diff), {}); + await writeFile( + './diff.yaml', + YAML.dump(ctx.diff, { noRefs: true }), + { encoding: 'utf-8' }, + ); task.output = 'Detail diff result has been wrote to diff.yaml'; }, }, diff --git a/apps/cli/src/command/dump.command.ts b/apps/cli/src/command/dump.command.ts index 92b1be27..d06adffe 100644 --- a/apps/cli/src/command/dump.command.ts +++ b/apps/cli/src/command/dump.command.ts @@ -1,7 +1,7 @@ +import { dump } from 'js-yaml'; import { Listr } from 'listr2'; import { writeFile } from 'node:fs/promises'; import path from 'node:path'; -import { Scalar, stringify } from 'yaml'; import { LoadRemoteConfigurationTask } from '../tasks'; import { InitializeBackendTask } from '../tasks/init_backend'; @@ -69,32 +69,9 @@ export const DumpCommand = new BackendCommand( task: async (ctx, task) => { await writeFile( opts.output, - stringify(resortConfiguration(ctx.remote), { - sortMapEntries: (a, b) => { - const nameKey = 'name'; - const descKey = 'description'; - const labelKey = 'labels'; - const consumerUsernameKey = 'username'; - const aKey = (a.key as Scalar)?.value; - const bKey = (b.key as Scalar)?.value; - - // make sure the metadata is always at the top - if (aKey && bKey) { - if (aKey === nameKey || bKey === nameKey) - return aKey === nameKey ? -1 : 1; - if ( - aKey === consumerUsernameKey || - bKey === consumerUsernameKey - ) - return aKey === consumerUsernameKey ? -1 : 1; - if (aKey === descKey || bKey === descKey) - return aKey === descKey ? -1 : 1; - if (aKey === labelKey || bKey === labelKey) - return aKey === labelKey ? -1 : 1; - } - - return a.key > b.key ? 1 : a.key < b.key ? -1 : 0; - }, + dump(resortConfiguration(ctx.remote), { + noRefs: true, + sortKeys: true, }), { encoding: 'utf8' }, ); diff --git a/apps/cli/src/tasks/experimental.ts b/apps/cli/src/tasks/experimental.ts index 008eb633..84c1c385 100644 --- a/apps/cli/src/tasks/experimental.ts +++ b/apps/cli/src/tasks/experimental.ts @@ -1,5 +1,5 @@ import { readFile } from 'fs/promises'; -import YAML from 'yaml'; +import YAML from 'js-yaml'; export const ExperimentalRemoteStateFileTask = (file: string) => ({ task: async (ctx) => { @@ -7,6 +7,6 @@ export const ExperimentalRemoteStateFileTask = (file: string) => ({ (await readFile(file, { encoding: 'utf-8', })) ?? ''; - ctx.remote = YAML.parse(fileContent); + ctx.remote = YAML.load(fileContent); }, }); diff --git a/apps/cli/src/tasks/load_local.ts b/apps/cli/src/tasks/load_local.ts index 8a094ce0..fef15f21 100644 --- a/apps/cli/src/tasks/load_local.ts +++ b/apps/cli/src/tasks/load_local.ts @@ -2,9 +2,9 @@ import * as ADCSDK from '@api7/adc-sdk'; import { existsSync } from 'fs'; import { readFile } from 'fs/promises'; import { globSync } from 'glob'; +import YAML from 'js-yaml'; import { ListrTask } from 'listr2'; import path from 'node:path'; -import YAML from 'yaml'; import { fillLabels, @@ -51,7 +51,13 @@ export const LoadLocalConfigurationTask = ( const fileContent = (await readFile(filePath, { encoding: 'utf-8' })) ?? ''; - subCtx.configurations[filePath] = YAML.parse(fileContent) ?? {}; + const ext = path.extname(filePath).toLowerCase(); + if (ext === '.json') { + subCtx.configurations[filePath] = + JSON.parse(fileContent) ?? {}; + return; + } + subCtx.configurations[filePath] = YAML.load(fileContent) ?? {}; }, }; }), diff --git a/libs/converter-openapi/test/basic.spec.ts b/libs/converter-openapi/test/basic.spec.ts index e7e9445f..8229fca3 100644 --- a/libs/converter-openapi/test/basic.spec.ts +++ b/libs/converter-openapi/test/basic.spec.ts @@ -1,11 +1,11 @@ -import { readFileSync } from 'node:fs'; -import { join } from 'node:path'; -import { OpenAPIV3 } from 'openapi-types'; -import { parse } from 'yaml'; +import { load } from 'js-yaml'; import { OpenAPIConverter } from '../src'; import { loadAsset, runTask } from './utils'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const parse = (content: string): any => load(content); + describe('Basic', () => { it('case 1 (single path)', async () => { const oas = parse(loadAsset('basic-1.yaml')); diff --git a/libs/converter-openapi/test/extension.spec.ts b/libs/converter-openapi/test/extension.spec.ts index 6f97e847..68a87c79 100644 --- a/libs/converter-openapi/test/extension.spec.ts +++ b/libs/converter-openapi/test/extension.spec.ts @@ -1,8 +1,11 @@ -import { parse } from 'yaml'; +import { load } from 'js-yaml'; import { OpenAPIConverter } from '../src'; import { loadAsset, runTask } from './utils'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const parse = (content: string): any => load(content); + describe('Extension', () => { it('case 1 (override resource name)', async () => { const oas = parse(loadAsset('extension-1.yaml')); diff --git a/package.json b/package.json index 5044c879..16390b9c 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "dotenv": "^16.4.5", "glob": "^11.0.0", "immer": "^10.1.1", + "js-yaml": "^4.1.0", "json-schema": "^0.4.0", "listr2": "^8.2.1", "lodash": "^4.17.21", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f7e2eb49..f1f83126 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: immer: specifier: ^10.1.1 version: 10.1.1 + js-yaml: + specifier: ^4.1.0 + version: 4.1.0 json-schema: specifier: ^0.4.0 version: 0.4.0