switch to JS action

This commit is contained in:
2023-10-24 12:35:54 +02:00
parent e2c94cfebc
commit 6dae9dd4e9
535 changed files with 190322 additions and 1 deletions
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2017 asamuzaK
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+261
View File
@@ -0,0 +1,261 @@
[![build](https://github.com/asamuzaK/semverParser/workflows/build/badge.svg)](https://github.com/asamuzaK/semverParser/actions?query=workflow%3Abuild)
[![CodeQL](https://github.com/asamuzaK/semverParser/workflows/CodeQL/badge.svg)](https://github.com/asamuzaK/semverParser/actions?query=workflow%3ACodeQL)
[![npm](https://img.shields.io/npm/v/semver-parser)](https://www.npmjs.com/package/semver-parser)
# SemVer Parser
Parse, verify, compare [SemVer](https://semver.org/ "Semantic Versioning 2.0.0 | Semantic Versioning").
## Install
```console
npm install semver-parser
```
## API
APIs can be used either synchronously or asynchronously.
Async function returns Promise which resolves with the result.
sync:
```javascript
import { compareSemVer, isValidSemVer, parseSemVer } from 'semver-parser';
```
async:
```javascript
import { promises } from 'semver-parser';
const { compareSemVer, isValidSemVer, parseSemVer } = promises;
```
NOTE: [Is "v1.2.3" a semantic version?](https://github.com/mojombo/semver/blob/master/semver.md#is-v123-a-semantic-version "semver/semver.md at master · mojombo/semver")
> Is "v1.2.3" a semantic version?
>
> No, "v1.2.3" is not a semantic version. However, prefixing a semantic version with a "v" is a common way (in English) to indicate it is a version number.
For ease of use, this parser supports "v" prefixed string.
If you do not want to accept "v" prefix, set `strict` param to `true`.
### parseSemVer(version, strict)
Parses version string.
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {Object} - parsed result, contains properties below
- version {string} - given version string
- matches {boolean} - matches SemVer format
- major {number|undefined} - major version
- minor {number|undefined} - minor version
- patch {number|undefined} - patch version
- pre {Array<string|number>|undefined} - pre release version in array
- build {Array<string|number>|undefined} - build ID in array
### isValidSemVer(version, strict)
Determine whether the given argument is a valid SemVer string.
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {boolean} - result
### compareSemVer(version, base, strict)
Compare versions in SemVer format.
* @param {string} version - version string
* @param {string} base - base version string to compare from
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {number}
- -1 or negative number, if version is less than base version
- 0, if version is equal to base version
- 1 or positive number, if version is greater than base version
## [BackusNaur Form Grammar for Valid SemVer Versions](https://github.com/mojombo/semver/blob/master/semver.md#backusnaur-form-grammar-for-valid-semver-versions "semver/semver.md at master · mojombo/semver") to JavaScript RegExp
### valid semver
```bnf
<valid semver> ::= <version core>
| <version core> "-" <pre-release>
| <version core> "+" <build>
| <version core> "-" <pre-release> "+" <build>
```
```javascript
(?:0|[1-9]\d*)(?:\.(?:0|[1-9]\d*)){2}(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*))*)?(?:\+(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+)(?:\.(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+))*)?
```
### version core
```bnf
<version core> ::= <major> "." <minor> "." <patch>
```
```javascript
(?:0|[1-9]\d*)(?:\.(?:0|[1-9]\d*)){2}
```
### major
```bnf
<major> ::= <numeric identifier>
```
```javascript
0|[1-9]\d*
```
### minor
```bnf
<minor> ::= <numeric identifier>
```
```javascript
0|[1-9]\d*
```
### patch
```bnf
<patch> ::= <numeric identifier>
```
```javascript
0|[1-9]\d*
```
### pre-release
```bnf
<pre-release> ::= <dot-separated pre-release identifiers>
```
```javascript
(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*))*
```
### dot-separated pre-release identifiers
```bnf
<dot-separated pre-release identifiers> ::= <pre-release identifier>
| <pre-release identifier> "." <dot-separated pre-release identifiers>
```
```javascript
(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*))*
```
### build
```bnf
<build> ::= <dot-separated build identifiers>
```
```javascript
(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+)(?:\.(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+))*
```
### dot-separated build identifiers
```bnf
<dot-separated build identifiers> ::= <build identifier>
| <build identifier> "." <dot-separated build identifiers>
```
```javascript
(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+)(?:\.(?:\d*[A-Za-z-][\dA-Za-z-]*|\d+))*
```
### pre-release identifier
```bnf
<pre-release identifier> ::= <alphanumeric identifier>
| <numeric identifier>
```
```javascript
0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*
```
### build identifier
```bnf
<build identifier> ::= <alphanumeric identifier>
| <digits>
```
```javascript
\d*[A-Za-z-][\dA-Za-z-]*|\d+
```
### alphanumeric identifier
```bnf
<alphanumeric identifier> ::= <non-digit>
| <non-digit> <identifier characters>
| <identifier characters> <non-digit>
| <identifier characters> <non-digit> <identifier characters>
```
```javascript
[\dA-Za-z-]*[A-Za-z-][\dA-Za-z-]*
```
optimized:
```javascript
\d*[A-Za-z-][\dA-Za-z-]*
```
### numeric identifier
```bnf
<numeric identifier> ::= "0"
| <positive digit>
| <positive digit> <digits>
```
```javascript
0|[1-9]\d*
```
### identifier characters
```bnf
<identifier characters> ::= <identifier character>
| <identifier character> <identifier characters>
```
```javascript
[\dA-Za-z-]+
```
### identifier character
```bnf
<identifier character> ::= <digit>
| <non-digit>
```
```javascript
[\dA-Za-z-]
```
### non-digit
```bnf
<non-digit> ::= <letter>
| "-"
```
```javascript
[A-Za-z-]
```
### digits
```bnf
<digits> ::= <digit>
| <digit> <digits>
```
```javascript
\d+
```
### digit
```bnf
<digit> ::= "0"
| <positive digit>
```
```javascript
\d
```
### positive digit
```bnf
<positive digit> ::= "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
```
```javascript
[1-9]
```
### letter
```bnf
<letter> ::= "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J"
| "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T"
| "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d"
| "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n"
| "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x"
| "y" | "z"
```
```javascript
[A-Za-z]
```
+12
View File
@@ -0,0 +1,12 @@
/*!
* SemVer Parser
*
* @license MIT
* @copyright asamuzaK (Kazz)
* @see {@link https://github.com/asamuzaK/semverParser/blob/master/LICENSE}
* @see {@link https://semver.org/ Semantic Versioning 2.0.0}
*/
export {
compareSemVer, isValidSemVer, parseSemVer, promises
} from './modules/semver.js';
+22
View File
@@ -0,0 +1,22 @@
/**
* common.js
*/
/* constants */
const TYPE_FROM = 8;
const TYPE_TO = -1;
/**
* get type
* @param {*} o - object to check
* @returns {string} - type of object
*/
export const getType = o =>
Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
/**
* is string
* @param {*} o - object to check
* @returns {boolean} - result
*/
export const isString = o => typeof o === 'string' || o instanceof String;
+234
View File
@@ -0,0 +1,234 @@
/**
* semver.js
* @see {@link http://semver.org/|Semantic Versioning}
* @see {@link https://github.com/mojombo/semver/|mojombo/semver}
*/
/* api */
import { getType, isString } from './common.js';
/* constants */
const BASE = 10;
const INT = '0|[1-9]\\d*';
const ALPHA_NUM = '\\d*[A-Za-z-][A-Za-z\\d-]*';
const PRE_PART = `(?:${ALPHA_NUM}|${INT})`;
const PRE = `${PRE_PART}(?:\\.${PRE_PART})*`;
const BUILD_PART = `(?:${ALPHA_NUM}|\\d+)`;
const BUILD = `${BUILD_PART}(?:\\.${BUILD_PART})*`;
const SEMVER =
`((?:${INT})(?:\\.(?:${INT})){2})(?:-(${PRE}))?(?:\\+(${BUILD}))?`;
const REGEXP_INT = new RegExp(`^(?:${INT})$`);
const REGEXP_SEMVER = new RegExp(`^v?${SEMVER}$`);
const REGEXP_SEMVER_STRICT = new RegExp(`^${SEMVER}$`);
/**
* parsed SemVer object
* @typedef {object} SemVerObject
* @property {string} version - version string
* @property {boolean} matches - matches SemVer format
* @property {number|undefined} major - major version
* @property {number|undefined} minor - minor version
* @property {number|undefined} patch - patch version
* @property {Array<string|number>|undefined} pre - pre-release version in array
* @property {Array<string|number>|undefined} build - build ID in array
*/
/**
* is valid SemVer string
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {boolean} - result
*/
export const isValidSemVer = (version, strict = false) => {
if (!isString(version)) {
throw new TypeError(`Expected String but got ${getType(version)}.`);
}
const reg = strict ? REGEXP_SEMVER_STRICT : REGEXP_SEMVER;
return reg.test(version);
};
/**
* parse version part
* @param {string} part - version part
* @param {boolean} [nonPosInt] - accept non positive integer
* @returns {string|number} - parsed version part
*/
export const parseVersionPart = (part, nonPosInt = false) => {
if (!isString(part)) {
throw new TypeError(`Expected String but got ${getType(part)}.`);
}
if (!(nonPosInt || REGEXP_INT.test(part))) {
throw new Error(`${part} is not a stringified positive integer.`);
}
let parsedPart;
if (REGEXP_INT.test(part)) {
parsedPart = parseInt(part, BASE);
if (!Number.isSafeInteger(parsedPart)) {
throw new RangeError(`${parsedPart} exceeds ${Number.MAX_SAFE_INTEGER}.`);
}
} else {
parsedPart = part;
}
return parsedPart;
};
/**
* compare SemVer
* @param {string} version - version string
* @param {string} base - base version string to compare from
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {number}
* - -1 or negative number, if version is less than base version
* 0, if version is equal to base version
* 1 or positive number, if version is greater than base version
*/
export const compareSemVer = (version, base, strict = false) => {
if (!isString(version)) {
throw new TypeError(`Expected String but got ${getType(version)}.`);
}
if (!isString(base)) {
throw new TypeError(`Expected String but got ${getType(base)}.`);
}
if (!isValidSemVer(version, !!strict)) {
throw new Error(`${version} is not valid version string.`);
}
if (!isValidSemVer(base, !!strict)) {
throw new Error(`${base} is not valid version string.`);
}
let result;
if (version === base) {
result = 0;
} else {
const reg = strict ? REGEXP_SEMVER_STRICT : REGEXP_SEMVER;
const [, vRel, vPre] = version.match(reg);
const [, bRel, bPre] = base.match(reg);
const [vMajor, vMinor, vPatch] =
vRel.split('.').map(part => parseVersionPart(part));
const [bMajor, bMinor, bPatch] =
bRel.split('.').map(part => parseVersionPart(part));
if (vMajor > bMajor) {
result = 1;
} else if (vMajor < bMajor) {
result = -1;
} else if (vMinor > bMinor) {
result = 1;
} else if (vMinor < bMinor) {
result = -1;
} else if (vPatch > bPatch) {
result = 1;
} else if (vPatch < bPatch) {
result = -1;
} else if (vPre === bPre) {
result = 0;
} else if (!vPre && bPre) {
result = 1;
} else if (vPre && !bPre) {
result = -1;
} else {
const vPreParts = vPre.split('.').map(part =>
parseVersionPart(part, true)
);
const bPreParts = bPre.split('.').map(part =>
parseVersionPart(part, true)
);
const l = Math.max(vPreParts.length, bPreParts.length);
let i = 0;
while (i < l) {
const vPart = vPreParts[i];
const bPart = bPreParts[i];
if ((vPart && !bPart) || (isString(vPart) && Number.isInteger(bPart))) {
result = 1;
} else if ((!vPart && bPart) ||
(Number.isInteger(vPart) && isString(bPart))) {
result = -1;
} else if (vPart !== bPart && isString(vPart) && isString(bPart)) {
result = vPart.localeCompare(bPart);
} else if (Number.isInteger(vPart) && Number.isInteger(bPart)) {
if (vPart > bPart) {
result = 1;
} else if (vPart < bPart) {
result = -1;
}
}
if (Number.isInteger(result)) {
break;
}
i++;
}
}
}
return result;
};
/**
* parse SemVer string
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {SemVerObject} - result
*/
export const parseSemVer = (version, strict = false) => {
if (!isString(version)) {
throw new TypeError(`Expected String but got ${getType(version)}.`);
}
const matches = isValidSemVer(version, !!strict);
let major, minor, patch, pre, build;
if (matches) {
const reg = strict ? REGEXP_SEMVER_STRICT : REGEXP_SEMVER;
const [, vRel, vPre, vBuild] = version.match(reg);
[major, minor, patch] = vRel.split('.').map(part => parseVersionPart(part));
if (vPre) {
pre = vPre.split('.').map(part => parseVersionPart(part, true));
}
if (vBuild) {
build = vBuild.split('.').map(part => parseVersionPart(part, true));
}
}
return {
version, matches, major, minor, patch, pre, build
};
};
/* async wrappers */
/**
* compare SemVer (async)
* @param {string} version - version string
* @param {string} base - base version string to compare from
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {Promise.<number>}
* - -1 or negative number, if version is less than base version
* 0, if version is equal to base version
* 1 or positive number, if version is greater than base version
*/
const compareSemVerAsync = async (version, base, strict = false) => {
const res = compareSemVer(version, base, strict);
return res;
};
/**
* is valid SemVer string (async)
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {Promise.<boolean>} - result
*/
const isValidSemVerAsync = async (version, strict = false) => {
const res = isValidSemVer(version, strict);
return res;
};
/**
* parse SemVer string (async)
* @param {string} version - version string
* @param {boolean} [strict] - reject 'v' prefixed
* @returns {Promise.<SemVerObject>} - result
*/
const parseSemVerAsync = async (version, strict = false) => {
const res = parseSemVer(version, strict);
return res;
};
/* export async functions */
export const promises = {
compareSemVer: compareSemVerAsync,
isValidSemVer: isValidSemVerAsync,
parseSemVer: parseSemVerAsync
};
+36
View File
@@ -0,0 +1,36 @@
{
"name": "semver-parser",
"description": "SemVer parser. parse, verify, compare SemVer.",
"author": "asamuzaK",
"license": "MIT",
"homepage": "https://github.com/asamuzaK/semverParser",
"bugs": "https://github.com/asamuzaK/semverParser/issues",
"repository": {
"type": "git",
"url": "https://github.com/asamuzaK/semverParser.git"
},
"type": "module",
"main": "index.js",
"types": "types/index.d.ts",
"devDependencies": {
"c8": "^7.13.0",
"chai": "^4.3.7",
"eslint": "^8.38.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^43.0.6",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-regexp": "^1.14.0",
"mocha": "^10.2.0",
"typescript": "^5.0.4"
},
"scripts": {
"build": "npm run tsc && npm run lint && npm run test",
"lint": "eslint --fix .",
"test": "c8 --reporter=text mocha --exit test",
"tsc": "node -e \"fs.rmSync('types',{recursive:true,force:true})\" && npx tsc"
},
"version": "4.1.4"
}
+16
View File
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationDir": "types",
"emitDeclarationOnly": true,
"module": "esnext",
"moduleResolution": "node",
"newLine": "LF",
"removeComments": true,
"resolveJsonModule": true,
"target": "esnext"
},
"include": ["index.js"]
}
+1
View File
@@ -0,0 +1 @@
export { compareSemVer, isValidSemVer, parseSemVer, promises } from "./modules/semver.js";
+2
View File
@@ -0,0 +1,2 @@
export function getType(o: any): string;
export function isString(o: any): boolean;
+22
View File
@@ -0,0 +1,22 @@
export function isValidSemVer(version: string, strict?: boolean): boolean;
export function parseVersionPart(part: string, nonPosInt?: boolean): string | number;
export function compareSemVer(version: string, base: string, strict?: boolean): number;
export function parseSemVer(version: string, strict?: boolean): SemVerObject;
export namespace promises {
export { compareSemVerAsync as compareSemVer };
export { isValidSemVerAsync as isValidSemVer };
export { parseSemVerAsync as parseSemVer };
}
export type SemVerObject = {
version: string;
matches: boolean;
major: number | undefined;
minor: number | undefined;
patch: number | undefined;
pre: Array<string | number> | undefined;
build: Array<string | number> | undefined;
};
declare function compareSemVerAsync(version: string, base: string, strict?: boolean): Promise<number>;
declare function isValidSemVerAsync(version: string, strict?: boolean): Promise<boolean>;
declare function parseSemVerAsync(version: string, strict?: boolean): Promise<SemVerObject>;
export {};