bestax-migrate 2.2.0 → 2.2.1

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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Minimal semver-range reading for the manifest passes, shared by every source.
3
+ *
4
+ * Not a semver implementation: the workspace deliberately carries no `semver`
5
+ * dependency for this, and the two questions the passes ask are narrow. Both
6
+ * are answered conservatively, so an unrecognised shape is left alone rather
7
+ * than guessed at. The one thing this file must never do is rewrite a value it
8
+ * does not understand, so every accepting path below goes through one grammar.
9
+ */
10
+ /**
11
+ * True only when `range` PROVABLY admits no version >= 1.0.0.
12
+ *
13
+ * The first version of this matched a leading `0` and nothing else, so a range
14
+ * written as comparators (`>=0.7 <1`) was left on 0.x and then reported as
15
+ * already v1. It lived in the rbx source only; the react-bulma-components
16
+ * manifest pass kept the regex until review found the unported half.
17
+ * This walks each `||` alternative and its comparators: a set is pre-v1 when
18
+ * some comparator caps it below 1.0.0 and none of them opens it at 1 or above.
19
+ *
20
+ * Conservative by design: an unrecognised shape returns false and the range is
21
+ * left alone (and reported as such). Bumping a range that might already admit
22
+ * v1 would be the best-guess rewrite this package refuses to make.
23
+ */
24
+ export declare function isPreV1(range: string): boolean;
25
+ /**
26
+ * True when every comparator in every alternative parses to a semver major,
27
+ * so the headline can tell "already v1" apart from "not a version range at
28
+ * all" (`latest`, a git URL) rather than calling both v1.
29
+ */
30
+ export declare function isRecognisedRange(range: string): boolean;
31
+ //# sourceMappingURL=semver-range.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semver-range.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/semver-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA4BH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAG9C;AAgGD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAoBxD"}
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Minimal semver-range reading for the manifest passes, shared by every source.
3
+ *
4
+ * Not a semver implementation: the workspace deliberately carries no `semver`
5
+ * dependency for this, and the two questions the passes ask are narrow. Both
6
+ * are answered conservatively, so an unrecognised shape is left alone rather
7
+ * than guessed at. The one thing this file must never do is rewrite a value it
8
+ * does not understand, so every accepting path below goes through one grammar.
9
+ */
10
+ const NUMERIC = String.raw `(?:0|[1-9]\d*)`;
11
+ const WILD = String.raw `(?:x|X|\*)`;
12
+ // SemVer's own identifier grammar: dot-separated, non-empty, no leading zero on
13
+ // a numeric prerelease identifier. Looser fragments accepted `0.9.0-alpha..1`,
14
+ // `0.9.0-01` and `0.9.0+foo..bar` as complete versions and overwrote them.
15
+ const PRE_ID = String.raw `(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)`;
16
+ const PRERELEASE = String.raw `-${PRE_ID}(?:\.${PRE_ID})*`;
17
+ const BUILD = String.raw `\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*`;
18
+ /**
19
+ * An exclusive upper bound that sits exactly at 1.0.0: `1`, `1.0`, `1.0.0`,
20
+ * and the x-ranges that desugar to it (`1.x`, `1.0.x`, `1.*`), optionally with
21
+ * build metadata, which carries no precedence. `1.1.x` desugars to 1.1.0 and
22
+ * still admits 1.0.x, so it is deliberately not here.
23
+ */
24
+ const STABLE_ONE_BOUND = new RegExp(`^1(?:\\.(?:0|${WILD}))?(?:\\.(?:0|${WILD}))?(?:${BUILD})?$`);
25
+ /**
26
+ * A plain version or x-range: `N`, `N.N`, `N.N.N[-pre][+build]`, `N.x`,
27
+ * `N.x.x`, `N.N.x`. SemVer forbids leading zeros in numeric parts, and once a
28
+ * component is a wildcard everything after it must be a wildcard or omitted.
29
+ */
30
+ const VERSION = new RegExp(`^(${NUMERIC})(?:\\.(?:${NUMERIC}(?:\\.(?:${WILD}|${NUMERIC}(?:${PRERELEASE})?(?:${BUILD})?))?|${WILD}(?:\\.${WILD})?))?$`);
31
+ /**
32
+ * True only when `range` PROVABLY admits no version >= 1.0.0.
33
+ *
34
+ * The first version of this matched a leading `0` and nothing else, so a range
35
+ * written as comparators (`>=0.7 <1`) was left on 0.x and then reported as
36
+ * already v1. It lived in the rbx source only; the react-bulma-components
37
+ * manifest pass kept the regex until review found the unported half.
38
+ * This walks each `||` alternative and its comparators: a set is pre-v1 when
39
+ * some comparator caps it below 1.0.0 and none of them opens it at 1 or above.
40
+ *
41
+ * Conservative by design: an unrecognised shape returns false and the range is
42
+ * left alone (and reported as such). Bumping a range that might already admit
43
+ * v1 would be the best-guess rewrite this package refuses to make.
44
+ */
45
+ export function isPreV1(range) {
46
+ const alternatives = range.trim().split(/\s*\|\|\s*/);
47
+ return alternatives.length > 0 && alternatives.every(setIsPreV1);
48
+ }
49
+ function setIsPreV1(set) {
50
+ // npm accepts whitespace between an operator and its version
51
+ // (`>= 0.7.0 < 1.0.0`); splitting on whitespace first made the operator a
52
+ // token of its own, so the range parsed as unrecognised and was left alone.
53
+ const text = glueOperators(set);
54
+ if (text === '' || /^(\*|x|X|latest)$/.test(text))
55
+ return false;
56
+ const hyphen = text.match(/^(\S+)\s+-\s+(\S+)$/);
57
+ if (hyphen) {
58
+ // Both endpoints must be plain versions; `not-a-range - 0.9.4` was
59
+ // accepted on its upper bound alone and overwritten.
60
+ const lower = versionMajor(hyphen[1]);
61
+ const upper = versionMajor(hyphen[2]);
62
+ if (lower === null || upper === null)
63
+ return false;
64
+ return upper === 0 || (upper === 1 && isPrereleaseOfOne(hyphen[2]));
65
+ }
66
+ let cappedBelowOne = false;
67
+ for (const token of text.split(/\s+/)) {
68
+ const match = token.match(/^(>=|<=|>|<|=)?(.*)$/);
69
+ if (!match)
70
+ return false;
71
+ const [, op = '', version] = match;
72
+ // After a comparator only a plain version may follow: `==0.9.4` and
73
+ // `<^0.9` were each read by stripping a second operator, then overwritten.
74
+ const major = op ? versionMajor(version) : majorOf(version);
75
+ if (major === null)
76
+ return false;
77
+ const plain = version.replace(/^v/, '');
78
+ switch (op) {
79
+ case '>':
80
+ case '>=':
81
+ // A lower bound on a 1.0.0 prerelease (`>=1.0.0-rc.1`) does not open
82
+ // the range at a stable v1; keep scanning for an upper cap.
83
+ if (major >= 1 && !isPrereleaseOfOne(version))
84
+ return false;
85
+ break;
86
+ case '<':
87
+ // `<1`, `<1.0`, `<1.0.0` (build metadata carries no precedence, so
88
+ // `<1.0.0+build.1` is the same) exclude every stable v1, as does a
89
+ // prerelease of 1.0.0 (`<1.0.0-0`, `<1.0.0-rc.1`); `<0.9` does too.
90
+ // A higher upper bound (`<2` in `<1 <2`) never widens the set, so it
91
+ // is neutral rather than disqualifying; the result still needs some
92
+ // other comparator to cap it. Alone, `<2` therefore stays unbumped.
93
+ if (major === 0 ||
94
+ (major === 1 && STABLE_ONE_BOUND.test(plain)) ||
95
+ isPrereleaseOfOne(version)) {
96
+ cappedBelowOne = true;
97
+ }
98
+ break;
99
+ case '<=':
100
+ // `<=1.0.0-0` caps at the lowest 1.0.0 prerelease, so it excludes
101
+ // every stable v1 just as `<1.0.0-0` does. A higher inclusive bound
102
+ // is neutral for the same reason as above.
103
+ if (major === 0 || isPrereleaseOfOne(version)) {
104
+ cappedBelowOne = true;
105
+ }
106
+ break;
107
+ default:
108
+ // `0.9.4`, `=0.9.4`, `^0.9`, `~0.7.5`, `0.x`: caret and tilde never
109
+ // cross a major, so major 0 stays below 1. An exact `1.0.0-rc.1` pins
110
+ // a prerelease and admits no stable v1 either; `^1.0.0-rc.1` does.
111
+ if (major === 0) {
112
+ cappedBelowOne = true;
113
+ }
114
+ else if (!/^[~^]/.test(version) &&
115
+ isPrereleaseOfOne(version.replace(/^=/, ''))) {
116
+ cappedBelowOne = true;
117
+ }
118
+ else {
119
+ return false;
120
+ }
121
+ }
122
+ }
123
+ return cappedBelowOne;
124
+ }
125
+ /**
126
+ * `1.0.0-0`, `1.0.0-rc.1`: a prerelease of exactly 1.0.0 orders below every
127
+ * stable 1.x, so as an upper bound or an exact pin it admits no usable v1.
128
+ * Three numeric parts only, matching semver; `1.0-beta` is not a token this
129
+ * parser reads and is left alone. A caret or tilde on one is different
130
+ * (`^1.0.0-rc.1` admits 1.0.4), which is why the callers check the operator.
131
+ * Accepts the same optional `v` that the version grammar does.
132
+ */
133
+ function isPrereleaseOfOne(version) {
134
+ return /^v?1\.0\.0-/.test(version);
135
+ }
136
+ function glueOperators(set) {
137
+ // Only when what follows starts a plain version. Gluing unconditionally
138
+ // turned the invalid `> =0.7` into a valid `>=0.7`, which was then bumped.
139
+ // node-semver normalises a spaced tilde or caret (`~ 0.7.5`) the same way.
140
+ return set.trim().replace(/(>=|<=|>|<|=|~|\^)\s+(?=[0-9vxX*])/g, '$1');
141
+ }
142
+ /**
143
+ * True when every comparator in every alternative parses to a semver major,
144
+ * so the headline can tell "already v1" apart from "not a version range at
145
+ * all" (`latest`, a git URL) rather than calling both v1.
146
+ */
147
+ export function isRecognisedRange(range) {
148
+ return range
149
+ .trim()
150
+ .split(/\s*\|\|\s*/)
151
+ .every(alt => {
152
+ const text = glueOperators(alt);
153
+ if (/^(\*|x|X)$/.test(text))
154
+ return true;
155
+ const hyphen = text.match(/^(\S+)\s+-\s+(\S+)$/);
156
+ if (hyphen) {
157
+ return (versionMajor(hyphen[1]) !== null && versionMajor(hyphen[2]) !== null);
158
+ }
159
+ return text.split(/\s+/).every(tok => {
160
+ const m = tok.match(/^(>=|<=|>|<|=)?(.*)$/);
161
+ if (!m)
162
+ return false;
163
+ const [, op = '', v] = m;
164
+ return (op ? versionMajor(v) : majorOf(v)) !== null;
165
+ });
166
+ });
167
+ }
168
+ /**
169
+ * The major of a COMPLETE plain version or x-range, or null. npm's optional
170
+ * leading `v` is the only prefix allowed here. Reading a numeric prefix alone
171
+ * accepted a dist-tag like `0.next` as major 0, and the manifest was then
172
+ * overwritten with `^1.0.4`, which is the one thing this parser must never do
173
+ * to a value it does not understand.
174
+ */
175
+ function versionMajor(version) {
176
+ const m = version.replace(/^v/, '').match(VERSION);
177
+ return m ? Number(m[1]) : null;
178
+ }
179
+ /**
180
+ * The major of a BARE token, which may carry exactly one range prefix (`^`,
181
+ * `~`, `=`) before the version. Stripping any run of prefix characters
182
+ * accepted `^^0.9.4` and `vv0.9.4` as major 0 and overwrote them.
183
+ */
184
+ function majorOf(token) {
185
+ return versionMajor(token.replace(/^[~^=]/, ''));
186
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/sources/rbx/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAgHzD,eAAO,MAAM,kBAAkB,EAAE,kBAqLhC,CAAC"}
1
+ {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/sources/rbx/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAsBzD,eAAO,MAAM,kBAAkB,EAAE,kBAqLhC,CAAC"}
@@ -13,6 +13,7 @@
13
13
  * see the note on that below.
14
14
  * says so by name.
15
15
  */
16
+ import { isPreV1, isRecognisedRange } from '../_shared/semver-range.js';
16
17
  const BESTAX_RANGE = '^5';
17
18
  const BULMA_RANGE = '^1.0.4';
18
19
  // Bulma v1's sass tree uses `color.channel(…)` — needs dart-sass ≥ 1.79.
@@ -29,102 +30,6 @@ const RBX_STYLE_DEPS = [
29
30
  'bulma-tooltip',
30
31
  ];
31
32
  const DEP_SECTIONS = ['dependencies', 'devDependencies'];
32
- /**
33
- * True only when `range` PROVABLY admits no version >= 1.0.0.
34
- *
35
- * The first version matched a leading `0` and nothing else, so a range written
36
- * as comparators (`>=0.7 <1`) was left on 0.x and then reported as already v1.
37
- * This walks each `||` alternative and its comparators: a set is pre-v1 when
38
- * some comparator caps it below 1.0.0 and none of them opens it at 1 or above.
39
- *
40
- * Conservative by design: an unrecognised shape returns false and the range is
41
- * left alone (and reported as such). Bumping a range that might already admit
42
- * v1 would be the best-guess rewrite this package refuses to make.
43
- */
44
- function isPreV1(range) {
45
- const alternatives = range.trim().split(/\s*\|\|\s*/);
46
- return alternatives.length > 0 && alternatives.every(setIsPreV1);
47
- }
48
- function setIsPreV1(set) {
49
- // npm accepts whitespace between an operator and its version
50
- // (`>= 0.7.0 < 1.0.0`); splitting on whitespace first made the operator a
51
- // token of its own, so the range parsed as unrecognised and was left alone.
52
- const text = glueOperators(set);
53
- if (text === '' || /^(\*|x|X|latest)$/.test(text))
54
- return false;
55
- const hyphen = text.match(/^(\S+)\s+-\s+(\S+)$/);
56
- if (hyphen)
57
- return majorOf(hyphen[2]) === 0;
58
- let cappedBelowOne = false;
59
- for (const token of text.split(/\s+/)) {
60
- const match = token.match(/^(>=|<=|>|<|=)?\s*v?(.*)$/);
61
- if (!match)
62
- return false;
63
- const [, op = '', version] = match;
64
- const major = majorOf(version);
65
- if (major === null)
66
- return false;
67
- switch (op) {
68
- case '>':
69
- case '>=':
70
- if (major >= 1)
71
- return false;
72
- break;
73
- case '<':
74
- // `<1`, `<1.0`, `<1.0.0` exclude every v1; `<0.9` does too.
75
- if (major === 0 || (major === 1 && /^1(\.0)*$/.test(version))) {
76
- cappedBelowOne = true;
77
- }
78
- else {
79
- return false;
80
- }
81
- break;
82
- case '<=':
83
- if (major === 0)
84
- cappedBelowOne = true;
85
- else
86
- return false;
87
- break;
88
- default:
89
- // `0.9.4`, `=0.9.4`, `^0.9`, `~0.7.5`, `0.x`: caret and tilde never
90
- // cross a major, so major 0 stays below 1.
91
- if (major === 0)
92
- cappedBelowOne = true;
93
- else
94
- return false;
95
- }
96
- }
97
- return cappedBelowOne;
98
- }
99
- function glueOperators(set) {
100
- return set.trim().replace(/(>=|<=|>|<|=)\s+/g, '$1');
101
- }
102
- /**
103
- * True when every comparator in every alternative parses to a semver major,
104
- * so the headline can tell "already v1" apart from "not a version range at
105
- * all" (`latest`, a git URL) rather than calling both v1.
106
- */
107
- function isRecognisedRange(range) {
108
- return range
109
- .trim()
110
- .split(/\s*\|\|\s*/)
111
- .every(alt => {
112
- const text = glueOperators(alt);
113
- if (/^(\*|x|X)$/.test(text))
114
- return true;
115
- const hyphen = text.match(/^(\S+)\s+-\s+(\S+)$/);
116
- if (hyphen) {
117
- return majorOf(hyphen[1]) !== null && majorOf(hyphen[2]) !== null;
118
- }
119
- return text
120
- .split(/\s+/)
121
- .every(tok => majorOf(tok.replace(/^(>=|<=|>|<|=)/, '')) !== null);
122
- });
123
- }
124
- function majorOf(version) {
125
- const m = version.replace(/^[~^=v]+/, '').match(/^(\d+)(?:\.|$)/);
126
- return m ? Number(m[1]) : null;
127
- }
128
33
  export const updateDependencies = (filePath, pkg, collector, options) => {
129
34
  const changes = [];
130
35
  const next = pkg;
@@ -5,11 +5,11 @@
5
5
  * identical.
6
6
  *
7
7
  * Note what it does NOT do: a `bulma-*` extension import in Sass is left in
8
- * place with a TODO, not removed. Only the JS/CSS-import side of rbx's
9
- * extension cleanup is automatic (transform.ts prunes
10
- * `bulma-badge`/`bulma-divider`/`bulma-pageloader`/`bulma-tooltip` CSS
11
- * imports outright, since bestax ships all four as components). A Sass
12
- * `@import` of one may be pulling in customisation the codemod cannot see,
8
+ * place with a TODO, not removed. The JS/CSS-import side in transform.ts does
9
+ * the same for `bulma-badge`/`bulma-divider`/`bulma-pageloader`/`bulma-tooltip`
10
+ * (kept, with a TODO), and the manifest pass reports rather than removes the
11
+ * packages, since markup outside rbx may still use the extension's classes. A
12
+ * Sass `@import` of one may be pulling in customisation the codemod cannot see,
13
13
  * so it is flagged for a human instead.
14
14
  *
15
15
  * rbx's own stylesheet is `rbx/rbx` (its Sass entry, usually imported as
@@ -5,11 +5,11 @@
5
5
  * identical.
6
6
  *
7
7
  * Note what it does NOT do: a `bulma-*` extension import in Sass is left in
8
- * place with a TODO, not removed. Only the JS/CSS-import side of rbx's
9
- * extension cleanup is automatic (transform.ts prunes
10
- * `bulma-badge`/`bulma-divider`/`bulma-pageloader`/`bulma-tooltip` CSS
11
- * imports outright, since bestax ships all four as components). A Sass
12
- * `@import` of one may be pulling in customisation the codemod cannot see,
8
+ * place with a TODO, not removed. The JS/CSS-import side in transform.ts does
9
+ * the same for `bulma-badge`/`bulma-divider`/`bulma-pageloader`/`bulma-tooltip`
10
+ * (kept, with a TODO), and the manifest pass reports rather than removes the
11
+ * packages, since markup outside rbx may still use the extension's classes. A
12
+ * Sass `@import` of one may be pulling in customisation the codemod cannot see,
13
13
  * so it is flagged for a human instead.
14
14
  *
15
15
  * rbx's own stylesheet is `rbx/rbx` (its Sass entry, usually imported as
@@ -1 +1 @@
1
- {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/deps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAazD,eAAO,MAAM,kBAAkB,EAAE,kBAqHhC,CAAC"}
1
+ {"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/deps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAUzD,eAAO,MAAM,kBAAkB,EAAE,kBAqHhC,CAAC"}
@@ -4,14 +4,12 @@
4
4
  * with dart-sass. Pure data-in/data-out — the CLI owns file IO, and no
5
5
  * package manager is ever invoked (the report tells the user to install).
6
6
  */
7
+ import { isPreV1 } from '../_shared/semver-range.js';
7
8
  const BESTAX_RANGE = '^5';
8
9
  const BULMA_RANGE = '^1.0.4';
9
10
  // Bulma v1's sass tree uses `color.channel(…)` — needs dart-sass ≥ 1.79.
10
11
  const SASS_RANGE = '^1.79.0';
11
12
  const DEP_SECTIONS = ['dependencies', 'devDependencies'];
12
- function isPreV1(range) {
13
- return /^[~^]?0[.x]/.test(range.trim());
14
- }
15
13
  export const updateDependencies = (filePath, pkg, collector, options) => {
16
14
  const changes = [];
17
15
  const next = pkg;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-migrate",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Codemods for migrating existing React apps from other Bulma libraries to @allxsmith/bestax-bulma",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,7 +51,7 @@
51
51
  "react-dom": "^19.2.8",
52
52
  "ts-jest": "^29.4.12",
53
53
  "typescript": "^6.0.3",
54
- "@allxsmith/bestax-bulma": "^5.11.7"
54
+ "@allxsmith/bestax-bulma": "^5.12.0"
55
55
  },
56
56
  "publishConfig": {
57
57
  "access": "public"