@lablup/ui-common-cli 0.2.0-alpha.15 → 0.2.0-alpha.17

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.
@@ -125,14 +125,16 @@ function listAstryxCodemods(repo, from, to) {
125
125
  * @param {string} version ui-common version to record under
126
126
  * @param {{from: string, to: string}} astryx
127
127
  * @param {{codemods: Array<{id: string, version: string, title: string}>, optional: string[]}} listed
128
+ * @param {{from: string, to: string} | null} [lab] the lab canary move, when `--lab` was given
128
129
  */
129
- export function upstreamManifest(repo, version, astryx, listed) {
130
+ export function upstreamManifest(repo, version, astryx, listed, lab = null) {
130
131
  const file = join(repo, CLI_PACKAGE_DIR, "codemods", version, "upstream.json");
131
132
  /** @type {any} */
132
133
  let manifest = {
133
134
  $comment:
134
- "Written by `ui-common sync-astryx`. Astryx codemods consumers need when they upgrade across this ui-common version; `ui-common upgrade` runs them with @lablup/ui-common specifiers swapped for Astryx's.",
135
+ "Written by `ui-common sync-astryx`. Astryx codemods consumers need when they upgrade across this ui-common version; `ui-common upgrade` runs them with @lablup/ui-common specifiers swapped for Astryx's, and moves the consumer's lab pin and core override.",
135
136
  astryx,
137
+ ...(lab ? { lab } : {}),
136
138
  codemods: listed.codemods,
137
139
  optional: listed.optional,
138
140
  };
@@ -143,6 +145,14 @@ export function upstreamManifest(repo, version, astryx, listed) {
143
145
  manifest = {
144
146
  ...manifest,
145
147
  astryx: { from: previous.astryx.from, to: astryx.to },
148
+ ...(lab || previous.lab
149
+ ? {
150
+ lab: {
151
+ from: previous.lab?.from ?? lab.from,
152
+ to: lab?.to ?? previous.lab.to,
153
+ },
154
+ }
155
+ : {}),
146
156
  codemods: [
147
157
  ...previous.codemods,
148
158
  ...listed.codemods.filter((c) => !ids.has(c.id)),
@@ -162,6 +172,23 @@ export function upstreamManifest(repo, version, astryx, listed) {
162
172
  * @param {string} pin the new @astryxdesign/core pin
163
173
  * @returns {Array<{name: string, file: string, after: string}>}
164
174
  */
175
+ /**
176
+ * Where the 0.1 -> 0.2 migration tells a consumer which `@astryxdesign/lab`
177
+ * to add (`requiresPackages` in migration/0.1-to-0.2.json). It is the exact
178
+ * canary ui-common peers on, so it moves with `--lab`.
179
+ */
180
+ export function labRequirementEdits(repo, lab) {
181
+ const name = `${CLI_PACKAGE_DIR}/migration/0.1-to-0.2.json`;
182
+ const file = join(repo, name);
183
+ if (!existsSync(file)) return [];
184
+ const before = readFileSync(file, "utf8");
185
+ const after = before.replace(
186
+ /("@astryxdesign\/lab":\s*")[^"]+(")/g,
187
+ (_, open, close) => `${open}${lab}${close}`,
188
+ );
189
+ return after === before ? [] : [{ name, file, before, after }];
190
+ }
191
+
165
192
  export function labOverrideEdits(repo, pin) {
166
193
  const edits = [];
167
194
  for (const name of ["README.md", "pnpm-workspace.yaml"]) {
@@ -279,6 +306,11 @@ export async function syncAstryxCommand(argv) {
279
306
  for (const edit of labOverrideEdits(repo, target)) {
280
307
  out(` ${edit.name}: lab's core override → ${target}`);
281
308
  }
309
+ if (lab) {
310
+ for (const edit of labRequirementEdits(repo, lab)) {
311
+ out(` ${edit.name}: the lab pin consumers are told to add → ${lab}`);
312
+ }
313
+ }
282
314
 
283
315
  /** @param {string} title @param {string} cmd @param {string[]} args */
284
316
  const step = (title, cmd, args) => {
@@ -328,6 +360,9 @@ export async function syncAstryxCommand(argv) {
328
360
  recordAs,
329
361
  { from: current, to: target },
330
362
  listed,
363
+ lab
364
+ ? { from: pkg.peerDependencies?.[LAB] ?? pkg.devDependencies?.[LAB], to: lab }
365
+ : null,
331
366
  );
332
367
  out(
333
368
  `\nWould record ${manifest.codemods.length} codemod(s) in ${file.slice(repo.length + 1)} (as listed by the installed CLI; the new CLI may add more):`,
@@ -350,6 +385,12 @@ export async function syncAstryxCommand(argv) {
350
385
  writeFileSync(pkgFile, `${JSON.stringify(pkg, null, 2)}\n`);
351
386
  writeFileSync(cliPkgFile, `${JSON.stringify(cliPkg, null, 2)}\n`);
352
387
  out(` package.json and ${CLI_PACKAGE_DIR}/package.json written`);
388
+ if (lab) {
389
+ for (const edit of labRequirementEdits(repo, lab)) {
390
+ writeFileSync(edit.file, edit.after);
391
+ out(` ${edit.name}: the lab pin consumers are told to add moved to ${lab}`);
392
+ }
393
+ }
353
394
  for (const edit of labOverrideEdits(repo, target)) {
354
395
  writeFileSync(edit.file, edit.after);
355
396
  out(` ${edit.name}: lab's core override moved to ${target}`);
@@ -398,6 +439,9 @@ export async function syncAstryxCommand(argv) {
398
439
  recordAs,
399
440
  { from: current, to: target },
400
441
  listed,
442
+ lab
443
+ ? { from: pkg.peerDependencies?.[LAB] ?? pkg.devDependencies?.[LAB], to: lab }
444
+ : null,
401
445
  );
402
446
  mkdirSync(join(file, ".."), { recursive: true });
403
447
  writeFileSync(file, `${JSON.stringify(manifest, null, 2)}\n`);
@@ -19,7 +19,7 @@ import { LAB_PACKAGE, stylexPeer, UIC } from "./map.mjs";
19
19
  /** The CLI package, released in lockstep with ui-common. */
20
20
  export const CLI_PACKAGE = "@lablup/ui-common-cli";
21
21
 
22
- const FIELDS = /** @type {const} */ ([
22
+ export const FIELDS = /** @type {const} */ ([
23
23
  "dependencies",
24
24
  "devDependencies",
25
25
  "peerDependencies",
@@ -37,7 +37,7 @@ function isSorted(object) {
37
37
  * @param {string} name
38
38
  * @param {string} range
39
39
  */
40
- function addDependency(pkg, field, name, range) {
40
+ export function addDependency(pkg, field, name, range) {
41
41
  const current = pkg[field] ?? {};
42
42
  const next = { ...current, [name]: range };
43
43
  pkg[field] = isSorted(current)
@@ -50,8 +50,9 @@ function addDependency(pkg, field, name, range) {
50
50
  * @param {string} to
51
51
  * @returns {{value: string, note?: string} | null}
52
52
  */
53
- function bumpSpec(spec, to) {
54
- if (/^(workspace:|link:|file:|npm:|git|https?:)/.test(spec)) return null;
53
+ export function bumpSpec(spec, to) {
54
+ // `catalog:` names a pnpm catalog entry; the version lives there, not here.
55
+ if (/^(workspace:|link:|file:|npm:|catalog:|git|https?:)/.test(spec)) return null;
55
56
  const simple = /^([\^~]?)v?\d+(\.\d+){0,2}(-[0-9A-Za-z.-]+)?$/.exec(spec.trim());
56
57
  if (simple) return { value: `${simple[1]}${to}` };
57
58
  return {
@@ -166,7 +167,7 @@ export function narrowReactRange(range, floor) {
166
167
  * @param {any} pkg parsed package.json, edited in place
167
168
  * @param {{projectDir?: string, note: (message: string) => void, editFile?: (path: string, edit: (current: string | null) => string | undefined) => void}} ctx
168
169
  */
169
- function addLabOverride(pkg, ctx) {
170
+ export function addLabOverride(pkg, ctx) {
170
171
  const pin = uiCommonPackageJson(targetUiCommonRoot(ctx.projectDir)).dependencies?.[
171
172
  CORE
172
173
  ];
@@ -0,0 +1,24 @@
1
+ {
2
+ "$comment": "Written by `ui-common sync-astryx`. Astryx codemods consumers need when they upgrade across this ui-common version; `ui-common upgrade` runs them with @lablup/ui-common specifiers swapped for Astryx's, and moves the consumer's lab pin and core override.",
3
+ "astryx": {
4
+ "from": "0.6.2",
5
+ "to": "0.6.5"
6
+ },
7
+ "lab": {
8
+ "from": "0.6.2-canary.c9fb1ad",
9
+ "to": "0.6.5-canary.8701623"
10
+ },
11
+ "codemods": [
12
+ {
13
+ "id": "migrate-theme-catalog-to-descriptors",
14
+ "version": "0.6.4",
15
+ "title": "Give each integration theme a typed descriptor instead of the manifest.json catalog"
16
+ },
17
+ {
18
+ "id": "migrate-native-picker-to-presentation",
19
+ "version": "0.6.4",
20
+ "title": "Migrate nativePicker to presentation"
21
+ }
22
+ ],
23
+ "optional": []
24
+ }
@@ -14,6 +14,8 @@
14
14
  */
15
15
  import { importAstryxInternal } from "../cli/paths.mjs";
16
16
  import { rewriteSpecifiers } from "../cli/rewrite.mjs";
17
+ import { LAB_PACKAGE, UIC } from "./0.2/map.mjs";
18
+ import { addLabOverride, bumpSpec, CLI_PACKAGE, FIELDS } from "./0.2/package-json.mjs";
17
19
 
18
20
  const DEFAULT_EXTENSIONS = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
19
21
 
@@ -85,7 +87,7 @@ export function swapModuleSpecifiers(j, source, swap) {
85
87
  }
86
88
 
87
89
  /**
88
- * @typedef {{astryx: {from: string, to: string}, codemods: Array<{id: string, version: string, title?: string}>}} UpstreamManifest
90
+ * @typedef {{astryx: {from: string, to: string}, lab?: {from: string, to: string}, codemods: Array<{id: string, version: string, title?: string}>}} UpstreamManifest
89
91
  */
90
92
 
91
93
  /**
@@ -107,6 +109,11 @@ export function wrapAstryxTransform(entry, version) {
107
109
  { path: file.path, source: swapped },
108
110
  { jscodeshift: j, stats: () => {}, report: () => {} },
109
111
  );
112
+ if (out != null && typeof out.then === "function") {
113
+ throw new Error(
114
+ `Astryx codemod "${entry.name}" is asynchronous (not a file transform); run \`ui-common astryx upgrade\` for it.`,
115
+ );
116
+ }
110
117
  if (out == null || out === swapped) return undefined;
111
118
  return swapModuleSpecifiers(j, out, rewriteSpecifiers);
112
119
  },
@@ -145,11 +152,80 @@ export async function upstreamStep(manifest) {
145
152
  );
146
153
  continue;
147
154
  }
155
+ // A project codemod takes the package root and returns a plan of writes,
156
+ // not a file transform; it concerns an Astryx integration package (theme
157
+ // catalogs, manifests), which a ui-common consumer is not.
158
+ if (found.entry.meta?.codemodType === "project") {
159
+ notes.push(
160
+ `Astryx codemod "${codemod.id}" rewrites an Astryx integration package (${found.entry.meta.title}); run \`ui-common astryx upgrade\` if this project is one.`,
161
+ );
162
+ continue;
163
+ }
148
164
  transforms.push(wrapAstryxTransform(found.entry, found.version));
149
165
  }
150
166
  return {
151
167
  title: `Astryx ${manifest.astryx.from} → ${manifest.astryx.to} codemods`,
152
168
  transforms,
153
169
  notes,
170
+ packageJson: (text, ctx) => transformPackageJson(text, ctx, manifest),
154
171
  };
155
172
  }
173
+
174
+ /**
175
+ * The package.json side of an Astryx bump. The codemods above rewrite source;
176
+ * this moves what a consumer pins by hand: the exact `@lablup/ui-common` and
177
+ * `@lablup/ui-common-cli` versions to the target, and, in a project that
178
+ * declares `@astryxdesign/lab`, the lab canary to the one this ui-common
179
+ * peers on, with lab's core override pointed at the new core (the 0.2 step's
180
+ * own logic, reused). Without it an alpha-to-alpha upgrade ran the codemods
181
+ * and left the old lab beside the new core.
182
+ *
183
+ * @param {string} text package.json source
184
+ * @param {{to: string, projectDir?: string, note: (message: string) => void, editFile?: Function}} ctx
185
+ * @param {UpstreamManifest} manifest
186
+ */
187
+ export function transformPackageJson(text, ctx, manifest) {
188
+ const pkg = JSON.parse(text);
189
+ const indent = /^([ \t]+)"/m.exec(text)?.[1] ?? " ";
190
+ const fields = FIELDS.filter((f) => pkg[f]?.[UIC] != null);
191
+ if (fields.length === 0) return undefined;
192
+
193
+ for (const [name, exact] of [
194
+ [UIC, false],
195
+ [CLI_PACKAGE, true],
196
+ ]) {
197
+ for (const field of FIELDS) {
198
+ const spec = pkg[field]?.[name];
199
+ if (spec == null) continue;
200
+ const bumped = bumpSpec(spec, ctx.to);
201
+ if (!bumped) {
202
+ ctx.note(
203
+ `${field}["${name}"] is "${spec}"; not a version, so it was left alone.`,
204
+ );
205
+ continue;
206
+ }
207
+ const value = exact ? ctx.to : bumped.value;
208
+ if (value !== spec) {
209
+ pkg[field][name] = value;
210
+ ctx.note(`${field}["${name}"]: "${spec}" → "${value}".`);
211
+ }
212
+ }
213
+ }
214
+
215
+ const lab = manifest.lab?.to;
216
+ const labFields = FIELDS.filter((f) => pkg[f]?.[LAB_PACKAGE] != null);
217
+ if (lab && labFields.length > 0) {
218
+ for (const field of labFields) {
219
+ const spec = pkg[field][LAB_PACKAGE];
220
+ if (spec === lab || bumpSpec(spec, lab) == null) continue;
221
+ pkg[field][LAB_PACKAGE] = lab;
222
+ ctx.note(
223
+ `${field}["${LAB_PACKAGE}"]: "${spec}" → "${lab}": ${UIC} ${ctx.to} peers on this lab canary exactly.`,
224
+ );
225
+ }
226
+ addLabOverride(pkg, ctx);
227
+ }
228
+
229
+ const out = `${JSON.stringify(pkg, null, indent)}${text.endsWith("\n") ? "\n" : ""}`;
230
+ return out === text ? undefined : out;
231
+ }
@@ -212,7 +212,7 @@
212
212
  "names": { "Drawer": "Drawer", "DrawerProps": "DrawerProps" }
213
213
  },
214
214
  "alternatives": [],
215
- "requiresPackages": { "@astryxdesign/lab": "0.6.2-canary.c9fb1ad" },
215
+ "requiresPackages": { "@astryxdesign/lab": "0.6.5-canary.8701623" },
216
216
  "propRenames": [
217
217
  {
218
218
  "from": "onClose",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lablup/ui-common-cli",
3
- "version": "0.2.0-alpha.15",
3
+ "version": "0.2.0-alpha.17",
4
4
  "description": "The ui-common command line: the pinned Astryx CLI in @lablup/ui-common terms, the agent block, and the upgrade codemods",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Lablup Inc.",
@@ -36,15 +36,15 @@
36
36
  "./package.json": "./package.json"
37
37
  },
38
38
  "dependencies": {
39
- "@astryxdesign/cli": "0.6.2",
39
+ "@astryxdesign/cli": "0.6.5",
40
40
  "jscodeshift": "^17.4.0",
41
41
  "postcss": "^8.5.25",
42
42
  "postcss-selector-parser": "^7.1.6"
43
43
  },
44
44
  "peerDependencies": {
45
- "@lablup/ui-common": "0.2.0-alpha.15"
45
+ "@lablup/ui-common": "0.2.0-alpha.17"
46
46
  },
47
47
  "devDependencies": {
48
- "@lablup/ui-common": "0.2.0-alpha.15"
48
+ "@lablup/ui-common": "0.2.0-alpha.17"
49
49
  }
50
50
  }