@memberjunction/cli 6.1.0-edge.1 → 6.1.0-edge.3

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.
Files changed (91) hide show
  1. package/LICENSE +180 -4
  2. package/README.md +1 -1
  3. package/dist/commands/artifacts/reclassify.d.ts.map +1 -1
  4. package/dist/commands/artifacts/reclassify.js +2 -1
  5. package/dist/commands/artifacts/reclassify.js.map +1 -1
  6. package/dist/commands/codegen/manifest.d.ts +14 -0
  7. package/dist/commands/codegen/manifest.d.ts.map +1 -1
  8. package/dist/commands/codegen/manifest.js +26 -7
  9. package/dist/commands/codegen/manifest.js.map +1 -1
  10. package/dist/commands/dev/index.d.ts +7 -0
  11. package/dist/commands/dev/index.d.ts.map +1 -0
  12. package/dist/commands/dev/index.js +11 -0
  13. package/dist/commands/dev/index.js.map +1 -0
  14. package/dist/commands/dev/usage.d.ts +7 -0
  15. package/dist/commands/dev/usage.d.ts.map +1 -0
  16. package/dist/commands/dev/usage.js +10 -0
  17. package/dist/commands/dev/usage.js.map +1 -0
  18. package/dist/commands/dev/workspace/clean.d.ts +27 -0
  19. package/dist/commands/dev/workspace/clean.d.ts.map +1 -0
  20. package/dist/commands/dev/workspace/clean.js +87 -0
  21. package/dist/commands/dev/workspace/clean.js.map +1 -0
  22. package/dist/commands/dev/workspace/doctor.d.ts +28 -0
  23. package/dist/commands/dev/workspace/doctor.d.ts.map +1 -0
  24. package/dist/commands/dev/workspace/doctor.js +62 -0
  25. package/dist/commands/dev/workspace/doctor.js.map +1 -0
  26. package/dist/commands/dev/workspace/index.d.ts +60 -0
  27. package/dist/commands/dev/workspace/index.d.ts.map +1 -0
  28. package/dist/commands/dev/workspace/index.js +279 -0
  29. package/dist/commands/dev/workspace/index.js.map +1 -0
  30. package/dist/commands/dev/workspace/status.d.ts +19 -0
  31. package/dist/commands/dev/workspace/status.d.ts.map +1 -0
  32. package/dist/commands/dev/workspace/status.js +46 -0
  33. package/dist/commands/dev/workspace/status.js.map +1 -0
  34. package/dist/lib/cli-plugins.d.ts.map +1 -1
  35. package/dist/lib/cli-plugins.js +5 -0
  36. package/dist/lib/cli-plugins.js.map +1 -1
  37. package/dist/lib/dev-workspace/build.d.ts +180 -0
  38. package/dist/lib/dev-workspace/build.d.ts.map +1 -0
  39. package/dist/lib/dev-workspace/build.js +570 -0
  40. package/dist/lib/dev-workspace/build.js.map +1 -0
  41. package/dist/lib/dev-workspace/clean.d.ts +40 -0
  42. package/dist/lib/dev-workspace/clean.d.ts.map +1 -0
  43. package/dist/lib/dev-workspace/clean.js +193 -0
  44. package/dist/lib/dev-workspace/clean.js.map +1 -0
  45. package/dist/lib/dev-workspace/detect.d.ts +56 -0
  46. package/dist/lib/dev-workspace/detect.d.ts.map +1 -0
  47. package/dist/lib/dev-workspace/detect.js +343 -0
  48. package/dist/lib/dev-workspace/detect.js.map +1 -0
  49. package/dist/lib/dev-workspace/dir-flag.d.ts +23 -0
  50. package/dist/lib/dev-workspace/dir-flag.d.ts.map +1 -0
  51. package/dist/lib/dev-workspace/dir-flag.js +24 -0
  52. package/dist/lib/dev-workspace/dir-flag.js.map +1 -0
  53. package/dist/lib/dev-workspace/doctor.d.ts +96 -0
  54. package/dist/lib/dev-workspace/doctor.d.ts.map +1 -0
  55. package/dist/lib/dev-workspace/doctor.js +400 -0
  56. package/dist/lib/dev-workspace/doctor.js.map +1 -0
  57. package/dist/lib/dev-workspace/lockfile.d.ts +62 -0
  58. package/dist/lib/dev-workspace/lockfile.d.ts.map +1 -0
  59. package/dist/lib/dev-workspace/lockfile.js +456 -0
  60. package/dist/lib/dev-workspace/lockfile.js.map +1 -0
  61. package/dist/lib/dev-workspace/member-installs.d.ts +35 -0
  62. package/dist/lib/dev-workspace/member-installs.d.ts.map +1 -0
  63. package/dist/lib/dev-workspace/member-installs.js +139 -0
  64. package/dist/lib/dev-workspace/member-installs.js.map +1 -0
  65. package/dist/lib/dev-workspace/pnpm.d.ts +29 -0
  66. package/dist/lib/dev-workspace/pnpm.d.ts.map +1 -0
  67. package/dist/lib/dev-workspace/pnpm.js +59 -0
  68. package/dist/lib/dev-workspace/pnpm.js.map +1 -0
  69. package/dist/lib/dev-workspace/status.d.ts +16 -0
  70. package/dist/lib/dev-workspace/status.d.ts.map +1 -0
  71. package/dist/lib/dev-workspace/status.js +185 -0
  72. package/dist/lib/dev-workspace/status.js.map +1 -0
  73. package/dist/lib/dev-workspace/types.d.ts +312 -0
  74. package/dist/lib/dev-workspace/types.d.ts.map +1 -0
  75. package/dist/lib/dev-workspace/types.js +14 -0
  76. package/dist/lib/dev-workspace/types.js.map +1 -0
  77. package/dist/lib/dev-workspace/usage.d.ts +30 -0
  78. package/dist/lib/dev-workspace/usage.d.ts.map +1 -0
  79. package/dist/lib/dev-workspace/usage.js +177 -0
  80. package/dist/lib/dev-workspace/usage.js.map +1 -0
  81. package/dist/lib/dev-workspace/write.d.ts +25 -0
  82. package/dist/lib/dev-workspace/write.d.ts.map +1 -0
  83. package/dist/lib/dev-workspace/write.js +75 -0
  84. package/dist/lib/dev-workspace/write.js.map +1 -0
  85. package/dist/light-commands.d.ts.map +1 -1
  86. package/dist/light-commands.js +7 -0
  87. package/dist/light-commands.js.map +1 -1
  88. package/dist/utils/open-app-context.js +1 -1
  89. package/dist/utils/open-app-context.js.map +1 -1
  90. package/oclif.manifest.json +3432 -3173
  91. package/package.json +22 -22
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Teardown for `mj dev workspace clean`.
3
+ *
4
+ * SIDE EFFECTS: this module DELETES the generated files, the lockfile and the
5
+ * `node_modules` tree at the parent directory. Everything it can remove is named
6
+ * by a constant here — it never globs, never shells out to `rm`, and never
7
+ * follows a symlink out of the tree (see {@link removeTarget}).
8
+ *
9
+ * The safety ladder, in the order {@link AssertCleanAllowed} applies it:
10
+ * 1. The parent must not itself be a git repo root — the same guard the
11
+ * generator uses ({@link AssertParentDirSafe}).
12
+ * 2. Without `--force`, a valid sentinel must be present: clean refuses to
13
+ * remove a workspace it cannot prove it generated.
14
+ * 3. Deletion happens only in {@link ExecuteClean}; `--dry-run` stops after
15
+ * {@link PlanClean} + {@link RenderCleanPlan}, which never write.
16
+ *
17
+ * {@link ReadSentinel} is read-only and is shared with the status reporter.
18
+ *
19
+ * @module lib/dev-workspace/clean
20
+ */
21
+ import { existsSync, readFileSync, rmSync } from 'node:fs';
22
+ import path from 'node:path';
23
+ import chalk from 'chalk';
24
+ import { SENTINEL_MARKER } from './build.js';
25
+ import { AssertParentDirSafe, GENERATED_FILE_NAMES, SENTINEL_FILE_NAME, WORKSPACE_FILE_NAMES } from './write.js';
26
+ /** Lockfile `pnpm install` produces at the parent. */
27
+ export const LOCKFILE_NAME = 'pnpm-lock.yaml';
28
+ /** Dependency tree `pnpm install` produces at the parent. */
29
+ export const NODE_MODULES_NAME = 'node_modules';
30
+ /** Largest sentinel we will parse; anything bigger is not something we wrote. */
31
+ const MAX_SENTINEL_BYTES = 100_000;
32
+ /** Retry cap for a single removal (Windows and virus scanners hold file handles briefly). */
33
+ const RM_MAX_RETRIES = 3;
34
+ /**
35
+ * Number of paths clean owns: the four workspace files, the lockfile, the
36
+ * node_modules tree, and the sentinel. Asserted in {@link PlanClean} so editing a
37
+ * file-name constant can never silently widen or narrow what clean deletes.
38
+ */
39
+ export const CLEAN_TARGET_COUNT = WORKSPACE_FILE_NAMES.length + 3;
40
+ /** Type guard: parsed JSON carries our marker and both string lists. */
41
+ function isSentinelShape(value) {
42
+ if (typeof value !== 'object' || value === null)
43
+ return false;
44
+ const record = value;
45
+ return record.generatedBy === SENTINEL_MARKER && isStringArray(record.files) && isStringArray(record.members);
46
+ }
47
+ /** Type guard for a `string[]` inside parsed JSON. */
48
+ function isStringArray(value) {
49
+ return Array.isArray(value) && value.every((item) => typeof item === 'string');
50
+ }
51
+ /** Parses sentinel text. Returns 'valid' or 'invalid' with a reason — never 'absent'. */
52
+ function parseSentinel(raw) {
53
+ let parsed;
54
+ try {
55
+ parsed = JSON.parse(raw);
56
+ }
57
+ catch (error) {
58
+ const message = error instanceof Error ? error.message : String(error);
59
+ return { Kind: 'invalid', Reason: `unparseable JSON: ${message}` };
60
+ }
61
+ if (!isSentinelShape(parsed)) {
62
+ return { Kind: 'invalid', Reason: `no "generatedBy": "${SENTINEL_MARKER}" marker with files and members lists` };
63
+ }
64
+ return { Kind: 'valid', Sentinel: parsed };
65
+ }
66
+ /**
67
+ * Reads the sentinel at a parent directory. Read-only, and never throws for a
68
+ * malformed file: a sentinel that is absent or not ours is a decision the caller
69
+ * makes (refuse, or proceed under `--force`), not a crash.
70
+ */
71
+ export function ReadSentinel(parentDir) {
72
+ const sentinelPath = path.join(parentDir, SENTINEL_FILE_NAME);
73
+ if (!existsSync(sentinelPath))
74
+ return { Kind: 'absent' };
75
+ const raw = readFileSync(sentinelPath, 'utf8');
76
+ if (raw.length > MAX_SENTINEL_BYTES) {
77
+ return { Kind: 'invalid', Reason: `over ${MAX_SENTINEL_BYTES} bytes — not a generated sentinel` };
78
+ }
79
+ return parseSentinel(raw);
80
+ }
81
+ /** Refusal text for a clean with no valid sentinel and no `--force`. */
82
+ function refusalMessage(parentDir, sentinel) {
83
+ const escapeHatch = `clean only removes a workspace it can prove it generated. Re-run with --force to remove ` +
84
+ `${GENERATED_FILE_NAMES.join(', ')}, ${LOCKFILE_NAME} and ${NODE_MODULES_NAME} anyway ` +
85
+ `(--dry-run --force lists them without deleting).`;
86
+ if (sentinel.Kind === 'invalid') {
87
+ return `${path.join(parentDir, SENTINEL_FILE_NAME)} is not a sentinel this tool wrote (${sentinel.Reason}): ${escapeHatch}`;
88
+ }
89
+ return (`No ${SENTINEL_FILE_NAME} at ${parentDir} — this workspace was hand-made, or generated before the ` +
90
+ `sentinel existed: ${escapeHatch}`);
91
+ }
92
+ /**
93
+ * Applies the pre-deletion safety ladder and returns what the sentinel said.
94
+ * Throws when the parent is not a safe workspace parent, or when no valid
95
+ * sentinel is present and `force` was not given.
96
+ */
97
+ export function AssertCleanAllowed(parentDir, force) {
98
+ AssertParentDirSafe(parentDir);
99
+ const sentinel = ReadSentinel(parentDir);
100
+ if (sentinel.Kind === 'valid' || force)
101
+ return sentinel;
102
+ throw new Error(refusalMessage(parentDir, sentinel));
103
+ }
104
+ /**
105
+ * The paths clean owns, in removal order. The sentinel goes LAST on purpose: if a
106
+ * removal fails part-way, the sentinel is still there and a re-run is allowed to
107
+ * finish the job without `--force`.
108
+ */
109
+ function ownedPaths() {
110
+ return [
111
+ ...WORKSPACE_FILE_NAMES.map((Name) => ({ Name, Kind: 'file' })),
112
+ { Name: LOCKFILE_NAME, Kind: 'file' },
113
+ { Name: NODE_MODULES_NAME, Kind: 'directory' },
114
+ { Name: SENTINEL_FILE_NAME, Kind: 'file' },
115
+ ];
116
+ }
117
+ /** `<name>.bak` copies the generator's `--force` path leaves behind. Clean never removes these. */
118
+ function findBackups(parentDir) {
119
+ return GENERATED_FILE_NAMES.map((name) => `${name}.bak`).filter((name) => existsSync(path.join(parentDir, name)));
120
+ }
121
+ /**
122
+ * Builds the removal plan for a parent directory: every owned path with whether it
123
+ * exists right now, plus the `.bak` files that will be left alone. Read-only.
124
+ */
125
+ export function PlanClean(parentDir) {
126
+ if (!path.isAbsolute(parentDir)) {
127
+ throw new Error(`PlanClean requires an absolute path, got: ${parentDir}`);
128
+ }
129
+ const targets = ownedPaths().map((owned) => ({
130
+ ...owned,
131
+ Exists: existsSync(path.join(parentDir, owned.Name)),
132
+ }));
133
+ if (targets.length !== CLEAN_TARGET_COUNT) {
134
+ throw new Error(`clean plan has ${targets.length} targets, expected ${CLEAN_TARGET_COUNT}`);
135
+ }
136
+ return { ParentDir: parentDir, Targets: targets, PreservedBackups: findBackups(parentDir) };
137
+ }
138
+ /**
139
+ * Removes one owned path.
140
+ *
141
+ * `fs.rmSync`'s recursive walk lstats every entry and unlinks symlinks instead of
142
+ * descending into them, so a linked dependency inside `node_modules` can never
143
+ * lead the delete outside the tree. A shell `rm -rf` gives no such guarantee,
144
+ * which is why this never spawns one.
145
+ */
146
+ function removeTarget(targetPath, kind) {
147
+ const recursive = kind === 'directory';
148
+ rmSync(targetPath, { recursive, force: true, maxRetries: RM_MAX_RETRIES });
149
+ }
150
+ /**
151
+ * Deletes every existing target in plan order. Targets that are already absent
152
+ * are reported, not treated as failures. A failed removal aborts and names what
153
+ * had already gone — the sentinel is removed last, so a re-run resumes.
154
+ */
155
+ export function ExecuteClean(plan) {
156
+ const removed = [];
157
+ const alreadyGone = [];
158
+ for (const target of plan.Targets) {
159
+ if (!target.Exists) {
160
+ alreadyGone.push(target.Name);
161
+ continue;
162
+ }
163
+ try {
164
+ removeTarget(path.join(plan.ParentDir, target.Name), target.Kind);
165
+ }
166
+ catch (error) {
167
+ const message = error instanceof Error ? error.message : String(error);
168
+ throw new Error(`Failed to remove ${target.Name} at ${plan.ParentDir}: ${message}. ` +
169
+ `Removed so far: ${removed.join(', ') || '(nothing)'} — re-run clean to finish.`);
170
+ }
171
+ removed.push(target.Name);
172
+ }
173
+ return { Removed: removed, AlreadyGone: alreadyGone };
174
+ }
175
+ /**
176
+ * Renders the `--dry-run` report: only the paths that actually exist (so the list
177
+ * is what a real clean would delete), plus the `.bak` files it would leave. Pure.
178
+ */
179
+ export function RenderCleanPlan(plan) {
180
+ const present = plan.Targets.filter((t) => t.Exists);
181
+ if (present.length === 0) {
182
+ return [chalk.dim(`Nothing to remove at ${plan.ParentDir} — no workspace files, lockfile or node_modules.`)];
183
+ }
184
+ const lines = [chalk.bold(`Would remove at ${plan.ParentDir}:`)];
185
+ for (const target of present) {
186
+ lines.push(` ${target.Name}${target.Kind === 'directory' ? '/ (tree)' : ''}`);
187
+ }
188
+ for (const backup of plan.PreservedBackups) {
189
+ lines.push(chalk.dim(` keeping ${backup} (backups are never removed)`));
190
+ }
191
+ return lines;
192
+ }
193
+ //# sourceMappingURL=clean.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clean.js","sourceRoot":"","sources":["../../../src/lib/dev-workspace/clean.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { CandidateRepo } from './types.js';
2
+ /** Root package name that identifies the MJ monorepo checkout. */
3
+ export declare const MJ_MONOREPO_PACKAGE_NAME = "memberjunction-workspace";
4
+ /** Workspace globs assumed for a member repo that has no `pnpm-workspace.yaml`. */
5
+ export declare const DEFAULT_WORKSPACE_GLOBS: readonly string[];
6
+ export interface DetectOptions {
7
+ /** Override for tests only; defaults to {@link MAX_SIBLING_DIRS}. */
8
+ MaxSiblingDirs?: number;
9
+ }
10
+ /**
11
+ * Converts a workspace glob to an anchored RegExp over repo-relative paths:
12
+ * `*` matches within one segment; `**` matches across `/` INCLUDING zero
13
+ * segments (globstar-zero, as fast-glob/pnpm behave) — so a `!**\/dist\/**`
14
+ * guard rejects `packages/a/dist` itself, not only paths beneath it.
15
+ * Exported for tests.
16
+ */
17
+ export declare function GlobToRegExp(glob: string): RegExp;
18
+ /**
19
+ * Parses the top-level `packages:` list out of a pnpm-workspace.yaml. Pure.
20
+ * Deliberately minimal — pnpm-workspace.yaml's `packages:` list is the only YAML
21
+ * this command reads, so a hand-rolled parser beats a yaml dependency. Handles
22
+ * block lists at any indent (zero included) and single- or multi-line flow style;
23
+ * anchors/aliases and other exotica yield [] and are surfaced by the command's
24
+ * zero-globs warning. Returns every entry verbatim (negations included).
25
+ */
26
+ export declare function ParseWorkspacePackagesGlobs(yamlText: string): string[];
27
+ /** Result of {@link SelectPackagesGlobs}: the globs plus whether the default had to stand in. */
28
+ export interface SelectedPackagesGlobs {
29
+ Globs: string[];
30
+ /** True when the member declared no packages-rooted positive glob and {@link DEFAULT_WORKSPACE_GLOBS} was substituted. */
31
+ UsedFallback: boolean;
32
+ }
33
+ /**
34
+ * Filters a member's declared workspace globs down to the ones this generator
35
+ * re-prefixes. POSITIVE globs must be rooted under `packages/` (producer packages
36
+ * only — app-shell globs like `apps/*` are dropped because shell names collide
37
+ * across repos; see `build.ts`). NEGATIONS are ALL kept, packages-rooted or not
38
+ * (a `!**\/dist\/**` guard included): a negation only subtracts, and dropping one inverts
39
+ * its guard — dist/ copies of package.json would join the workspace (review
40
+ * finding on #3795). Leading `./` is stripped and duplicates collapse. When no
41
+ * packages-rooted positive remains, the default stands in (negations still kept)
42
+ * and `UsedFallback` reports it so the command can warn — a silent fallback was
43
+ * the core #3795 disease. Pure.
44
+ */
45
+ export declare function SelectPackagesGlobs(declaredGlobs: readonly string[]): SelectedPackagesGlobs;
46
+ /**
47
+ * Loads one sibling directory as a repo, with detection reasons.
48
+ * Returns null when the directory has no root package.json (not a repo at all).
49
+ */
50
+ export declare function LoadRepo(parentDir: string, dirName: string): CandidateRepo | null;
51
+ /**
52
+ * Scans the parent directory's immediate subdirectories and returns every
53
+ * candidate member repo, sorted by name.
54
+ */
55
+ export declare function DetectCandidates(parentDir: string, options?: DetectOptions): CandidateRepo[];
56
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/lib/dev-workspace/detect.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAmB,aAAa,EAA8D,MAAM,YAAY,CAAC;AAE7H,kEAAkE;AAClE,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAEnE,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAAmB,CAAC;AAUzE,MAAM,WAAW,aAAa;IAC5B,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAcD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWjD;AA0FD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAWtE;AAoDD,iGAAiG;AACjG,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,0HAA0H;IAC1H,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,qBAAqB,CAe3F;AA8BD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAmBjF;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,aAAa,EAAE,CAoB5F"}
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Member-repo detection for `mj dev workspace`.
3
+ *
4
+ * SIDE EFFECTS: read-only filesystem access (directory listings + JSON reads).
5
+ * All content decisions belong to the pure builders in `build.ts`; this module
6
+ * only loads the metadata they consume.
7
+ *
8
+ * A sibling directory of the parent qualifies as a candidate when it has a root
9
+ * `package.json` AND any of:
10
+ * - it carries an `mj-app.json` (an Open App repo),
11
+ * - any package its workspace globs enumerate mentions the `@mj-biz-apps/`
12
+ * scope in its own name or dependency sections — such a repo either publishes
13
+ * into that scope or consumes it, which is exactly what makes linking it
14
+ * locally worthwhile,
15
+ * - it is the MJ monorepo (root package name `memberjunction-workspace`).
16
+ *
17
+ * Each member's own `pnpm-workspace.yaml` is read here too: its `packages:` globs
18
+ * (positives filtered to packages-rooted ones) become the member's
19
+ * {@link CandidateRepo.WorkspaceGlobs}, so a repo that nests its packages (the MJ
20
+ * monorepo declares 42 globs) contributes all of them to the generated workspace
21
+ * instead of a hardcoded `packages/*` (#3795). Those same globs drive the package
22
+ * ENUMERATION here, so nested packages feed the family `workspace:*` overrides —
23
+ * one-level enumeration would see 59 of MJ's 307 packages. The member's committed
24
+ * lockfile is loaded here too (see `lockfile.ts`).
25
+ *
26
+ * @module lib/dev-workspace/detect
27
+ */
28
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
29
+ import path from 'node:path';
30
+ import { ReadMemberLockfile } from './lockfile.js';
31
+ /** Root package name that identifies the MJ monorepo checkout. */
32
+ export const MJ_MONOREPO_PACKAGE_NAME = 'memberjunction-workspace';
33
+ /** Workspace globs assumed for a member repo that has no `pnpm-workspace.yaml`. */
34
+ export const DEFAULT_WORKSPACE_GLOBS = ['packages/*'];
35
+ /** Hard caps so every walk is bounded; hitting one is an error, not a truncation. */
36
+ const MAX_SIBLING_DIRS = 500;
37
+ const MAX_PACKAGES_PER_REPO = 1000;
38
+ /** Directory-visit cap for one repo's recursive `**` glob walks. */
39
+ const MAX_GLOB_WALK_DIRS = 30_000;
40
+ /** Longest member pnpm-workspace.yaml we will parse (a bigger file is not plausibly one). */
41
+ const MAX_MEMBER_WORKSPACE_YAML_BYTES = 1_000_000;
42
+ /** Reads and parses a JSON file, returning null when absent; throws on unparseable JSON. */
43
+ function readJsonFile(filePath) {
44
+ if (!existsSync(filePath))
45
+ return null;
46
+ const raw = readFileSync(filePath, 'utf8');
47
+ try {
48
+ return JSON.parse(raw);
49
+ }
50
+ catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ throw new Error(`Unparseable JSON at ${filePath}: ${message}`);
53
+ }
54
+ }
55
+ /**
56
+ * Converts a workspace glob to an anchored RegExp over repo-relative paths:
57
+ * `*` matches within one segment; `**` matches across `/` INCLUDING zero
58
+ * segments (globstar-zero, as fast-glob/pnpm behave) — so a `!**\/dist\/**`
59
+ * guard rejects `packages/a/dist` itself, not only paths beneath it.
60
+ * Exported for tests.
61
+ */
62
+ export function GlobToRegExp(glob) {
63
+ const escaped = glob.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
64
+ const pattern = escaped
65
+ .replace(/\/\*\*/g, '<SLASH_GLOBSTAR>')
66
+ .replace(/\*\*\//g, '<GLOBSTAR_SLASH>')
67
+ .replace(/\*\*/g, '<GLOBSTAR>')
68
+ .replace(/\*/g, '[^/]*')
69
+ .replace(/<SLASH_GLOBSTAR>/g, '(?:/.*)?')
70
+ .replace(/<GLOBSTAR_SLASH>/g, '(?:.*/)?')
71
+ .replace(/<GLOBSTAR>/g, '.*');
72
+ return new RegExp(`^${pattern}$`);
73
+ }
74
+ /** True when any of the negation regexes rejects this repo-relative path. */
75
+ function isNegated(relPath, negations) {
76
+ return negations.some((negation) => negation.test(relPath));
77
+ }
78
+ /** Lists immediate subdirectories of a dir, skipping dot-dirs and node_modules. */
79
+ function childDirs(dirPath) {
80
+ if (!existsSync(dirPath) || !statSync(dirPath).isDirectory())
81
+ return [];
82
+ return readdirSync(dirPath, { withFileTypes: true })
83
+ .filter((e) => e.isDirectory() && !e.name.startsWith('.') && e.name !== 'node_modules')
84
+ .map((e) => e.name);
85
+ }
86
+ /** Recursively collects package dirs under `base` for a `base/**` glob (bounded walk). */
87
+ function walkRecursiveGlob(repoPath, base, negations) {
88
+ const found = [];
89
+ const stack = [base];
90
+ let visited = 0;
91
+ while (stack.length > 0) {
92
+ const rel = stack.pop();
93
+ if (++visited > MAX_GLOB_WALK_DIRS) {
94
+ throw new Error(`Glob walk under ${path.join(repoPath, base)} exceeded ${MAX_GLOB_WALK_DIRS} directories — not a plausible packages tree`);
95
+ }
96
+ if (rel !== base && !isNegated(rel, negations) && existsSync(path.join(repoPath, rel, 'package.json'))) {
97
+ found.push(rel);
98
+ }
99
+ for (const child of childDirs(path.join(repoPath, rel))) {
100
+ stack.push(`${rel}/${child}`);
101
+ }
102
+ }
103
+ return found;
104
+ }
105
+ /**
106
+ * Expands one positive glob to package-dir paths relative to the repo root.
107
+ * Supported shapes (100% of those observed in the wild): a fixed path, a
108
+ * trailing `/*` (one level), a trailing `/**` (recursive). Anything else is
109
+ * refused — returned as unsupported so the command reports it, never silent.
110
+ */
111
+ function expandPositiveGlob(repoPath, glob, negations) {
112
+ const hasPackageJson = (rel) => existsSync(path.join(repoPath, rel, 'package.json'));
113
+ if (!glob.includes('*')) {
114
+ const keep = !isNegated(glob, negations) && hasPackageJson(glob);
115
+ return { Dirs: keep ? [glob] : [], Unsupported: false };
116
+ }
117
+ if (glob.endsWith('/*') && !glob.slice(0, -2).includes('*')) {
118
+ const base = glob.slice(0, -2);
119
+ const dirs = childDirs(path.join(repoPath, base))
120
+ .map((child) => `${base}/${child}`)
121
+ .filter((rel) => !isNegated(rel, negations) && hasPackageJson(rel));
122
+ return { Dirs: dirs, Unsupported: false };
123
+ }
124
+ if (glob.endsWith('/**') && !glob.slice(0, -3).includes('*')) {
125
+ return { Dirs: walkRecursiveGlob(repoPath, glob.slice(0, -3), negations), Unsupported: false };
126
+ }
127
+ return { Dirs: [], Unsupported: true };
128
+ }
129
+ /**
130
+ * Enumerates every package the member's own workspace globs cover — nested dirs
131
+ * included, so the family `workspace:*` overrides see all of MJ's 307 packages,
132
+ * not the 59 a one-level scan finds. Bounded; over-cap throws.
133
+ */
134
+ function loadRepoPackages(repoPath, globs) {
135
+ const negations = globs.filter((g) => g.startsWith('!')).map((g) => GlobToRegExp(g.slice(1)));
136
+ const unsupported = [];
137
+ const seen = new Set();
138
+ for (const glob of globs.filter((g) => !g.startsWith('!'))) {
139
+ const expanded = expandPositiveGlob(repoPath, glob, negations);
140
+ if (expanded.Unsupported)
141
+ unsupported.push(glob);
142
+ for (const dir of expanded.Dirs)
143
+ seen.add(dir);
144
+ }
145
+ if (seen.size > MAX_PACKAGES_PER_REPO) {
146
+ throw new Error(`${repoPath} globs enumerate ${seen.size} packages — over the ${MAX_PACKAGES_PER_REPO} cap; not a plausible member repo`);
147
+ }
148
+ const packages = [];
149
+ for (const rel of [...seen].sort()) {
150
+ const pkgJson = readJsonFile(path.join(repoPath, rel, 'package.json'));
151
+ if (pkgJson !== null)
152
+ packages.push({ RelPath: rel, PackageJson: pkgJson });
153
+ }
154
+ return { Packages: packages, UnsupportedGlobs: unsupported };
155
+ }
156
+ /** Matches one YAML block-list entry at ANY indent (zero included): `- value`, `- 'value'`, `- "value"`, optional trailing comment. */
157
+ const YAML_LIST_ENTRY_PATTERN = /^\s*-\s+(?:'([^']*)'|"([^"]*)"|([^\s#][^#]*?))\s*(?:#.*)?$/;
158
+ /** Matches the top-level `packages:` key line, capturing whatever follows the colon. */
159
+ const PACKAGES_KEY_PATTERN = /^packages:\s*(.*)$/;
160
+ /**
161
+ * Parses the top-level `packages:` list out of a pnpm-workspace.yaml. Pure.
162
+ * Deliberately minimal — pnpm-workspace.yaml's `packages:` list is the only YAML
163
+ * this command reads, so a hand-rolled parser beats a yaml dependency. Handles
164
+ * block lists at any indent (zero included) and single- or multi-line flow style;
165
+ * anchors/aliases and other exotica yield [] and are surfaced by the command's
166
+ * zero-globs warning. Returns every entry verbatim (negations included).
167
+ */
168
+ export function ParseWorkspacePackagesGlobs(yamlText) {
169
+ const lines = yamlText.split('\n');
170
+ for (let i = 0; i < lines.length; i++) {
171
+ const match = PACKAGES_KEY_PATTERN.exec(lines[i].trimEnd());
172
+ if (match === null)
173
+ continue;
174
+ const remainder = match[1].trim();
175
+ if (remainder.startsWith('['))
176
+ return parseFlowEntries(lines, i);
177
+ if (remainder.length === 0 || remainder.startsWith('#'))
178
+ return parseBlockEntries(lines, i + 1);
179
+ return []; // `packages: <scalar/anchor>` — not a list this parser understands
180
+ }
181
+ return [];
182
+ }
183
+ /**
184
+ * Reads block-list entries starting at `startIndex`. Blank lines and full-line
185
+ * comments NEVER end the list — a maintainer's `# --- AI ---` section comment
186
+ * inside MJ's 42-glob list must not silently truncate the parse (review finding
187
+ * on #3795: it dropped 39 of 42 globs). Only a line that is not an entry, not
188
+ * blank, and not a comment (i.e. the next `key:` line) ends it.
189
+ */
190
+ function parseBlockEntries(lines, startIndex) {
191
+ const entries = [];
192
+ for (let i = startIndex; i < lines.length; i++) {
193
+ const bare = lines[i].trim();
194
+ if (bare.length === 0 || bare.startsWith('#'))
195
+ continue;
196
+ const match = YAML_LIST_ENTRY_PATTERN.exec(lines[i].trimEnd());
197
+ if (match === null)
198
+ break; // the next key (any indent) ends the list
199
+ const value = match[1] ?? match[2] ?? match[3];
200
+ if (value !== undefined && value.length > 0)
201
+ entries.push(value);
202
+ }
203
+ return entries;
204
+ }
205
+ /**
206
+ * Reads a flow-style list (`packages: ['a', 'b']`), which may span lines, up to
207
+ * its closing bracket. An unterminated list yields whatever was collected — the
208
+ * command's zero-globs warning surfaces any resulting nonsense.
209
+ */
210
+ function parseFlowEntries(lines, keyIndex) {
211
+ const pieces = [];
212
+ let text = lines[keyIndex].slice(lines[keyIndex].indexOf('[') + 1);
213
+ for (let i = keyIndex; i < lines.length; i++) {
214
+ const close = text.indexOf(']');
215
+ if (close >= 0) {
216
+ pieces.push(text.slice(0, close));
217
+ break;
218
+ }
219
+ pieces.push(text);
220
+ text = i + 1 < lines.length ? lines[i + 1].trimEnd() : '';
221
+ }
222
+ return pieces
223
+ .join(',')
224
+ .split(',')
225
+ .map((entry) => stripQuotes(entry.trim()))
226
+ .filter((entry) => entry.length > 0);
227
+ }
228
+ /** Strips one matching pair of surrounding quotes off a scalar, if present. */
229
+ function stripQuotes(value) {
230
+ const match = /^'([^']*)'$|^"([^"]*)"$/.exec(value);
231
+ return match === null ? value : (match[1] ?? match[2] ?? '');
232
+ }
233
+ /**
234
+ * Filters a member's declared workspace globs down to the ones this generator
235
+ * re-prefixes. POSITIVE globs must be rooted under `packages/` (producer packages
236
+ * only — app-shell globs like `apps/*` are dropped because shell names collide
237
+ * across repos; see `build.ts`). NEGATIONS are ALL kept, packages-rooted or not
238
+ * (a `!**\/dist\/**` guard included): a negation only subtracts, and dropping one inverts
239
+ * its guard — dist/ copies of package.json would join the workspace (review
240
+ * finding on #3795). Leading `./` is stripped and duplicates collapse. When no
241
+ * packages-rooted positive remains, the default stands in (negations still kept)
242
+ * and `UsedFallback` reports it so the command can warn — a silent fallback was
243
+ * the core #3795 disease. Pure.
244
+ */
245
+ export function SelectPackagesGlobs(declaredGlobs) {
246
+ const selected = [];
247
+ const seen = new Set();
248
+ for (const raw of declaredGlobs) {
249
+ const negated = raw.startsWith('!');
250
+ const body = (negated ? raw.slice(1) : raw).replace(/^\.\//, '');
251
+ if (!negated && !body.startsWith('packages/'))
252
+ continue;
253
+ const glob = negated ? `!${body}` : body;
254
+ if (seen.has(glob))
255
+ continue;
256
+ seen.add(glob);
257
+ selected.push(glob);
258
+ }
259
+ const hasPositiveGlob = selected.some((glob) => !glob.startsWith('!'));
260
+ if (hasPositiveGlob)
261
+ return { Globs: selected, UsedFallback: false };
262
+ return { Globs: [...DEFAULT_WORKSPACE_GLOBS, ...selected], UsedFallback: true };
263
+ }
264
+ /** Loads a repo's workspace globs, with their provenance, from its pnpm-workspace.yaml (bounded read). */
265
+ function loadWorkspaceGlobs(repoPath) {
266
+ const yamlPath = path.join(repoPath, 'pnpm-workspace.yaml');
267
+ if (!existsSync(yamlPath))
268
+ return { Globs: [...DEFAULT_WORKSPACE_GLOBS], Source: 'no-workspace-yaml' };
269
+ const size = statSync(yamlPath).size;
270
+ if (size > MAX_MEMBER_WORKSPACE_YAML_BYTES) {
271
+ throw new Error(`${yamlPath} is ${size} bytes — over the ${MAX_MEMBER_WORKSPACE_YAML_BYTES} cap; not a plausible pnpm-workspace.yaml`);
272
+ }
273
+ const selected = SelectPackagesGlobs(ParseWorkspacePackagesGlobs(readFileSync(yamlPath, 'utf8')));
274
+ return { Globs: selected.Globs, Source: selected.UsedFallback ? 'workspace-yaml-without-packages-globs' : 'member-workspace-yaml' };
275
+ }
276
+ /** True when any of the package's name/dependency sections mentions the bizapps scope. */
277
+ function mentionsBizAppsScope(pkg) {
278
+ if (pkg.name?.startsWith('@mj-biz-apps/'))
279
+ return true;
280
+ const sections = [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies];
281
+ return sections.some((section) => Object.keys(section ?? {}).some((name) => name.startsWith('@mj-biz-apps/')));
282
+ }
283
+ /** Computes the detection reasons for one sibling repo (empty array = not a candidate). */
284
+ function detectReasons(repoPath, rootPkg, packages) {
285
+ const reasons = [];
286
+ if (existsSync(path.join(repoPath, 'mj-app.json')))
287
+ reasons.push('mj-app-json');
288
+ if (packages.some((p) => mentionsBizAppsScope(p.PackageJson)))
289
+ reasons.push('bizapps-packages');
290
+ if (rootPkg.name === MJ_MONOREPO_PACKAGE_NAME)
291
+ reasons.push('mj-monorepo');
292
+ return reasons;
293
+ }
294
+ /**
295
+ * Loads one sibling directory as a repo, with detection reasons.
296
+ * Returns null when the directory has no root package.json (not a repo at all).
297
+ */
298
+ export function LoadRepo(parentDir, dirName) {
299
+ const repoPath = path.join(parentDir, dirName);
300
+ const rootPkg = readJsonFile(path.join(repoPath, 'package.json'));
301
+ if (rootPkg === null)
302
+ return null;
303
+ const workspaceGlobs = loadWorkspaceGlobs(repoPath);
304
+ const enumerated = loadRepoPackages(repoPath, workspaceGlobs.Globs);
305
+ const turboPath = path.join(repoPath, 'turbo.json');
306
+ return {
307
+ Name: dirName,
308
+ Path: repoPath,
309
+ Reasons: detectReasons(repoPath, rootPkg, enumerated.Packages),
310
+ RootPackageJson: rootPkg,
311
+ Packages: enumerated.Packages,
312
+ UnsupportedGlobs: enumerated.UnsupportedGlobs,
313
+ Lockfile: ReadMemberLockfile(repoPath),
314
+ TurboJson: existsSync(turboPath) ? readFileSync(turboPath, 'utf8') : null,
315
+ WorkspaceGlobs: workspaceGlobs.Globs,
316
+ WorkspaceGlobsSource: workspaceGlobs.Source,
317
+ };
318
+ }
319
+ /**
320
+ * Scans the parent directory's immediate subdirectories and returns every
321
+ * candidate member repo, sorted by name.
322
+ */
323
+ export function DetectCandidates(parentDir, options) {
324
+ if (!path.isAbsolute(parentDir)) {
325
+ throw new Error(`DetectCandidates requires an absolute path, got: ${parentDir}`);
326
+ }
327
+ if (!existsSync(parentDir) || !statSync(parentDir).isDirectory()) {
328
+ throw new Error(`Parent directory does not exist: ${parentDir}`);
329
+ }
330
+ const maxSiblings = options?.MaxSiblingDirs ?? MAX_SIBLING_DIRS;
331
+ const dirs = readdirSync(parentDir, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith('.') && e.name !== 'node_modules');
332
+ if (dirs.length > maxSiblings) {
333
+ throw new Error(`${parentDir} has ${dirs.length} subdirectories — over the ${maxSiblings} cap; is this really the repos' parent dir?`);
334
+ }
335
+ const candidates = [];
336
+ for (const dir of dirs) {
337
+ const repo = LoadRepo(parentDir, dir.name);
338
+ if (repo !== null && repo.Reasons.length > 0)
339
+ candidates.push(repo);
340
+ }
341
+ return candidates.sort((a, b) => a.Name.localeCompare(b.Name));
342
+ }
343
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../src/lib/dev-workspace/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * The `--dir` contract shared by every `mj dev workspace` command.
3
+ *
4
+ * NO SIDE EFFECTS: a constant and a pure function. oclif does the actual
5
+ * resolution (its `env` flag binding gives flag > env > default for free); this
6
+ * module only names the variable and reports which input won, so `status` can
7
+ * tell the user where its parent directory came from.
8
+ *
9
+ * @module lib/dev-workspace/dir-flag
10
+ */
11
+ import type { DirSource } from './types.js';
12
+ /** Environment variable every dev workspace command binds to its `--dir` flag. */
13
+ export declare const WORKSPACE_DIR_ENV_VAR = "MJ_DEV_WORKSPACE_DIR";
14
+ /**
15
+ * Determines which input supplied `--dir`, mirroring oclif's own precedence: an
16
+ * explicit flag beats the environment variable, which beats the default. Pure —
17
+ * the caller passes its raw argv and the environment value, so this never reads
18
+ * `process.env` itself.
19
+ */
20
+ export declare function ResolveDirSource(argv: readonly string[], envValue: string | undefined): DirSource;
21
+ /** How a resolved `--dir` should be described in output. */
22
+ export declare function DescribeDirSource(source: DirSource): string;
23
+ //# sourceMappingURL=dir-flag.d.ts.map