@vzn/vx-migrate 0.0.636 → 0.0.638

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.
@@ -4,17 +4,23 @@
4
4
  // and each is installed beside vx at vx-migrate's own version (plugins
5
5
  // pin their core peer to the release they shipped with).
6
6
 
7
- import { existsSync, readdirSync } from 'node:fs'
7
+ import { existsSync } from 'node:fs'
8
8
  import path from 'node:path'
9
+ import { REMOTE_CACHE, remoteCacheSignal } from './remote-cache.js'
9
10
  import { lockfilePlugin } from './workspace-notes.js'
10
11
 
12
+ export { workspaceFileAt } from './workspace-notes.js'
13
+
11
14
  export interface WorkspacePlugin {
12
15
  readonly pkg: string
13
16
  readonly factory: string
14
17
  }
15
18
 
16
- export function workspacePlugins(root: string): WorkspacePlugin[] {
19
+ /** `runner`: the Turbo or Nx repo's own remote cache, where the repo shows one. */
20
+ export function workspacePlugins(root: string, runner?: 'turbo' | 'nx'): WorkspacePlugin[] {
17
21
  const out: WorkspacePlugin[] = []
22
+ if (runner !== undefined && remoteCacheSignal(root, runner) !== undefined)
23
+ out.push({ pkg: '@vzn/vx-migrate', factory: REMOTE_CACHE[runner] })
18
24
  const lock = lockfilePlugin(root)
19
25
  if (lock !== undefined) out.push({ pkg: '@vzn/vx-lockfile', factory: lock.factory })
20
26
  out.push({ pkg: '@vzn/vx-schedule-history', factory: 'scheduleHistoryPlugin' })
@@ -23,11 +29,6 @@ export function workspacePlugins(root: string): WorkspacePlugin[] {
23
29
  return out
24
30
  }
25
31
 
26
- /** The workspace file at `root`, in any extension the loader reads. */
27
- export function workspaceFileAt(root: string): string | undefined {
28
- return readdirSync(root).find((n) => /^vx\.workspace\.(ts|mts|js|mjs|cts|cjs)$/.test(n))
29
- }
30
-
31
32
  /** `plugins` that `text` does not already call. */
32
33
  export function undeclared(text: string, plugins: readonly WorkspacePlugin[]): WorkspacePlugin[] {
33
34
  return plugins.filter((p) => !new RegExp(`\\b${p.factory}\\s*\\(`).test(text))
@@ -41,7 +42,19 @@ function entries(plugins: readonly WorkspacePlugin[], indent: string): string[]
41
42
  return plugins.map((p) => `${indent}${p.factory}(),`)
42
43
  }
43
44
 
44
- /** `vx.workspace.<format>` declaring `plugins`. */
45
+ /** `run.concurrency` and `run.affectedBase` as one `run: { … }` line. */
46
+ function groupLines(
47
+ fields: readonly { readonly field: string; readonly source: string }[],
48
+ ): string[] {
49
+ const groups = new Map<string, string[]>()
50
+ for (const f of fields) {
51
+ const [group, key] = f.field.split('.') as [string, string]
52
+ groups.set(group, [...(groups.get(group) ?? []), `${key}: ${f.source}`])
53
+ }
54
+ return [...groups].map(([group, entries]) => ` ${group}: { ${entries.join(', ')} },`)
55
+ }
56
+
57
+ /** `.vx/workspace.<format>` declaring `plugins`. */
45
58
  export function renderWorkspaceFile(
46
59
  plugins: readonly WorkspacePlugin[],
47
60
  format: 'ts' | 'mjs',
@@ -55,14 +68,14 @@ export function renderWorkspaceFile(
55
68
  ' plugins: [',
56
69
  ...entries(plugins, ' '),
57
70
  ' ],',
58
- ...fields.map((f) => ` ${f.field}: ${f.source},`),
71
+ ...groupLines(fields),
59
72
  `}${format === 'ts' ? ' satisfies WorkspaceConfig' : ''}`,
60
73
  '',
61
74
  ].join('\n')
62
75
  }
63
76
 
64
77
  /**
65
- * Add `plugins` to the file `vx init` writes (`export default { plugins:
78
+ * Add `plugins` to a one-line workspace file (`export default { plugins:
66
79
  * [turbo()] }`); null for any other shape, which is left alone. A plugin
67
80
  * the file already calls is not added twice.
68
81
  */
@@ -83,13 +96,30 @@ export function extendWorkspaceFile(
83
96
  '',
84
97
  'export default {',
85
98
  ' plugins: [',
86
- ...(kept === '' ? [] : [` ${kept},`]),
99
+ ...topLevel(kept).map((k) => ` ${k},`),
87
100
  ...entries(added, ' '),
88
101
  ' ],',
89
102
  `}${tail}`,
90
103
  ].join('\n')
91
104
  }
92
105
 
106
+ /** `a(), b({ x, y })` → `['a()', 'b({ x, y })']`: the commas outside any bracket. */
107
+ function topLevel(list: string): string[] {
108
+ const out: string[] = []
109
+ let depth = 0
110
+ let from = 0
111
+ for (let i = 0; i < list.length; i++) {
112
+ const c = list[i]!
113
+ if ('([{'.includes(c)) depth++
114
+ else if (')]}'.includes(c)) depth--
115
+ else if (c === ',' && depth === 0) {
116
+ out.push(list.slice(from, i))
117
+ from = i + 1
118
+ }
119
+ }
120
+ return [...out, list.slice(from)].map((e) => e.trim()).filter((e) => e !== '')
121
+ }
122
+
93
123
  /**
94
124
  * The plugins of a workspace file vx wrote (`vx init`, `--keep`, a native
95
125
  * migration): `@vzn` imports and argument-less calls, nothing else. Null