From 5dfcc9405939d6469124290db9a8bf8bb1a438a1 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Tue, 14 Feb 2023 13:20:16 -0500 Subject: [PATCH 01/11] replace replaceAll with global regex replace --- src/queries/getPackageData.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 8cba77b..7e9ac44 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -16,11 +16,12 @@ function isCompatible(nodeVersion: string, depRange: string) { let compatible; const logicalOrRegEx = /\|\|/; + const spaceRegEx = /\s/g; if (depRange && logicalOrRegEx.test(depRange)) { - const rangeArray = depRange.split('||').map((range) => range.replaceAll(' ', '')); + const rangeArray = depRange.split('||').map((range) => range.replace(spaceRegEx, '')); compatible = rangeArray.some((range) => satisfies(nodeVersion, range)); } else { - compatible = satisfies(nodeVersion, depRange.replaceAll(' ', '')); + compatible = satisfies(nodeVersion, depRange.replace(spaceRegEx, '')); } return compatible; } From da136aab2c85082b586252f9d711b093280ed98f Mon Sep 17 00:00:00 2001 From: kindoflew Date: Wed, 15 Feb 2023 11:59:19 -0500 Subject: [PATCH 02/11] better whitespace regex, account for AND ranges --- src/queries/getPackageData.ts | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 7e9ac44..ee531ad 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -13,15 +13,26 @@ function isCompatible(nodeVersion: string, depRange: string) { // if a dependency has `*` for the node version, it's always compatible if (['x', '*'].includes(depRange)) return true; - let compatible; + return depRange + .split('||') + .map((range) => removeWhitespace(range)) + .some((range) => safeSatisfies(nodeVersion, range)); +} + +// accounts for `AND` ranges -- ie, `'>=1.2.9 <2.0.0'` +function safeSatisfies(nodeVersion: string, range: string) { + return range.split(' ').every((r) => satisfies(nodeVersion, r)); +} - const logicalOrRegEx = /\|\|/; - const spaceRegEx = /\s/g; - if (depRange && logicalOrRegEx.test(depRange)) { - const rangeArray = depRange.split('||').map((range) => range.replace(spaceRegEx, '')); - compatible = rangeArray.some((range) => satisfies(nodeVersion, range)); - } else { - compatible = satisfies(nodeVersion, depRange.replace(spaceRegEx, '')); - } - return compatible; +// trims leading and trailing whitespace and removes whitespace +// between the comparator operators and the actual version number +// ie, ' > = 12.0.0 ' becomes '>=12.0.0' +// +// does *not* handle whitespace between numbers/decimals +// in actual version number (ie, 1 2. 0 .0) -- the RegEx for +// it would be silly complex, so we handle that in `safeSatisfies` +// once we know we have a single version +function removeWhitespace(range: string) { + const extraSpaceRegEx = /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^))(\s+)(?=\d)|((?<=(\d|\.))(\s+)(?=(\d|\.)))/g; + return range.trim().replace(extraSpaceRegEx, ''); } From 34231b2e0f3c2ca8fc63695040a8b1552ac02e7e Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 16 Feb 2023 20:58:09 -0500 Subject: [PATCH 03/11] make regex better --- src/queries/getPackageData.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index ee531ad..05c0e8b 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -24,15 +24,16 @@ function safeSatisfies(nodeVersion: string, range: string) { return range.split(' ').every((r) => satisfies(nodeVersion, r)); } -// trims leading and trailing whitespace and removes whitespace -// between the comparator operators and the actual version number -// ie, ' > = 12.0.0 ' becomes '>=12.0.0' +// trims leading and trailing whitespace, whitespace +// between the comparator operators and the actual version number, +// whitespace between digits and decimals in the version number, and +// whitespace between the numbers/wildcards/decimals in the actual +// version number. ie, ' > = 12.0.0 ' becomes '>=12.0.0' // -// does *not* handle whitespace between numbers/decimals -// in actual version number (ie, 1 2. 0 .0) -- the RegEx for -// it would be silly complex, so we handle that in `safeSatisfies` -// once we know we have a single version +// it does *not* remove whitespace between versions in an `AND` range +// ie, '>=1.2.9 <2.0.0', because we want to split those later function removeWhitespace(range: string) { - const extraSpaceRegEx = /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^))(\s+)(?=\d)|((?<=(\d|\.))(\s+)(?=(\d|\.)))/g; + const extraSpaceRegEx = + /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^|~))(\s+)(?=\d)|((?<=(\d|\.|\*|x|X))(\s+)(?=(\d|\.|\*|x|X)))/g; return range.trim().replace(extraSpaceRegEx, ''); } From d71df34bdce8c36f678c2c3c60c15a8b9883cfd4 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 16 Feb 2023 20:59:20 -0500 Subject: [PATCH 04/11] package-lock version bump --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 3419c27..ed062d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "depngn", - "version": "0.2.0", + "version": "0.3.0", "license": "MIT", "dependencies": { "arg": "^5.0.2", From 0af1bee73bb5ad0ee1c507451c6aa904a777e819 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 16 Feb 2023 21:33:58 -0500 Subject: [PATCH 05/11] one last regex improvement --- src/queries/getPackageData.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 05c0e8b..a361302 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -30,10 +30,10 @@ function safeSatisfies(nodeVersion: string, range: string) { // whitespace between the numbers/wildcards/decimals in the actual // version number. ie, ' > = 12.0.0 ' becomes '>=12.0.0' // -// it does *not* remove whitespace between versions in an `AND` range +// it also ensures there's only one space in logical `AND` ranges // ie, '>=1.2.9 <2.0.0', because we want to split those later function removeWhitespace(range: string) { const extraSpaceRegEx = - /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^|~))(\s+)(?=\d)|((?<=(\d|\.|\*|x|X))(\s+)(?=(\d|\.|\*|x|X)))/g; + /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^|~))(\s+)(?=\d)|((?<=(\d|\.|\*|x|X))(\s+)(?=(\d|\.|\*|x|X)))|(?<=\d)(\s+)(?=\s<|>)/g; return range.trim().replace(extraSpaceRegEx, ''); } From dea69a58fa7fe35f25741d11f7f3047e130b4d4a Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 16 Feb 2023 21:42:11 -0500 Subject: [PATCH 06/11] fix comment --- src/queries/getPackageData.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index a361302..48a357f 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -25,9 +25,8 @@ function safeSatisfies(nodeVersion: string, range: string) { } // trims leading and trailing whitespace, whitespace -// between the comparator operators and the actual version number, -// whitespace between digits and decimals in the version number, and -// whitespace between the numbers/wildcards/decimals in the actual +// between the comparator operators and the actual version number, +// and whitespace between the numbers/wildcards/decimals in the actual // version number. ie, ' > = 12.0.0 ' becomes '>=12.0.0' // // it also ensures there's only one space in logical `AND` ranges From 3b692a42bf7cc5879acbb16c556290a6ea980938 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 16 Feb 2023 21:43:28 -0500 Subject: [PATCH 07/11] one more comment fix --- src/queries/getPackageData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 48a357f..43a7790 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -27,7 +27,7 @@ function safeSatisfies(nodeVersion: string, range: string) { // trims leading and trailing whitespace, whitespace // between the comparator operators and the actual version number, // and whitespace between the numbers/wildcards/decimals in the actual -// version number. ie, ' > = 12.0.0 ' becomes '>=12.0.0' +// version number. ie, ' > = 1 2. 0 .0 ' becomes '>=12.0.0' // // it also ensures there's only one space in logical `AND` ranges // ie, '>=1.2.9 <2.0.0', because we want to split those later From 087e686f79c55894bf6693303cb106c292d9b8b1 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 23 Feb 2023 18:31:41 -0500 Subject: [PATCH 08/11] one last filter --- src/queries/getPackageData.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 43a7790..db1ca16 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -21,11 +21,17 @@ function isCompatible(nodeVersion: string, depRange: string) { // accounts for `AND` ranges -- ie, `'>=1.2.9 <2.0.0'` function safeSatisfies(nodeVersion: string, range: string) { - return range.split(' ').every((r) => satisfies(nodeVersion, r)); + return ( + range + .split(' ') + // filter out any whitespace we may have missed with the RegEx -- ie, `'>=4.2.0 8.0.0'` + .filter((r) => !!r) + .every((r) => satisfies(nodeVersion, r)) + ); } // trims leading and trailing whitespace, whitespace -// between the comparator operators and the actual version number, +// between the comparator operators and the actual version number, // and whitespace between the numbers/wildcards/decimals in the actual // version number. ie, ' > = 1 2. 0 .0 ' becomes '>=12.0.0' // From cfc18d3304f483b902691241f028dc14d65be8e5 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Thu, 2 Mar 2023 17:47:31 -0500 Subject: [PATCH 09/11] actually probably the last regex version --- src/queries/getPackageData.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index db1ca16..71973e6 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -24,7 +24,7 @@ function safeSatisfies(nodeVersion: string, range: string) { return ( range .split(' ') - // filter out any whitespace we may have missed with the RegEx -- ie, `'>=4.2.0 8.0.0'` + // filter out any whitespace we may have missed with the RegEx -- ie, `'>4 <8'` .filter((r) => !!r) .every((r) => satisfies(nodeVersion, r)) ); @@ -38,7 +38,13 @@ function safeSatisfies(nodeVersion: string, range: string) { // it also ensures there's only one space in logical `AND` ranges // ie, '>=1.2.9 <2.0.0', because we want to split those later function removeWhitespace(range: string) { - const extraSpaceRegEx = - /((?<=(<|>))(\s+)(?=(=)))|(?<=(<|>|=|\^|~))(\s+)(?=\d)|((?<=(\d|\.|\*|x|X))(\s+)(?=(\d|\.|\*|x|X)))|(?<=\d)(\s+)(?=\s<|>)/g; - return range.trim().replace(extraSpaceRegEx, ''); + const comparatorWhitespace = /((?<=(<|>))(\s+)(?=(=)))/g; + const comparatorAndVersionWhiteSpace = /(?<=(<|>|=|\^|~))(\s+)(?=\d)/g; + const remainingRange = + /(((\d\s*){1,3})\.\s*(\d\s*){1,3}\.\s*((0\s*)|(\d\s*){1,2})(?!(((<|>)=?)|~|^)?(((\d\s*){1,3})\.)|(\d)))/g; + return range + .trim() + .replace(comparatorWhitespace, '') + .replace(comparatorAndVersionWhiteSpace, '') + .replace(remainingRange, (match: string) => match.replace(/\s+/g, '')); } From c1cf09625bc2a1a7cee6ef375619d0997a1044db Mon Sep 17 00:00:00 2001 From: kindoflew Date: Fri, 3 Mar 2023 16:54:39 -0500 Subject: [PATCH 10/11] implement invalid range handling --- src/cli/reporter/html.ts | 29 +++++++++++++++++++---------- src/cli/reporter/table.ts | 4 ++-- src/queries/getPackageData.ts | 28 ++++++++++++++-------------- src/types.ts | 2 +- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/cli/reporter/html.ts b/src/cli/reporter/html.ts index dc243ea..2212f27 100644 --- a/src/cli/reporter/html.ts +++ b/src/cli/reporter/html.ts @@ -1,11 +1,15 @@ import { writeFile } from 'fs/promises'; import { CompatData } from '../../types'; -export async function createHtml(compatData: Record, version: string, path: string = 'compat.html') { +export async function createHtml( + compatData: Record, + version: string, + path: string = 'compat.html' +) { const compatDataKeys = Object.keys(compatData); - const classGreen = "green"; - const classRed = "red"; - const classYellow = "yellow"; + const classGreen = 'green'; + const classRed = 'red'; + const classYellow = 'yellow'; const style = ` h1{ @@ -32,21 +36,26 @@ export async function createHtml(compatData: Record, version } .${classYellow}{ color: #ce8d02; - }` + }`; const tableData = compatDataKeys .map((key) => { const compatible = compatData[key].compatible; - const compatibleClass = compatible === undefined ? classYellow : compatible ? classGreen : classRed; + const compatibleClass = + compatible === undefined || compatible === 'invalid' + ? classYellow + : compatible + ? classGreen + : classRed; return ` ${key} ${compatible} ${compatData[key].range} - ` + `; }) - .join(""); + .join(''); const out = ` @@ -67,8 +76,8 @@ export async function createHtml(compatData: Record, version ${tableData} - ` + `; await writeFile(path, out); console.log(`File generated at ${path}`); -} \ No newline at end of file +} diff --git a/src/cli/reporter/table.ts b/src/cli/reporter/table.ts index e355239..86bfd1d 100644 --- a/src/cli/reporter/table.ts +++ b/src/cli/reporter/table.ts @@ -21,8 +21,8 @@ export function createTable(compatData: Record, version: str console.log(table(out, config)); } -function toColorString(value: boolean | undefined) { - if (value === undefined) return yellow('undefined'); +function toColorString(value: boolean | string | undefined) { + if (value === undefined || value === 'invalid') return yellow(`${value}`); const outputColor = value ? green : red; return outputColor(value.toString()); } diff --git a/src/queries/getPackageData.ts b/src/queries/getPackageData.ts index 71973e6..8c1f81a 100644 --- a/src/queries/getPackageData.ts +++ b/src/queries/getPackageData.ts @@ -1,7 +1,7 @@ import { satisfies } from 'compare-versions'; -import { EnginesData } from '../types'; +import { CompatData, EnginesData } from '../types'; -export function getPackageData(dep: EnginesData, version: string) { +export function getPackageData(dep: EnginesData, version: string): CompatData { const range = dep.range ? dep.range : 'n/a'; const compatible = isCompatible(version, dep.range); return { compatible, range }; @@ -13,10 +13,17 @@ function isCompatible(nodeVersion: string, depRange: string) { // if a dependency has `*` for the node version, it's always compatible if (['x', '*'].includes(depRange)) return true; - return depRange + try { + return depRange .split('||') .map((range) => removeWhitespace(range)) .some((range) => safeSatisfies(nodeVersion, range)); + } catch (error) { + if ((error as Error).message.match(/Invalid argument not valid semver/)) { + return 'invalid'; + } + throw error; + } } // accounts for `AND` ranges -- ie, `'>=1.2.9 <2.0.0'` @@ -30,21 +37,14 @@ function safeSatisfies(nodeVersion: string, range: string) { ); } -// trims leading and trailing whitespace, whitespace -// between the comparator operators and the actual version number, -// and whitespace between the numbers/wildcards/decimals in the actual -// version number. ie, ' > = 1 2. 0 .0 ' becomes '>=12.0.0' -// -// it also ensures there's only one space in logical `AND` ranges -// ie, '>=1.2.9 <2.0.0', because we want to split those later +// trims leading and trailing whitespace and whitespace +// between the comparator operators and the actual version number +// version number. ie, ' > = 12.0.0 ' becomes '>=12.0.0' function removeWhitespace(range: string) { const comparatorWhitespace = /((?<=(<|>))(\s+)(?=(=)))/g; const comparatorAndVersionWhiteSpace = /(?<=(<|>|=|\^|~))(\s+)(?=\d)/g; - const remainingRange = - /(((\d\s*){1,3})\.\s*(\d\s*){1,3}\.\s*((0\s*)|(\d\s*){1,2})(?!(((<|>)=?)|~|^)?(((\d\s*){1,3})\.)|(\d)))/g; return range .trim() .replace(comparatorWhitespace, '') - .replace(comparatorAndVersionWhiteSpace, '') - .replace(remainingRange, (match: string) => match.replace(/\s+/g, '')); + .replace(comparatorAndVersionWhiteSpace, ''); } diff --git a/src/types.ts b/src/types.ts index ab2bb87..ed7238e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,7 +6,7 @@ export interface EnginesData { export type EnginesDataArray = Array; export interface CompatData { - compatible: boolean | undefined; + compatible: boolean | 'invalid' | undefined; range: string; } From 5f09dbb87b8357c66b3a26f270a83968e5966236 Mon Sep 17 00:00:00 2001 From: kindoflew Date: Fri, 3 Mar 2023 17:14:35 -0500 Subject: [PATCH 11/11] update README --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 11ba8b3..77ad0c6 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ And it returns a promise that resolves to: type DepngnReturn = Record; interface CompatData { - compatible: boolean | undefined; + compatible: boolean | 'invalid' | undefined; range: string; } ``` @@ -95,6 +95,15 @@ const generateReport = async () => { }; ``` +There's also a chance there *is* an `engines` field specified in the package, but the range is invalid in some way. Since RegEx for SemVer can be tricky, we return the folling, if that's the case: + +```javascript +{ + compatible: 'invalid', + range: '1 .2 . 0not-a-valid-range' +} +``` + ## Supported Package Managers For now, this package supports `npm` and `yarn`. If you want support for