@flyingboat/upup 0.1.0 → 0.1.2
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/package.json +13 -6
- package/CHANGELOG.md +0 -3
- package/examples/big/package.json +0 -25
- package/rolldown.config.ts +0 -12
- package/src/cli.ts +0 -64
- package/src/helpers.ts +0 -28
- package/src/main.ts +0 -73
- package/src/npm.ts +0 -84
- package/tsconfig.json +0 -26
package/package.json
CHANGED
|
@@ -1,25 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flyingboat/upup",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CLI tool for listing outdated dependencies",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"author": "Francois Lajoie",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/flyingboat-dev/upup.git"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
8
12
|
"cli",
|
|
9
13
|
"tool",
|
|
10
14
|
"dependencies",
|
|
11
15
|
"update"
|
|
12
16
|
],
|
|
13
|
-
"author": "Francois Lajoie",
|
|
14
17
|
"type": "module",
|
|
15
18
|
"main": "dist/bundle.js",
|
|
19
|
+
"bin": {
|
|
20
|
+
"upup": "./dist/bundle.js"
|
|
21
|
+
},
|
|
22
|
+
"files": ["dist"],
|
|
16
23
|
"scripts": {
|
|
17
24
|
"dev": "node src/main.ts",
|
|
18
25
|
"build": "rolldown -c rolldown.config.ts"
|
|
19
26
|
},
|
|
20
27
|
"packageManager": "pnpm@10.28.2",
|
|
21
28
|
"devDependencies": {
|
|
22
|
-
"@types/node": "^25.
|
|
29
|
+
"@types/node": "^25.2.0",
|
|
23
30
|
"rolldown": "^1.0.0-rc.2",
|
|
24
31
|
"typescript": "~5.9.3"
|
|
25
32
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"@flyingboat/form-store-editor-ace": "workspace:*",
|
|
4
|
-
"@flyingboat/form-store-api": "workspace:*",
|
|
5
|
-
"@tailwindcss/postcss": "^4.1.16",
|
|
6
|
-
"@tailwindcss/vite": "^4.1.16",
|
|
7
|
-
"@tanstack/nitro-v2-vite-plugin": "^1.133.19",
|
|
8
|
-
"@tanstack/router-plugin": "^1.133.36",
|
|
9
|
-
"@tanstack/solid-query": "^5.90.8",
|
|
10
|
-
"@tanstack/solid-router": "^1.134.1",
|
|
11
|
-
"@tanstack/solid-router-devtools": "^1.134.1",
|
|
12
|
-
"@tanstack/solid-start": "^1.134.3",
|
|
13
|
-
"solid-js": "^1.9.10",
|
|
14
|
-
"tailwindcss": "^4.1.16"
|
|
15
|
-
},
|
|
16
|
-
"devDependencies": {
|
|
17
|
-
"daisyui": "^5.3.10",
|
|
18
|
-
"postcss": "^8.5.6",
|
|
19
|
-
"tailwind-merge": "^3.3.1",
|
|
20
|
-
"tailwindcss-animate": "^1.0.7",
|
|
21
|
-
"typescript": "^5.9.3",
|
|
22
|
-
"vite": "7.1.12",
|
|
23
|
-
"vite-plugin-solid": "2.11.10"
|
|
24
|
-
}
|
|
25
|
-
}
|
package/rolldown.config.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "rolldown";
|
|
2
|
-
|
|
3
|
-
export default defineConfig({
|
|
4
|
-
input: "src/main.ts",
|
|
5
|
-
output: {
|
|
6
|
-
file: "dist/bundle.js",
|
|
7
|
-
format: "esm",
|
|
8
|
-
},
|
|
9
|
-
// For Node CLIs: don't try to bundle Node built-ins
|
|
10
|
-
external: [/^node:/],
|
|
11
|
-
platform: "node",
|
|
12
|
-
});
|
package/src/cli.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { Dependency } from "./npm.ts";
|
|
2
|
-
import { timeAgoFromAge } from "./helpers.ts";
|
|
3
|
-
|
|
4
|
-
const defaultRefreshInterval = 80;
|
|
5
|
-
export const spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
6
|
-
|
|
7
|
-
export type RenderProps = {
|
|
8
|
-
deps: Row[]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export type Row = {
|
|
12
|
-
dep: Dependency,
|
|
13
|
-
status: string,
|
|
14
|
-
needUpdate: boolean
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class Renderer<TProps = RenderProps> {
|
|
18
|
-
private readonly _renderFn: (props: TProps) => void;
|
|
19
|
-
|
|
20
|
-
constructor(renderFn: (props: TProps) => void) {
|
|
21
|
-
this._renderFn = renderFn;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public render(props: TProps) {
|
|
25
|
-
this._renderFn(props);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function spinner(refreshInterval: number = defaultRefreshInterval) {
|
|
30
|
-
const i = Math.floor(Date.now() / refreshInterval) % spinnerFrames.length;
|
|
31
|
-
return spinnerFrames[i];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function renderDepsTable(rows: Row[], refreshInterval: number = defaultRefreshInterval) {
|
|
35
|
-
const nDeps = rows.filter(x => x.dep.type === 'dep').length;
|
|
36
|
-
const nDevDeps = rows.filter(x => x.dep.type === 'devDep').length;
|
|
37
|
-
const fn = (r: Row) => {
|
|
38
|
-
return {
|
|
39
|
-
package: r.dep.name,
|
|
40
|
-
current: r.dep.version,
|
|
41
|
-
age: r.dep.localDep ? "" : r.dep.versionAge ? timeAgoFromAge(r.dep.versionAge) : spinner(refreshInterval),
|
|
42
|
-
latest: r.dep.latestVersion ?? spinner(refreshInterval),
|
|
43
|
-
latestAge: r.dep.localDep ? "" : r.dep.latestVersionAge ? timeAgoFromAge(r.dep.latestVersionAge) : spinner(refreshInterval),
|
|
44
|
-
status: r.status === "pending" ? spinner(refreshInterval) : r.status === "done" && r.needUpdate ? "need update" : "ok",
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (nDeps > 0) {
|
|
48
|
-
console.log(`${nDeps} Dependencies`);
|
|
49
|
-
console.table(
|
|
50
|
-
rows.filter(x => x.dep.type === 'dep')
|
|
51
|
-
.map((r) => fn(r))
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (nDevDeps > 0) {
|
|
56
|
-
console.log(`${nDevDeps} Dev Dependencies`);
|
|
57
|
-
console.table(
|
|
58
|
-
rows.filter(x => x.dep.type === 'devDep')
|
|
59
|
-
.map((r) => fn(r))
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
package/src/helpers.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
const minute = 60_000;
|
|
2
|
-
const hour = 60 * minute;
|
|
3
|
-
const day = 24 * hour;
|
|
4
|
-
const year = 365 * day;
|
|
5
|
-
|
|
6
|
-
function plural(n: number, unit: string): string {
|
|
7
|
-
return `${n} ${unit}${n === 1 ? "" : "s"}`;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function timeAgoFromAge(ts: number): string {
|
|
11
|
-
if (ts < minute) {
|
|
12
|
-
return plural(0, "min");
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
if (ts < hour) {
|
|
16
|
-
return plural(Math.floor(ts / minute), "min");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (ts < day) {
|
|
20
|
-
return plural(Math.floor(ts / hour), "hour");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (ts < year) {
|
|
24
|
-
return plural(Math.floor(ts / day), "day");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return plural(Math.floor(ts / year), "year");
|
|
28
|
-
}
|
package/src/main.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import * as process from "node:process";
|
|
2
|
-
import { getLatestVersion, getPackageJsonDeps, getPkgRegistryInfo, getVersionAgeOf } from "./npm.ts";
|
|
3
|
-
import { renderDepsTable, Renderer, type RenderProps } from "./cli.ts";
|
|
4
|
-
|
|
5
|
-
if (!process || !process.argv) {
|
|
6
|
-
console.log("no process");
|
|
7
|
-
process.exit(1);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
let args: string[] = process.argv
|
|
11
|
-
args = args.slice(2);
|
|
12
|
-
|
|
13
|
-
let cwd = process.cwd();
|
|
14
|
-
if (args.length > 0) {
|
|
15
|
-
cwd = args[0];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const refreshInterval = 80;
|
|
19
|
-
|
|
20
|
-
async function run() {
|
|
21
|
-
const renderer = new Renderer<RenderProps>((props) => {
|
|
22
|
-
console.clear();
|
|
23
|
-
console.log("Checking for updates...\n");
|
|
24
|
-
renderDepsTable(props.deps);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const props: RenderProps = {
|
|
28
|
-
deps: getPackageJsonDeps(`${cwd}/package.json`).map((dep) => ({
|
|
29
|
-
dep,
|
|
30
|
-
needUpdate: false,
|
|
31
|
-
status: "pending"
|
|
32
|
-
}))
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const ticker = setInterval(() => renderer.render(props), refreshInterval);
|
|
36
|
-
|
|
37
|
-
const tasks = props.deps.map(async (row) => {
|
|
38
|
-
try {
|
|
39
|
-
if (row.dep.localDep) {
|
|
40
|
-
row.dep.latestVersion = "local";
|
|
41
|
-
row.status = "done";
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const info = await getPkgRegistryInfo(row.dep.name);
|
|
45
|
-
row.dep.latestVersion = getLatestVersion(info);
|
|
46
|
-
if (row.dep.latestVersion) {
|
|
47
|
-
row.dep.latestVersionAge = getVersionAgeOf(info, row.dep.latestVersion);
|
|
48
|
-
}
|
|
49
|
-
row.dep.versionAge = getVersionAgeOf(info, row.dep.version);
|
|
50
|
-
row.needUpdate = row.dep.version !== row.dep.latestVersion;
|
|
51
|
-
row.status = "done";
|
|
52
|
-
} catch {
|
|
53
|
-
row.status = "error";
|
|
54
|
-
} finally {
|
|
55
|
-
// update as each finishes
|
|
56
|
-
renderer.render(props);
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
await Promise.all(tasks);
|
|
61
|
-
|
|
62
|
-
clearInterval(ticker);
|
|
63
|
-
renderer.render(props); // final render
|
|
64
|
-
|
|
65
|
-
const nOutdated = props.deps.filter(x => x.needUpdate).length;
|
|
66
|
-
const nUpToDate = props.deps.filter(x => !x.needUpdate).length;
|
|
67
|
-
console.log(`\n${nOutdated} outdated, ${nUpToDate} up to date`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
run().catch((err) => {
|
|
71
|
-
console.error(err);
|
|
72
|
-
process.exit(1);
|
|
73
|
-
});
|
package/src/npm.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
|
|
3
|
-
export type PackageJson = {
|
|
4
|
-
deps: Record<string, string>,
|
|
5
|
-
devDeps: Record<string, string>
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export type Dependency = {
|
|
9
|
-
type: 'dep' | 'devDep',
|
|
10
|
-
localDep: boolean,
|
|
11
|
-
name: string,
|
|
12
|
-
version: string,
|
|
13
|
-
versionAge: number | undefined,
|
|
14
|
-
info: RegistryInfo | undefined,
|
|
15
|
-
latestVersion: string | undefined;
|
|
16
|
-
latestVersionAge: number | undefined;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export type RegistryInfo = {
|
|
20
|
-
"dist-tags": Record<string, string>,
|
|
21
|
-
versions: Record<string, any>[],
|
|
22
|
-
time: Record<string, string>
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getPackageJson(packageJsonPath: string): PackageJson {
|
|
26
|
-
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf-8');
|
|
27
|
-
const packageJson = JSON.parse(packageJsonContent);
|
|
28
|
-
return {
|
|
29
|
-
deps: packageJson.dependencies || {},
|
|
30
|
-
devDeps: packageJson.devDependencies || {}
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export function getPackageJsonDeps(packageJsonPath: string): Dependency[] {
|
|
35
|
-
const packageJson = getPackageJson(packageJsonPath);
|
|
36
|
-
const deps: Dependency[] = [];
|
|
37
|
-
const fn = (entries: Record<string, string>, t: string) => {
|
|
38
|
-
for (const [name, version] of Object.entries(entries)) {
|
|
39
|
-
const localDep = version.startsWith('file:') || version.startsWith("workspace:");
|
|
40
|
-
const v = localDep ? version : normalizeVersion(version);
|
|
41
|
-
deps.push({
|
|
42
|
-
type: t as Dependency["type"],
|
|
43
|
-
localDep,
|
|
44
|
-
name,
|
|
45
|
-
version: v,
|
|
46
|
-
versionAge: undefined,
|
|
47
|
-
info: undefined,
|
|
48
|
-
latestVersion: undefined,
|
|
49
|
-
latestVersionAge: undefined
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
fn(packageJson.deps, 'dep');
|
|
54
|
-
fn(packageJson.devDeps, 'devDep');
|
|
55
|
-
return deps;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// remove first non digit character
|
|
60
|
-
export function normalizeVersion(version: string): string {
|
|
61
|
-
return version.replace(/^[^0-9]/, '');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function getPkgRegistryInfo(pkg: string): Promise<RegistryInfo> {
|
|
65
|
-
const url = `https://registry.npmjs.org/${pkg}`;
|
|
66
|
-
const response = await fetch(url);
|
|
67
|
-
if (!response.ok) {
|
|
68
|
-
throw new Error(`Failed to fetch ${url}`);
|
|
69
|
-
}
|
|
70
|
-
return response.json();
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function getVersionReleaseDateOf(info: RegistryInfo, version: string): string | undefined {
|
|
74
|
-
return info.time[version] || undefined;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function getLatestVersion(info: RegistryInfo): string | undefined {
|
|
78
|
-
return info["dist-tags"].latest ?? undefined;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function getVersionAgeOf(info: RegistryInfo, version: string): number | undefined {
|
|
82
|
-
const releaseDate = getVersionReleaseDateOf(info, version);
|
|
83
|
-
return releaseDate ? Date.now() - new Date(releaseDate as string).getTime() : undefined;
|
|
84
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"useDefineForClassFields": true,
|
|
5
|
-
"module": "NodeNext",
|
|
6
|
-
"lib": ["ES2022", "DOM"],
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"skipLibCheck": true,
|
|
9
|
-
|
|
10
|
-
/* Bundler mode */
|
|
11
|
-
"moduleResolution": "bundler",
|
|
12
|
-
"allowImportingTsExtensions": true,
|
|
13
|
-
"verbatimModuleSyntax": true,
|
|
14
|
-
"moduleDetection": "force",
|
|
15
|
-
"noEmit": true,
|
|
16
|
-
|
|
17
|
-
/* Linting */
|
|
18
|
-
"strict": true,
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"erasableSyntaxOnly": false,
|
|
22
|
-
"noFallthroughCasesInSwitch": true,
|
|
23
|
-
"noUncheckedSideEffectImports": true
|
|
24
|
-
},
|
|
25
|
-
"include": ["src"]
|
|
26
|
-
}
|