@mittwald/flow-codemods 1.1.43 → 1.1.44

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.
@@ -39,6 +39,21 @@ const keptSubpaths = new Set([
39
39
  // owned by password-tools-subpath-renamed
40
40
  "password-tools",
41
41
  ]);
42
+ /**
43
+ * Splits a bundler's asset query or fragment off a specifier. `all.css?url` is
44
+ * the subpath `all.css`, requested as a URL — not a subpath named
45
+ * `all.css?url`. Matching the whole string carried the suffix past the
46
+ * leave-alone set and into the catch-all below, which rewrote `import
47
+ * flowStyles from "…/all.css?url"` into a named import of a JS export that does
48
+ * not exist, and `import "…/all-layered.css?inline"` into a side-effect import
49
+ * of the package root — stylesheet gone, no error anywhere.
50
+ */
51
+ const splitAssetSuffix = (subpath) => {
52
+ const suffixAt = subpath.search(/[?#]/);
53
+ return suffixAt === -1
54
+ ? [subpath, ""]
55
+ : [subpath.slice(0, suffixAt), subpath.slice(suffixAt)];
56
+ };
42
57
  const importsToPackageRootTransform = (fileInfo, { j }) => {
43
58
  const flowPackage = "@mittwald/flow-react-components";
44
59
  const root = j(fileInfo.source, {
@@ -50,14 +65,21 @@ const importsToPackageRootTransform = (fileInfo, { j }) => {
50
65
  .forEach((i) => {
51
66
  const specifiers = i.node.specifiers ?? [];
52
67
  const importPath = String(i.node.source.value);
53
- const importRelativePath = importPath.slice(flowPackage.length + 1);
68
+ const [importRelativePath, assetSuffix] = splitAssetSuffix(importPath.slice(flowPackage.length + 1));
54
69
  if (keptSubpaths.has(importRelativePath)) {
55
70
  return;
56
71
  }
57
72
  if (importRelativePath === "all.css" ||
58
73
  importRelativePath === "globals.css" ||
59
74
  importRelativePath === "global.css") {
60
- i.node.source.value = `${flowPackage}/all.css`;
75
+ i.node.source.value = `${flowPackage}/all.css${assetSuffix}`;
76
+ return;
77
+ }
78
+ // Everything below rewrites a *module* import: it moves the specifier
79
+ // onto a JS entry and turns a default specifier into a named one. An
80
+ // asset import survives neither, and a suffix reaching this point names a
81
+ // path this transform cannot resolve to an export — leave it to a human.
82
+ if (assetSuffix !== "") {
61
83
  return;
62
84
  }
63
85
  if (importRelativePath.startsWith("react-hook-form")) {
@@ -23,11 +23,22 @@ const passwordToolsRuleTransform = (fileInfo, { j }) => {
23
23
  const flowPackages = [
24
24
  "@mittwald/flow-react-components/mittwald-password-tools-js",
25
25
  ];
26
+ /**
27
+ * The same entry under the name it had when this change shipped. It was
28
+ * renamed later (alpha.1000, `password-tools-subpath-renamed`), and `since`
29
+ * puts that rename _after_ this transform — so a consumer coming from before
30
+ * alpha.802 still spells the import `password-tools` when this runs, and
31
+ * matching only the current name left `AsyncRule` untouched for the rename to
32
+ * carry onto an entry that does not export it. Kept out of `flowPackages`
33
+ * because `remoteScope.test.ts` holds every name in there against the export
34
+ * map the packages have _today_, where this one is gone.
35
+ */
36
+ const renamedFlowPackage = "@mittwald/flow-react-components/password-tools";
26
37
  const renames = new Map([
27
38
  ["AsyncRule", "Rule"],
28
39
  ["SyncRule", "Rule"],
29
40
  ]);
30
- const isFlowImport = (source) => flowPackages.includes(source);
41
+ const isFlowImport = (source) => flowPackages.includes(source) || source === renamedFlowPackage;
31
42
  // ast-types models `importKind` on the declaration only, while babel also
32
43
  // puts it on the specifier — which is where a per-specifier `type X` lives.
33
44
  const isTypeOnly = (specifier) => specifier.importKind === "type";
@@ -12,9 +12,11 @@ const newPath = "@mittwald/flow-react-components/all.css";
12
12
  * always the side-effect form (`import "…/styles"`), which is why that case is
13
13
  * the one the fixtures lead with.
14
14
  *
15
- * Exact match, not a prefix: `./styles` was a single export with nothing
16
- * underneath it, so there is no deeper path to rewrite and no risk of touching
17
- * an unrelated `styles` of someone else's.
15
+ * Exact match on the path, not a prefix: `./styles` was a single export with
16
+ * nothing underneath it, so there is no deeper path to rewrite and no risk of
17
+ * touching an unrelated `styles` of someone else's. A bundler query or fragment
18
+ * (`?url`, `?inline`) is split off before that comparison and carried over — it
19
+ * addresses the export, it does not name a different one.
18
20
  *
19
21
  * What this cannot reach is an `@import` in a `.css` or `.scss` file —
20
22
  * jscodeshift only walks the JavaScript and TypeScript extensions. `apply` says
@@ -23,11 +25,23 @@ const newPath = "@mittwald/flow-react-components/all.css";
23
25
  const renamedCssExportTransform = (fileInfo, { j }) => {
24
26
  const root = j(fileInfo.source, { parser: "tsx" });
25
27
  let changed = false;
28
+ // A bundler addresses an asset through a query or fragment on the specifier,
29
+ // so `…/styles?url` is the old export requested as a URL. The rename applies
30
+ // to it just the same: match the path, carry the suffix over. Comparing the
31
+ // whole string leaves it pointing at an export the package no longer has.
26
32
  const rewrite = (node) => {
27
- if (node.value === oldPath) {
28
- node.value = newPath;
29
- changed = true;
33
+ if (typeof node.value !== "string") {
34
+ return;
30
35
  }
36
+ const suffixAt = node.value.search(/[?#]/);
37
+ const [path, suffix] = suffixAt === -1
38
+ ? [node.value, ""]
39
+ : [node.value.slice(0, suffixAt), node.value.slice(suffixAt)];
40
+ if (path !== oldPath) {
41
+ return;
42
+ }
43
+ node.value = `${newPath}${suffix}`;
44
+ changed = true;
31
45
  };
32
46
  // import … from "…", import "…"
33
47
  root.find(j.ImportDeclaration).forEach((path) => rewrite(path.node.source));
@@ -235,7 +235,7 @@ export const migrations = [
235
235
  kind: "migration",
236
236
  action: "codemod",
237
237
  remotePackage: false,
238
- apply: 'Rewrite every subdirectory import from `@mittwald/flow-react-components` to the package root, except `react-hook-form` and `nextjs`, which move to `@mittwald/flow-react-components/react-hook-form` and `@mittwald/flow-react-components/nextjs`. If you hit missing module errors, set `"module": "esnext"` in `tsconfig.json`.',
238
+ apply: 'Rewrite every subdirectory import from `@mittwald/flow-react-components` to the package root, except `react-hook-form` and `nextjs`, which move to `@mittwald/flow-react-components/react-hook-form` and `@mittwald/flow-react-components/nextjs`. Asset imports are not part of this: a CSS specifier stays a CSS specifier — `all.css` and `all-layered.css` unchanged, a stale `global.css` or `globals.css` rewritten to `all.css` — and keeps any bundler query it carries (`?url`, `?inline`, `?raw`). It never becomes a named import from the package root, which has no JS binding behind a stylesheet. If you hit missing module errors, set `"module": "esnext"` in `tsconfig.json`.',
239
239
  },
240
240
  {
241
241
  id: "renamed-css-export",
@@ -244,6 +244,6 @@ export const migrations = [
244
244
  kind: "migration",
245
245
  action: "codemod",
246
246
  remotePackage: false,
247
- apply: "Replace the import `@mittwald/flow-react-components/styles` with `@mittwald/flow-react-components/all.css`. A codemod does this for JavaScript and TypeScript files. An `@import` of the old path inside a `.css` or `.scss` file is not covered — search for it by hand.",
247
+ apply: "Replace the import `@mittwald/flow-react-components/styles` with `@mittwald/flow-react-components/all.css`, keeping any bundler query the specifier carries (`.../styles?url` becomes `.../all.css?url`). A codemod does this for JavaScript and TypeScript files. An `@import` of the old path inside a `.css` or `.scss` file is not covered — search for it by hand.",
248
248
  },
249
249
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mittwald/flow-codemods",
3
- "version": "1.1.43",
3
+ "version": "1.1.44",
4
4
  "type": "module",
5
5
  "description": "Codemods and an upgrade CLI for consumers of Flow, mittwald's design system",
6
6
  "homepage": "https://flow.mittwald.de",
@@ -38,5 +38,5 @@
38
38
  "vitest": "^4.1.11",
39
39
  "yaml": "^2.8.1"
40
40
  },
41
- "gitHead": "0bdee16eb75f00f81efc3601b406e38c9a15e66e"
41
+ "gitHead": "14793f4989dd6a07c685b2b4d9fba9f077db9da9"
42
42
  }