bestax-migrate 2.3.7 → 2.3.9

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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.d.ts +3 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +16 -6
  5. package/dist/sources/_shared/bestax-import.d.ts +45 -0
  6. package/dist/sources/_shared/bestax-import.d.ts.map +1 -0
  7. package/dist/sources/_shared/bestax-import.js +141 -0
  8. package/dist/sources/_shared/css-imports.d.ts +33 -0
  9. package/dist/sources/_shared/css-imports.d.ts.map +1 -0
  10. package/dist/sources/_shared/css-imports.js +103 -0
  11. package/dist/sources/_shared/deps-common.d.ts +46 -0
  12. package/dist/sources/_shared/deps-common.d.ts.map +1 -0
  13. package/dist/sources/_shared/deps-common.js +98 -0
  14. package/dist/sources/_shared/make-styles-transform.d.ts +6 -2
  15. package/dist/sources/_shared/make-styles-transform.d.ts.map +1 -1
  16. package/dist/sources/_shared/make-styles-transform.js +12 -4
  17. package/dist/sources/_shared/specials-utils.d.ts +1 -1
  18. package/dist/sources/_shared/specials-utils.d.ts.map +1 -1
  19. package/dist/sources/_shared/specials-utils.js +19 -1
  20. package/dist/sources/bloomer/deps.d.ts.map +1 -1
  21. package/dist/sources/bloomer/deps.js +14 -89
  22. package/dist/sources/bloomer/transform.d.ts.map +1 -1
  23. package/dist/sources/bloomer/transform.js +9 -185
  24. package/dist/sources/rbx/deps.d.ts.map +1 -1
  25. package/dist/sources/rbx/deps.js +29 -117
  26. package/dist/sources/rbx/mapping.d.ts.map +1 -1
  27. package/dist/sources/rbx/mapping.js +9 -1
  28. package/dist/sources/rbx/specials.d.ts.map +1 -1
  29. package/dist/sources/rbx/specials.js +20 -10
  30. package/dist/sources/rbx/transform.d.ts.map +1 -1
  31. package/dist/sources/rbx/transform.js +19 -203
  32. package/dist/sources/react-bulma-components/deps.d.ts.map +1 -1
  33. package/dist/sources/react-bulma-components/deps.js +12 -87
  34. package/dist/sources/react-bulma-components/mapping.js +1 -1
  35. package/dist/sources/react-bulma-components/specials.d.ts.map +1 -1
  36. package/dist/sources/react-bulma-components/specials.js +42 -4
  37. package/dist/sources/react-bulma-components/transform.d.ts.map +1 -1
  38. package/dist/sources/react-bulma-components/transform.js +13 -186
  39. package/dist/types.d.ts +7 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +3 -3
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/bestax-migrate.svg)](https://www.npmjs.com/package/bestax-migrate)
4
4
  [![npm downloads](https://img.shields.io/npm/dm/bestax-migrate.svg)](https://www.npmjs.com/package/bestax-migrate)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![Socket Badge](https://socket.dev/api/badge/npm/package/bestax-migrate)](https://socket.dev/npm/package/bestax-migrate/overview)
6
+ [![Socket Badge](https://badge.socket.dev/npm/package/bestax-migrate/latest)](https://socket.dev/npm/package/bestax-migrate/overview)
7
7
  [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/allxsmith/bestax/badge)](https://scorecard.dev/viewer/?uri=github.com/allxsmith/bestax)
8
8
  [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/14361/badge)](https://www.bestpractices.dev/projects/14361)
9
9
  [![npm provenance](https://img.shields.io/badge/npm-provenance-3fb950.svg)](https://www.npmjs.com/package/bestax-migrate#provenance)
package/dist/cli.d.ts CHANGED
@@ -15,6 +15,7 @@ import { createInterface } from 'node:readline/promises';
15
15
  import type { Readable, Writable } from 'node:stream';
16
16
  import { Command } from 'commander';
17
17
  import { type MigrateRunStats } from './telemetry.js';
18
+ import type { MigrationSource } from './types.js';
18
19
  export declare function collectFiles(targets: string[], extensions: string[]): string[];
19
20
  /** Nearest package.json for each target, walking up to the filesystem root. */
20
21
  export declare function findPackageJsons(targets: string[]): string[];
@@ -75,6 +76,8 @@ export declare function blankComments(text: string): string;
75
76
  * short as `rbx`: prose and a sibling package like `rbx-utils` both counted.
76
77
  */
77
78
  export declare function makeSourceImportRe(name: string): RegExp;
79
+ /** The package a source migrates away from, or null when it has none. */
80
+ export declare function sourcePackage(source: MigrationSource): string | null;
78
81
  /**
79
82
  * One-question consent prompt (readline — this package carries no interactive
80
83
  * prompt dependency). Returns null when the question is cancelled (Ctrl-C /
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAqBxE,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAkBV;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5D;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgDlD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBvD;AA8JD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,KAAK,EACT,KAAK,GAAE,QAAwB,EAC/B,MAAM,GAAE,QAAyB,EAGjC,aAAa,GAAE,OAAO,eAAiC,GACtD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,EAAE,EAAE,KAAK,EACT,aAAa,GAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAA0B,GAC7E,OAAO,CAAC,IAAI,CAAC,CAqBf;AAYD,wBAAgB,SAAS,CACvB,EAAE,GAAE,KAAkD,GACrD,OAAO,CAkHT"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAW,eAAe,EAAE,MAAM,YAAY,CAAC;AAoB3D,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EAAE,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAkBV;AAED,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAkB5D;AAED,MAAM,WAAW,KAAK;IACpB,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AASD;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgDlD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsBvD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAEpE;AAoKD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,KAAK,EACT,KAAK,GAAE,QAAwB,EAC/B,MAAM,GAAE,QAAyB,EAGjC,aAAa,GAAE,OAAO,eAAiC,GACtD,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyBzB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,eAAe,EACtB,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,EAAE,EAAE,KAAK,EACT,aAAa,GAAE,CAAC,EAAE,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAA0B,GAC7E,OAAO,CAAC,IAAI,CAAC,CAqBf;AAYD,wBAAgB,SAAS,CACvB,EAAE,GAAE,KAAkD,GACrD,OAAO,CAkHT"}
package/dist/cli.js CHANGED
@@ -201,10 +201,19 @@ export function makeSourceImportRe(name) {
201
201
  `${lead}(?:import|require(?:\\.resolve)?)\\s*\\(\\s*${spec}`,
202
202
  ].join('|'));
203
203
  }
204
+ /** The package a source migrates away from, or null when it has none. */
205
+ export function sourcePackage(source) {
206
+ return source.packageName === undefined ? source.name : source.packageName;
207
+ }
208
+ /** Whether `text` still imports the source's package (never, without one). */
209
+ function importsSource(importRe, text) {
210
+ return importRe !== null && importRe.test(blankComments(text));
211
+ }
204
212
  function migrateFiles(source, files, reporter, io, options) {
205
213
  let bulmaReferenced = false;
206
214
  let sourceStillImported = false;
207
- const sourceImportRe = makeSourceImportRe(source.name);
215
+ const pkg = sourcePackage(source);
216
+ const sourceImportRe = pkg === null ? null : makeSourceImportRe(pkg);
208
217
  for (const file of files) {
209
218
  const sourceText = fs.readFileSync(file, 'utf8');
210
219
  const collector = reporter.startFile();
@@ -233,7 +242,7 @@ function migrateFiles(source, files, reporter, io, options) {
233
242
  // the file still imports it, we just couldn't rewrite it.
234
243
  if (/['"](?:~?bulma\/)/.test(sourceText))
235
244
  bulmaReferenced = true;
236
- if (sourceImportRe.test(blankComments(sourceText)))
245
+ if (importsSource(sourceImportRe, sourceText))
237
246
  sourceStillImported = true;
238
247
  reporter.finishFile(file, false, collector.entries);
239
248
  continue;
@@ -241,7 +250,7 @@ function migrateFiles(source, files, reporter, io, options) {
241
250
  if (/['"](?:~?bulma\/)/.test(output ?? sourceText)) {
242
251
  bulmaReferenced = true;
243
252
  }
244
- if (sourceImportRe.test(blankComments(output ?? sourceText))) {
253
+ if (importsSource(sourceImportRe, output ?? sourceText)) {
245
254
  sourceStillImported = true;
246
255
  }
247
256
  if (output !== null) {
@@ -260,13 +269,14 @@ function migrateFiles(source, files, reporter, io, options) {
260
269
  */
261
270
  function reportUnsupportedFiles(source, targets, reporter, extensions) {
262
271
  const unsupported = UNSUPPORTED_EXTENSIONS.filter(ext => !extensions.includes(ext));
263
- if (unsupported.length === 0)
272
+ const pkg = sourcePackage(source);
273
+ if (unsupported.length === 0 || pkg === null)
264
274
  return false;
265
275
  // Whether any unsupported file still references the source package. These
266
276
  // are reported but never rewritten, so the reference survives the run —
267
277
  // and the manifest pass must not remove the package out from under it.
268
278
  let stillImported = false;
269
- const importRe = makeSourceImportRe(source.name);
279
+ const importRe = makeSourceImportRe(pkg);
270
280
  for (const file of collectFiles(targets, unsupported)) {
271
281
  const text = fs.readFileSync(file, 'utf8');
272
282
  // A substring match is not evidence of an import. `rbx` is three
@@ -283,7 +293,7 @@ function reportUnsupportedFiles(source, targets, reporter, extensions) {
283
293
  file,
284
294
  line,
285
295
  rule: 'unsupported-file',
286
- message: `imports ${source.name}, but ${path.extname(file)} files cannot be parsed by the codemod — migrate this file by hand`,
296
+ message: `imports ${pkg}, but ${path.extname(file)} files cannot be parsed by the codemod — migrate this file by hand`,
287
297
  });
288
298
  reporter.finishFile(file, false, collector.entries);
289
299
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The `@allxsmith/bestax-bulma` import a migrated file ends up with.
3
+ *
4
+ * Every source does the same three things: seed the components an existing
5
+ * bestax import already binds (so the JSX reuses their locals), record which
6
+ * components the passes actually ask for, and then either merge the new ones
7
+ * into that existing import or write a fresh declaration. Where the fresh
8
+ * declaration goes is the caller's call; a library source puts it where the
9
+ * library's own import was.
10
+ */
11
+ import type { TransformContext } from './jsx-utils.js';
12
+ export declare const BESTAX = "@allxsmith/bestax-bulma";
13
+ export interface BestaxImportState {
14
+ /** The existing declaration new specifiers merge into, if any. */
15
+ existing: any | undefined;
16
+ /** Components the existing declaration already binds as values. */
17
+ preExisting: Set<string>;
18
+ /** Components the passes asked for through `ctx.reserve`. */
19
+ requested: Set<string>;
20
+ }
21
+ /**
22
+ * Call once `ctx.reserve` is final and before any pass reserves a name: it
23
+ * wraps `reserve` to record requests and seeds `ctx.needed` from an existing
24
+ * bestax import.
25
+ */
26
+ export declare function seedBestaxImport(ctx: TransformContext, root: any): BestaxImportState;
27
+ /** The fresh declaration for components not already imported, or null. */
28
+ export declare function buildBestaxImport(ctx: TransformContext, state: BestaxImportState): any | null;
29
+ /**
30
+ * Locals that bind a bestax VALUE once the import is written. A type-only
31
+ * specifier the seeding recorded, and nothing promoted, binds no value.
32
+ */
33
+ export declare function bestaxValueLocals(ctx: TransformContext, state: BestaxImportState): Set<string>;
34
+ /**
35
+ * Merge `fresh` into the existing bestax import, or insert it before
36
+ * `before` when there is none.
37
+ */
38
+ export declare function placeBestaxImport(state: BestaxImportState, fresh: any | null, before: any): void;
39
+ /**
40
+ * A pruned declaration takes its comments with it — a licence header, an
41
+ * eslint directive. Hand them to `carrier` (the bestax import that survives),
42
+ * or to the next statement, or keep them where they were.
43
+ */
44
+ export declare function carryPrunedComments(node: any, importPath: any, carrier: any | null): void;
45
+ //# sourceMappingURL=bestax-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bestax-import.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/bestax-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAIvD,eAAO,MAAM,MAAM,4BAA4B,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,kEAAkE;IAClE,QAAQ,EAAE,GAAG,GAAG,SAAS,CAAC;IAC1B,mEAAmE;IACnE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,6DAA6D;IAC7D,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,GAAG,GACR,iBAAiB,CA+CnB;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,GAAG,IAAI,CAgBZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,iBAAiB,GACvB,GAAG,CAAC,MAAM,CAAC,CASb;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,iBAAiB,EACxB,KAAK,EAAE,GAAG,GAAG,IAAI,EACjB,MAAM,EAAE,GAAG,GACV,IAAI,CAyBN;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,GAAG,EACT,UAAU,EAAE,GAAG,EACf,OAAO,EAAE,GAAG,GAAG,IAAI,GAClB,IAAI,CAsBN"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * The `@allxsmith/bestax-bulma` import a migrated file ends up with.
3
+ *
4
+ * Every source does the same three things: seed the components an existing
5
+ * bestax import already binds (so the JSX reuses their locals), record which
6
+ * components the passes actually ask for, and then either merge the new ones
7
+ * into that existing import or write a fresh declaration. Where the fresh
8
+ * declaration goes is the caller's call; a library source puts it where the
9
+ * library's own import was.
10
+ */
11
+ import { nameOf } from './imports.js';
12
+ /* eslint-disable @typescript-eslint/no-explicit-any */
13
+ export const BESTAX = '@allxsmith/bestax-bulma';
14
+ /**
15
+ * Call once `ctx.reserve` is final and before any pass reserves a name: it
16
+ * wraps `reserve` to record requests and seeds `ctx.needed` from an existing
17
+ * bestax import.
18
+ */
19
+ export function seedBestaxImport(ctx, root) {
20
+ const { j } = ctx;
21
+ // Names the passes actually asked for. `ctx.needed` is also seeded from an
22
+ // existing bestax import's specifiers below (so JSX reuses their locals),
23
+ // and that seeding alone must not turn a type-only specifier into a value
24
+ // import nobody needed.
25
+ const requested = new Set();
26
+ const baseReserve = ctx.reserve;
27
+ ctx.reserve = name => {
28
+ requested.add(name);
29
+ return baseReserve(name);
30
+ };
31
+ // Only a declaration made entirely of NAMED specifiers can be merged into.
32
+ // `import * as Bulma from '@allxsmith/bestax-bulma'` matches the source too,
33
+ // and appending named specifiers to it emitted
34
+ // `import * as Bulma, { Box } from …` — not valid JavaScript, so the whole
35
+ // file failed to parse after a migration that reported success.
36
+ const existing = root
37
+ .find(j.ImportDeclaration, { source: { value: BESTAX } })
38
+ .paths()
39
+ .find((path) =>
40
+ // A type-only declaration cannot take a value specifier: merging a
41
+ // component into `import type { … }` erases it at runtime.
42
+ path.node.importKind !== 'type' &&
43
+ (path.node.specifiers ?? []).every((spec) => spec.type === 'ImportSpecifier'));
44
+ const preExisting = new Set();
45
+ if (existing) {
46
+ for (const spec of existing.node.specifiers ?? []) {
47
+ if (spec.type === 'ImportSpecifier' && spec.local) {
48
+ // The local name is reused either way, so the JSX never needs an
49
+ // alias. But an inline `type` specifier (`import { type Box }`) is
50
+ // not a value binding: it is not counted as already imported, so the
51
+ // component is written as a value below — onto this specifier, which
52
+ // keeps its name, rather than as a duplicate.
53
+ ctx.needed.set(nameOf(spec.imported), nameOf(spec.local));
54
+ if (spec.importKind !== 'type') {
55
+ preExisting.add(nameOf(spec.imported));
56
+ }
57
+ }
58
+ }
59
+ }
60
+ return { existing, preExisting, requested };
61
+ }
62
+ /** The fresh declaration for components not already imported, or null. */
63
+ export function buildBestaxImport(ctx, state) {
64
+ const { j } = ctx;
65
+ const freshNames = [...ctx.needed.entries()]
66
+ .filter(([imported]) => state.requested.has(imported) && !state.preExisting.has(imported))
67
+ .sort((a, b) => a[0].localeCompare(b[0]));
68
+ return freshNames.length > 0
69
+ ? j.importDeclaration(freshNames.map(([imported, local]) => j.importSpecifier(j.identifier(imported), j.identifier(local))), j.stringLiteral(BESTAX))
70
+ : null;
71
+ }
72
+ /**
73
+ * Locals that bind a bestax VALUE once the import is written. A type-only
74
+ * specifier the seeding recorded, and nothing promoted, binds no value.
75
+ */
76
+ export function bestaxValueLocals(ctx, state) {
77
+ return new Set([...ctx.needed.entries()]
78
+ .filter(([imported]) => state.requested.has(imported) || state.preExisting.has(imported))
79
+ .map(([, local]) => local));
80
+ }
81
+ /**
82
+ * Merge `fresh` into the existing bestax import, or insert it before
83
+ * `before` when there is none.
84
+ */
85
+ export function placeBestaxImport(state, fresh, before) {
86
+ if (!fresh)
87
+ return;
88
+ if (!state.existing) {
89
+ before.insertBefore(fresh);
90
+ return;
91
+ }
92
+ const current = state.existing.node.specifiers ?? [];
93
+ const appended = [];
94
+ for (const spec of fresh.specifiers) {
95
+ // A type-only specifier for the same name becomes the value
96
+ // import (a value import carries the type too); appending a
97
+ // second `Box` beside `type Box` would be a duplicate identifier.
98
+ const typeOnly = current.find((existingSpec) => existingSpec.type === 'ImportSpecifier' &&
99
+ existingSpec.importKind === 'type' &&
100
+ nameOf(existingSpec.imported) === nameOf(spec.imported));
101
+ if (typeOnly) {
102
+ typeOnly.importKind = null;
103
+ }
104
+ else {
105
+ appended.push(spec);
106
+ }
107
+ }
108
+ state.existing.node.specifiers = [...current, ...appended];
109
+ }
110
+ /**
111
+ * A pruned declaration takes its comments with it — a licence header, an
112
+ * eslint directive. Hand them to `carrier` (the bestax import that survives),
113
+ * or to the next statement, or keep them where they were.
114
+ */
115
+ export function carryPrunedComments(node, importPath, carrier) {
116
+ const comments = node.comments ?? [];
117
+ if (comments.length === 0)
118
+ return;
119
+ const body = importPath.parent?.node?.body ?? [];
120
+ const index = body.indexOf(node);
121
+ const target = carrier ?? (index >= 0 ? body[index + 1] : undefined);
122
+ if (target) {
123
+ target.comments = [...comments, ...(target.comments ?? [])];
124
+ }
125
+ else if (index > 0) {
126
+ // The import was the last statement: the comments stay where they
127
+ // were, after what precedes it.
128
+ const previous = body[index - 1];
129
+ previous.comments = [
130
+ ...(previous.comments ?? []),
131
+ ...comments.map((c) => ({ ...c, leading: false, trailing: true })),
132
+ ];
133
+ }
134
+ else {
135
+ // The import was the only statement: the comments become the file's.
136
+ const program = importPath.parent?.node;
137
+ if (program)
138
+ program.comments = [...comments, ...(program.comments ?? [])];
139
+ }
140
+ node.comments = [];
141
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The stylesheet-import pass every source runs before its JSX work.
3
+ *
4
+ * `--css bestax` (the default) converges every Bulma stylesheet import on the
5
+ * combined `bestax.css` bundle, which already carries the extras; `bulma`
6
+ * keeps plain Bulma v1 CSS and adds the extras import beside it; `keep`
7
+ * leaves the app's own Bulma import alone and only retargets a source
8
+ * library's stylesheet, which no longer resolves once the library is gone.
9
+ *
10
+ * What differs per source is the source's own stylesheet (react-bulma-components'
11
+ * v3 bundle, `rbx/index.css`; bloomer ships none) and anything the source
12
+ * handles before the shared rules (rbx's extension stylesheets).
13
+ */
14
+ import type { CssMode } from '../../types.js';
15
+ import { type TransformContext } from './jsx-utils.js';
16
+ export interface StylesheetImportOptions {
17
+ /**
18
+ * The source library's own stylesheet, retargeted wherever Bulma's is:
19
+ * which specifiers are it, and how the keep-mode TODO names it (e.g.
20
+ * "rbx's CSS import"). One object, so a matcher never lacks its label.
21
+ */
22
+ sourceCss?: {
23
+ is: (specifier: string) => boolean;
24
+ label: string;
25
+ };
26
+ /**
27
+ * Runs first for every import; returning true means the source handled it
28
+ * and the shared rules skip it.
29
+ */
30
+ handleOwn?: (path: any, specifier: string) => boolean;
31
+ }
32
+ export declare function rewriteStylesheetImports(ctx: TransformContext, root: any, cssMode: CssMode, options?: StylesheetImportOptions): void;
33
+ //# sourceMappingURL=css-imports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"css-imports.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/css-imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAuBhE,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,EAAE,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CACvD;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,gBAAgB,EACrB,IAAI,EAAE,GAAG,EACT,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,uBAA4B,GACpC,IAAI,CA4EN"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The stylesheet-import pass every source runs before its JSX work.
3
+ *
4
+ * `--css bestax` (the default) converges every Bulma stylesheet import on the
5
+ * combined `bestax.css` bundle, which already carries the extras; `bulma`
6
+ * keeps plain Bulma v1 CSS and adds the extras import beside it; `keep`
7
+ * leaves the app's own Bulma import alone and only retargets a source
8
+ * library's stylesheet, which no longer resolves once the library is gone.
9
+ *
10
+ * What differs per source is the source's own stylesheet (react-bulma-components'
11
+ * v3 bundle, `rbx/index.css`; bloomer ships none) and anything the source
12
+ * handles before the shared rules (rbx's extension stylesheets).
13
+ */
14
+ import { addTodo } from './jsx-utils.js';
15
+ /* eslint-disable @typescript-eslint/no-explicit-any */
16
+ const BULMA_CSS = 'bulma/css/bulma.min.css';
17
+ const BESTAX_CSS = '@allxsmith/bestax-bulma/bestax.css';
18
+ const EXTRAS_CSS = '@allxsmith/bestax-bulma/extras.css';
19
+ const BULMA_CSS_SPECIFIERS = new Set([
20
+ 'bulma/css/bulma.css',
21
+ 'bulma/css/bulma.min.css',
22
+ ]);
23
+ const BESTAX_CSS_SPECIFIERS = new Set([
24
+ BESTAX_CSS,
25
+ '@allxsmith/bestax-bulma/bestax.min.css',
26
+ '@allxsmith/bestax-bulma/dist/bestax.css',
27
+ '@allxsmith/bestax-bulma/dist/bestax.min.css',
28
+ ]);
29
+ const EXTRAS_CSS_SPECIFIERS = new Set([
30
+ EXTRAS_CSS,
31
+ '@allxsmith/bestax-bulma/dist/extras.css',
32
+ ]);
33
+ export function rewriteStylesheetImports(ctx, root, cssMode, options = {}) {
34
+ const { j } = ctx;
35
+ const isSourceCss = options.sourceCss?.is ?? (() => false);
36
+ const specifierOf = (p) => String(p.node.source.value);
37
+ let sawBestaxCss = root
38
+ .find(j.ImportDeclaration)
39
+ .paths()
40
+ .some((p) => BESTAX_CSS_SPECIFIERS.has(specifierOf(p)));
41
+ // Whether some import in this file will become bestax.css, regardless of
42
+ // where it sits relative to an existing extras import.
43
+ const willAdoptBestaxCss = cssMode === 'bestax' &&
44
+ root
45
+ .find(j.ImportDeclaration)
46
+ .paths()
47
+ .some((p) => {
48
+ const specifier = specifierOf(p);
49
+ return isSourceCss(specifier) || BULMA_CSS_SPECIFIERS.has(specifier);
50
+ });
51
+ root.find(j.ImportDeclaration).forEach((path) => {
52
+ const source = specifierOf(path);
53
+ if (options.handleOwn?.(path, source))
54
+ return;
55
+ const isOwnCss = isSourceCss(source);
56
+ const isBulmaCss = BULMA_CSS_SPECIFIERS.has(source);
57
+ const isExtrasCss = EXTRAS_CSS_SPECIFIERS.has(source);
58
+ if (!isOwnCss && !isBulmaCss && !isExtrasCss)
59
+ return;
60
+ if (cssMode === 'bestax') {
61
+ if (isOwnCss || isBulmaCss) {
62
+ if (sawBestaxCss) {
63
+ path.prune(); // bestax.css already imported elsewhere in this file
64
+ }
65
+ else {
66
+ path.node.source = j.stringLiteral(BESTAX_CSS);
67
+ sawBestaxCss = true;
68
+ }
69
+ ctx.dirty = true;
70
+ }
71
+ else if (isExtrasCss && (sawBestaxCss || willAdoptBestaxCss)) {
72
+ // bestax.css already contains the extras. `willAdoptBestaxCss` covers
73
+ // the case where the extras import comes FIRST in the file and the
74
+ // import that becomes bestax.css has not been visited yet —
75
+ // otherwise the extras survive alongside it and double-load.
76
+ path.prune();
77
+ ctx.dirty = true;
78
+ }
79
+ }
80
+ else if (cssMode === 'bulma') {
81
+ if (isOwnCss) {
82
+ path.node.source = j.stringLiteral(BULMA_CSS);
83
+ ctx.dirty = true;
84
+ }
85
+ if ((isOwnCss || isBulmaCss) && !sawBestaxCss) {
86
+ const hasExtras = root
87
+ .find(j.ImportDeclaration)
88
+ .paths()
89
+ .some((p) => EXTRAS_CSS_SPECIFIERS.has(specifierOf(p)));
90
+ if (!hasExtras) {
91
+ // Themed Radio/Checkbox need the bestax extras next to plain Bulma.
92
+ path.insertAfter(j.importDeclaration([], j.stringLiteral(EXTRAS_CSS)));
93
+ ctx.dirty = true;
94
+ }
95
+ }
96
+ }
97
+ else if (isOwnCss && options.sourceCss) {
98
+ // keep: minimal fix — the source's stylesheet goes with the source.
99
+ path.node.source = j.stringLiteral(BULMA_CSS);
100
+ addTodo(ctx, path, 'css', `replaced ${options.sourceCss.label} with '${BULMA_CSS}'; install bulma@^1 (see https://bestax.io/docs/guides/getting-started/installation)`);
101
+ }
102
+ });
103
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The package.json steps every source's manifest pass takes once the source
3
+ * library itself is dealt with: bring in bestax-bulma, move the app's Bulma to
4
+ * v1, report peer ranges bestax-bulma cannot install beside, and swap the
5
+ * dead node-sass for dart-sass. Pure data-in/data-out, like the passes that
6
+ * call it: no package manager is ever invoked.
7
+ */
8
+ import type { TodoCollector } from '../../types.js';
9
+ export declare const BULMA_RANGE = "^1.0.4";
10
+ export declare const DEP_SECTIONS: readonly ["dependencies", "devDependencies"];
11
+ type Section = (typeof DEP_SECTIONS)[number];
12
+ export interface Manifest {
13
+ /** The manifest being edited in place. */
14
+ next: Record<string, Record<string, string> | unknown>;
15
+ section(name: Section): Record<string, string> | undefined;
16
+ /** Record a change: it counts as an edit and lands in the report. */
17
+ note(message: string): void;
18
+ /** Report without counting as an edit. */
19
+ report(rule: string, message: string): void;
20
+ /** The edited manifest, or null when nothing changed. */
21
+ result(): Record<string, unknown> | null;
22
+ }
23
+ export declare function openManifest(filePath: string, pkg: Record<string, unknown>, collector: TodoCollector | undefined): Manifest;
24
+ /** @allxsmith/bestax-bulma comes in as a runtime dependency. */
25
+ export declare function addBestax(manifest: Manifest): void;
26
+ export interface BulmaOutcome {
27
+ /** The declared range before any bump, or null when none was declared. */
28
+ declared: string | null;
29
+ bumped: boolean;
30
+ added: boolean;
31
+ }
32
+ /**
33
+ * Bump a pre-1 Bulma range; add one only when sources still reference
34
+ * bulma/… directly (otherwise it arrives transitively via bestax-bulma).
35
+ */
36
+ export declare function moveBulmaToV1(manifest: Manifest, bulmaReferenced: boolean | undefined): BulmaOutcome;
37
+ /**
38
+ * Report ranges bestax-bulma's peers cannot install beside. Report only: a
39
+ * React major and a Font Awesome major (whose icon names change) are the
40
+ * app's own migration steps.
41
+ */
42
+ export declare function reportPeerRanges(manifest: Manifest): void;
43
+ /** node-sass is dead; dart-sass replaces it in the same section. */
44
+ export declare function replaceNodeSass(manifest: Manifest): void;
45
+ export {};
46
+ //# sourceMappingURL=deps-common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps-common.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/deps-common.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAIpD,eAAO,MAAM,WAAW,WAAW,CAAC;AAIpC,eAAO,MAAM,YAAY,8CAA+C,CAAC;AACzE,KAAK,OAAO,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7C,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC;IACvD,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC3D,qEAAqE;IACrE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,0CAA0C;IAC1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,yDAAyD;IACzD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,EAAE,aAAa,GAAG,SAAS,GACnC,QAAQ,CAiBV;AAED,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAclD;AAED,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,OAAO,GAAG,SAAS,GACnC,YAAY,CA2Bd;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAqBzD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAexD"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * The package.json steps every source's manifest pass takes once the source
3
+ * library itself is dealt with: bring in bestax-bulma, move the app's Bulma to
4
+ * v1, report peer ranges bestax-bulma cannot install beside, and swap the
5
+ * dead node-sass for dart-sass. Pure data-in/data-out, like the passes that
6
+ * call it: no package manager is ever invoked.
7
+ */
8
+ import { isPreV1 } from './semver-range.js';
9
+ const BESTAX_RANGE = '^5';
10
+ export const BULMA_RANGE = '^1.0.4';
11
+ // Bulma v1's sass tree uses `color.channel(…)` — needs dart-sass ≥ 1.79.
12
+ const SASS_RANGE = '^1.79.0';
13
+ export const DEP_SECTIONS = ['dependencies', 'devDependencies'];
14
+ export function openManifest(filePath, pkg, collector) {
15
+ const changes = [];
16
+ const next = pkg;
17
+ const report = (rule, message) => collector?.add({ file: filePath, line: null, rule, message });
18
+ return {
19
+ next,
20
+ section: name => (next[name] ?? undefined),
21
+ note: message => {
22
+ changes.push(message);
23
+ report('deps', message);
24
+ },
25
+ report,
26
+ result: () => changes.length > 0 ? next : null,
27
+ };
28
+ }
29
+ /** @allxsmith/bestax-bulma comes in as a runtime dependency. */
30
+ export function addBestax(manifest) {
31
+ const dependencies = (manifest.next.dependencies ??= {});
32
+ if (!dependencies['@allxsmith/bestax-bulma'] &&
33
+ !manifest.section('devDependencies')?.['@allxsmith/bestax-bulma']) {
34
+ dependencies['@allxsmith/bestax-bulma'] = BESTAX_RANGE;
35
+ manifest.note(`added @allxsmith/bestax-bulma ${BESTAX_RANGE} to dependencies`);
36
+ }
37
+ }
38
+ /**
39
+ * Bump a pre-1 Bulma range; add one only when sources still reference
40
+ * bulma/… directly (otherwise it arrives transitively via bestax-bulma).
41
+ */
42
+ export function moveBulmaToV1(manifest, bulmaReferenced) {
43
+ const outcome = { declared: null, bumped: false, added: false };
44
+ for (const name of DEP_SECTIONS) {
45
+ const deps = manifest.section(name);
46
+ if (deps?.bulma) {
47
+ outcome.declared = deps.bulma;
48
+ if (isPreV1(deps.bulma)) {
49
+ deps.bulma = BULMA_RANGE;
50
+ outcome.bumped = true;
51
+ manifest.note(`bumped bulma to ${BULMA_RANGE} in ${name} (was pre-1.0)`);
52
+ }
53
+ }
54
+ }
55
+ if (outcome.declared === null && bulmaReferenced) {
56
+ const dependencies = (manifest.next.dependencies ??= {});
57
+ dependencies.bulma = BULMA_RANGE;
58
+ outcome.added = true;
59
+ manifest.note(`added bulma ${BULMA_RANGE} to dependencies (sources import bulma/… directly)`);
60
+ }
61
+ return outcome;
62
+ }
63
+ /**
64
+ * Report ranges bestax-bulma's peers cannot install beside. Report only: a
65
+ * React major and a Font Awesome major (whose icon names change) are the
66
+ * app's own migration steps.
67
+ */
68
+ export function reportPeerRanges(manifest) {
69
+ for (const name of DEP_SECTIONS) {
70
+ const range = manifest.section(name)?.react;
71
+ if (range && /^[~^]?(?:[0-9]|1[0-7])(?:[.x]|$)/.test(range.trim())) {
72
+ manifest.report('peer-deps', `react ${range} predates bestax-bulma's peer range (^18 || ^19) — upgrade react and react-dom to 18 or 19 before installing`);
73
+ }
74
+ }
75
+ // Font Awesome older than 6 conflicts with bestax-bulma's optional peer
76
+ // range and makes `npm install` fail with ERESOLVE.
77
+ for (const name of DEP_SECTIONS) {
78
+ const range = manifest.section(name)?.['@fortawesome/fontawesome-free'];
79
+ if (range && /^[~^]?[0-5](?:[.x]|$)/.test(range.trim())) {
80
+ manifest.report('peer-deps', `@fortawesome/fontawesome-free ${range} predates bestax-bulma's optional peer range (^6.7.2 || ^7.0.0) — upgrade it, or install with \`npm install --legacy-peer-deps\``);
81
+ }
82
+ }
83
+ }
84
+ /** node-sass is dead; dart-sass replaces it in the same section. */
85
+ export function replaceNodeSass(manifest) {
86
+ for (const name of DEP_SECTIONS) {
87
+ const deps = manifest.section(name);
88
+ if (deps && 'node-sass' in deps) {
89
+ delete deps['node-sass'];
90
+ manifest.note(`removed node-sass from ${name}`);
91
+ const sassDeclared = DEP_SECTIONS.some(s => manifest.section(s)?.sass);
92
+ if (!sassDeclared) {
93
+ deps.sass = SASS_RANGE;
94
+ manifest.note(`added sass ${SASS_RANGE} to ${name} (replaces node-sass)`);
95
+ }
96
+ }
97
+ }
98
+ }
@@ -14,8 +14,11 @@
14
14
  */
15
15
  import type { StylesTransform } from '../../types.js';
16
16
  export interface StylesConfig {
17
- /** npm package name of the source library, e.g. `rbx`. */
18
- packageName: string;
17
+ /**
18
+ * npm package name of the source library, e.g. `rbx`. Omitted for a source
19
+ * with no package, whose stylesheets only ever import Bulma itself.
20
+ */
21
+ packageName?: string;
19
22
  /** URL of that source's migration guide, linked from every TODO. */
20
23
  guideUrl: string;
21
24
  /**
@@ -32,6 +35,7 @@ export interface StylesConfig {
32
35
  * `packageName` drives two regexes — one matching any `@import` of that
33
36
  * package, one narrowing to its *root* stylesheet (which becomes a Bulma v1
34
37
  * root rather than being dropped). Everything else is Bulma-side and shared.
38
+ * Without a package neither can match, and only the Bulma rewriting runs.
35
39
  */
36
40
  export declare function makeStylesTransform(config: StylesConfig): StylesTransform;
37
41
  //# sourceMappingURL=make-styles-transform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"make-styles-transform.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/make-styles-transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC;AAyMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CA6UzE"}
1
+ {"version":3,"file":"make-styles-transform.d.ts","sourceRoot":"","sources":["../../../src/sources/_shared/make-styles-transform.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAiB,MAAM,gBAAgB,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,sBAAsB,EAAE,MAAM,EAAE,CAAC;CAClC;AAyMD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,CAsVzE"}
@@ -197,10 +197,14 @@ function report(collector, file, line, rule, message) {
197
197
  * `packageName` drives two regexes — one matching any `@import` of that
198
198
  * package, one narrowing to its *root* stylesheet (which becomes a Bulma v1
199
199
  * root rather than being dropped). Everything else is Bulma-side and shared.
200
+ * Without a package neither can match, and only the Bulma rewriting runs.
200
201
  */
201
202
  export function makeStylesTransform(config) {
202
203
  const { packageName, guideUrl: GUIDE } = config;
203
- const pkg = packageName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
204
+ // `packageName` is interpolated into messages only after one of these
205
+ // matched, so the no-package case never reaches them.
206
+ const NEVER = /(?!)/;
207
+ const pkg = packageName?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
204
208
  // Already regex fragments — see StylesConfig.
205
209
  const roots = config.rootStylesheetSuffixes.join('|');
206
210
  /**
@@ -210,11 +214,15 @@ export function makeStylesTransform(config) {
210
214
  * and SOURCE_ROOT_STYLESHEET below already accepts that bare form — so
211
215
  * requiring the slash here made the bare case unreachable.
212
216
  */
213
- const SOURCE_STYLE_IMPORT = new RegExp(`^(\\s*)@import\\s+(['"])((?:\\.\\.?/)+node_modules/|~)?${pkg}(?:/[^'"]*)?\\2\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
217
+ const SOURCE_STYLE_IMPORT = pkg === undefined
218
+ ? NEVER
219
+ : new RegExp(`^(\\s*)@import\\s+(['"])((?:\\.\\.?/)+node_modules/|~)?${pkg}(?:/[^'"]*)?\\2\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
214
220
  /** Cheap "is this file even about us?" pre-filter (see the guard below). */
215
- const SOURCE_MENTION = new RegExp(pkg);
221
+ const SOURCE_MENTION = pkg === undefined ? NEVER : new RegExp(pkg);
216
222
  /** …narrowed to the ones that stand in for a whole Bulma root. */
217
- const SOURCE_ROOT_STYLESHEET = new RegExp(`^\\s*@import\\s+(['"])(?:(?:\\.\\.?/)+node_modules/|~)?${pkg}${roots ? `(?:${roots})?` : ''}\\1\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
223
+ const SOURCE_ROOT_STYLESHEET = pkg === undefined
224
+ ? NEVER
225
+ : new RegExp(`^\\s*@import\\s+(['"])(?:(?:\\.\\.?/)+node_modules/|~)?${pkg}${roots ? `(?:${roots})?` : ''}\\1\\s*;?\\s*(?://[^\\n]*)?\\s*$`);
218
226
  const transformStyles = (filePath, source, collector, options) => {
219
227
  const cssMode = options.cssMode ?? 'bestax';
220
228
  // Cheap pre-filter. It must accept a file that names only the SOURCE