Conversation
Co-authored-by: raineorshine <750276+raineorshine@users.noreply.github.com>
raineorshine
left a comment
There was a problem hiding this comment.
DEP0169] DeprecationWarning: url.parse() behavior is not standardized and prone to errors that have security implications. Use the WHATWG URL API instead. CVEs are not issued for url.parse() vulnerabilities.
…DEP0169 warning in Node v24 Co-authored-by: raineorshine <750276+raineorshine@users.noreply.github.com>
Co-authored-by: raineorshine <750276+raineorshine@users.noreply.github.com>
Fixed in commit 30a7722. The I replaced the Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
Maybe wait for jonschlinkert/parse-github-url#35 |
|
FYI I did that pull request specifically for npm-check-updates. : ) |
|
Although no-one responded in 5 days so it is not looking good. You might just want to accept copilot's pull request, as it is only an extra 112 lines to maintain and doesn't look that complicated. |
|
Thanks, I was thinking the same thing. Have you looked over the implementation to see if it compares favorably to Alternatively I could just point towards your fork temporarily, then switch it back after they merge. It's not just the script that’s needed for maintenance but the test suite, too. |
i haven't. |
|
I'm referring to the |
|
ohhh. i could try running copilot's code on their test suite. i'll do that now. |
|
It didn't pass all the tests. Copilot iterated on it and made this: interface ParsedGitHubUrl {
auth: string | null
blob?: string | null
branch?: string
filepath: string | null
hash: string | null
host: string
href: string
name: string | null
owner: string | null
path: string
pathname: string
protocol: string | null
repo: string | null
repository: string | null
}
type ParsedBase = {
auth?: string | null
hash: string | null
host: string | null
href: string
path: string | null
pathname: string | null
protocol: string | null
}
const cache: Record<string, ParsedGitHubUrl | null> = Object.create(null)
function isChecksum(str: string): boolean {
return (/^[a-f0-9]{40}$/i).test(str)
}
function getBranch(str: string, obj: ParsedGitHubUrl): string {
const segs = str.split('#')
let branch: string | undefined
if (segs.length > 1) {
branch = segs[segs.length - 1]
}
if (!branch && obj.hash && obj.hash.charAt(0) === '#') {
branch = obj.hash.slice(1)
}
return branch || 'master'
}
function trimSlash(path: string): string {
return path.charAt(0) === '/' ? path.slice(1) : path
}
function parseName(str: string | undefined): string | null {
return str ? str.replace(/\.git$/, '') : null
}
function parseOwner(str: string | undefined): string | null {
if (!str) {
return null
}
const idx = str.indexOf(':')
if (idx > -1) {
return str.slice(idx + 1)
}
return str
}
function parseScpLike(str: string): ParsedBase | null {
let branch = ''
const hashIndex = str.indexOf('#')
let target = str
if (hashIndex > -1) {
branch = str.slice(hashIndex)
target = str.slice(0, hashIndex)
}
const match = target.match(/^git@([^:]+):(.+)$/)
if (!match) {
return null
}
return {
hash: branch || null,
host: match[1],
href: str,
path: match[2],
pathname: match[2],
protocol: null,
}
}
function parseGitHubShorthand(str: string): ParsedBase {
let hash = ''
let target = str
const hashIndex = str.indexOf('#')
if (hashIndex > -1) {
hash = str.slice(hashIndex)
target = str.slice(0, hashIndex)
}
return {
hash: hash || null,
host: null,
href: str,
path: target,
pathname: target,
protocol: null,
}
}
function parseWithUrlApi(str: string): ParsedBase | null {
try {
const parsed = new URL(str)
if (!parsed.hostname && parsed.protocol && parsed.protocol !== 'github:') {
return null
}
return {
auth: parsed.username ? (parsed.password ? `${parsed.username}:${parsed.password}` : parsed.username) : null,
hash: parsed.hash || null,
host: parsed.host || null,
href: parsed.href || str,
path: parsed.pathname || null,
pathname: parsed.pathname || null,
protocol: parsed.protocol || null,
}
} catch {
return null
}
}
function parseUrl(str: string): ParsedBase | null {
if ((/^git@/).test(str)) {
return parseScpLike(str)
}
if ((/^(?:github:)[^/]+\/[^/]+/).test(str)) {
return parseGitHubShorthand(str.slice(7))
}
if ((/^[a-z][a-z0-9+.-]*:[^/]/i).test(str)) {
return null
}
const parsed = parseWithUrlApi(str)
if (parsed) {
return parsed
}
return parseGitHubShorthand(str)
}
function parse(str: string): ParsedGitHubUrl | null {
if (typeof str !== 'string' || !str.length) {
return null
}
if (str.indexOf('git@gist') !== -1 || str.indexOf('//gist') !== -1) {
return null
}
const parsed = parseUrl(str)
if (!parsed || typeof parsed.path !== 'string' || !parsed.path.length || typeof parsed.pathname !== 'string' || !parsed.pathname.length) {
return null
}
const obj: ParsedGitHubUrl = {
auth: parsed.auth || null,
filepath: null,
hash: parsed.hash,
host: parsed.host || 'github.com',
href: parsed.href,
name: null,
owner: null,
path: trimSlash(parsed.path),
pathname: trimSlash(parsed.pathname),
protocol: parsed.protocol,
repo: null,
repository: null,
}
if (obj.path.indexOf('repos') === 0) {
obj.path = obj.path.slice(6)
}
const seg = obj.path.split('/').filter(Boolean)
const hasBlob = seg[2] === 'blob'
if (hasBlob && !isChecksum(seg[3])) {
obj.branch = seg[3]
if (seg.length > 4) {
obj.filepath = seg.slice(4).join('/')
}
}
const blob = str.indexOf('blob')
if (hasBlob && blob !== -1) {
obj.blob = str.slice(blob + 5)
}
const hasTree = seg[2] === 'tree'
const tree = str.indexOf('tree')
if (hasTree && tree !== -1) {
const idx = tree + 5
let branch = str.slice(idx)
const slash = branch.indexOf('/')
if (slash !== -1) {
branch = branch.slice(0, slash)
}
obj.branch = branch
}
obj.owner = parseOwner(seg[0])
obj.name = parseName(seg[1])
if (seg.length > 1 && obj.owner && obj.name) {
obj.repo = `${obj.owner}/${obj.name}`
} else {
const href = obj.href.split(':')
if (href.length === 2 && obj.href.indexOf('//') === -1) {
obj.repo = obj.repo || href[href.length - 1]
const repoSegments = obj.repo.split('/')
obj.owner = repoSegments[0]
obj.name = repoSegments[1]
} else {
const match = obj.href.match(/\/([^/]*)$/)
obj.owner = match ? match[1] : null
obj.repo = null
}
if (obj.repo && (!obj.owner || !obj.name)) {
const segs = obj.repo.split('/')
if (segs.length === 2) {
obj.owner = segs[0]
obj.name = segs[1]
}
}
}
if (!obj.branch) {
obj.branch = seg[2] || getBranch(obj.path, obj)
if (seg.length > 3) {
obj.filepath = seg.slice(3).join('/')
}
}
obj.host = obj.host || 'github.com'
obj.owner = obj.owner || null
obj.name = obj.name || null
obj.repository = obj.repo
obj.blob = obj.blob || null
return obj
}
export default function parseGitHubUrl(str: string): ParsedGitHubUrl | null {
if (!(str in cache)) {
cache[str] = parse(str)
}
return cache[str]
}This version passes the tests, but the code looks significantly different now, so up to you as to which version you want. |
|
We're looking for the minimal change needed to fix the deprecation warning, not an entire rewrite. This strikes me as a bit "let's try something and see what happens", which does not instill confidence. We have a bit more responsibility to the users of this library. |
Adds Node.js v24 to the CI test matrix alongside existing v20 and v22 coverage, and fixes compatibility issues so tests pass on Node v24.
Changes
.github/workflows/test.yml: Added24to thematrix.nodearraysrc/lib/parseGitHubUrl.ts: New local WHATWG URL-based replacement for theparse-github-urlpackage, which used the deprecatedurl.parse()that emits a DEP0169 warning to stderr in Node v24 (causing tests that assert empty stderr to fail)src/lib/version-util.ts: Updated import to use localparseGitHubUrl; simplifiedisGitHubUrlby removing a try/catch that was only needed due tourl.parse()throwing on certain inputssrc/package-managers/gitTags.ts: Updated import to use localparseGitHubUrlOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.