bestax-migrate 2.1.0 → 2.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"specials.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/specials.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAUL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AA6wBD,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,GACX,aAAa,CAIf;AAED,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAGjE,CAAC"}
1
+ {"version":3,"file":"specials.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/specials.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAUL,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAIxB,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AA+xBD,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,EAClB,OAAO,EAAE,GAAG,GACX,aAAa,CAIf;AAED,kEAAkE;AAClE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAGjE,CAAC"}
@@ -131,14 +131,27 @@ const SPECIALS = {
131
131
  ctx.dirty = true;
132
132
  return { handledProps: ['multiline'] };
133
133
  },
134
- /** `<Button remove />` is Bulma's delete cross → bestax `<Delete />`. */
135
- button(ctx, _path, element) {
134
+ /**
135
+ * `<Button remove />` (or any truthy literal) is Bulma's delete
136
+ * cross → bestax `<Delete />`. A falsy literal just drops the prop; only a
137
+ * genuine expression can render as either one depending on runtime state, so
138
+ * it's a TODO instead of a silent guess.
139
+ */
140
+ button(ctx, path, element) {
136
141
  const attr = findAttr(element, 'remove');
137
142
  if (!attr)
138
143
  return {};
139
- removeAttr(element, attr);
140
- ctx.dirty = true;
141
- return { target: 'Delete' };
144
+ const literal = literalValueOf(attr);
145
+ if (literal.kind !== 'expression') {
146
+ // A statically-known value always renders the same at runtime: truthy
147
+ // (`remove`, `remove={true}`, `remove="true"`) → `<Delete />`; falsy
148
+ // (`remove={false}`, `remove=""`, `remove={0}`) → just drop the prop.
149
+ removeAttr(element, attr);
150
+ ctx.dirty = true;
151
+ return literal.value ? { target: 'Delete' } : {};
152
+ }
153
+ addTodo(ctx, path, 'prop:remove', '`remove` has a dynamic value; this can render as either a Button or a Delete cross — split the branch by hand');
154
+ return {};
142
155
  },
143
156
  /** Heading → Title / SubTitle / plain `.heading` paragraph. */
144
157
  heading(ctx, path, element) {
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAqFrE,eAAO,MAAM,eAAe,EAAE,eAmL7B,CAAC"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/sources/react-bulma-components/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAuKrE,eAAO,MAAM,eAAe,EAAE,eAmL7B,CAAC"}
@@ -60,13 +60,98 @@ const OTHER_BULMA_IMPORT = /^\s*@import\s+['"][^'"]*bulma[^'"]*['"]/;
60
60
  const EXTENSION_IMPORT = /^\s*@import\s+['"][^'"]*\bbulma-([\w-]+?)(?:\/|\.|['"])/;
61
61
  /** Any `$name: value;` declaration (with or without `!default`). */
62
62
  const VAR_DECL = /^\s*\$([\w-]+)\s*:\s*(.+?)\s*(!default)?\s*;\s*$/;
63
+ /**
64
+ * Strips Sass block comments (slash-star … star-slash spans) from a value
65
+ * before it is analyzed for foldability or top-level commas. A comment can
66
+ * carry an unbalanced quote (an apostrophe in `user's`) or a stray `(`/`$`
67
+ * that would otherwise fool the character scanners into mis-reading the
68
+ * value's structure; the comment is inert to Sass, so removing it for
69
+ * analysis is safe. The emitted value still carries the comment verbatim.
70
+ *
71
+ * The scan tracks quote state first and only recognizes a block comment
72
+ * outside a string, in one pass — a bare regex would treat a slash-star …
73
+ * star-slash-shaped span that straddles two quoted strings (opening marker in
74
+ * one string, closing marker in the next) as a comment and delete the real
75
+ * top-level comma between them, so a genuine list would fold unparenthesized.
76
+ * An unterminated comment consumes the rest of the value.
77
+ */
78
+ function stripSassComments(value) {
79
+ let result = '';
80
+ let quote = null;
81
+ let escaped = false;
82
+ for (let i = 0; i < value.length; i += 1) {
83
+ const char = value[i];
84
+ if (quote) {
85
+ result += char;
86
+ if (escaped) {
87
+ escaped = false;
88
+ }
89
+ else if (char === '\\') {
90
+ escaped = true;
91
+ }
92
+ else if (char === quote) {
93
+ quote = null;
94
+ }
95
+ continue;
96
+ }
97
+ if (char === '/' && value[i + 1] === '*') {
98
+ const end = value.indexOf('*/', i + 2);
99
+ if (end === -1)
100
+ break; // unterminated comment — drop the rest
101
+ i = end + 1; // resume after the closing */
102
+ continue;
103
+ }
104
+ if (char === '"' || char === "'")
105
+ quote = char;
106
+ result += char;
107
+ }
108
+ return result;
109
+ }
63
110
  /**
64
111
  * A value is fold-safe for `with (…)` when it is a plain literal — no
65
112
  * function calls, interpolation, variable references, or at-rules. Hex
66
- * colors (`#ff6b35`) are fine; `#{…}` interpolation is not.
113
+ * colors (`#ff6b35`) are fine; `#{…}` interpolation is not. Block comments are
114
+ * ignored for this test — their contents don't make the value non-literal.
67
115
  */
68
116
  function isFoldableValue(value) {
69
- return !/[()$@]|#\{/.test(value);
117
+ return !/[()$@]|#\{/.test(stripSassComments(value));
118
+ }
119
+ /**
120
+ * Whether `value` has a comma outside any quoted string — a bare Sass list
121
+ * (`'Nunito', sans-serif`) that must be parenthesized before it can sit
122
+ * inside `with (…)`, or Dart Sass reads the comma as an argument separator
123
+ * instead of a list delimiter. Block comments are stripped first so a quote or
124
+ * comma inside one (an apostrophe in `user's`) can't skew the scan.
125
+ */
126
+ function hasTopLevelComma(value) {
127
+ let quote = null;
128
+ let escaped = false;
129
+ for (const char of stripSassComments(value)) {
130
+ if (escaped) {
131
+ escaped = false;
132
+ continue;
133
+ }
134
+ if (char === '\\') {
135
+ escaped = true;
136
+ continue;
137
+ }
138
+ if (quote) {
139
+ if (char === quote)
140
+ quote = null;
141
+ continue;
142
+ }
143
+ if (char === '"' || char === "'") {
144
+ quote = char;
145
+ }
146
+ else if (char === ',') {
147
+ return true;
148
+ }
149
+ }
150
+ return false;
151
+ }
152
+ /** Formats a folded value for the `with (…)` clause, parenthesizing a bare list. */
153
+ function formatFoldedValue(value) {
154
+ return hasTopLevelComma(value) ? `(${value})` : value;
70
155
  }
71
156
  function report(collector, file, line, rule, message) {
72
157
  collector?.add({ file, line, rule, message });
@@ -113,7 +198,7 @@ export const transformStyles = (filePath, source, collector, options) => {
113
198
  out.push(`${indent}@use '${bulmaSass}' with (`);
114
199
  foldableVars.forEach(({ name, value }, index) => {
115
200
  const comma = index < foldableVars.length - 1 ? ',' : '';
116
- out.push(`${indent} $${name}: ${value}${comma}`);
201
+ out.push(`${indent} $${name}: ${formatFoldedValue(value)}${comma}`);
117
202
  });
118
203
  out.push(`${indent});`);
119
204
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bestax-migrate",
3
- "version": "2.1.0",
3
+ "version": "2.1.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": {