From a09d298cc0647b48d8dd30aa65b225cda4756647 Mon Sep 17 00:00:00 2001 From: Jakub Vacek Date: Tue, 11 May 2021 08:45:37 +0200 Subject: [PATCH 1/3] feat: more version utils --- src/interfaces/ast/index.ts | 1 + src/interfaces/ast/utils.ts | 79 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/interfaces/ast/index.ts b/src/interfaces/ast/index.ts index b0f4251..11b5020 100644 --- a/src/interfaces/ast/index.ts +++ b/src/interfaces/ast/index.ts @@ -3,3 +3,4 @@ export * from './map-ast.utils'; export * from './profile-ast'; export * from './profile-ast.utils'; export * from './utils'; +export * from './split'; diff --git a/src/interfaces/ast/utils.ts b/src/interfaces/ast/utils.ts index b6c0e99..c52f9e5 100644 --- a/src/interfaces/ast/utils.ts +++ b/src/interfaces/ast/utils.ts @@ -17,6 +17,15 @@ export function isValidProviderName(input: string): boolean { return PROVIDER_NAME_RE.test(input); } +/** + * Checks if input string is valid version string. + * + * Example: + * ``` + * isValidVersionString('1.2.3') // true + * isValidVersionString('1.2.3-test') // true + * ``` + */ export function isValidVersionString(version: string): boolean { const [restVersion, label] = splitLimit(version, '-', 1); const [majorStr, minorStr, patchStr] = splitLimit(restVersion, '.', 2); @@ -42,3 +51,73 @@ export function isValidVersionString(version: string): boolean { return true; } + +/** + * Tries to extract valid version string from input string contining @. + * + * Example: + * ``` + * extractVersionString('test/test@1.2.3') // '1.2.3' + * ``` + */ +export function extractVersionString(input: string): string { + const [, version] = splitLimit(input, '@', 1); + if (!isValidVersionString(version)) { + throw new Error(`Invalid version string in "${input}"`); + } + + return version; +} + +/** + * Tries to parse numeric string (0-9) to number. + * + * Example: + * ``` + * parseVersionNumber('3') // 3 + * parseVersionNumber(' 3 ') // 3 + * ``` + */ +export function parseVersionNumber(str: string): number { + const value = str.trim(); + if (!VERSION_NUMBER_RE.test(value)) { + throw new Error(`Unable to parse version string "${str}"`); + } + + return parseInt(value, 10); +} + +/** + * Tries to extract version object from version string. + * + * Example: + * ``` + * parseVersionNumber('1.2.3') // {major: 1, minor: 2, patch: 3} + * parseVersionNumber('1.2.3-test') // {major: 1, minor: 2, patch: 3, label: 'test'} + * ``` + */ +export function extractVersion( + versionString: string +): { + major: number; + minor?: number; + patch?: number; + label?: string; +} { + const [version, label] = splitLimit(versionString, '-', 1); + const [majorStr, minorStr, patchStr] = splitLimit(version, '.', 2); + + const major = parseVersionNumber(majorStr); + + let minor = undefined; + if (minorStr !== undefined) { + minor = parseVersionNumber(minorStr); + } + + let patch = undefined; + if (patchStr !== undefined) { + patch = parseVersionNumber(patchStr); + } + + return { major, minor, patch, label }; +} From aaa5add8d1502fb921d3263f09ad6a1f86132130 Mon Sep 17 00:00:00 2001 From: Jakub Vacek Date: Tue, 11 May 2021 13:05:34 +0200 Subject: [PATCH 2/3] test: add tests for new utils --- src/interfaces/ast/utils.test.ts | 122 +++++++++++++++++++++++++++++++ src/interfaces/ast/utils.ts | 9 +++ 2 files changed, 131 insertions(+) diff --git a/src/interfaces/ast/utils.test.ts b/src/interfaces/ast/utils.test.ts index 688de77..bd397ad 100644 --- a/src/interfaces/ast/utils.test.ts +++ b/src/interfaces/ast/utils.test.ts @@ -1,8 +1,11 @@ import { + extractVersion, + extractVersionString, isValidDocumentName, isValidIdentifier, isValidProviderName, isValidVersionString, + parseVersionNumber, } from './utils'; describe('utils', () => { @@ -43,6 +46,7 @@ describe('utils', () => { expect(isValidVersionString('test')).toEqual(false); expect(isValidVersionString('1.t.0')).toEqual(false); expect(isValidVersionString('1.0.t')).toEqual(false); + expect(isValidVersionString('1')).toEqual(true); expect(isValidVersionString('1.0')).toEqual(true); expect(isValidVersionString('0.0.1')).toEqual(true); expect(isValidVersionString('1.0.0')).toEqual(true); @@ -52,4 +56,122 @@ describe('utils', () => { expect(isValidVersionString('1.0.0-t.t')).toEqual(false); }); }); + + describe('when extracting version string', () => { + it('extracts version correctly', () => { + expect(() => extractVersionString('')).toThrow( + new Error(`Invalid empty version string`) + ); + expect(() => extractVersionString('@')).toThrow( + new Error(`Invalid version string in "@"`) + ); + expect(() => extractVersionString('test@test')).toThrow( + new Error(`Invalid version string in "test@test"`) + ); + expect(() => extractVersionString('test@1.t.0')).toThrow( + new Error(`Invalid version string in "test@1.t.0"`) + ); + expect(() => extractVersionString('1,23@1.0.t')).toThrow( + new Error(`Invalid version string in "1,23@1.0.t"`) + ); + expect(extractVersionString('1.2@1.0')).toEqual('1.0'); + expect(extractVersionString('test@0.0.1')).toEqual('0.0.1'); + expect(extractVersionString('@1.0.0')).toEqual('1.0.0'); + expect(extractVersionString('+:@9.9.9')).toEqual('9.9.9'); + expect(extractVersionString(' @1.0.0-label')).toEqual('1.0.0-label'); + expect(() => extractVersionString('test@1.0.7-TesT')).toThrow( + new Error(`Invalid version string in "test@1.0.7-TesT"`) + ); + expect(() => extractVersionString('test@1.0.0-t.t')).toThrow( + new Error(`Invalid version string in "test@1.0.0-t.t"`) + ); + }); + }); + + describe('when parsing version stfing', () => { + it('parses version correctly', () => { + expect(() => parseVersionNumber('')).toThrow( + new Error(`Unable to parse version string ""`) + ); + expect(() => parseVersionNumber('@')).toThrow( + new Error(`Unable to parse version string "@"`) + ); + expect(() => parseVersionNumber('T')).toThrow( + new Error(`Unable to parse version string "T"`) + ); + expect(() => parseVersionNumber('0T')).toThrow( + new Error(`Unable to parse version string "0T"`) + ); + expect(parseVersionNumber('99')).toEqual(99); + expect(parseVersionNumber('1')).toEqual(1); + expect(parseVersionNumber(' 8')).toEqual(8); + expect(parseVersionNumber('7 ')).toEqual(7); + expect(parseVersionNumber('0')).toEqual(0); + }); + }); + + describe('when extracting version object', () => { + it('extracts version correctly', () => { + expect(() => extractVersion('')).toThrow( + new Error(`Unable to parse version string ""`) + ); + expect(() => extractVersion('@')).toThrow( + new Error(`Unable to parse version string "@"`) + ); + expect(() => extractVersion('1.E.6')).toThrow( + new Error(`Unable to parse version string "E"`) + ); + expect(() => extractVersion('E.!.1')).toThrow( + new Error(`Unable to parse version string "E"`) + ); + expect(() => extractVersion('1.0.t')).toThrow( + new Error(`Unable to parse version string "t"`) + ); + expect(() => extractVersion('1.')).toThrow( + new Error(`Unable to parse version string ""`) + ); + expect(() => extractVersion('1.0.0-!ab3l')).toThrow( + new Error(`Invalid version label "!ab3l"`) + ); + expect(() => extractVersion('1.0.0-Lab3l')).toThrow( + new Error(`Invalid version label "Lab3l"`) + ); + + expect(extractVersion('1')).toEqual({ major: 1 }); + expect(extractVersion('1.0')).toEqual({ major: 1, minor: 0 }); + expect(extractVersion('0.0.1')).toEqual({ major: 0, minor: 0, patch: 1 }); + expect(extractVersion('1.0.0')).toEqual({ major: 1, minor: 0, patch: 0 }); + expect(extractVersion('9.9.9')).toEqual({ major: 9, minor: 9, patch: 9 }); + expect(extractVersion('1.0.0-label')).toEqual({ + major: 1, + minor: 0, + patch: 0, + label: 'label', + }); + expect(extractVersion('1.0.0-lab3l')).toEqual({ + major: 1, + minor: 0, + patch: 0, + label: 'lab3l', + }); + expect(extractVersion('1.0.0-la-b3l')).toEqual({ + major: 1, + minor: 0, + patch: 0, + label: 'la-b3l', + }); + expect(extractVersion('1.0.0-lab3l')).toEqual({ + major: 1, + minor: 0, + patch: 0, + label: 'lab3l', + }); + expect(extractVersion('1.0.0-la_b3l')).toEqual({ + major: 1, + minor: 0, + patch: 0, + label: 'la_b3l', + }); + }); + }); }); diff --git a/src/interfaces/ast/utils.ts b/src/interfaces/ast/utils.ts index c52f9e5..10e8373 100644 --- a/src/interfaces/ast/utils.ts +++ b/src/interfaces/ast/utils.ts @@ -61,6 +61,9 @@ export function isValidVersionString(version: string): boolean { * ``` */ export function extractVersionString(input: string): string { + if (input === '') { + throw new Error('Invalid empty version string'); + } const [, version] = splitLimit(input, '@', 1); if (!isValidVersionString(version)) { throw new Error(`Invalid version string in "${input}"`); @@ -119,5 +122,11 @@ export function extractVersion( patch = parseVersionNumber(patchStr); } + if (label !== undefined) { + if (!isValidDocumentName(label)) { + throw new Error(`Invalid version label "${label}"`); + } + } + return { major, minor, patch, label }; } From c57b6fa5f22c2929b4be2ce3be22bb32464b66bf Mon Sep 17 00:00:00 2001 From: Jakub Vacek Date: Tue, 11 May 2021 13:41:50 +0200 Subject: [PATCH 3/3] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3547ac9..8f3c861 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@superfaceai/ast", - "version": "0.0.23", + "version": "0.0.25", "description": "Superface profile and map language ASTs, https://superface.ai", "main": "dist/language.js", "source": "src/index.ts",