@askrjs/cli 0.0.2 → 0.0.4
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/README.md +46 -7
- package/dist/add.d.ts +16 -0
- package/dist/add.js +558 -1
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +43 -16
- package/dist/create.d.ts +5 -0
- package/dist/create.js +104 -26
- package/dist/directory-swap-DWoHtx7C.js +35 -0
- package/dist/discovery-Difb7Y4G.js +323 -0
- package/dist/generate.d.ts +5 -0
- package/dist/generate.js +461 -0
- package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
- package/dist/openapi.d.ts +25 -0
- package/dist/openapi.js +49 -16
- package/dist/planner-VAj7qlxr.js +285 -0
- package/dist/range-YUs9eimn.js +125 -0
- package/dist/registry-CyrRHRG5.js +209 -0
- package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
- package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
- package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
- package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
- package/dist/skills.d.ts +18 -0
- package/dist/skills.js +1 -1
- package/dist/specification-DXnDOC-0.js +49 -0
- package/dist/ssg-config.d.ts +41 -0
- package/dist/ssg-config.js +1 -0
- package/dist/ssg.d.ts +61 -0
- package/dist/ssg.js +360 -24
- package/dist/templates/full-stack/AGENTS.md +0 -1
- package/dist/templates/full-stack/README.md +0 -1
- package/dist/templates/full-stack/index.html +0 -1
- package/dist/templates/full-stack/package.json +5 -3
- package/dist/templates/full-stack/server.ts +5 -9
- package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
- package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
- package/dist/templates/full-stack/src/i18n.ts +4 -4
- package/dist/templates/full-stack/src/main.tsx +4 -5
- package/dist/templates/full-stack/src/pages/home.tsx +5 -5
- package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
- package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
- package/dist/templates/full-stack/src/routes.tsx +11 -12
- package/dist/templates/full-stack/src/schemas.ts +1 -2
- package/dist/templates/full-stack/src/server/action-registry.ts +5 -10
- package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
- package/dist/templates/full-stack/src/server/app.ts +67 -57
- package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
- package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
- package/dist/templates/full-stack/src/telemetry.ts +1 -2
- package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
- package/dist/templates/full-stack/tsconfig.json +1 -2
- package/dist/templates/full-stack/vite.config.ts +5 -6
- package/dist/templates/spa/AGENTS.md +1 -1
- package/dist/templates/spa/package.json +3 -4
- package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
- package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
- package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
- package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
- package/dist/templates/spa/src/styles.css +1 -1
- package/dist/templates/spa/tsconfig.json +2 -1
- package/dist/templates/spa/vitest.config.ts +0 -4
- package/dist/templates/ssg/README.md +1 -1
- package/dist/templates/ssg/package.json +1 -1
- package/dist/templates/ssg/ssg.config.ts +7 -0
- package/dist/templates/ssg/tests/ssg-config.test.ts +5 -3
- package/dist/templates/ssg/tsconfig.json +2 -1
- package/dist/templates/ssg/vitest.config.ts +0 -4
- package/dist/templates/ssr/package.json +2 -2
- package/dist/templates/ssr/server.ts +4 -10
- package/dist/templates/ssr/src/entry-server.tsx +6 -4
- package/dist/templates/startkit/package.json +2 -2
- package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
- package/dist/templates/startkit/tsconfig.json +2 -1
- package/dist/update.d.ts +41 -0
- package/dist/update.js +282 -2
- package/dist/writer-D8qe_7ud.js +226 -0
- package/package.json +23 -22
- package/dist/add-DqhqRzBQ.js +0 -555
- package/dist/add-DqhqRzBQ.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/create.js.map +0 -1
- package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
- package/dist/openapi.js.map +0 -1
- package/dist/skills-Bh0mEhIx.js.map +0 -1
- package/dist/ssg.js.map +0 -1
- package/dist/templates/full-stack/src/vite-server.d.ts +0 -6
- package/dist/templates/spa/src/styles.d.ts +0 -1
- package/dist/templates/ssg/src/vite-env.d.ts +0 -5
- package/dist/templates/ssr/src/vite-server.d.ts +0 -7
- package/dist/templates/startkit/src/vite-env.d.ts +0 -5
- package/dist/update-DyW1na5V.js +0 -1140
- package/dist/update-DyW1na5V.js.map +0 -1
- package/skills/askr-accessibility/SKILL.md +0 -68
- package/skills/askr-accessibility/agents/openai.yaml +0 -4
- package/skills/askr-agent-execution/SKILL.md +0 -85
- package/skills/askr-agent-execution/agents/openai.yaml +0 -4
- package/skills/askr-agent-workflows/SKILL.md +0 -57
- package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
- package/skills/askr-api-integration/SKILL.md +0 -79
- package/skills/askr-api-integration/agents/openai.yaml +0 -4
- package/skills/askr-app-builder/SKILL.md +0 -99
- package/skills/askr-app-builder/agents/openai.yaml +0 -4
- package/skills/askr-auth-access/SKILL.md +0 -74
- package/skills/askr-auth-access/agents/openai.yaml +0 -4
- package/skills/askr-cli-vite/SKILL.md +0 -76
- package/skills/askr-cli-vite/agents/openai.yaml +0 -4
- package/skills/askr-dashboard-charts/SKILL.md +0 -82
- package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
- package/skills/askr-design-system/SKILL.md +0 -86
- package/skills/askr-design-system/agents/openai.yaml +0 -4
- package/skills/askr-env-config/SKILL.md +0 -74
- package/skills/askr-env-config/agents/openai.yaml +0 -4
- package/skills/askr-error-loading-empty/SKILL.md +0 -89
- package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
- package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
- package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
- package/skills/askr-forms-tables-crud/SKILL.md +0 -98
- package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
- package/skills/askr-mental-model/SKILL.md +0 -109
- package/skills/askr-mental-model/agents/openai.yaml +0 -4
- package/skills/askr-migration-react/SKILL.md +0 -81
- package/skills/askr-migration-react/agents/openai.yaml +0 -4
- package/skills/askr-observability-debugging/SKILL.md +0 -83
- package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
- package/skills/askr-project-structure/SKILL.md +0 -79
- package/skills/askr-project-structure/agents/openai.yaml +0 -4
- package/skills/askr-query-mutation/SKILL.md +0 -115
- package/skills/askr-query-mutation/agents/openai.yaml +0 -4
- package/skills/askr-realtime-streaming/SKILL.md +0 -76
- package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
- package/skills/askr-resources-data/SKILL.md +0 -100
- package/skills/askr-resources-data/agents/openai.yaml +0 -4
- package/skills/askr-routing-layouts/SKILL.md +0 -107
- package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
- package/skills/askr-runtime-reactivity/SKILL.md +0 -92
- package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
- package/skills/askr-ssr-ssg/SKILL.md +0 -76
- package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
- package/skills/askr-testing-determinism/SKILL.md +0 -75
- package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
- package/skills/askr-theming/SKILL.md +0 -86
- package/skills/askr-theming/agents/openai.yaml +0 -4
- package/skills/askr-ui-composition/SKILL.md +0 -92
- package/skills/askr-ui-composition/agents/openai.yaml +0 -4
- package/templates/full-stack/AGENTS.md +0 -12
- package/templates/full-stack/README.md +0 -18
- package/templates/full-stack/gitignore.template +0 -4
- package/templates/full-stack/index.html +0 -14
- package/templates/full-stack/package.json +0 -37
- package/templates/full-stack/server.ts +0 -13
- package/templates/full-stack/src/action-authorizations.ts +0 -10
- package/templates/full-stack/src/actions/create-message.ts +0 -10
- package/templates/full-stack/src/i18n.ts +0 -8
- package/templates/full-stack/src/main.tsx +0 -12
- package/templates/full-stack/src/pages/home.tsx +0 -25
- package/templates/full-stack/src/pages/layout.tsx +0 -33
- package/templates/full-stack/src/pages/not-found.tsx +0 -4
- package/templates/full-stack/src/routes.tsx +0 -20
- package/templates/full-stack/src/schemas.ts +0 -11
- package/templates/full-stack/src/server/action-registry.ts +0 -12
- package/templates/full-stack/src/server/actions/create-message.ts +0 -14
- package/templates/full-stack/src/server/app.ts +0 -66
- package/templates/full-stack/src/server/dependencies.ts +0 -55
- package/templates/full-stack/src/server/entry-server.ts +0 -8
- package/templates/full-stack/src/telemetry.ts +0 -4
- package/templates/full-stack/src/vite-server.d.ts +0 -6
- package/templates/full-stack/tests/actions/create-message.test.ts +0 -13
- package/templates/full-stack/tsconfig.json +0 -16
- package/templates/full-stack/vite.config.ts +0 -11
- package/templates/spa/AGENTS.md +0 -60
- package/templates/spa/README.md +0 -96
- package/templates/spa/gitignore.template +0 -16
- package/templates/spa/index.html +0 -13
- package/templates/spa/package.json +0 -35
- package/templates/spa/src/adapters/operations-client.ts +0 -90
- package/templates/spa/src/components/shared/metric-card.tsx +0 -27
- package/templates/spa/src/components/shared/status-badge.tsx +0 -24
- package/templates/spa/src/features/operations/operations.query.ts +0 -9
- package/templates/spa/src/main.tsx +0 -10
- package/templates/spa/src/pages/_layout.tsx +0 -9
- package/templates/spa/src/pages/_routes.tsx +0 -27
- package/templates/spa/src/pages/app/_layout.tsx +0 -94
- package/templates/spa/src/pages/app/_routes.tsx +0 -10
- package/templates/spa/src/pages/app/admin-home.tsx +0 -152
- package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
- package/templates/spa/src/pages/app/settings.tsx +0 -91
- package/templates/spa/src/pages/auth/_layout.tsx +0 -38
- package/templates/spa/src/pages/auth/_routes.tsx +0 -6
- package/templates/spa/src/pages/auth/login.tsx +0 -63
- package/templates/spa/src/pages/not-found.tsx +0 -22
- package/templates/spa/src/pages/public/_layout.tsx +0 -47
- package/templates/spa/src/pages/public/_routes.tsx +0 -6
- package/templates/spa/src/pages/public/home.tsx +0 -143
- package/templates/spa/src/shared/format.ts +0 -12
- package/templates/spa/src/shared/navigation.ts +0 -15
- package/templates/spa/src/styles/components.css +0 -49
- package/templates/spa/src/styles/layout.css +0 -192
- package/templates/spa/src/styles/reset.css +0 -44
- package/templates/spa/src/styles/theme.css +0 -57
- package/templates/spa/src/styles/tokens.css +0 -20
- package/templates/spa/src/styles.css +0 -7
- package/templates/spa/src/styles.d.ts +0 -1
- package/templates/spa/tests/app.test.tsx +0 -37
- package/templates/spa/tests/components/shared.test.tsx +0 -12
- package/templates/spa/tests/resources.test.ts +0 -22
- package/templates/spa/tsconfig.json +0 -20
- package/templates/spa/tsconfig.node.json +0 -10
- package/templates/spa/vite.config.ts +0 -24
- package/templates/spa/vitest.config.ts +0 -17
- package/templates/ssg/AGENTS.md +0 -55
- package/templates/ssg/README.md +0 -39
- package/templates/ssg/gitignore.template +0 -17
- package/templates/ssg/index.html +0 -13
- package/templates/ssg/package.json +0 -35
- package/templates/ssg/src/app.tsx +0 -14
- package/templates/ssg/src/components/badge.tsx +0 -3
- package/templates/ssg/src/components/counter.tsx +0 -30
- package/templates/ssg/src/components/site-shell.tsx +0 -111
- package/templates/ssg/src/jsx.d.ts +0 -23
- package/templates/ssg/src/main.tsx +0 -8
- package/templates/ssg/src/pages/about.tsx +0 -82
- package/templates/ssg/src/pages/content.tsx +0 -63
- package/templates/ssg/src/pages/example.tsx +0 -97
- package/templates/ssg/src/pages/home.tsx +0 -51
- package/templates/ssg/src/resources/user.ts +0 -15
- package/templates/ssg/src/routes.tsx +0 -15
- package/templates/ssg/src/styles.css +0 -89
- package/templates/ssg/src/vite-env.d.ts +0 -5
- package/templates/ssg/ssg.config.ts +0 -34
- package/templates/ssg/tests/app.test.tsx +0 -19
- package/templates/ssg/tests/components/counter.test.tsx +0 -18
- package/templates/ssg/tests/resources.test.ts +0 -11
- package/templates/ssg/tests/ssg-config.test.ts +0 -11
- package/templates/ssg/tsconfig.json +0 -20
- package/templates/ssg/tsconfig.node.json +0 -10
- package/templates/ssg/vite.config.ts +0 -24
- package/templates/ssg/vitest.config.ts +0 -17
- package/templates/ssr/AGENTS.md +0 -28
- package/templates/ssr/README.md +0 -38
- package/templates/ssr/gitignore.template +0 -16
- package/templates/ssr/index.html +0 -13
- package/templates/ssr/package.json +0 -34
- package/templates/ssr/server.ts +0 -16
- package/templates/ssr/src/app.tsx +0 -21
- package/templates/ssr/src/components/counter.tsx +0 -26
- package/templates/ssr/src/entry-server.tsx +0 -10
- package/templates/ssr/src/main.tsx +0 -11
- package/templates/ssr/src/pages/about.tsx +0 -75
- package/templates/ssr/src/pages/example.tsx +0 -113
- package/templates/ssr/src/pages/home.tsx +0 -56
- package/templates/ssr/src/resources/user.ts +0 -15
- package/templates/ssr/src/routes.tsx +0 -13
- package/templates/ssr/src/styles.css +0 -148
- package/templates/ssr/src/vite-server.d.ts +0 -7
- package/templates/ssr/tests/app.test.tsx +0 -24
- package/templates/ssr/tests/components/counter.test.tsx +0 -13
- package/templates/ssr/tests/resources.test.ts +0 -11
- package/templates/ssr/tsconfig.json +0 -22
- package/templates/ssr/tsconfig.node.json +0 -10
- package/templates/ssr/tsconfig.server.json +0 -15
- package/templates/ssr/vite.config.ts +0 -25
- package/templates/ssr/vitest.config.ts +0 -13
- package/templates/startkit/AGENTS.md +0 -77
- package/templates/startkit/README.md +0 -192
- package/templates/startkit/gitignore.template +0 -16
- package/templates/startkit/index.html +0 -13
- package/templates/startkit/package.json +0 -35
- package/templates/startkit/src/components/app-header.tsx +0 -93
- package/templates/startkit/src/components/app-sidebar.tsx +0 -95
- package/templates/startkit/src/components/data-table.tsx +0 -80
- package/templates/startkit/src/components/empty-state.tsx +0 -13
- package/templates/startkit/src/components/page-header.tsx +0 -23
- package/templates/startkit/src/components/stat-card.tsx +0 -24
- package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
- package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
- package/templates/startkit/src/lib/format.ts +0 -31
- package/templates/startkit/src/lib/mock-data.ts +0 -441
- package/templates/startkit/src/lib/routes.ts +0 -116
- package/templates/startkit/src/main.tsx +0 -12
- package/templates/startkit/src/pages/_layout.tsx +0 -56
- package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
- package/templates/startkit/src/pages/auth/login.tsx +0 -129
- package/templates/startkit/src/pages/home.tsx +0 -83
- package/templates/startkit/src/pages/not-found.tsx +0 -24
- package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
- package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
- package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
- package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
- package/templates/startkit/src/router.tsx +0 -7
- package/templates/startkit/src/routes/auth-config.ts +0 -38
- package/templates/startkit/src/routes/auth.ts +0 -8
- package/templates/startkit/src/routes/index.ts +0 -28
- package/templates/startkit/src/routes/public.ts +0 -8
- package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
- package/templates/startkit/src/routes/workspace/index.ts +0 -14
- package/templates/startkit/src/styles/components.css +0 -396
- package/templates/startkit/src/styles/layout.css +0 -192
- package/templates/startkit/src/styles/reset.css +0 -38
- package/templates/startkit/src/styles/theme.css +0 -76
- package/templates/startkit/src/styles/tokens.css +0 -67
- package/templates/startkit/src/styles.css +0 -7
- package/templates/startkit/src/toast.ts +0 -55
- package/templates/startkit/src/utils/join-classes.ts +0 -4
- package/templates/startkit/src/vite-env.d.ts +0 -5
- package/templates/startkit/tests/app.test.tsx +0 -32
- package/templates/startkit/tests/preferences.test.ts +0 -43
- package/templates/startkit/tests/resources.test.ts +0 -82
- package/templates/startkit/tsconfig.json +0 -20
- package/templates/startkit/tsconfig.node.json +0 -10
- package/templates/startkit/vite.config.ts +0 -32
- package/templates/startkit/vitest.config.ts +0 -13
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { n as isBreakingChange, r as rewriteRange, t as analyzeRange } from "./range-YUs9eimn.js";
|
|
2
|
+
import { t as parseDependencySpecification } from "./specification-DXnDOC-0.js";
|
|
3
|
+
import semver from "semver";
|
|
4
|
+
//#region src/update/planner.ts
|
|
5
|
+
const STATUS_PRIORITY = {
|
|
6
|
+
current: 0,
|
|
7
|
+
local: 1,
|
|
8
|
+
safe: 2,
|
|
9
|
+
breaking: 3,
|
|
10
|
+
manual: 4,
|
|
11
|
+
error: 5
|
|
12
|
+
};
|
|
13
|
+
function publishedVersions(packument) {
|
|
14
|
+
return Object.keys(packument.versions ?? {}).filter((version) => semver.valid(version) !== null).sort(semver.compare);
|
|
15
|
+
}
|
|
16
|
+
function selectedTarget(packument, tag) {
|
|
17
|
+
const value = packument["dist-tags"]?.[tag];
|
|
18
|
+
return typeof value === "string" && semver.valid(value) ? value : null;
|
|
19
|
+
}
|
|
20
|
+
function plannedOccurrence(occurrence, packument, failure, selectedTag, force) {
|
|
21
|
+
const base = {
|
|
22
|
+
workspace: occurrence.workspace,
|
|
23
|
+
manifestPath: occurrence.manifestPath,
|
|
24
|
+
relativeManifestPath: occurrence.relativeManifestPath,
|
|
25
|
+
section: occurrence.section,
|
|
26
|
+
currentSpecification: occurrence.currentSpecification,
|
|
27
|
+
proposedSpecification: null,
|
|
28
|
+
allowedVersion: null
|
|
29
|
+
};
|
|
30
|
+
if (occurrence.kind === "local") return {
|
|
31
|
+
targetVersion: null,
|
|
32
|
+
occurrence: {
|
|
33
|
+
...base,
|
|
34
|
+
status: "local",
|
|
35
|
+
reason: occurrence.reason
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
if (occurrence.kind === "manual") return {
|
|
39
|
+
targetVersion: null,
|
|
40
|
+
occurrence: {
|
|
41
|
+
...base,
|
|
42
|
+
status: "manual",
|
|
43
|
+
reason: occurrence.reason
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
if (failure) return {
|
|
47
|
+
targetVersion: null,
|
|
48
|
+
occurrence: {
|
|
49
|
+
...base,
|
|
50
|
+
status: "error",
|
|
51
|
+
reason: failure
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
if (occurrence.kind === "current") return {
|
|
55
|
+
targetVersion: packument ? selectedTarget(packument, selectedTag) : null,
|
|
56
|
+
occurrence: {
|
|
57
|
+
...base,
|
|
58
|
+
status: "current",
|
|
59
|
+
reason: occurrence.reason
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
if (!packument) return {
|
|
63
|
+
targetVersion: null,
|
|
64
|
+
occurrence: {
|
|
65
|
+
...base,
|
|
66
|
+
status: "error",
|
|
67
|
+
reason: "package metadata is unavailable"
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
const targetVersion = selectedTarget(packument, selectedTag);
|
|
71
|
+
if (!targetVersion) return {
|
|
72
|
+
targetVersion: null,
|
|
73
|
+
occurrence: {
|
|
74
|
+
...base,
|
|
75
|
+
status: "error",
|
|
76
|
+
reason: `dist-tag '${selectedTag}' is not published`
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const versions = publishedVersions(packument);
|
|
80
|
+
if (!versions.includes(targetVersion)) return {
|
|
81
|
+
targetVersion: null,
|
|
82
|
+
occurrence: {
|
|
83
|
+
...base,
|
|
84
|
+
status: "error",
|
|
85
|
+
reason: `dist-tag '${selectedTag}' does not identify a published version`
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const allowedVersion = semver.maxSatisfying(versions, occurrence.currentSpecification);
|
|
89
|
+
if (!allowedVersion) return {
|
|
90
|
+
targetVersion,
|
|
91
|
+
occurrence: {
|
|
92
|
+
...base,
|
|
93
|
+
status: "manual",
|
|
94
|
+
reason: "no published version satisfies the current specification"
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
if (semver.satisfies(targetVersion, occurrence.currentSpecification) || !semver.gt(targetVersion, allowedVersion)) return {
|
|
98
|
+
targetVersion,
|
|
99
|
+
occurrence: {
|
|
100
|
+
...base,
|
|
101
|
+
allowedVersion,
|
|
102
|
+
status: "current",
|
|
103
|
+
reason: "selected target is already covered by the current specification"
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const analysis = analyzeRange(occurrence.currentSpecification);
|
|
107
|
+
if (!analysis.shape) return {
|
|
108
|
+
targetVersion,
|
|
109
|
+
occurrence: {
|
|
110
|
+
...base,
|
|
111
|
+
allowedVersion,
|
|
112
|
+
status: "manual",
|
|
113
|
+
reason: analysis.reason
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
const breaking = isBreakingChange(allowedVersion, targetVersion);
|
|
117
|
+
const eligible = !breaking || force;
|
|
118
|
+
return {
|
|
119
|
+
targetVersion,
|
|
120
|
+
occurrence: {
|
|
121
|
+
...base,
|
|
122
|
+
allowedVersion,
|
|
123
|
+
proposedSpecification: eligible ? rewriteRange(analysis.shape, targetVersion, breaking) : null,
|
|
124
|
+
status: breaking ? "breaking" : "safe",
|
|
125
|
+
reason: breaking ? eligible ? "latest version is eligible for askr upgrade" : "breaking update is available via askr upgrade" : "compatible update is available"
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function occurrenceKey(occurrence, packageName) {
|
|
130
|
+
return [
|
|
131
|
+
occurrence.manifestPath,
|
|
132
|
+
occurrence.section,
|
|
133
|
+
packageName ?? occurrence.package,
|
|
134
|
+
occurrence.currentSpecification
|
|
135
|
+
].join("\0");
|
|
136
|
+
}
|
|
137
|
+
function resolveSpecificationVersion(specification, packument) {
|
|
138
|
+
const versions = publishedVersions(packument);
|
|
139
|
+
const parsed = parseDependencySpecification(specification);
|
|
140
|
+
if (parsed.type === "tag") {
|
|
141
|
+
const tagged = packument["dist-tags"]?.[parsed.rawSpec];
|
|
142
|
+
return typeof tagged === "string" && semver.valid(tagged) ? tagged : null;
|
|
143
|
+
}
|
|
144
|
+
if (parsed.type === "version") return semver.valid(parsed.rawSpec);
|
|
145
|
+
if (parsed.type === "range") return semver.maxSatisfying(versions, parsed.rawSpec);
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function versionMetadata(packument, version) {
|
|
149
|
+
const metadata = packument.versions?.[version];
|
|
150
|
+
return metadata && typeof metadata === "object" && !Array.isArray(metadata) ? metadata : null;
|
|
151
|
+
}
|
|
152
|
+
function applyPeerCompatibilityGuard(decisions, contextOccurrences, packuments) {
|
|
153
|
+
const plannedByKey = /* @__PURE__ */ new Map();
|
|
154
|
+
for (const decision of decisions) for (const occurrence of decision.occurrences) plannedByKey.set(occurrenceKey(occurrence, decision.package), occurrence);
|
|
155
|
+
const contextByWorkspace = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const occurrence of contextOccurrences) {
|
|
157
|
+
const entries = contextByWorkspace.get(occurrence.workspace) ?? [];
|
|
158
|
+
entries.push(occurrence);
|
|
159
|
+
contextByWorkspace.set(occurrence.workspace, entries);
|
|
160
|
+
}
|
|
161
|
+
for (const [workspace, context] of contextByWorkspace) {
|
|
162
|
+
const states = context.flatMap((dependency) => {
|
|
163
|
+
if (!dependency.registryManaged) return [];
|
|
164
|
+
const packument = packuments.get(dependency.package);
|
|
165
|
+
if (!packument) return [];
|
|
166
|
+
const planned = plannedByKey.get(occurrenceKey(dependency));
|
|
167
|
+
const currentVersion = resolveSpecificationVersion(dependency.currentSpecification, packument);
|
|
168
|
+
const futureVersion = resolveSpecificationVersion(planned?.proposedSpecification ?? dependency.currentSpecification, packument);
|
|
169
|
+
return currentVersion && futureVersion ? [{
|
|
170
|
+
dependency,
|
|
171
|
+
packument,
|
|
172
|
+
planned,
|
|
173
|
+
currentVersion,
|
|
174
|
+
futureVersion,
|
|
175
|
+
changed: Boolean(planned?.proposedSpecification)
|
|
176
|
+
}] : [];
|
|
177
|
+
});
|
|
178
|
+
const blockers = /* @__PURE__ */ new Map();
|
|
179
|
+
for (const provider of states) {
|
|
180
|
+
const currentPeers = versionMetadata(provider.packument, provider.currentVersion)?.peerDependencies ?? {};
|
|
181
|
+
const futurePeers = versionMetadata(provider.packument, provider.futureVersion)?.peerDependencies ?? {};
|
|
182
|
+
const peerNames = /* @__PURE__ */ new Set([...Object.keys(currentPeers), ...Object.keys(futurePeers)]);
|
|
183
|
+
for (const peerName of peerNames) {
|
|
184
|
+
const currentRequirement = currentPeers[peerName];
|
|
185
|
+
const futureRequirement = futurePeers[peerName];
|
|
186
|
+
if (futureRequirement !== void 0 && typeof futureRequirement !== "string") continue;
|
|
187
|
+
for (const peer of states.filter((state) => state.dependency.package === peerName)) {
|
|
188
|
+
const currentAccepted = typeof currentRequirement !== "string" || semver.satisfies(peer.currentVersion, currentRequirement);
|
|
189
|
+
const futureAccepted = typeof futureRequirement !== "string" || semver.satisfies(peer.futureVersion, futureRequirement);
|
|
190
|
+
if (!currentAccepted || futureAccepted) continue;
|
|
191
|
+
const reason = `${provider.dependency.package}@${provider.futureVersion} requires ${peerName}@${futureRequirement}`;
|
|
192
|
+
if (provider.changed && provider.planned) blockers.set(provider.planned, reason);
|
|
193
|
+
if (peer.changed && peer.planned) blockers.set(peer.planned, reason);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
for (const [planned, reason] of blockers) {
|
|
198
|
+
planned.status = "manual";
|
|
199
|
+
planned.proposedSpecification = null;
|
|
200
|
+
planned.reason = reason;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function aggregateStatus(occurrences) {
|
|
205
|
+
return occurrences.reduce((status, occurrence) => STATUS_PRIORITY[occurrence.status] > STATUS_PRIORITY[status] ? occurrence.status : status, "current");
|
|
206
|
+
}
|
|
207
|
+
function summarize(decisions) {
|
|
208
|
+
const summary = {
|
|
209
|
+
packages: decisions.length,
|
|
210
|
+
occurrences: 0,
|
|
211
|
+
changedOccurrences: 0,
|
|
212
|
+
current: 0,
|
|
213
|
+
safe: 0,
|
|
214
|
+
breaking: 0,
|
|
215
|
+
local: 0,
|
|
216
|
+
manual: 0,
|
|
217
|
+
error: 0
|
|
218
|
+
};
|
|
219
|
+
for (const decision of decisions) {
|
|
220
|
+
decision.status = aggregateStatus(decision.occurrences);
|
|
221
|
+
decision.reason = decision.occurrences.find((entry) => entry.status === decision.status)?.reason ?? "";
|
|
222
|
+
summary[decision.status] += 1;
|
|
223
|
+
summary.occurrences += decision.occurrences.length;
|
|
224
|
+
summary.changedOccurrences += decision.occurrences.filter((entry) => entry.proposedSpecification).length;
|
|
225
|
+
}
|
|
226
|
+
return summary;
|
|
227
|
+
}
|
|
228
|
+
function planUpdates(options) {
|
|
229
|
+
const failures = options.failures ?? /* @__PURE__ */ new Map();
|
|
230
|
+
const tags = options.tags ?? {};
|
|
231
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
232
|
+
for (const occurrence of options.occurrences) {
|
|
233
|
+
const entries = grouped.get(occurrence.package) ?? [];
|
|
234
|
+
entries.push(occurrence);
|
|
235
|
+
grouped.set(occurrence.package, entries);
|
|
236
|
+
}
|
|
237
|
+
const decisions = [...grouped.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([packageName, occurrences]) => {
|
|
238
|
+
const selectedTag = options.cliTag ?? tags[packageName] ?? "latest";
|
|
239
|
+
const planned = occurrences.map((occurrence) => plannedOccurrence(occurrence, options.packuments.get(packageName), failures.get(packageName), selectedTag, options.force ?? false));
|
|
240
|
+
const targetVersion = planned.find((entry) => entry.targetVersion)?.targetVersion ?? null;
|
|
241
|
+
const plannedOccurrences = planned.map((entry) => entry.occurrence);
|
|
242
|
+
const status = aggregateStatus(plannedOccurrences);
|
|
243
|
+
return {
|
|
244
|
+
package: packageName,
|
|
245
|
+
selectedTag,
|
|
246
|
+
targetVersion,
|
|
247
|
+
status,
|
|
248
|
+
reason: plannedOccurrences.find((entry) => entry.status === status)?.reason ?? "",
|
|
249
|
+
occurrences: plannedOccurrences
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
const selectedNames = new Set(grouped.keys());
|
|
253
|
+
for (const [packageName, failure] of [...failures].sort(([left], [right]) => left.localeCompare(right))) {
|
|
254
|
+
if (selectedNames.has(packageName)) continue;
|
|
255
|
+
const context = (options.contextOccurrences ?? []).filter((occurrence) => occurrence.package === packageName).map((occurrence) => ({
|
|
256
|
+
workspace: occurrence.workspace,
|
|
257
|
+
manifestPath: occurrence.manifestPath,
|
|
258
|
+
relativeManifestPath: occurrence.relativeManifestPath,
|
|
259
|
+
section: occurrence.section,
|
|
260
|
+
currentSpecification: occurrence.currentSpecification,
|
|
261
|
+
proposedSpecification: null,
|
|
262
|
+
allowedVersion: null,
|
|
263
|
+
status: "error",
|
|
264
|
+
reason: `peer compatibility lookup failed: ${failure}`
|
|
265
|
+
}));
|
|
266
|
+
decisions.push({
|
|
267
|
+
package: packageName,
|
|
268
|
+
selectedTag: options.cliTag ?? tags[packageName] ?? "latest",
|
|
269
|
+
targetVersion: null,
|
|
270
|
+
status: "error",
|
|
271
|
+
reason: `peer compatibility lookup failed: ${failure}`,
|
|
272
|
+
occurrences: context
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
decisions.sort((left, right) => left.package.localeCompare(right.package));
|
|
276
|
+
applyPeerCompatibilityGuard(decisions, options.contextOccurrences ?? options.occurrences, options.packuments);
|
|
277
|
+
const summary = summarize(decisions);
|
|
278
|
+
return {
|
|
279
|
+
decisions,
|
|
280
|
+
summary,
|
|
281
|
+
hasErrors: summary.error > 0
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
//#endregion
|
|
285
|
+
export { planUpdates };
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
//#region src/update/range.ts
|
|
3
|
+
const FULL_VERSION = String.raw`\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?`;
|
|
4
|
+
const PARTIAL_VERSION = String.raw`\d+(?:\.\d+){0,2}`;
|
|
5
|
+
function analyzeAtomicRange(specification) {
|
|
6
|
+
const value = specification.trim();
|
|
7
|
+
if (/^(?:\*|x|X)$/.test(value)) return {
|
|
8
|
+
shape: null,
|
|
9
|
+
tracking: true,
|
|
10
|
+
reason: "wildcard range tracks the selected tag"
|
|
11
|
+
};
|
|
12
|
+
if (new RegExp(`^${FULL_VERSION}$`).test(value) && semver.valid(value)) return {
|
|
13
|
+
shape: { kind: "exact" },
|
|
14
|
+
tracking: false,
|
|
15
|
+
reason: ""
|
|
16
|
+
};
|
|
17
|
+
const operator = value.match(new RegExp(`^([~^])\\s*(${FULL_VERSION}|${PARTIAL_VERSION})$`));
|
|
18
|
+
if (operator && semver.validRange(value)) return {
|
|
19
|
+
shape: {
|
|
20
|
+
kind: "operator",
|
|
21
|
+
operator: operator[1]
|
|
22
|
+
},
|
|
23
|
+
tracking: false,
|
|
24
|
+
reason: ""
|
|
25
|
+
};
|
|
26
|
+
const bounded = value.match(/^((?:>=|>)\s*\d+(?:\.\d+){0,2})\s+(?:<|<=)\s*\d+(?:\.\d+){0,2}$/);
|
|
27
|
+
if (bounded && semver.validRange(value)) return {
|
|
28
|
+
shape: {
|
|
29
|
+
kind: "bounded",
|
|
30
|
+
lower: bounded[1].replace(/\s+/g, "")
|
|
31
|
+
},
|
|
32
|
+
tracking: false,
|
|
33
|
+
reason: ""
|
|
34
|
+
};
|
|
35
|
+
const xRange = value.match(/^(\d+|[xX*])(?:\.(\d+|[xX*]))?(?:\.(\d+|[xX*]))?$/);
|
|
36
|
+
if (xRange && semver.validRange(value)) {
|
|
37
|
+
const parts = xRange.slice(1).filter((part) => part !== void 0);
|
|
38
|
+
return {
|
|
39
|
+
shape: {
|
|
40
|
+
kind: "x",
|
|
41
|
+
parts,
|
|
42
|
+
wildcard: parts.find((part) => /^[xX*]$/.test(part)) ?? null
|
|
43
|
+
},
|
|
44
|
+
tracking: false,
|
|
45
|
+
reason: ""
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
shape: null,
|
|
50
|
+
tracking: false,
|
|
51
|
+
reason: "unsupported complex semver range"
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function analyzeRange(specification) {
|
|
55
|
+
const clauses = specification.split("||").map((clause) => clause.trim());
|
|
56
|
+
if (clauses.length === 1) return analyzeAtomicRange(specification);
|
|
57
|
+
if (clauses.some((clause) => clause.length === 0)) return {
|
|
58
|
+
shape: null,
|
|
59
|
+
tracking: false,
|
|
60
|
+
reason: "unsupported complex semver range"
|
|
61
|
+
};
|
|
62
|
+
const analyzed = clauses.map(analyzeAtomicRange);
|
|
63
|
+
if (analyzed.some((entry) => !entry.shape || entry.shape.kind === "union" || entry.tracking)) return {
|
|
64
|
+
shape: null,
|
|
65
|
+
tracking: false,
|
|
66
|
+
reason: "unsupported complex semver union"
|
|
67
|
+
};
|
|
68
|
+
const minimums = clauses.map((clause) => semver.minVersion(clause));
|
|
69
|
+
if (minimums.some((version) => version === null)) return {
|
|
70
|
+
shape: null,
|
|
71
|
+
tracking: false,
|
|
72
|
+
reason: "unsupported complex semver union"
|
|
73
|
+
};
|
|
74
|
+
let highestIndex = 0;
|
|
75
|
+
for (let index = 1; index < minimums.length; index += 1) if (semver.gt(minimums[index], minimums[highestIndex])) highestIndex = index;
|
|
76
|
+
return {
|
|
77
|
+
shape: {
|
|
78
|
+
kind: "union",
|
|
79
|
+
clauses: analyzed.map((entry) => entry.shape),
|
|
80
|
+
sourceClauses: clauses,
|
|
81
|
+
highestIndex
|
|
82
|
+
},
|
|
83
|
+
tracking: false,
|
|
84
|
+
reason: ""
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function isBreakingChange(allowedVersion, targetVersion) {
|
|
88
|
+
const allowed = new semver.SemVer(allowedVersion);
|
|
89
|
+
const target = new semver.SemVer(targetVersion);
|
|
90
|
+
if (allowed.major !== target.major) return true;
|
|
91
|
+
return allowed.major === 0 && allowed.minor !== target.minor;
|
|
92
|
+
}
|
|
93
|
+
function nextBreakingBoundary(version) {
|
|
94
|
+
const parsed = new semver.SemVer(version);
|
|
95
|
+
return parsed.major === 0 ? `0.${parsed.minor + 1}.0` : `${parsed.major + 1}.0.0`;
|
|
96
|
+
}
|
|
97
|
+
function rewriteXRange(shape, target) {
|
|
98
|
+
const parsed = new semver.SemVer(target);
|
|
99
|
+
const count = shape.parts.length;
|
|
100
|
+
if (shape.wildcard) {
|
|
101
|
+
const wildcardIndex = shape.parts.findIndex((part) => /^[xX*]$/.test(part));
|
|
102
|
+
if (wildcardIndex === 0) return shape.wildcard;
|
|
103
|
+
if (wildcardIndex === 1) return `${parsed.major}.${shape.wildcard}`;
|
|
104
|
+
return `${parsed.major}.${parsed.minor}.${shape.wildcard}`;
|
|
105
|
+
}
|
|
106
|
+
if (count === 1) return String(parsed.major);
|
|
107
|
+
return `${parsed.major}.${parsed.minor}`;
|
|
108
|
+
}
|
|
109
|
+
function rewriteAtomic(shape, target, forcedBreaking) {
|
|
110
|
+
if (shape.kind === "exact") return target;
|
|
111
|
+
if (shape.kind === "operator") return `${shape.operator}${target}`;
|
|
112
|
+
if (shape.kind === "x") return rewriteXRange(shape, target);
|
|
113
|
+
const boundary = nextBreakingBoundary(target);
|
|
114
|
+
return forcedBreaking ? `>=${target} <${boundary}` : `${shape.lower} <${boundary}`;
|
|
115
|
+
}
|
|
116
|
+
function rewriteRange(shape, target, forcedBreaking) {
|
|
117
|
+
if (shape.kind !== "union") return rewriteAtomic(shape, target, forcedBreaking);
|
|
118
|
+
const highestShape = shape.clauses[shape.highestIndex];
|
|
119
|
+
if (forcedBreaking) return rewriteAtomic(highestShape, target, true);
|
|
120
|
+
const rewritten = [...shape.sourceClauses];
|
|
121
|
+
rewritten[shape.highestIndex] = rewriteAtomic(highestShape, target, false);
|
|
122
|
+
return rewritten.join(" || ");
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { isBreakingChange as n, rewriteRange as r, analyzeRange as t };
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { t as parseDependencySpecification } from "./specification-DXnDOC-0.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { existsSync } from "node:fs";
|
|
4
|
+
import { execFile } from "node:child_process";
|
|
5
|
+
import semver from "semver";
|
|
6
|
+
//#region src/update/registry.ts
|
|
7
|
+
function installedNpmCli(executable) {
|
|
8
|
+
const directories = /* @__PURE__ */ new Set([path.dirname(process.execPath)]);
|
|
9
|
+
if (executable && path.isAbsolute(executable)) directories.add(path.dirname(executable));
|
|
10
|
+
for (const directory of directories) for (const candidate of [path.join(directory, "node_modules", "npm", "bin", "npm-cli.js"), path.resolve(directory, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")]) if (existsSync(candidate)) return candidate;
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
function npmInvocation(env) {
|
|
14
|
+
const executable = env.npm_execpath;
|
|
15
|
+
const executableName = executable ? path.basename(executable).toLowerCase() : "";
|
|
16
|
+
const isNpmExecutable = executableName === "npm" || executableName === "npm.cmd" || /^npm(?:-cli)?\.(?:cjs|js|mjs)$/.test(executableName);
|
|
17
|
+
if (executable && isNpmExecutable) {
|
|
18
|
+
const extension = path.extname(executable).toLowerCase();
|
|
19
|
+
if ([
|
|
20
|
+
".cjs",
|
|
21
|
+
".js",
|
|
22
|
+
".mjs"
|
|
23
|
+
].includes(extension)) return {
|
|
24
|
+
executable: process.execPath,
|
|
25
|
+
prefix: [executable]
|
|
26
|
+
};
|
|
27
|
+
const npmCli = installedNpmCli(executable);
|
|
28
|
+
return npmCli ? {
|
|
29
|
+
executable: process.execPath,
|
|
30
|
+
prefix: [npmCli]
|
|
31
|
+
} : {
|
|
32
|
+
executable,
|
|
33
|
+
prefix: []
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const npmCli = installedNpmCli();
|
|
37
|
+
if (npmCli) return {
|
|
38
|
+
executable: process.execPath,
|
|
39
|
+
prefix: [npmCli]
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
executable: process.platform === "win32" ? "npm.cmd" : "npm",
|
|
43
|
+
prefix: []
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function executionEnvironment(env) {
|
|
47
|
+
if (env === process.env) return { ...process.env };
|
|
48
|
+
const inherited = { ...process.env };
|
|
49
|
+
for (const name of Object.keys(inherited)) if (/^npm_config_/i.test(name)) delete inherited[name];
|
|
50
|
+
return {
|
|
51
|
+
...inherited,
|
|
52
|
+
...env
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function loadNpmConfiguration(root, env = process.env) {
|
|
56
|
+
const effectiveEnvironment = executionEnvironment(env);
|
|
57
|
+
return {
|
|
58
|
+
cwd: root,
|
|
59
|
+
env: effectiveEnvironment,
|
|
60
|
+
invocation: npmInvocation(effectiveEnvironment)
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function npmError(error, stderr) {
|
|
64
|
+
const details = `${String(error.code ?? "")}\n${stderr}`;
|
|
65
|
+
const safe = /* @__PURE__ */ new Error("npm registry lookup failed");
|
|
66
|
+
safe.code = (details.match(/\bE(?:401|403|404|CONNRESET|TIMEDOUT|TIMEOUT)\b/i)?.[0])?.toUpperCase() ?? (typeof error.code === "string" ? error.code : "");
|
|
67
|
+
if (safe.code === "E401") safe.statusCode = 401;
|
|
68
|
+
if (safe.code === "E403") safe.statusCode = 403;
|
|
69
|
+
if (safe.code === "E404") safe.statusCode = 404;
|
|
70
|
+
return safe;
|
|
71
|
+
}
|
|
72
|
+
function executeNpmJson(args, configuration, preferOnline) {
|
|
73
|
+
const [command, ...positionals] = args;
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
execFile(configuration.invocation.executable, [
|
|
76
|
+
...configuration.invocation.prefix,
|
|
77
|
+
command,
|
|
78
|
+
"--json",
|
|
79
|
+
preferOnline ? "--prefer-online" : "--prefer-offline",
|
|
80
|
+
"--offline=false",
|
|
81
|
+
"--loglevel=error",
|
|
82
|
+
"--update-notifier=false",
|
|
83
|
+
"--",
|
|
84
|
+
...positionals
|
|
85
|
+
], {
|
|
86
|
+
cwd: configuration.cwd,
|
|
87
|
+
encoding: "utf8",
|
|
88
|
+
env: configuration.env,
|
|
89
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
90
|
+
windowsHide: true
|
|
91
|
+
}, (error, stdout, stderr) => {
|
|
92
|
+
if (error) {
|
|
93
|
+
reject(npmError(error, stderr));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
resolve(JSON.parse(stdout));
|
|
98
|
+
} catch {
|
|
99
|
+
reject(/* @__PURE__ */ new Error("npm registry returned malformed JSON"));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function isRecord(value) {
|
|
105
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
106
|
+
}
|
|
107
|
+
function basePackument(value) {
|
|
108
|
+
if (!isRecord(value) || !Array.isArray(value.versions) || !isRecord(value["dist-tags"])) return null;
|
|
109
|
+
const versions = value.versions.filter((version) => typeof version === "string");
|
|
110
|
+
if (versions.length === 0) return null;
|
|
111
|
+
return {
|
|
112
|
+
"dist-tags": value["dist-tags"],
|
|
113
|
+
versions: Object.fromEntries(versions.map((version) => [version, { version }]))
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function selectedVersions(packument, specifications) {
|
|
117
|
+
const versions = Object.keys(packument.versions ?? {}).filter((version) => semver.valid(version) !== null);
|
|
118
|
+
const selected = new Set(Object.values(packument["dist-tags"] ?? {}).filter((version) => typeof version === "string" && semver.valid(version) !== null && versions.includes(version)));
|
|
119
|
+
for (const specification of specifications) {
|
|
120
|
+
const parsed = parseDependencySpecification(specification);
|
|
121
|
+
if (parsed.type === "tag") {
|
|
122
|
+
const tagged = packument["dist-tags"]?.[parsed.rawSpec];
|
|
123
|
+
if (typeof tagged === "string" && versions.includes(tagged)) selected.add(tagged);
|
|
124
|
+
} else if (parsed.type === "version") {
|
|
125
|
+
if (versions.includes(parsed.rawSpec)) selected.add(parsed.rawSpec);
|
|
126
|
+
} else if (parsed.type === "range") {
|
|
127
|
+
const matching = semver.maxSatisfying(versions, parsed.rawSpec);
|
|
128
|
+
if (matching) selected.add(matching);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [...selected].sort(semver.compare);
|
|
132
|
+
}
|
|
133
|
+
function mergeVersionMetadata(packument, value, selected) {
|
|
134
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
135
|
+
const merged = /* @__PURE__ */ new Set();
|
|
136
|
+
for (const entry of entries) {
|
|
137
|
+
if (typeof entry === "string") {
|
|
138
|
+
if (packument.versions?.[entry]) merged.add(entry);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!isRecord(entry) || typeof entry.version !== "string") continue;
|
|
142
|
+
const metadata = packument.versions?.[entry.version];
|
|
143
|
+
if (!isRecord(metadata)) continue;
|
|
144
|
+
if (isRecord(entry.peerDependencies)) metadata.peerDependencies = entry.peerDependencies;
|
|
145
|
+
merged.add(entry.version);
|
|
146
|
+
}
|
|
147
|
+
return selected.every((version) => merged.has(version));
|
|
148
|
+
}
|
|
149
|
+
async function executeNpmView(packageName, configuration, specifications) {
|
|
150
|
+
const packument = basePackument(await executeNpmJson([
|
|
151
|
+
"view",
|
|
152
|
+
packageName,
|
|
153
|
+
"versions",
|
|
154
|
+
"dist-tags"
|
|
155
|
+
], configuration, true));
|
|
156
|
+
if (!packument) return null;
|
|
157
|
+
const versions = selectedVersions(packument, specifications);
|
|
158
|
+
if (versions.length === 0) return packument;
|
|
159
|
+
return mergeVersionMetadata(packument, await executeNpmJson([
|
|
160
|
+
"view",
|
|
161
|
+
`${packageName}@${versions.join(" || ")}`,
|
|
162
|
+
"version",
|
|
163
|
+
"peerDependencies"
|
|
164
|
+
], configuration, false), versions) ? packument : null;
|
|
165
|
+
}
|
|
166
|
+
function isPackument(value) {
|
|
167
|
+
return isRecord(value) && isRecord(value["dist-tags"]) && isRecord(value.versions);
|
|
168
|
+
}
|
|
169
|
+
function sanitizeRegistryError(error) {
|
|
170
|
+
const value = error && typeof error === "object" ? error : {};
|
|
171
|
+
if (value.statusCode === 404 || value.code === "E404") return "package was not found in the selected registry";
|
|
172
|
+
if (value.statusCode === 401 || value.statusCode === 403 || value.code === "E401" || value.code === "E403") return "registry authentication or authorization failed";
|
|
173
|
+
const code = typeof value.code === "string" ? value.code.toUpperCase() : "";
|
|
174
|
+
if ([
|
|
175
|
+
"ETIMEDOUT",
|
|
176
|
+
"ETIMEOUT",
|
|
177
|
+
"FETCH_ERROR",
|
|
178
|
+
"ECONNRESET"
|
|
179
|
+
].includes(code)) return "registry request timed out or was interrupted";
|
|
180
|
+
if (/^[A-Z][A-Z0-9_]{1,30}$/.test(code)) return `registry request failed (${code})`;
|
|
181
|
+
return "registry request failed";
|
|
182
|
+
}
|
|
183
|
+
async function fetchPackuments(packageNames, configuration, options = {}) {
|
|
184
|
+
const names = [...new Set(packageNames)].sort((left, right) => left.localeCompare(right));
|
|
185
|
+
const packuments = /* @__PURE__ */ new Map();
|
|
186
|
+
const failures = /* @__PURE__ */ new Map();
|
|
187
|
+
const viewPackage = options.viewPackage ?? executeNpmView;
|
|
188
|
+
let nextIndex = 0;
|
|
189
|
+
const worker = async () => {
|
|
190
|
+
while (nextIndex < names.length) {
|
|
191
|
+
const packageName = names[nextIndex];
|
|
192
|
+
nextIndex += 1;
|
|
193
|
+
try {
|
|
194
|
+
const result = await viewPackage(packageName, configuration, options.requirements?.specifications?.get(packageName) ?? []);
|
|
195
|
+
if (isPackument(result)) packuments.set(packageName, result);
|
|
196
|
+
else failures.set(packageName, "registry returned malformed package metadata");
|
|
197
|
+
} catch (error) {
|
|
198
|
+
failures.set(packageName, sanitizeRegistryError(error));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
await Promise.all(Array.from({ length: Math.min(8, names.length) }, worker));
|
|
203
|
+
return {
|
|
204
|
+
packuments,
|
|
205
|
+
failures
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
export { fetchPackuments, loadNpmConfiguration };
|