convert to typescript

This commit is contained in:
silverwind 2024-05-23 23:53:45 +02:00
parent 78a6095b17
commit 61a00a7e34
Signed by: silverwind
GPG Key ID: 2E62B41C93869443
12 changed files with 1663 additions and 367 deletions

@ -1,2 +1,4 @@
root: true root: true
extends: silverwind extends:
- silverwind
- silverwind-typescript

1
.gitattributes vendored

@ -1,3 +1,4 @@
* text=auto eol=lf * text=auto eol=lf
*.snap linguist-language=JavaScript linguist-generated *.snap linguist-language=JavaScript linguist-generated
fixtures/** linguist-generated fixtures/** linguist-generated
vendor/** linguist-vendored

@ -7,17 +7,11 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
node: [18, 20, 22] node: [18, 20, 22]
bun: [latest] os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest, macos-latest] runs-on: ${{matrix.os}}
runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: ${{matrix.node}} node-version: ${{matrix.node}}
- uses: oven-sh/setup-bun@v1
with:
bun-version: ${{matrix.bun}}
- run: make lint test - run: make lint test
- run: bun test

@ -1,5 +1,5 @@
SRC := updates.js SOURCE_FILES := index.ts
DST := dist/updates.js DIST_FILES := dist/index.js
node_modules: package-lock.json node_modules: package-lock.json
npm install --no-save npm install --no-save
@ -10,11 +10,13 @@ deps: node_modules
.PHONY: lint .PHONY: lint
lint: node_modules lint: node_modules
npx eslint --color . npx eslint --ext js,jsx,ts,tsx --color .
npx tsc
.PHONY: lint-fix .PHONY: lint-fix
lint-fix: node_modules lint-fix: node_modules
npx eslint --color . --fix npx eslint --ext js,jsx,ts,tsx --color . --fix
npx tsc
.PHONY: test .PHONY: test
test: node_modules build test: node_modules build
@ -24,18 +26,12 @@ test: node_modules build
test-update: node_modules build test-update: node_modules build
npx vitest -u npx vitest -u
.PHONY: test
test-bun: node_modules build
bun test
rm -rf __snapshots__
.PHONY: build .PHONY: build
build: $(DST) build: node_modules $(DIST_FILES)
$(DST): $(SRC) node_modules $(DIST_FILES): $(SOURCE_FILES) package-lock.json vite.config.ts
# workaround for https://github.com/evanw/esbuild/issues/1921 npx vite build
npx esbuild --log-level=warning --platform=node --target=node18 --format=esm --bundle --minify --legal-comments=none --banner:js="import {createRequire} from 'module';const require = createRequire(import.meta.url);" --define:import.meta.VERSION=\"$(shell jq .version package.json)\" --outfile=$(DST) $(SRC) chmod +x $(DIST_FILES)
chmod +x $(DST)
.PHONY: publish .PHONY: publish
publish: node_modules publish: node_modules
@ -43,23 +39,23 @@ publish: node_modules
npm publish npm publish
.PHONY: update .PHONY: update
update: node_modules build update: node_modules
node $(DST) -u npx updates -cu
rm -rf node_modules package-lock.json rm -rf node_modules package-lock.json
npm install npm install
@touch node_modules @touch node_modules
.PHONY: patch .PHONY: path
patch: node_modules lint test patch: node_modules lint test build
npx versions -c 'make --no-print-directory build' patch package.json package-lock.json npx versions patch package.json package-lock.json
@$(MAKE) --no-print-directory publish @$(MAKE) --no-print-directory publish
.PHONY: minor .PHONY: minor
minor: node_modules lint test minor: node_modules lint test build
npx versions -c 'make --no-print-directory build' minor package.json package-lock.json npx versions minor package.json package-lock.json
@$(MAKE) --no-print-directory publish @$(MAKE) --no-print-directory publish
.PHONY: major .PHONY: major
major: node_modules lint test major: node_modules lint test build
npx versions -c 'make --no-print-directory build' major package.json package-lock.json npx versions major package.json package-lock.json
@$(MAKE) --no-print-directory publish @$(MAKE) --no-print-directory publish

@ -6,6 +6,8 @@ import {writeFile, readFile, rm} from "node:fs/promises";
import {fileURLToPath} from "node:url"; import {fileURLToPath} from "node:url";
import {tmpdir} from "node:os"; import {tmpdir} from "node:os";
import {env} from "node:process"; import {env} from "node:process";
import type {Server} from "node:http";
import type {Service, Protocol} from "restana";
const testFile = fileURLToPath(new URL("fixtures/npm-test/package.json", import.meta.url)); const testFile = fileURLToPath(new URL("fixtures/npm-test/package.json", import.meta.url));
const emptyFile = fileURLToPath(new URL("fixtures/npm-empty/package.json", import.meta.url)); const emptyFile = fileURLToPath(new URL("fixtures/npm-empty/package.json", import.meta.url));
@ -14,7 +16,7 @@ const dualFile = fileURLToPath(new URL("fixtures/dual", import.meta.url));
const testPkg = JSON.parse(readFileSync(testFile, "utf8")); const testPkg = JSON.parse(readFileSync(testFile, "utf8"));
const testDir = mkdtempSync(join(tmpdir(), "updates-")); const testDir = mkdtempSync(join(tmpdir(), "updates-"));
const script = fileURLToPath(new URL("updates.js", import.meta.url)); const script = fileURLToPath(new URL("dist/index.js", import.meta.url));
const dependencyTypes = [ const dependencyTypes = [
"dependencies", "dependencies",
@ -24,7 +26,7 @@ const dependencyTypes = [
"resolutions", "resolutions",
]; ];
const testPackages = new Set(); const testPackages: Set<string> = new Set();
for (const dependencyType of dependencyTypes) { for (const dependencyType of dependencyTypes) {
for (const name of Object.keys(testPkg[dependencyType] || [])) { for (const name of Object.keys(testPkg[dependencyType] || [])) {
testPackages.add(name); testPackages.add(name);
@ -33,22 +35,29 @@ for (const dependencyType of dependencyTypes) {
const pyTestPackages = new Set(["djlint", "PyYAML"]); const pyTestPackages = new Set(["djlint", "PyYAML"]);
function makeUrl(server) { function makeUrl(server: Server) {
const {port} = server.address(); const {port}: any = server.address();
return Object.assign(new URL("http://localhost"), {port}).toString(); return Object.assign(new URL("http://localhost"), {port}).toString();
} }
function defaultRoute(req, res) { function defaultRoute(req: any, res: any) {
console.error(`default handler hit for ${req.url}`); console.error(`default handler hit for ${req.url}`);
res.send(404); res.send(404);
} }
function resolutionsBasePackage(name) { function resolutionsBasePackage(name: string) {
const packages = name.match(/(@[^/]+\/)?([^/]+)/g) || []; const packages = name.match(/(@[^/]+\/)?([^/]+)/g) || [];
return packages[packages.length - 1]; return packages[packages.length - 1];
} }
let npmServer, githubServer, githubUrl, pypiServer, pypiUrl, npmUrl; let npmServer: Service<Protocol.HTTP> | Server;
let githubServer: Service<Protocol.HTTP> | Server;
let pypiServer: Service<Protocol.HTTP> | Server;
let githubUrl: string;
let pypiUrl: string;
let npmUrl: string;
beforeAll(async () => { beforeAll(async () => {
let commits, tags; let commits, tags;
@ -98,7 +107,7 @@ afterAll(async () => {
]); ]);
}); });
function makeTest(args) { function makeTest(args: string) {
return async () => { return async () => {
const argsArr = [ const argsArr = [
...args.split(/\s+/), "-c", ...args.split(/\s+/), "-c",

@ -16,6 +16,16 @@ import {getProperty} from "dot-prop";
import pAll from "p-all"; import pAll from "p-all";
import memize from "memize"; import memize from "memize";
import picomatch from "picomatch"; import picomatch from "picomatch";
import {version} from "./package.json" with {type: "json"};
import type {AuthOptions} from "registry-auth-token";
import type {AgentOptions} from "node:https";
type Npmrc = {
registry?: string,
ca?: string,
cafile?: string,
[other: string]: any,
}
// regexes for url dependencies. does only github and only hash or exact semver // regexes for url dependencies. does only github and only hash or exact semver
// https://regex101.com/r/gCZzfK/2 // https://regex101.com/r/gCZzfK/2
@ -23,11 +33,11 @@ const stripRe = /^.*?:\/\/(.*?@)?(github\.com[:/])/i;
const partsRe = /^([^/]+)\/([^/#]+)?.*?\/([0-9a-f]+|v?[0-9]+\.[0-9]+\.[0-9]+)$/i; const partsRe = /^([^/]+)\/([^/#]+)?.*?\/([0-9a-f]+|v?[0-9]+\.[0-9]+\.[0-9]+)$/i;
const hashRe = /^[0-9a-f]{7,}$/i; const hashRe = /^[0-9a-f]{7,}$/i;
const versionRe = /[0-9]+(\.[0-9]+)?(\.[0-9]+)?/g; const versionRe = /[0-9]+(\.[0-9]+)?(\.[0-9]+)?/g;
const esc = str => str.replace(/[|\\{}()[\]^$+*?.-]/g, "\\$&"); const esc = (str: string) => str.replace(/[|\\{}()[\]^$+*?.-]/g, "\\$&");
const gitInfo = memize(hostedGitInfo.fromUrl); const gitInfo = memize(hostedGitInfo.fromUrl);
const registryAuthToken = memize(rat); const registryAuthToken = memize(rat);
const normalizeUrl = memize(url => url.endsWith("/") ? url.substring(0, url.length - 1) : url); const normalizeUrl = memize(url => url.endsWith("/") ? url.substring(0, url.length - 1) : url);
const packageVersion = import.meta.VERSION || "0.0.0"; const packageVersion = version || "0.0.0";
const sep = "\0"; const sep = "\0";
const args = minimist(argv.slice(2), { const args = minimist(argv.slice(2), {
@ -89,32 +99,32 @@ const minor = argSetToRegexes(parseMixedArg(args.minor));
const allowDowngrade = parseMixedArg(args["allow-downgrade"]); const allowDowngrade = parseMixedArg(args["allow-downgrade"]);
const githubApiUrl = args.githubapi ? normalizeUrl(args.githubapi) : "https://api.github.com"; const githubApiUrl = args.githubapi ? normalizeUrl(args.githubapi) : "https://api.github.com";
const pypiApiUrl = args.pypiapi ? normalizeUrl(args.pypiapi) : "https://pypi.org"; const pypiApiUrl = args.pypiapi ? normalizeUrl(args.pypiapi) : "https://pypi.org";
const stripV = str => str.replace(/^v/, ""); const stripV = (str: string) => str.replace(/^v/, "");
function matchesAny(str, set) { function matchesAny(str: string, set: boolean | Set<RegExp>) {
for (const re of (set instanceof Set ? set : [])) { for (const re of (set instanceof Set ? set : [])) {
if (re.test(str)) return true; if (re.test(str)) return true;
} }
return false; return false;
} }
const registryUrl = memize((scope, npmrc) => { const registryUrl = memize((scope: string, npmrc: Npmrc) => {
const url = npmrc[`${scope}:registry`] || npmrc.registry; const url = npmrc[`${scope}:registry`] || npmrc.registry;
return url.endsWith("/") ? url : `${url}/`; return url.endsWith("/") ? url : `${url}/`;
}); });
function findUpSync(filename, dir) { function findUpSync(filename: string, dir: string): string | null {
const path = join(dir, filename); const path = join(dir, filename);
try { accessSync(path); return path; } catch {} try { accessSync(path); return path; } catch {}
const parent = dirname(dir); const parent = dirname(dir);
return parent === dir ? null : findUpSync(filename, parent); return parent === dir ? null : findUpSync(filename, parent);
} }
function getAuthAndRegistry(name, registry, authTokenOpts, npmrc) { function getAuthAndRegistry(name: string, registry: string, authTokenOpts: AuthOptions, npmrc: Npmrc) {
if (!name.startsWith("@")) { if (!name.startsWith("@")) {
return [registryAuthToken(registry, authTokenOpts), registry]; return [registryAuthToken(registry, authTokenOpts), registry];
} else { } else {
const scope = (/@[a-z0-9][\w-.]+/.exec(name) || [])[0]; const scope = (/@[a-z0-9][\w-.]+/.exec(name) || [""])[0];
const url = normalizeUrl(registryUrl(scope, npmrc)); const url = normalizeUrl(registryUrl(scope, npmrc));
if (url !== registry) { if (url !== registry) {
try { try {
@ -126,7 +136,7 @@ function getAuthAndRegistry(name, registry, authTokenOpts, npmrc) {
} }
} }
const getFetchOpts = memize((agentOpts, authType, authToken) => { const getFetchOpts = memize((agentOpts: AgentOptions, authType?: string, authToken?: string) => {
return { return {
...(Object.keys(agentOpts).length && {agentOpts}), ...(Object.keys(agentOpts).length && {agentOpts}),
headers: { headers: {
@ -136,14 +146,14 @@ const getFetchOpts = memize((agentOpts, authType, authToken) => {
}; };
}); });
async function doFetch(url, opts) { async function doFetch(url: string, opts: RequestInit) {
if (args.verbose) console.error(`${magenta("fetch")} ${url}`); if (args.verbose) console.error(`${magenta("fetch")} ${url}`);
const res = await fetch(url, opts); const res = await fetch(url, opts);
if (args.verbose) console.error(`${res.ok ? green("done") : red("error")} ${url}`); if (args.verbose) console.error(`${res.ok ? green("done") : red("error")} ${url}`);
return res; return res;
} }
async function fetchNpmInfo(name, type, originalRegistry, agentOpts, authTokenOpts, npmrc) { async function fetchNpmInfo(name: string, type: string, originalRegistry: string, agentOpts: AgentOptions, authTokenOpts: AuthOptions, npmrc: Npmrc) {
const [auth, registry] = getAuthAndRegistry(name, originalRegistry, authTokenOpts, npmrc); const [auth, registry] = getAuthAndRegistry(name, originalRegistry, authTokenOpts, npmrc);
const packageName = type === "resolutions" ? basename(name) : name; const packageName = type === "resolutions" ? basename(name) : name;
const urlName = packageName.replace(/\//g, "%2f"); const urlName = packageName.replace(/\//g, "%2f");
@ -161,7 +171,7 @@ async function fetchNpmInfo(name, type, originalRegistry, agentOpts, authTokenOp
} }
} }
async function fetchPypiInfo(name, type, agentOpts) { async function fetchPypiInfo(name: string, type: string, agentOpts: AgentOptions) {
const url = `${pypiApiUrl}/pypi/${name}/json`; const url = `${pypiApiUrl}/pypi/${name}/json`;
const res = await doFetch(url, getFetchOpts(agentOpts)); const res = await doFetch(url, getFetchOpts(agentOpts));
@ -176,7 +186,7 @@ async function fetchPypiInfo(name, type, agentOpts) {
} }
} }
function getInfoUrl({repository, homepage, info}, registry, name) { function getInfoUrl({repository, homepage, info}: {repository: string | {[other: string]: any}, homepage: string, info: {[other: string]: any}}, registry: string, name: string) {
if (info) { // pypi if (info) { // pypi
repository = repository =
info.project_urls.repository || info.project_urls.repository ||
@ -202,10 +212,10 @@ function getInfoUrl({repository, homepage, info}, registry, name) {
if (browse) { if (browse) {
infoUrl = browse; infoUrl = browse;
} }
if (infoUrl && repository.directory && info.treepath) { if (infoUrl && typeof repository !== "string" && repository.directory && info?.treepath) {
infoUrl = `${infoUrl}/${info.treepath}/HEAD/${repository.directory}`; infoUrl = `${infoUrl}/${info.treepath}/HEAD/${repository.directory}`;
} }
if (!infoUrl && repository?.url && /^https?:/.test(repository.url)) { if (!infoUrl && typeof repository !== "string" && repository?.url && /^https?:/.test(repository.url)) {
infoUrl = repository.url; infoUrl = repository.url;
} }
if (!infoUrl && url) { if (!infoUrl && url) {
@ -216,12 +226,12 @@ function getInfoUrl({repository, homepage, info}, registry, name) {
return infoUrl || homepage || ""; return infoUrl || homepage || "";
} }
function finishWithMessage(message) { function finishWithMessage(message: string) {
console.info(args.json ? JSON.stringify({message}) : message); console.info(args.json ? JSON.stringify({message}) : message);
doExit(); doExit();
} }
function doExit(err) { function doExit(err?: Error | void) {
if (err) { if (err) {
const error = err.stack ?? err.message; const error = err.stack ?? err.message;
console.info(args.json ? JSON.stringify({error}) : red(error)); console.info(args.json ? JSON.stringify({error}) : red(error));
@ -229,18 +239,44 @@ function doExit(err) {
process.exit(err ? 1 : 0); process.exit(err ? 1 : 0);
} }
function outputDeps(deps = {}) { type Dep = {
"old": string,
"new": string,
"oldPrint"?: string,
"newPrint"?: string,
"oldOriginal"?: string,
"info"?: string,
"age"?: string,
}
type Deps = {
[name: string]: Dep,
}
type DepsByMode = {
[mode: string]: Deps,
}
type Output = {
results: {
[mode: string]: {
[type: string]: Deps,
}
}
}
function outputDeps(deps: DepsByMode = {}) {
for (const mode of Object.keys(deps)) { for (const mode of Object.keys(deps)) {
for (const value of Object.values(deps[mode])) { for (const value of Object.values(deps[mode])) {
if ("oldPrint" in value) { if (typeof value.oldPrint === "string") {
value.old = value.oldPrint; value.old = value.oldPrint;
delete value.oldPrint; delete value.oldPrint;
} }
if ("newPrint" in value) { if (typeof value.newPrint === "string") {
value.new = value.newPrint; value.new = value.newPrint;
delete value.newPrint; delete value.newPrint;
} }
if ("oldOriginal" in value) { if (typeof value.oldOriginal === "string") {
value.old = value.oldOriginal; value.old = value.oldOriginal;
delete value.oldOriginal; delete value.oldOriginal;
} }
@ -253,7 +289,7 @@ function outputDeps(deps = {}) {
} }
if (args.json) { if (args.json) {
const output = {results: {}}; const output: Output = {results: {}};
for (const mode of Object.keys(deps)) { for (const mode of Object.keys(deps)) {
for (const [key, value] of Object.entries(deps[mode])) { for (const [key, value] of Object.entries(deps[mode])) {
const [type, name] = key.split(sep); const [type, name] = key.split(sep);
@ -277,14 +313,14 @@ function outputDeps(deps = {}) {
} }
// preserve file metadata on windows // preserve file metadata on windows
async function write(file, content) { async function write(file: string, content: string) {
const {platform} = await import("node:os"); const {platform} = await import("node:os");
const isWindows = platform() === "win32"; const isWindows = platform() === "win32";
if (isWindows) truncateSync(file, 0); if (isWindows) truncateSync(file, 0);
writeFileSync(file, content, isWindows ? {flag: "r+"} : undefined); writeFileSync(file, content, isWindows ? {flag: "r+"} : undefined);
} }
function highlightDiff(a, b, colorFn) { function highlightDiff(a: string, b: string, colorFn: (str: string) => string) {
if (a === b) return a; if (a === b) return a;
const aParts = a.split(/\./); const aParts = a.split(/\./);
const bParts = b.split(/\./); const bParts = b.split(/\./);
@ -308,7 +344,7 @@ function highlightDiff(a, b, colorFn) {
return res; return res;
} }
function formatDeps(deps) { function formatDeps(deps: DepsByMode) {
const arr = [["NAME", "OLD", "NEW", "AGE", "INFO"]]; const arr = [["NAME", "OLD", "NEW", "AGE", "INFO"]];
const seen = new Set(); const seen = new Set();
@ -323,7 +359,7 @@ function formatDeps(deps) {
highlightDiff(data.old, data.new, red), highlightDiff(data.old, data.new, red),
highlightDiff(data.new, data.old, green), highlightDiff(data.new, data.old, green),
data.age || "", data.age || "",
data.info, data.info || "",
]); ]);
} }
} }
@ -334,7 +370,7 @@ function formatDeps(deps) {
}); });
} }
function updatePackageJson(pkgStr, deps) { function updatePackageJson(pkgStr: string, deps: Deps) {
let newPkgStr = pkgStr; let newPkgStr = pkgStr;
for (const key of Object.keys(deps)) { for (const key of Object.keys(deps)) {
const name = key.split(sep)[1]; const name = key.split(sep)[1];
@ -345,7 +381,7 @@ function updatePackageJson(pkgStr, deps) {
return newPkgStr; return newPkgStr;
} }
function updateProjectToml(pkgStr, deps) { function updateProjectToml(pkgStr: string, deps: Deps) {
let newPkgStr = pkgStr; let newPkgStr = pkgStr;
for (const key of Object.keys(deps)) { for (const key of Object.keys(deps)) {
const name = key.split(sep)[1]; const name = key.split(sep)[1];
@ -356,34 +392,42 @@ function updateProjectToml(pkgStr, deps) {
return newPkgStr; return newPkgStr;
} }
function updateRange(range, version) { function updateRange(range: string, version: string) {
return range.replace(/[0-9]+\.[0-9]+\.[0-9]+(-.+)?/g, version); return range.replace(/[0-9]+\.[0-9]+\.[0-9]+(-.+)?/g, version);
} }
function isVersionPrerelease(version) { function isVersionPrerelease(version: string) {
const parsed = parse(version); const parsed = parse(version);
if (!parsed) return false; if (!parsed) return false;
return Boolean(parsed.prerelease.length); return Boolean(parsed.prerelease.length);
} }
function isRangePrerelease(range) { function isRangePrerelease(range: string) {
// can not use coerce here because it ignores prerelease tags // can not use coerce here because it ignores prerelease tags
return /[0-9]+\.[0-9]+\.[0-9]+-.+/.test(range); return /[0-9]+\.[0-9]+\.[0-9]+-.+/.test(range);
} }
function rangeToVersion(range) { function rangeToVersion(range: string) {
try { try {
return coerce(range).version; return coerce(range)?.version ?? null;
} catch { } catch {
return null; return null;
} }
} }
function findVersion(data, versions, {range, semvers, usePre, useRel, useGreatest} = {}) { type NpmData = {[other: string]: any};
type FindVersionOpts = {
range: string,
semvers: Set<string>,
usePre: boolean,
useRel: boolean,
useGreatest: boolean,
}
function findVersion(data: NpmData, versions: string[], {range, semvers, usePre, useRel, useGreatest}: FindVersionOpts) {
let tempVersion = rangeToVersion(range); let tempVersion = rangeToVersion(range);
let tempDate = 0; let tempDate = 0;
semvers = new Set(semvers);
usePre = isRangePrerelease(range) || usePre; usePre = isRangePrerelease(range) || usePre;
if (usePre) { if (usePre) {
@ -395,14 +439,16 @@ function findVersion(data, versions, {range, semvers, usePre, useRel, useGreates
for (const version of versions) { for (const version of versions) {
const parsed = parse(version); const parsed = parse(version);
if (parsed.prerelease.length && (!usePre || useRel)) continue; if (!parsed || !tempVersion || parsed.prerelease.length && (!usePre || useRel)) continue;
const d = diff(tempVersion, parsed.version); const d = diff(tempVersion, parsed.version);
if (!d || !semvers.has(d)) continue; if (!d || !semvers.has(d)) continue;
// some registries like github don't have data.time available, fall back to greatest on them // some registries like github don't have data.time available, fall back to greatest on them
if (useGreatest || !("time" in data)) { if (useGreatest || !("time" in data)) {
if (gte(coerce(parsed.version).version, tempVersion)) { const coerced = coerce(parsed?.version)?.version;
if (!coerced) continue;
if (gte(coerced, tempVersion)) {
tempVersion = parsed.version; tempVersion = parsed.version;
} }
} else { } else {
@ -417,12 +463,22 @@ function findVersion(data, versions, {range, semvers, usePre, useRel, useGreates
return tempVersion || null; return tempVersion || null;
} }
function findNewVersion(data, {mode, range, useGreatest, useRel, usePre, semvers} = {}) { type FindNewVersionOpts = {
mode: string,
range: string,
usePre: boolean,
useRel: boolean,
useGreatest: boolean,
semvers: Set<string>,
}
function findNewVersion(data: NpmData, {mode, range, useGreatest, useRel, usePre, semvers}: FindNewVersionOpts) {
if (range === "*") return null; // ignore wildcard if (range === "*") return null; // ignore wildcard
if (range.includes("||")) return null; // ignore or-chains if (range.includes("||")) return null; // ignore or-chains
const versions = Object.keys(mode === "pypi" ? data.releases : data.versions) const versions = Object.keys(mode === "pypi" ? data.releases : data.versions)
.filter(version => valid(version)); .filter(version => valid(version));
const version = findVersion(data, versions, {range, semvers, usePre, useRel, useGreatest}); const version = findVersion(data, versions, {range, semvers, usePre, useRel, useGreatest});
if (!version) return null;
if (useGreatest) { if (useGreatest) {
return version; return version;
@ -431,12 +487,16 @@ function findNewVersion(data, {mode, range, useGreatest, useRel, usePre, semvers
let originalLatestTag; let originalLatestTag;
if (mode === "pypi") { if (mode === "pypi") {
originalLatestTag = data.info.version; // may not be a 3-part semver originalLatestTag = data.info.version; // may not be a 3-part semver
latestTag = coerce(data.info.version).version; // add .0 to 6.0 so semver eats it const coerced = coerce(data.info.version);
if (!coerced) throw new Error(`Unable to coerce ${data.info.version}`);
latestTag = coerced.version; // add .0 to 6.0 so semver eats it
} else { } else {
latestTag = data["dist-tags"].latest; latestTag = data["dist-tags"].latest;
} }
const oldVersion = coerce(range).version; const coerced = coerce(range);
if (!coerced) throw new Error(`Unable to coerce ${range}`);
const oldVersion = coerced.version;
const oldIsPre = isRangePrerelease(range); const oldIsPre = isRangePrerelease(range);
const newIsPre = isVersionPrerelease(version); const newIsPre = isVersionPrerelease(version);
const latestIsPre = isVersionPrerelease(latestTag); const latestIsPre = isVersionPrerelease(latestTag);
@ -487,8 +547,8 @@ function findNewVersion(data, {mode, range, useGreatest, useRel, usePre, semvers
} }
} }
function fetchGitHub(url) { function fetchGitHub(url: string) {
const opts = {}; const opts: RequestInit = {};
const token = env.UPDATES_GITHUB_API_TOKEN || env.GITHUB_API_TOKEN || env.GH_TOKEN || env.HOMEBREW_GITHUB_API_TOKEN; const token = env.UPDATES_GITHUB_API_TOKEN || env.GITHUB_API_TOKEN || env.GH_TOKEN || env.HOMEBREW_GITHUB_API_TOKEN;
if (token) { if (token) {
opts.headers = {Authorization: `Bearer ${token}`}; opts.headers = {Authorization: `Bearer ${token}`};
@ -496,10 +556,10 @@ function fetchGitHub(url) {
return doFetch(url, opts); return doFetch(url, opts);
} }
async function getLastestCommit(user, repo) { async function getLastestCommit(user: string, repo: string): Promise<{hash: string, commit: {[other: string]: any}}> {
const url = `${githubApiUrl}/repos/${user}/${repo}/commits`; const url = `${githubApiUrl}/repos/${user}/${repo}/commits`;
const res = await fetchGitHub(url); const res = await fetchGitHub(url);
if (!res || !res.ok) return; if (!res || !res.ok) return {hash: "", commit: {}};
const data = await res.json(); const data = await res.json();
const {sha: hash, commit} = data[0]; const {sha: hash, commit} = data[0];
return {hash, commit}; return {hash, commit};
@ -507,20 +567,21 @@ async function getLastestCommit(user, repo) {
// return list of tags sorted old to new // return list of tags sorted old to new
// TODO: newDate support, semver matching // TODO: newDate support, semver matching
async function getTags(user, repo) { async function getTags(user: string, repo: string): Promise<string[]> {
const res = await fetchGitHub(`${githubApiUrl}/repos/${user}/${repo}/git/refs/tags`); const res = await fetchGitHub(`${githubApiUrl}/repos/${user}/${repo}/git/refs/tags`);
if (!res || !res.ok) return; if (!res || !res.ok) return [];
const data = await res.json(); const data = await res.json();
const tags = data.map(entry => entry.ref.replace(/^refs\/tags\//, "")); const tags = data.map((entry: {ref: string}) => entry.ref.replace(/^refs\/tags\//, ""));
return tags; return tags;
} }
function selectTag(tags, oldRef, useGreatest) { function selectTag(tags: string[], oldRef: string, useGreatest: boolean) {
const oldRefBare = stripV(oldRef); const oldRefBare = stripV(oldRef);
if (!valid(oldRefBare)) return; if (!valid(oldRefBare)) return;
if (!useGreatest) { if (!useGreatest) {
const lastTag = tags.at(-1); const lastTag = tags.at(-1);
if (!lastTag) return;
const lastTagBare = stripV(lastTag); const lastTagBare = stripV(lastTag);
if (!valid(lastTagBare)) return; if (!valid(lastTagBare)) return;
@ -545,14 +606,14 @@ function selectTag(tags, oldRef, useGreatest) {
} }
} }
async function checkUrlDep([key, dep], {useGreatest} = {}) { async function checkUrlDep(key: string, dep: Dep, useGreatest: boolean) {
const stripped = dep.old.replace(stripRe, ""); const stripped = dep.old.replace(stripRe, "");
const [_, user, repo, oldRef] = partsRe.exec(stripped) || []; const [_, user, repo, oldRef] = partsRe.exec(stripped) || [];
if (!user || !repo || !oldRef) return; if (!user || !repo || !oldRef) return;
if (hashRe.test(oldRef)) { if (hashRe.test(oldRef)) {
const {hash, commit} = await getLastestCommit(user, repo); const {hash, commit} = await getLastestCommit(user, repo);
if (!hash?.length) return; if (!hash) return;
const newDate = commit?.committer?.date ?? commit?.author?.date; const newDate = commit?.committer?.date ?? commit?.author?.date;
const newRef = hash.substring(0, oldRef.length); const newRef = hash.substring(0, oldRef.length);
@ -569,13 +630,16 @@ async function checkUrlDep([key, dep], {useGreatest} = {}) {
} }
} }
function normalizeRange(range) { function normalizeRange(range: string) {
const versionMatches = range.match(versionRe); const versionMatches = range.match(versionRe);
if (versionMatches?.length !== 1) return range; if (versionMatches?.length !== 1) return range;
return range.replace(versionRe, coerce(versionMatches[0])); const coerced = coerce(versionMatches[0]);
if (!coerced) return range;
// @ts-ignore
return range.replace(versionRe, coerced);
} }
function parseMixedArg(arg) { function parseMixedArg(arg: any) {
if (arg === undefined) { if (arg === undefined) {
return false; return false;
} else if (arg === "") { } else if (arg === "") {
@ -589,17 +653,17 @@ function parseMixedArg(arg) {
} }
} }
function extractCerts(str) { function extractCerts(str: string): string[] {
return Array.from(str.matchAll(/(----BEGIN CERT[^]+?IFICATE----)/g), m => m[0]); return Array.from(str.matchAll(/(----BEGIN CERT[^]+?IFICATE----)/g), (m: string[]) => m[0]);
} }
async function getCerts(extra = []) { async function getCerts(extra: string[] = []) {
return [...(await import("node:tls")).rootCertificates, ...extra]; return [...(await import("node:tls")).rootCertificates, ...extra];
} }
// convert arg from cli or config to regex // convert arg from cli or config to regex
function argToRegex(arg, cli) { function argToRegex(arg: string | RegExp, cli: boolean) {
if (cli) { if (cli && typeof arg === "string") {
return /\/.+\//.test(arg) ? new RegExp(arg.slice(1, -1)) : picomatch.makeRe(arg); return /\/.+\//.test(arg) ? new RegExp(arg.slice(1, -1)) : picomatch.makeRe(arg);
} else { } else {
return arg instanceof RegExp ? arg : picomatch.makeRe(arg); return arg instanceof RegExp ? arg : picomatch.makeRe(arg);
@ -607,7 +671,7 @@ function argToRegex(arg, cli) {
} }
// parse cli arg into regex set // parse cli arg into regex set
function argSetToRegexes(arg) { function argSetToRegexes(arg: any) {
if (arg instanceof Set) { if (arg instanceof Set) {
const ret = new Set(); const ret = new Set();
for (const entry of arg) { for (const entry of arg) {
@ -619,7 +683,7 @@ function argSetToRegexes(arg) {
} }
// parse include/exclude into a Set of regexes // parse include/exclude into a Set of regexes
function matchersToRegexSet(cliArgs, configArgs) { function matchersToRegexSet(cliArgs: string[], configArgs: string[]): Set<RegExp> {
const ret = new Set(); const ret = new Set();
for (const arg of cliArgs || []) { for (const arg of cliArgs || []) {
ret.add(argToRegex(arg, true)); ret.add(argToRegex(arg, true));
@ -627,10 +691,10 @@ function matchersToRegexSet(cliArgs, configArgs) {
for (const arg of configArgs || []) { for (const arg of configArgs || []) {
ret.add(argToRegex(arg, false)); ret.add(argToRegex(arg, false));
} }
return ret; return ret as Set<RegExp>;
} }
function canInclude(name, mode, {include, exclude}) { function canInclude(name: string, mode: string, include: Set<RegExp>, exclude: Set<RegExp>) {
if (mode === "pypi" && name === "python") return false; if (mode === "pypi" && name === "python") return false;
if (!include.size && !exclude.size) return true; if (!include.size && !exclude.size) return true;
for (const re of exclude) { for (const re of exclude) {
@ -642,7 +706,7 @@ function canInclude(name, mode, {include, exclude}) {
return include.size ? false : true; return include.size ? false : true;
} }
function resolveFiles(filesArg) { function resolveFiles(filesArg: Set<string>): Set<string> {
const resolvedFiles = new Set(); const resolvedFiles = new Set();
if (filesArg) { // check passed files if (filesArg) { // check passed files
@ -651,7 +715,7 @@ function resolveFiles(filesArg) {
try { try {
stat = lstatSync(file); stat = lstatSync(file);
} catch (err) { } catch (err) {
throw new Error(`Unable to open ${file}: ${err.message}`); throw new Error(`Unable to open ${file}: ${(err as Error).message}`);
} }
if (stat?.isFile()) { if (stat?.isFile()) {
@ -677,16 +741,17 @@ function resolveFiles(filesArg) {
if (file) resolvedFiles.add(resolve(file)); if (file) resolvedFiles.add(resolve(file));
} }
} }
return resolvedFiles; return resolvedFiles as Set<string>;
} }
async function main() { async function main() {
for (const stream of [process.stdout, process.stderr]) { for (const stream of [process.stdout, process.stderr]) {
// @ts-ignore
stream?._handle?.setBlocking?.(true); stream?._handle?.setBlocking?.(true);
} }
const maxSockets = 96; const maxSockets = 96;
const concurrency = typeof args.sockets === "number" ? parseInt(args.sockets) : maxSockets; const concurrency = typeof args.sockets === "number" ? args.sockets : maxSockets;
const {help, version, file: filesArg, types, update} = args; const {help, version, file: filesArg, types, update} = args;
if (help) { if (help) {
@ -731,13 +796,13 @@ async function main() {
} }
// output vars // output vars
const deps = {}; const deps: DepsByMode = {};
const maybeUrlDeps = {}; const maybeUrlDeps: DepsByMode = {};
const pkgStrs = {}; const pkgStrs: {[other: string]: string} = {};
const filePerMode = {}; const filePerMode: {[other: string]: string} = {};
let numDependencies = 0; let numDependencies = 0;
for (const file of resolveFiles(parseMixedArg(filesArg))) { for (const file of resolveFiles(parseMixedArg(filesArg) as Set<string>)) {
const projectDir = dirname(resolve(file)); const projectDir = dirname(resolve(file));
const filename = basename(file); const filename = basename(file);
@ -745,7 +810,7 @@ async function main() {
filePerMode[mode] = file; filePerMode[mode] = file;
if (!deps[mode]) deps[mode] = {}; if (!deps[mode]) deps[mode] = {};
let config = {}; let config: {[other: string]: any} = {};
try { try {
({default: config} = await Promise.any([ ({default: config} = await Promise.any([
"updates.config.js", "updates.config.js",
@ -759,7 +824,8 @@ async function main() {
].map(str => import(join(projectDir, ...str.split("/")))))); ].map(str => import(join(projectDir, ...str.split("/"))))));
} catch {} } catch {}
let includeCli, excludeCli; let includeCli: string[] = [];
let excludeCli: string[] = [];
if (args.include && args.include !== true) { // cli if (args.include && args.include !== true) { // cli
includeCli = (Array.isArray(args.include) ? args.include : [args.include]).flatMap(item => item.split(",")); includeCli = (Array.isArray(args.include) ? args.include : [args.include]).flatMap(item => item.split(","));
} }
@ -769,18 +835,19 @@ async function main() {
const include = matchersToRegexSet(includeCli, config?.include); const include = matchersToRegexSet(includeCli, config?.include);
const exclude = matchersToRegexSet(excludeCli, config?.exclude); const exclude = matchersToRegexSet(excludeCli, config?.exclude);
const agentOpts = {}; const agentOpts: AgentOptions = {};
const npmrc = rc("npm", {registry: "https://registry.npmjs.org"}); const npmrc: Npmrc = rc("npm", {registry: "https://registry.npmjs.org"});
const authTokenOpts = {npmrc, recursive: true}; const authTokenOpts = {npmrc, recursive: true};
if (mode === "npm") { if (mode === "npm") {
if (npmrc["strict-ssl"] === false) { if (npmrc["strict-ssl"] === false) {
agentOpts.rejectUnauthorized = false; agentOpts.rejectUnauthorized = false;
} }
if (npmrc?.cafile) { if (npmrc?.cafile) {
agentOpts.ca = getCerts(extractCerts(readFileSync(npmrc.cafile, "utf8"))); agentOpts.ca = await getCerts(extractCerts(readFileSync(npmrc.cafile, "utf8")));
} }
if (npmrc?.ca) { if (npmrc?.ca) {
agentOpts.ca = getCerts(Array.isArray(npmrc.ca) ? npmrc.ca : [npmrc.ca].map(ca => extractCerts(ca))); const cas = Array.isArray(npmrc.ca) ? npmrc.ca : [npmrc.ca];
agentOpts.ca = await getCerts(cas.flatMap(ca => extractCerts(ca)));
} }
} }
@ -809,11 +876,11 @@ async function main() {
} }
} }
let pkg; let pkg: {[other: string]: any};
try { try {
pkgStrs[mode] = readFileSync(file, "utf8"); pkgStrs[mode] = readFileSync(file, "utf8");
} catch (err) { } catch (err) {
throw new Error(`Unable to open ${file}: ${err.message}`); throw new Error(`Unable to open ${file}: ${(err as Error).message}`);
} }
try { try {
@ -823,11 +890,11 @@ async function main() {
pkg = (await import("@iarna/toml/parse-string.js")).default(pkgStrs[mode]); pkg = (await import("@iarna/toml/parse-string.js")).default(pkgStrs[mode]);
} }
} catch (err) { } catch (err) {
throw new Error(`Error parsing ${file}: ${err.message}`); throw new Error(`Error parsing ${file}: ${(err as Error).message}`);
} }
for (const depType of dependencyTypes) { for (const depType of dependencyTypes) {
let obj; let obj: {[other: string]: string};
if (mode === "npm") { if (mode === "npm") {
obj = pkg[depType] || {}; obj = pkg[depType] || {};
} else { } else {
@ -835,15 +902,17 @@ async function main() {
} }
for (const [name, value] of Object.entries(obj)) { for (const [name, value] of Object.entries(obj)) {
if (validRange(value) && canInclude(name, mode, {include, exclude})) { if (validRange(value) && canInclude(name, mode, include, exclude)) {
// @ts-ignore
deps[mode][`${depType}${sep}${name}`] = { deps[mode][`${depType}${sep}${name}`] = {
old: normalizeRange(value), old: normalizeRange(value),
oldOriginal: value, oldOriginal: value,
}; } as Partial<Dep>;
} else if (mode === "npm" && canInclude(name, mode, {include, exclude})) { } else if (mode === "npm" && canInclude(name, mode, include, exclude)) {
// @ts-ignore
maybeUrlDeps[`${depType}${sep}${name}`] = { maybeUrlDeps[`${depType}${sep}${name}`] = {
old: value, old: value,
}; } as Partial<Dep>;
} }
} }
} }
@ -851,7 +920,7 @@ async function main() {
numDependencies += Object.keys(deps[mode]).length + Object.keys(maybeUrlDeps).length; numDependencies += Object.keys(deps[mode]).length + Object.keys(maybeUrlDeps).length;
if (!numDependencies) continue; if (!numDependencies) continue;
let registry; let registry: string;
if (mode === "npm") { if (mode === "npm") {
registry = normalizeUrl(args.registry || config.registry || npmrc.registry); registry = normalizeUrl(args.registry || config.registry || npmrc.registry);
} }
@ -911,12 +980,15 @@ async function main() {
const results = await pAll(Object.entries(maybeUrlDeps).map(([key, dep]) => () => { const results = await pAll(Object.entries(maybeUrlDeps).map(([key, dep]) => () => {
const name = key.split(sep)[1]; const name = key.split(sep)[1];
const useGreatest = typeof greatest === "boolean" ? greatest : matchesAny(name, greatest); const useGreatest = typeof greatest === "boolean" ? greatest : matchesAny(name, greatest);
return checkUrlDep([key, dep], {useGreatest}); // @ts-ignore
return checkUrlDep(key, dep, useGreatest);
}), {concurrency}); }), {concurrency});
for (const res of (results || []).filter(Boolean)) { for (const res of (results || []).filter(Boolean)) {
// @ts-ignore
const {key, newRange, user, repo, oldRef, newRef, newDate} = res; const {key, newRange, user, repo, oldRef, newRef, newDate} = res;
deps[mode][key] = { deps[mode][key] = {
// @ts-ignore
old: maybeUrlDeps[key].old, old: maybeUrlDeps[key].old,
new: newRange, new: newRange,
oldPrint: hashRe.test(oldRef) ? oldRef.substring(0, 7) : oldRef, oldPrint: hashRe.test(oldRef) ? oldRef.substring(0, 7) : oldRef,
@ -952,7 +1024,7 @@ async function main() {
const fn = (mode === "npm") ? updatePackageJson : updateProjectToml; const fn = (mode === "npm") ? updatePackageJson : updateProjectToml;
await write(filePerMode[mode], fn(pkgStrs[mode], deps[mode])); await write(filePerMode[mode], fn(pkgStrs[mode], deps[mode]));
} catch (err) { } catch (err) {
throw new Error(`Error writing ${basename(filePerMode[mode])}: ${err.message}`); throw new Error(`Error writing ${basename(filePerMode[mode])}: ${(err as Error).message}`);
} }
// TODO: json // TODO: json
@ -960,7 +1032,7 @@ async function main() {
} }
} }
doExit(exitCode); process.exit(exitCode);
} }
main().catch(doExit).then(doExit); main().catch(doExit).then(doExit);

1509
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -15,11 +15,21 @@
], ],
"devDependencies": { "devDependencies": {
"@iarna/toml": "2.2.5", "@iarna/toml": "2.2.5",
"@types/hosted-git-info": "3.0.5",
"@types/iarna__toml": "2.0.5",
"@types/minimist": "1.2.5",
"@types/node": "20.12.12",
"@types/picomatch": "2.3.3",
"@types/rc": "1.2.4",
"@types/registry-auth-token": "4.2.4",
"@types/semver": "7.5.8",
"@types/text-table": "0.2.5",
"ansi-regex": "6.0.1", "ansi-regex": "6.0.1",
"dot-prop": "9.0.0", "dot-prop": "9.0.0",
"esbuild": "0.21.3", "esbuild": "0.21.3",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-silverwind": "85.1.2", "eslint-config-silverwind": "85.1.4",
"eslint-config-silverwind-typescript": "3.2.7",
"execa": "8.0.1", "execa": "8.0.1",
"glowie": "1.3.1", "glowie": "1.3.1",
"hosted-git-info": "7.0.2", "hosted-git-info": "7.0.2",
@ -34,7 +44,12 @@
"supports-color": "9.4.0", "supports-color": "9.4.0",
"text-table": "0.2.0", "text-table": "0.2.0",
"timerel": "5.6.3", "timerel": "5.6.3",
"versions": "12.0.1", "typescript": "5.4.5",
"typescript-config-silverwind": "4.3.2",
"versions": "12.1.0",
"vite": "5.2.11",
"vite-config-silverwind": "1.1.4",
"vite-plugin-dts": "3.9.1",
"vitest": "1.6.0", "vitest": "1.6.0",
"vitest-config-silverwind": "9.0.6" "vitest-config-silverwind": "9.0.6"
} }

@ -6,47 +6,47 @@ exports[`dual 1`] = `
"dependencies": { "dependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "7.11.5", "new": "7.24.5",
"old": "7.0.0", "old": "7.0.0",
}, },
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "4.0.0-beta.11", "new": "5.6.0",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"jpeg-buffer-orientation": { "jpeg-buffer-orientation": {
"info": "https://github.com/fisker/jpeg-buffer-orientation", "info": "https://github.com/fisker/jpeg-buffer-orientation",
"new": "2.0.3", "new": "4.1.1",
"old": "0.0.0", "old": "0.0.0",
}, },
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
"prismjs": { "prismjs": {
"info": "https://github.com/LeaVerou/prism", "info": "https://github.com/PrismJS/prism",
"new": "1.17.1", "new": "1.29.0",
"old": "1.0.0", "old": "1.0.0",
}, },
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.2.0", "new": "18.3.1",
"old": "18.0", "old": "18.0",
}, },
"styled-components": { "styled-components": {
"info": "https://github.com/styled-components/styled-components", "info": "https://github.com/styled-components/styled-components",
"new": "5.0.0-rc.2", "new": "6.1.11",
"old": "2.5.0-1", "old": "2.5.0-1",
}, },
"svgstore": { "svgstore": {
"info": "https://github.com/svgstore/svgstore", "info": "https://github.com/svgstore/svgstore",
"new": "^3.0.0-2", "new": "^3.0.1",
"old": "^3.0.0", "old": "^3.0.0",
}, },
"updates": { "updates": {
@ -58,14 +58,14 @@ exports[`dual 1`] = `
"peerDependencies": { "peerDependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "~7.11.5", "new": "~7.24.5",
"old": "~6.0.0", "old": "~6.0.0",
}, },
}, },
"resolutions": { "resolutions": {
"versions/updates": { "versions/updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "^10.0.0", "new": "^16.1.1",
"old": "^1.0.0", "old": "^1.0.0",
}, },
}, },
@ -100,7 +100,7 @@ exports[`dual 2 1`] = `
"dependencies": { "dependencies": {
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
}, },
@ -128,7 +128,7 @@ exports[`exclude 2 1`] = `
"dependencies": { "dependencies": {
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.2.0", "new": "18.3.1",
"old": "18.0", "old": "18.0",
}, },
}, },
@ -142,7 +142,7 @@ exports[`exclude 3 1`] = `
"dependencies": { "dependencies": {
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
}, },
@ -170,22 +170,22 @@ exports[`greatest 1`] = `
"dependencies": { "dependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "7.11.5", "new": "7.24.5",
"old": "7.0.0", "old": "7.0.0",
}, },
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "4.0.0-beta.11", "new": "5.6.0",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"jpeg-buffer-orientation": { "jpeg-buffer-orientation": {
"info": "https://github.com/fisker/jpeg-buffer-orientation", "info": "https://github.com/fisker/jpeg-buffer-orientation",
"new": "2.0.3", "new": "4.1.1",
"old": "0.0.0", "old": "0.0.0",
}, },
"noty": { "noty": {
@ -194,20 +194,25 @@ exports[`greatest 1`] = `
"old": "3.1.0", "old": "3.1.0",
}, },
"prismjs": { "prismjs": {
"info": "https://github.com/LeaVerou/prism", "info": "https://github.com/PrismJS/prism",
"new": "1.17.1", "new": "1.29.0",
"old": "1.0.0", "old": "1.0.0",
}, },
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.2.0", "new": "18.3.1",
"old": "18.0", "old": "18.0",
}, },
"styled-components": { "styled-components": {
"info": "https://github.com/styled-components/styled-components", "info": "https://github.com/styled-components/styled-components",
"new": "5.0.0-rc.2", "new": "6.1.11",
"old": "2.5.0-1", "old": "2.5.0-1",
}, },
"svgstore": {
"info": "https://github.com/svgstore/svgstore",
"new": "^3.0.1",
"old": "^3.0.0",
},
"updates": { "updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "537ccb7", "new": "537ccb7",
@ -217,14 +222,14 @@ exports[`greatest 1`] = `
"peerDependencies": { "peerDependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "~7.11.5", "new": "~7.24.5",
"old": "~6.0.0", "old": "~6.0.0",
}, },
}, },
"resolutions": { "resolutions": {
"versions/updates": { "versions/updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "^10.0.0", "new": "^16.1.1",
"old": "^1.0.0", "old": "^1.0.0",
}, },
}, },
@ -238,7 +243,7 @@ exports[`include 1`] = `
"dependencies": { "dependencies": {
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
}, },
@ -252,7 +257,7 @@ exports[`include 2 1`] = `
"dependencies": { "dependencies": {
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
}, },
@ -266,7 +271,7 @@ exports[`include 3 1`] = `
"dependencies": { "dependencies": {
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
}, },
@ -280,47 +285,47 @@ exports[`latest 1`] = `
"dependencies": { "dependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "7.11.5", "new": "7.24.5",
"old": "7.0.0", "old": "7.0.0",
}, },
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "4.0.0-beta.11", "new": "5.6.0",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"jpeg-buffer-orientation": { "jpeg-buffer-orientation": {
"info": "https://github.com/fisker/jpeg-buffer-orientation", "info": "https://github.com/fisker/jpeg-buffer-orientation",
"new": "2.0.3", "new": "4.1.1",
"old": "0.0.0", "old": "0.0.0",
}, },
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
"prismjs": { "prismjs": {
"info": "https://github.com/LeaVerou/prism", "info": "https://github.com/PrismJS/prism",
"new": "1.17.1", "new": "1.29.0",
"old": "1.0.0", "old": "1.0.0",
}, },
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.2.0", "new": "18.3.1",
"old": "18.0", "old": "18.0",
}, },
"styled-components": { "styled-components": {
"info": "https://github.com/styled-components/styled-components", "info": "https://github.com/styled-components/styled-components",
"new": "5.0.0-rc.2", "new": "6.1.11",
"old": "2.5.0-1", "old": "2.5.0-1",
}, },
"svgstore": { "svgstore": {
"info": "https://github.com/svgstore/svgstore", "info": "https://github.com/svgstore/svgstore",
"new": "^3.0.0-2", "new": "^3.0.1",
"old": "^3.0.0", "old": "^3.0.0",
}, },
"updates": { "updates": {
@ -332,14 +337,14 @@ exports[`latest 1`] = `
"peerDependencies": { "peerDependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "~7.11.5", "new": "~7.24.5",
"old": "~6.0.0", "old": "~6.0.0",
}, },
}, },
"resolutions": { "resolutions": {
"versions/updates": { "versions/updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "^10.0.0", "new": "^16.1.1",
"old": "^1.0.0", "old": "^1.0.0",
}, },
}, },
@ -358,7 +363,7 @@ exports[`patch 1`] = `
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "4.0.0-beta.11", "new": "4.0.4",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"noty": { "noty": {
@ -368,7 +373,7 @@ exports[`patch 1`] = `
}, },
"svgstore": { "svgstore": {
"info": "https://github.com/svgstore/svgstore", "info": "https://github.com/svgstore/svgstore",
"new": "^3.0.0-2", "new": "^3.0.1",
"old": "^3.0.0", "old": "^3.0.0",
}, },
"updates": { "updates": {
@ -394,47 +399,47 @@ exports[`prerelease 1`] = `
"dependencies": { "dependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "7.11.5", "new": "8.0.0-alpha.8",
"old": "7.0.0", "old": "7.0.0",
}, },
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "4.0.0-beta.11", "new": "5.6.0",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"jpeg-buffer-orientation": { "jpeg-buffer-orientation": {
"info": "https://github.com/fisker/jpeg-buffer-orientation", "info": "https://github.com/fisker/jpeg-buffer-orientation",
"new": "2.0.3", "new": "4.1.1",
"old": "0.0.0", "old": "0.0.0",
}, },
"noty": { "noty": {
"info": "https://github.com/needim/noty", "info": "https://github.com/needim/noty",
"new": "3.2.0-beta", "new": "3.2.0-beta-deprecated",
"old": "3.1.0", "old": "3.1.0",
}, },
"prismjs": { "prismjs": {
"info": "https://github.com/LeaVerou/prism", "info": "https://github.com/PrismJS/prism",
"new": "1.17.1", "new": "1.29.0",
"old": "1.0.0", "old": "1.0.0",
}, },
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.3.0-next-d1e35c703-20221110", "new": "19.0.0-rc-4c2e457c7c-20240522",
"old": "18.0", "old": "18.0",
}, },
"styled-components": { "styled-components": {
"info": "https://github.com/styled-components/styled-components", "info": "https://github.com/styled-components/styled-components",
"new": "5.0.0-rc.2", "new": "6.1.11",
"old": "2.5.0-1", "old": "2.5.0-1",
}, },
"svgstore": { "svgstore": {
"info": "https://github.com/svgstore/svgstore", "info": "https://github.com/svgstore/svgstore",
"new": "^3.0.0-2", "new": "^3.0.1",
"old": "^3.0.0", "old": "^3.0.0",
}, },
"updates": { "updates": {
@ -446,14 +451,14 @@ exports[`prerelease 1`] = `
"peerDependencies": { "peerDependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "~7.11.5", "new": "~8.0.0-alpha.8",
"old": "~6.0.0", "old": "~6.0.0",
}, },
}, },
"resolutions": { "resolutions": {
"versions/updates": { "versions/updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "^10.0.0", "new": "^16.1.1",
"old": "^1.0.0", "old": "^1.0.0",
}, },
}, },
@ -486,22 +491,22 @@ exports[`release 1`] = `
"dependencies": { "dependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "7.11.5", "new": "7.24.5",
"old": "7.0.0", "old": "7.0.0",
}, },
"gulp-sourcemaps": { "gulp-sourcemaps": {
"info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps", "info": "https://github.com/gulp-sourcemaps/gulp-sourcemaps",
"new": "2.6.5", "new": "3.0.0",
"old": "2.0.0", "old": "2.0.0",
}, },
"html-webpack-plugin": { "html-webpack-plugin": {
"info": "https://github.com/jantimon/html-webpack-plugin", "info": "https://github.com/jantimon/html-webpack-plugin",
"new": "3.2.0", "new": "5.6.0",
"old": "4.0.0-alpha.2", "old": "4.0.0-alpha.2",
}, },
"jpeg-buffer-orientation": { "jpeg-buffer-orientation": {
"info": "https://github.com/fisker/jpeg-buffer-orientation", "info": "https://github.com/fisker/jpeg-buffer-orientation",
"new": "2.0.3", "new": "4.1.1",
"old": "0.0.0", "old": "0.0.0",
}, },
"noty": { "noty": {
@ -510,23 +515,23 @@ exports[`release 1`] = `
"old": "3.1.0", "old": "3.1.0",
}, },
"prismjs": { "prismjs": {
"info": "https://github.com/LeaVerou/prism", "info": "https://github.com/PrismJS/prism",
"new": "1.17.1", "new": "1.29.0",
"old": "1.0.0", "old": "1.0.0",
}, },
"react": { "react": {
"info": "https://github.com/facebook/react/tree/HEAD/packages/react", "info": "https://github.com/facebook/react/tree/HEAD/packages/react",
"new": "18.2.0", "new": "18.3.1",
"old": "18.0", "old": "18.0",
}, },
"styled-components": { "styled-components": {
"info": "https://github.com/styled-components/styled-components", "info": "https://github.com/styled-components/styled-components",
"new": "4.4.1", "new": "6.1.11",
"old": "2.5.0-1", "old": "2.5.0-1",
}, },
"svgstore": { "svgstore": {
"info": "https://github.com/svgstore/svgstore", "info": "https://github.com/svgstore/svgstore",
"new": "^2.0.3", "new": "^3.0.1",
"old": "^3.0.0", "old": "^3.0.0",
}, },
"updates": { "updates": {
@ -538,14 +543,14 @@ exports[`release 1`] = `
"peerDependencies": { "peerDependencies": {
"@babel/preset-env": { "@babel/preset-env": {
"info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env", "info": "https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env",
"new": "~7.11.5", "new": "~7.24.5",
"old": "~6.0.0", "old": "~6.0.0",
}, },
}, },
"resolutions": { "resolutions": {
"versions/updates": { "versions/updates": {
"info": "https://github.com/silverwind/updates", "info": "https://github.com/silverwind/updates",
"new": "^10.0.0", "new": "^16.1.1",
"old": "^1.0.0", "old": "^1.0.0",
}, },
}, },

20
tsconfig.json Normal file

@ -0,0 +1,20 @@
{
"extends": "typescript-config-silverwind",
"include": [
"**/*",
"**/.*",
"**/.*/**/*",
"**/.*/**/.*",
],
"exclude": [
"**/dist/**",
],
"compilerOptions": {
"strict": true,
"types": [
"jest-extended",
"vite/client",
"vitest/globals",
],
},
}

11
vite.config.ts Normal file

@ -0,0 +1,11 @@
import {defineConfig} from "vite";
import {lib} from "vite-config-silverwind";
export default defineConfig(lib({
url: import.meta.url,
noDts: true,
build: {
target: "node18",
minify: true,
}
}));

@ -1,4 +1,4 @@
import {defineConfig} from "vitest/dist/config.js"; import {defineConfig} from "vitest/config";
import {backend} from "vitest-config-silverwind"; import {backend} from "vitest-config-silverwind";
export default defineConfig(backend({ export default defineConfig(backend({