@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,323 @@
|
|
|
1
|
+
import { t as analyzeRange } from "./range-YUs9eimn.js";
|
|
2
|
+
import { t as parseDependencySpecification } from "./specification-DXnDOC-0.js";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { load } from "js-yaml";
|
|
6
|
+
import { minimatch } from "minimatch";
|
|
7
|
+
//#region src/update/types.ts
|
|
8
|
+
const DEPENDENCY_SECTIONS = [
|
|
9
|
+
"dependencies",
|
|
10
|
+
"devDependencies",
|
|
11
|
+
"optionalDependencies",
|
|
12
|
+
"peerDependencies"
|
|
13
|
+
];
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/update/discovery.ts
|
|
16
|
+
async function isFile(filePath) {
|
|
17
|
+
return (await fs.stat(filePath).catch(() => null))?.isFile() ?? false;
|
|
18
|
+
}
|
|
19
|
+
async function readManifest(manifestPath) {
|
|
20
|
+
let source;
|
|
21
|
+
try {
|
|
22
|
+
source = await fs.readFile(manifestPath, "utf8");
|
|
23
|
+
} catch {
|
|
24
|
+
throw new Error(`Unable to read manifest: ${manifestPath}`);
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const value = JSON.parse(source.replace(/^\uFEFF/, ""));
|
|
28
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error();
|
|
29
|
+
return value;
|
|
30
|
+
} catch {
|
|
31
|
+
throw new Error(`Malformed package manifest: ${manifestPath}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function packageWorkspacePatterns(manifest) {
|
|
35
|
+
if (!("workspaces" in manifest)) return null;
|
|
36
|
+
const declaration = manifest.workspaces;
|
|
37
|
+
const patterns = Array.isArray(declaration) ? declaration : declaration && typeof declaration === "object" && !Array.isArray(declaration) ? declaration.packages : null;
|
|
38
|
+
if (!Array.isArray(patterns) || patterns.some((pattern) => typeof pattern !== "string")) throw new Error("Invalid package.json workspaces declaration; expected an array of paths.");
|
|
39
|
+
return patterns;
|
|
40
|
+
}
|
|
41
|
+
async function pnpmWorkspacePatterns(root) {
|
|
42
|
+
const workspacePath = path.join(root, "pnpm-workspace.yaml");
|
|
43
|
+
if (!await isFile(workspacePath)) return null;
|
|
44
|
+
const source = await fs.readFile(workspacePath, "utf8");
|
|
45
|
+
let value;
|
|
46
|
+
try {
|
|
47
|
+
value = load(source);
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error(`Malformed pnpm workspace declaration: ${workspacePath}`);
|
|
50
|
+
}
|
|
51
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid pnpm workspace declaration; expected a mapping with packages.");
|
|
52
|
+
const packages = value.packages;
|
|
53
|
+
if (!Array.isArray(packages) || packages.some((pattern) => typeof pattern !== "string")) throw new Error("Invalid pnpm workspace declaration; expected packages to be an array.");
|
|
54
|
+
return packages;
|
|
55
|
+
}
|
|
56
|
+
async function findProjectRoot(start) {
|
|
57
|
+
const resolved = path.resolve(start);
|
|
58
|
+
if (!(await fs.stat(resolved).catch(() => null))?.isDirectory()) throw new Error(`Working directory does not exist: ${resolved}`);
|
|
59
|
+
let directory = resolved;
|
|
60
|
+
let nearestManifestDirectory = null;
|
|
61
|
+
while (true) {
|
|
62
|
+
const manifestPath = path.join(directory, "package.json");
|
|
63
|
+
const hasManifest = await isFile(manifestPath);
|
|
64
|
+
if (hasManifest) {
|
|
65
|
+
const manifest = await readManifest(manifestPath);
|
|
66
|
+
nearestManifestDirectory ??= directory;
|
|
67
|
+
if (packageWorkspacePatterns(manifest) !== null) return directory;
|
|
68
|
+
}
|
|
69
|
+
if (await isFile(path.join(directory, "pnpm-workspace.yaml"))) {
|
|
70
|
+
if (!hasManifest) throw new Error(`Workspace root is missing package.json: ${directory}`);
|
|
71
|
+
await pnpmWorkspacePatterns(directory);
|
|
72
|
+
return directory;
|
|
73
|
+
}
|
|
74
|
+
const parent = path.dirname(directory);
|
|
75
|
+
if (parent === directory) break;
|
|
76
|
+
directory = parent;
|
|
77
|
+
}
|
|
78
|
+
if (nearestManifestDirectory) return nearestManifestDirectory;
|
|
79
|
+
throw new Error(`No package.json found from ${resolved}.`);
|
|
80
|
+
}
|
|
81
|
+
function parsePolicy(manifest) {
|
|
82
|
+
const empty = {
|
|
83
|
+
ignore: [],
|
|
84
|
+
tags: {}
|
|
85
|
+
};
|
|
86
|
+
if (!("askr" in manifest)) return empty;
|
|
87
|
+
if (!manifest.askr || typeof manifest.askr !== "object" || Array.isArray(manifest.askr)) throw new Error("Invalid askr update configuration in the workspace root.");
|
|
88
|
+
const update = manifest.askr.update;
|
|
89
|
+
if (update === void 0) return empty;
|
|
90
|
+
if (!update || typeof update !== "object" || Array.isArray(update)) throw new Error("Invalid askr.update configuration in the workspace root.");
|
|
91
|
+
const config = update;
|
|
92
|
+
const ignore = config.ignore ?? [];
|
|
93
|
+
const tags = config.tags ?? {};
|
|
94
|
+
if (!Array.isArray(ignore) || ignore.some((entry) => typeof entry !== "string")) throw new Error("Invalid askr.update.ignore configuration; expected an array of patterns.");
|
|
95
|
+
if (!tags || typeof tags !== "object" || Array.isArray(tags) || Object.entries(tags).some(([name, tag]) => !name || typeof tag !== "string" || !tag)) throw new Error("Invalid askr.update.tags configuration; expected package-to-tag strings.");
|
|
96
|
+
return {
|
|
97
|
+
ignore,
|
|
98
|
+
tags
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function relativeManifestPath(root, manifestPath) {
|
|
102
|
+
return path.relative(root, manifestPath).split(path.sep).join("/") || "package.json";
|
|
103
|
+
}
|
|
104
|
+
function workspaceName(manifest, fallback) {
|
|
105
|
+
return typeof manifest.name === "string" && manifest.name.trim() ? manifest.name : fallback;
|
|
106
|
+
}
|
|
107
|
+
const WORKSPACE_GLOB_OPTIONS = {
|
|
108
|
+
dot: true,
|
|
109
|
+
nocase: process.platform === "win32",
|
|
110
|
+
windowsPathsNoEscape: true
|
|
111
|
+
};
|
|
112
|
+
function normalizeWorkspacePattern(pattern) {
|
|
113
|
+
const leadingBangs = pattern.match(/^!+/)?.[0].length ?? 0;
|
|
114
|
+
const negative = leadingBangs % 2 === 1;
|
|
115
|
+
let value = pattern.slice(leadingBangs);
|
|
116
|
+
value = value.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
117
|
+
if (value.endsWith("/package.json")) value = value.slice(0, -13);
|
|
118
|
+
if (value === ".." || value.startsWith("../")) throw new Error(`Workspace patterns outside the project root are unsupported: ${pattern}`);
|
|
119
|
+
return {
|
|
120
|
+
negative,
|
|
121
|
+
value: value || "."
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function matchesWorkspace(relativeDirectory, patterns) {
|
|
125
|
+
let included = false;
|
|
126
|
+
for (const pattern of patterns) {
|
|
127
|
+
const normalized = normalizeWorkspacePattern(pattern);
|
|
128
|
+
if (minimatch(relativeDirectory, normalized.value, WORKSPACE_GLOB_OPTIONS)) included = !normalized.negative;
|
|
129
|
+
}
|
|
130
|
+
return included;
|
|
131
|
+
}
|
|
132
|
+
function mayContainWorkspace(relativeDirectory, patterns) {
|
|
133
|
+
return patterns.some((pattern) => {
|
|
134
|
+
const normalized = normalizeWorkspacePattern(pattern);
|
|
135
|
+
return !normalized.negative && minimatch(relativeDirectory, normalized.value, {
|
|
136
|
+
...WORKSPACE_GLOB_OPTIONS,
|
|
137
|
+
partial: true
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
async function mapDeclaredWorkspaces(root, patterns) {
|
|
142
|
+
const directories = [];
|
|
143
|
+
if (matchesWorkspace(".", patterns)) directories.push(root);
|
|
144
|
+
const visit = async (directory, relativeDirectory) => {
|
|
145
|
+
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
146
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
149
|
+
const childRelative = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
|
|
150
|
+
if (!mayContainWorkspace(childRelative, patterns)) continue;
|
|
151
|
+
const child = path.join(directory, entry.name);
|
|
152
|
+
const isSymbolicDirectory = entry.isSymbolicLink() && (await fs.stat(child).catch(() => null))?.isDirectory();
|
|
153
|
+
if (!entry.isDirectory() && !isSymbolicDirectory) continue;
|
|
154
|
+
if (matchesWorkspace(childRelative, patterns) && await isFile(path.join(child, "package.json"))) directories.push(child);
|
|
155
|
+
if (!entry.isSymbolicLink()) await visit(child, childRelative);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
await visit(root, "");
|
|
159
|
+
const mapped = /* @__PURE__ */ new Map();
|
|
160
|
+
for (const directory of directories.sort((left, right) => left.localeCompare(right))) {
|
|
161
|
+
const name = workspaceName(await readManifest(path.join(directory, "package.json")), path.basename(directory));
|
|
162
|
+
if (mapped.has(name)) throw new Error(`Multiple workspaces with the same name '${name}'.`);
|
|
163
|
+
mapped.set(name, directory);
|
|
164
|
+
}
|
|
165
|
+
return mapped;
|
|
166
|
+
}
|
|
167
|
+
async function discoverWorkspaces(root) {
|
|
168
|
+
const rootManifestPath = path.join(root, "package.json");
|
|
169
|
+
const rootManifest = await readManifest(rootManifestPath);
|
|
170
|
+
const policy = parsePolicy(rootManifest);
|
|
171
|
+
const packagePatterns = packageWorkspacePatterns(rootManifest) ?? [];
|
|
172
|
+
const pnpmPatterns = await pnpmWorkspacePatterns(root) ?? [];
|
|
173
|
+
const patterns = [...packagePatterns, ...pnpmPatterns];
|
|
174
|
+
const mapped = patterns.length > 0 ? await mapDeclaredWorkspaces(root, patterns) : /* @__PURE__ */ new Map();
|
|
175
|
+
const rootName = workspaceName(rootManifest, "(root)");
|
|
176
|
+
if (mapped.has(rootName)) throw new Error(`Duplicate workspace name '${rootName}' includes the workspace root.`);
|
|
177
|
+
const workspaces = [{
|
|
178
|
+
name: rootName,
|
|
179
|
+
directory: root,
|
|
180
|
+
manifestPath: rootManifestPath,
|
|
181
|
+
relativeManifestPath: "package.json",
|
|
182
|
+
manifest: rootManifest,
|
|
183
|
+
isRoot: true
|
|
184
|
+
}];
|
|
185
|
+
for (const [mappedName, directory] of mapped) {
|
|
186
|
+
const manifestPath = path.join(directory, "package.json");
|
|
187
|
+
const manifest = await readManifest(manifestPath);
|
|
188
|
+
workspaces.push({
|
|
189
|
+
name: workspaceName(manifest, mappedName),
|
|
190
|
+
directory,
|
|
191
|
+
manifestPath,
|
|
192
|
+
relativeManifestPath: relativeManifestPath(root, manifestPath),
|
|
193
|
+
manifest,
|
|
194
|
+
isRoot: false
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
workspaces.sort((left, right) => {
|
|
198
|
+
if (left.isRoot !== right.isRoot) return left.isRoot ? -1 : 1;
|
|
199
|
+
return left.name.localeCompare(right.name) || left.manifestPath.localeCompare(right.manifestPath);
|
|
200
|
+
});
|
|
201
|
+
return {
|
|
202
|
+
policy,
|
|
203
|
+
rootManifest,
|
|
204
|
+
workspaces
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function matchesAny(value, patterns) {
|
|
208
|
+
return patterns.some((pattern) => minimatch(value, pattern, { dot: true }));
|
|
209
|
+
}
|
|
210
|
+
function isRegistryPackageName(packageName) {
|
|
211
|
+
if (!packageName || packageName.length > 214 || /^[._-]/.test(packageName) || /[\s%\\:]/.test(packageName)) return false;
|
|
212
|
+
if (!packageName.startsWith("@")) return !packageName.includes("/");
|
|
213
|
+
const parts = packageName.slice(1).split("/");
|
|
214
|
+
return parts.length === 2 && parts.every((part) => part.length > 0 && !/^[._-]/.test(part));
|
|
215
|
+
}
|
|
216
|
+
function classifySpecification(packageName, specification, directory, localNames) {
|
|
217
|
+
if (localNames.has(packageName)) return {
|
|
218
|
+
kind: "local",
|
|
219
|
+
registryManaged: false,
|
|
220
|
+
reason: "dependency resolves to a discovered workspace"
|
|
221
|
+
};
|
|
222
|
+
if (/^workspace:/i.test(specification)) return {
|
|
223
|
+
kind: "local",
|
|
224
|
+
registryManaged: false,
|
|
225
|
+
reason: "workspace protocol is not registry-managed"
|
|
226
|
+
};
|
|
227
|
+
if (/^link:/i.test(specification)) return {
|
|
228
|
+
kind: "local",
|
|
229
|
+
registryManaged: false,
|
|
230
|
+
reason: "link protocol is not registry-managed"
|
|
231
|
+
};
|
|
232
|
+
if (!isRegistryPackageName(packageName)) return {
|
|
233
|
+
kind: "manual",
|
|
234
|
+
registryManaged: false,
|
|
235
|
+
reason: "invalid registry package name"
|
|
236
|
+
};
|
|
237
|
+
const parsed = parseDependencySpecification(specification);
|
|
238
|
+
if ([
|
|
239
|
+
"file",
|
|
240
|
+
"git",
|
|
241
|
+
"remote"
|
|
242
|
+
].includes(parsed.type)) return {
|
|
243
|
+
kind: "local",
|
|
244
|
+
registryManaged: false,
|
|
245
|
+
reason: `${parsed.type} specification is not registry-managed`
|
|
246
|
+
};
|
|
247
|
+
if (parsed.type === "alias") return {
|
|
248
|
+
kind: "manual",
|
|
249
|
+
registryManaged: false,
|
|
250
|
+
reason: "npm aliases require manual review"
|
|
251
|
+
};
|
|
252
|
+
if (parsed.type === "tag") return {
|
|
253
|
+
kind: "current",
|
|
254
|
+
registryManaged: true,
|
|
255
|
+
reason: "tracking tag is not rewritten"
|
|
256
|
+
};
|
|
257
|
+
if (parsed.type !== "range" && parsed.type !== "version") return {
|
|
258
|
+
kind: "manual",
|
|
259
|
+
registryManaged: false,
|
|
260
|
+
reason: "unsupported dependency specification"
|
|
261
|
+
};
|
|
262
|
+
const analysis = analyzeRange(specification);
|
|
263
|
+
if (analysis.tracking) return {
|
|
264
|
+
kind: "current",
|
|
265
|
+
registryManaged: true,
|
|
266
|
+
reason: analysis.reason
|
|
267
|
+
};
|
|
268
|
+
if (!analysis.shape) return {
|
|
269
|
+
kind: "manual",
|
|
270
|
+
registryManaged: false,
|
|
271
|
+
reason: analysis.reason
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
kind: "fetch",
|
|
275
|
+
registryManaged: true,
|
|
276
|
+
reason: ""
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function collectOccurrences(root, workspaces, localNames, policy, packagePatterns) {
|
|
280
|
+
const occurrences = [];
|
|
281
|
+
for (const workspace of workspaces) for (const section of DEPENDENCY_SECTIONS) {
|
|
282
|
+
const dependencies = workspace.manifest[section];
|
|
283
|
+
if (dependencies === void 0) continue;
|
|
284
|
+
if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) throw new Error(`Invalid ${section} in ${workspace.relativeManifestPath}; expected an object.`);
|
|
285
|
+
for (const [packageName, specification] of Object.entries(dependencies)) {
|
|
286
|
+
if (typeof specification !== "string") throw new Error(`Invalid ${section}.${packageName} in ${workspace.relativeManifestPath}.`);
|
|
287
|
+
if (packagePatterns.length > 0 && !matchesAny(packageName, packagePatterns)) continue;
|
|
288
|
+
if (packagePatterns.length === 0 && matchesAny(packageName, policy.ignore)) continue;
|
|
289
|
+
occurrences.push({
|
|
290
|
+
package: packageName,
|
|
291
|
+
workspace: workspace.name,
|
|
292
|
+
manifestPath: workspace.manifestPath,
|
|
293
|
+
relativeManifestPath: relativeManifestPath(root, workspace.manifestPath),
|
|
294
|
+
section,
|
|
295
|
+
currentSpecification: specification,
|
|
296
|
+
...classifySpecification(packageName, specification, workspace.directory, localNames)
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const sectionOrder = new Map(DEPENDENCY_SECTIONS.map((section, index) => [section, index]));
|
|
301
|
+
occurrences.sort((left, right) => left.package.localeCompare(right.package) || left.workspace.localeCompare(right.workspace) || left.relativeManifestPath.localeCompare(right.relativeManifestPath) || sectionOrder.get(left.section) - sectionOrder.get(right.section));
|
|
302
|
+
return occurrences;
|
|
303
|
+
}
|
|
304
|
+
async function discoverProject(options) {
|
|
305
|
+
const root = await findProjectRoot(options.cwd);
|
|
306
|
+
const { policy, workspaces } = await discoverWorkspaces(root);
|
|
307
|
+
const selectedWorkspaces = options.workspacePatterns.length === 0 ? workspaces : workspaces.filter((workspace) => matchesAny(workspace.name, options.workspacePatterns));
|
|
308
|
+
if (selectedWorkspaces.length === 0) throw new Error("No discovered workspace matches the requested --workspace filters.");
|
|
309
|
+
const localNames = new Set(workspaces.map((workspace) => workspace.name));
|
|
310
|
+
return {
|
|
311
|
+
root,
|
|
312
|
+
workspaces,
|
|
313
|
+
selectedWorkspaces,
|
|
314
|
+
policy,
|
|
315
|
+
occurrences: collectOccurrences(root, selectedWorkspaces, localNames, policy, options.packagePatterns),
|
|
316
|
+
contextOccurrences: collectOccurrences(root, selectedWorkspaces, localNames, {
|
|
317
|
+
ignore: [],
|
|
318
|
+
tags: policy.tags
|
|
319
|
+
}, [])
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
export { discoverProject };
|