From 4dee9a510219821b60d7b203b62cd28370a181f3 Mon Sep 17 00:00:00 2001 From: "FAREAST\\chunyu" Date: Sun, 12 Jan 2025 14:43:18 +0800 Subject: [PATCH] use semver to parse and compare version --- .../emitter/src/constants.ts | 1 + .../http-client-csharp/emitter/src/emitter.ts | 49 +++------ packages/http-client-csharp/package-lock.json | 104 +++++++++++------- packages/http-client-csharp/package.json | 4 +- 4 files changed, 86 insertions(+), 72 deletions(-) diff --git a/packages/http-client-csharp/emitter/src/constants.ts b/packages/http-client-csharp/emitter/src/constants.ts index 254849d381..b133645e86 100644 --- a/packages/http-client-csharp/emitter/src/constants.ts +++ b/packages/http-client-csharp/emitter/src/constants.ts @@ -7,3 +7,4 @@ export const projectedNameClientKey = "client"; export const mockApiVersion = "0000-00-00"; export const tspOutputFileName = "tspCodeModel.json"; export const configurationFileName = "Configuration.json"; +export const minVersionRequisiteForDotnet = "8.0.0"; diff --git a/packages/http-client-csharp/emitter/src/emitter.ts b/packages/http-client-csharp/emitter/src/emitter.ts index cf0d99c03d..2aa95d6a43 100644 --- a/packages/http-client-csharp/emitter/src/emitter.ts +++ b/packages/http-client-csharp/emitter/src/emitter.ts @@ -16,8 +16,13 @@ import { spawn, SpawnOptions } from "child_process"; import fs, { statSync } from "fs"; import { PreserveType, stringifyRefs } from "json-serialize-refs"; import { dirname } from "path"; +import * as semver from "semver"; import { fileURLToPath } from "url"; -import { configurationFileName, tspOutputFileName } from "./constants.js"; +import { + configurationFileName, + minVersionRequisiteForDotnet, + tspOutputFileName, +} from "./constants.js"; import { createModel } from "./lib/client-model-builder.js"; import { reportDiagnostic } from "./lib/lib.js"; import { LoggerLevel } from "./lib/log-level.js"; @@ -169,7 +174,7 @@ export async function $onEmit(context: EmitContext) { { stdio: "inherit" }, ); if (result.exitCode !== 0) { - const isValid = await validateDotnet(sdkContext.program, "8.0.0"); + const isValid = await validateDotnet(sdkContext.program, minVersionRequisiteForDotnet); // if the dotnet runtime is valid, the error is not runtime issue, log it as normal if (isValid) { if (result.stderr) Logger.getInstance().error(result.stderr); @@ -178,7 +183,7 @@ export async function $onEmit(context: EmitContext) { } } } catch (error: any) { - const isValid = await validateDotnet(sdkContext.program, "8.0.0"); + const isValid = await validateDotnet(sdkContext.program, minVersionRequisiteForDotnet); // if the dotnet runtime is valid, the error is not runtime issue, log it as normal if (isValid) throw new Error(error); } @@ -198,8 +203,8 @@ export async function $onEmit(context: EmitContext) { * @param minVersionRequisite The minimum required version */ async function validateDotnet(program: Program, minVersionRequisite: string): Promise { - const requiredVersions = minVersionRequisite.match(/(\d+)\.(\d+)\.(\d+)/g); - if (!requiredVersions) { + const parsedVersions = semver.parse(minVersionRequisite); + if (!parsedVersions) { Logger.getInstance().error("invalid parameter: minVersionRequisite."); return false; } @@ -208,15 +213,15 @@ async function validateDotnet(program: Program, minVersionRequisite: string): Pr const dotnetVersions = findDonetVersion(result.stdout) ?? findDonetVersion(result.stderr); if (dotnetVersions) { for (const version of dotnetVersions) { - if (compareVersion(version, minVersionRequisite) >= 0) return true; + if (semver.gt(version, minVersionRequisite)) return true; } reportDiagnostic(program, { code: "invalid-runtime-dependency", messageId: "invalidVersion", format: { installedVersion: dotnetVersions?.join(","), - dotnetMajorVersion: requiredVersions[0], - downloadUrl: `https://dotnet.microsoft.com/download/dotnet/${requiredVersions[0]}.0`, + dotnetMajorVersion: `${parsedVersions.major}`, + downloadUrl: `https://dotnet.microsoft.com/download/dotnet/${parsedVersions.major}.0`, }, target: NoTarget, }); @@ -231,8 +236,8 @@ async function validateDotnet(program: Program, minVersionRequisite: string): Pr code: "invalid-runtime-dependency", messageId: "missing", format: { - dotnetMajorVersion: requiredVersions[0], - downloadUrl: `https://dotnet.microsoft.com/download/dotnet/${requiredVersions[0]}.0`, + dotnetMajorVersion: `${parsedVersions.major}`, + downloadUrl: `https://dotnet.microsoft.com/download/dotnet/${parsedVersions.major}.0`, }, target: NoTarget, }); @@ -246,30 +251,6 @@ async function validateDotnet(program: Program, minVersionRequisite: string): Pr if (matches) return matches; return undefined; } - - /** - * Compare [semver](https://semver.org/) version strings to find greater, equal or lesser. - * This library supports the full semver specification, including comparing versions with different number of digits like `1.0.0`, `1.0`, `1`, and pre-release versions like `1.0.0-alpha`. - * @param v1 - First version to compare - * @param v2 - Second version to compare - * @returns Numeric value compatible with the [Array.sort(fn) interface](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters). - */ - function compareVersion(v1: string, v2: string): number { - const v1Versions = v1.match(/(\d+)\.(\d+)\.(\d+)/g); - const v2Versions = v2.match(/(\d+)\.(\d+)\.(\d+)/g); - if (!v1Versions || !v2Versions) { - Logger.getInstance().error("invalid parameter."); - return -1; - } - for (const i in v1Versions) { - if (v1Versions[i] < v2Versions[i]) { - return -1; - } else if (v1Versions[i] > v2Versions[i]) { - return 1; - } - } - return 0; - } } function constructCommandArg(arg: string): string { return arg !== "" ? ` ${arg}` : ""; diff --git a/packages/http-client-csharp/package-lock.json b/packages/http-client-csharp/package-lock.json index 46a7311ead..e131dfc6aa 100644 --- a/packages/http-client-csharp/package-lock.json +++ b/packages/http-client-csharp/package-lock.json @@ -9,7 +9,8 @@ "version": "0.1.9", "license": "MIT", "dependencies": { - "json-serialize-refs": "0.1.0-0" + "json-serialize-refs": "0.1.0-0", + "semver": "^7.6.3" }, "devDependencies": { "@azure-tools/azure-http-specs": "0.1.0-alpha.4", @@ -17,6 +18,7 @@ "@azure-tools/typespec-client-generator-core": "0.49.0", "@microsoft/api-extractor": "^7.47.11", "@types/node": "~22.7.5", + "@types/semver": "^7.5.8", "@typespec/compiler": "0.63.0", "@typespec/http": "0.63.0", "@typespec/http-specs": "0.1.0-alpha.5", @@ -1080,6 +1082,33 @@ "@rushstack/node-core-library": "5.10.1" } }, + "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@microsoft/api-extractor/node_modules/typescript": { "version": "5.4.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", @@ -1478,6 +1507,33 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@rushstack/rig-package": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz", @@ -1572,6 +1628,12 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", @@ -1626,19 +1688,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@typespec/compiler/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typespec/http": { "version": "0.63.0", "resolved": "https://registry.npmjs.org/@typespec/http/-/http-0.63.0.tgz", @@ -5667,14 +5716,9 @@ "license": "ISC" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -5682,19 +5726,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/send": { "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", @@ -7199,8 +7230,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/yaml": { "version": "2.5.1", diff --git a/packages/http-client-csharp/package.json b/packages/http-client-csharp/package.json index c281f1e341..6bef4f32f2 100644 --- a/packages/http-client-csharp/package.json +++ b/packages/http-client-csharp/package.json @@ -43,7 +43,8 @@ "dist/**" ], "dependencies": { - "json-serialize-refs": "0.1.0-0" + "json-serialize-refs": "0.1.0-0", + "semver": "^7.6.3" }, "peerDependencies": { "@azure-tools/typespec-azure-core": ">=0.49.0 <1.0.0 || ~0.50.0-0", @@ -61,6 +62,7 @@ "@azure-tools/typespec-client-generator-core": "0.49.0", "@microsoft/api-extractor": "^7.47.11", "@types/node": "~22.7.5", + "@types/semver": "^7.5.8", "@typespec/compiler": "0.63.0", "@typespec/http": "0.63.0", "@typespec/json-schema": "0.63.0",