@preventive/upstream 1.0.0-alpha.3 → 1.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-APACHE +202 -0
- package/advisories.d.ts +27 -16
- package/cargo.d.ts +18 -1
- package/cargo.js +2 -1
- package/github.d.ts +21 -11
- package/package.json +15 -3
- package/semver.d.ts +2 -1
- package/src/advisories/common.js +8 -4
- package/src/advisories/github.js +24 -8
- package/src/advisories/index.js +5 -5
- package/src/advisories/osv.js +25 -11
- package/src/advisories/repos.js +17 -35
- package/src/args.js +31 -2
- package/src/cache.js +20 -2
- package/src/{cargo.js → cargo/crate.js} +17 -11
- package/src/cargo/repos.js +52 -0
- package/src/github/read.js +57 -16
- package/src/http.js +16 -11
- package/src/npm/repos.js +2 -5
- package/src/npm/tarball.js +1 -6
- package/src/semver-peer.cjs +8 -0
- package/src/semver.js +26 -12
- package/src/soldeer.js +2 -9
- package/src/tree.js +7 -6
- /package/{LICENSE → LICENSE-MIT} +0 -0
package/src/semver.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
2
|
import { createRequire } from 'node:module'
|
|
3
3
|
import { basename, dirname, resolve } from 'node:path'
|
|
4
|
+
import requirePeer from './semver-peer.cjs'
|
|
4
5
|
|
|
5
6
|
// npm's own semver, borrowed from the npm next to node rather than added
|
|
6
|
-
// as a dependency: the same implementation `npm audit` uses.
|
|
7
|
+
// as a dependency: the same implementation `npm audit` uses. Where there is
|
|
8
|
+
// no npm, as in a bundled serverless function, the `semver` package itself,
|
|
9
|
+
// an optional peer dependency.
|
|
7
10
|
|
|
8
11
|
// Plain releases that semver.valid answers unchanged, so it need not be
|
|
9
12
|
// loaded for them: no leading zeros, and at most 15 digits a part, under
|
|
@@ -11,26 +14,37 @@ import { basename, dirname, resolve } from 'node:path'
|
|
|
11
14
|
// to semver.
|
|
12
15
|
const PLAIN_RELEASE = /^(?:0|[1-9]\d{0,14})\.(?:0|[1-9]\d{0,14})\.(?:0|[1-9]\d{0,14})$/u
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
// What load() returns if it is semver, or null if it is not or throws.
|
|
18
|
+
function attempt(load) {
|
|
19
|
+
try {
|
|
20
|
+
const lib = load()
|
|
21
|
+
if (['compare', 'intersects', 'satisfies', 'valid', 'validRange'].every((name) => typeof lib?.[name] === 'function')) return lib
|
|
22
|
+
} catch {}
|
|
23
|
+
return null
|
|
24
|
+
}
|
|
15
25
|
|
|
16
26
|
function find() {
|
|
17
27
|
const argv0 = process.argv[0]
|
|
18
28
|
// Another host executable's `../lib` is not npm's.
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const lib =
|
|
25
|
-
if (
|
|
26
|
-
}
|
|
29
|
+
if (['node', 'node.exe'].includes(basename(argv0 ?? ''))) {
|
|
30
|
+
// POSIX keeps npm in <prefix>/lib beside <prefix>/bin/node; Windows, beside node.exe.
|
|
31
|
+
for (const prefix of ['../lib', '.']) {
|
|
32
|
+
// Required from itself, which a bundle of any format leaves alone.
|
|
33
|
+
const path = resolve(dirname(argv0), prefix, 'node_modules/npm/node_modules/semver')
|
|
34
|
+
const lib = attempt(() => createRequire(path)(path))
|
|
35
|
+
if (lib) return lib
|
|
36
|
+
}
|
|
27
37
|
}
|
|
28
|
-
|
|
38
|
+
// The peer, by the plain require() a bundler follows; or, where an ESM
|
|
39
|
+
// bundle leaves it out, by node's own require() from beside the bundle.
|
|
40
|
+
return attempt(requirePeer) ?? attempt(() => createRequire(import.meta.url)('semver'))
|
|
29
41
|
}
|
|
30
42
|
|
|
43
|
+
let found
|
|
44
|
+
|
|
31
45
|
function semver() {
|
|
32
46
|
if (found === undefined) found = find()
|
|
33
|
-
assert.ok(found, 'semver: no npm beside node to borrow it from')
|
|
47
|
+
assert.ok(found, 'semver: no npm beside node to borrow it from, and the semver peer dependency is not installed')
|
|
34
48
|
return found
|
|
35
49
|
}
|
|
36
50
|
|
package/src/soldeer.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import assert from 'node:assert/strict'
|
|
2
2
|
|
|
3
|
-
import { assertSha256,
|
|
3
|
+
import { assertSha256, assertSoldeerPackage, show } from './args.js'
|
|
4
4
|
import { verifiedDownload } from './download.js'
|
|
5
5
|
import { SOLDEER_API, SOLDEER_REVISIONS, buildUrl, request } from './http.js'
|
|
6
6
|
|
|
7
7
|
const DIR = 'soldeer/zips' // No expiry: the registry refuses a version it already has.
|
|
8
|
-
// Soldeer's own rule for a name: 3 to 100 of lowercase letters, digits and
|
|
9
|
-
// `-`, starting with one of them or `@`, ending with a letter or digit.
|
|
10
|
-
const assertName = assertion('a Soldeer package name', matches(/^(?=.{3,100}$)[@\da-z][\da-z-]*[\da-z]$/u))
|
|
11
|
-
// Soldeer takes any version but an empty one. Its registry has semver
|
|
12
|
-
// (`5.7.0-rc.0`, `1.0.2-solc-0.8-simulate`), bare numbers and commit hashes.
|
|
13
|
-
const assertVersion = assertion('letters, digits, `.`, `_`, `+` and `-`', matches(/^(?=.{1,128}$)[\dA-Za-z][\w.+-]*$/u))
|
|
14
8
|
|
|
15
9
|
// Where the registry keeps the version's zip; it says nothing of what the
|
|
16
10
|
// zip hashes to.
|
|
@@ -26,8 +20,7 @@ async function zipUrl(name, version) {
|
|
|
26
20
|
// The registry has no hash to check a zip against, so the caller brings
|
|
27
21
|
// one, as soldeer.lock records it.
|
|
28
22
|
export async function getZip(name, version, checksum) {
|
|
29
|
-
|
|
30
|
-
assertVersion('getZip', 'version', version)
|
|
23
|
+
assertSoldeerPackage('getZip', name, version)
|
|
31
24
|
assertSha256('getZip', 'checksum', checksum)
|
|
32
25
|
return await verifiedDownload({ method: 'getZip', dir: DIR, what: `${name}@${version}`, ext: 'zip', algorithm: 'sha256', expected: checksum, locate: () => zipUrl(name, version) })
|
|
33
26
|
}
|
package/src/tree.js
CHANGED
|
@@ -28,7 +28,7 @@ const octal = (header, start, end) => {
|
|
|
28
28
|
const text = field(header, start, end).trim()
|
|
29
29
|
return /^[0-7]{1,12}$/u.test(text) ? Number.parseInt(text, 8) : Number.NaN
|
|
30
30
|
}
|
|
31
|
-
const objectId = (type, content) => createHash('sha1').update(`${type} ${content.length}\0`).update(content).digest()
|
|
31
|
+
export const objectId = (type, content) => createHash('sha1').update(`${type} ${content.length}\0`).update(content).digest()
|
|
32
32
|
const checksum = (header) => header.reduce((sum, byte, i) => sum + (i >= 148 && i < 156 ? 32 : byte), 0)
|
|
33
33
|
const isZero = (bytes) => bytes.every((byte) => byte === 0)
|
|
34
34
|
|
|
@@ -64,9 +64,9 @@ function emptyDirs(dir, prefix = '') {
|
|
|
64
64
|
// Git sorts a subtree as if its name ended in `/`.
|
|
65
65
|
function treeId(dir) {
|
|
66
66
|
const entries = [...dir].map(([name, entry]) => (entry instanceof Map ? { mode: '40000', name, id: treeId(entry) } : { ...entry, name }))
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
return objectId('tree', Buffer.concat(
|
|
67
|
+
const keyed = entries.map((entry) => [entry.mode === '40000' ? `${entry.name}/` : entry.name, entry])
|
|
68
|
+
keyed.sort(([a], [b]) => (a < b ? -1 : Number(a > b)))
|
|
69
|
+
return objectId('tree', Buffer.concat(keyed.flatMap(([, { mode, name, id }]) => [Buffer.from(`${mode} ${name}\0`, 'latin1'), id])))
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const EMPTY_TREE = objectId('tree', Buffer.alloc(0)).toString('hex')
|
|
@@ -90,11 +90,10 @@ async function holdsNothing(sha, listed) {
|
|
|
90
90
|
// names any, and one is put back only once its own listings show it holds
|
|
91
91
|
// nothing.
|
|
92
92
|
async function putBackEmptyTrees(dir, sha, listed) {
|
|
93
|
-
if (treeId(dir).toString('hex') === sha) return
|
|
94
93
|
for (const entry of await listed(sha)) {
|
|
95
94
|
if (entry.type !== 'tree') continue
|
|
96
95
|
const here = dir.get(entry.name)
|
|
97
|
-
if (here instanceof Map) await putBackEmptyTrees(here, entry.sha, listed)
|
|
96
|
+
if (here instanceof Map && treeId(here).toString('hex') !== entry.sha) await putBackEmptyTrees(here, entry.sha, listed)
|
|
98
97
|
else if (here === undefined && await holdsNothing(entry.sha, listed)) dir.set(entry.name, subtree(entry.sha))
|
|
99
98
|
}
|
|
100
99
|
}
|
|
@@ -177,6 +176,8 @@ export async function gitTreeOfTarball(gzipped, { expected, list } = {}) {
|
|
|
177
176
|
if (!isSha1(sha)) return `no tree: an empty directory, ${JSON.stringify(path)}, and no submodule there`
|
|
178
177
|
dir.set(name, { mode: '160000', id: Buffer.from(sha, 'hex') })
|
|
179
178
|
}
|
|
179
|
+
const id = treeId(root).toString('hex')
|
|
180
|
+
if (id === expected) return id
|
|
180
181
|
await putBackEmptyTrees(root, expected, listed)
|
|
181
182
|
return treeId(root).toString('hex')
|
|
182
183
|
}
|
/package/{LICENSE → LICENSE-MIT}
RENAMED
|
File without changes
|