@cssxjs/babel-plugin-rn-stylename-to-style 0.2.15 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,27 @@
1
+ # v0.2.17 (Mon Nov 10 2025)
2
+
3
+ #### 🐛 Bug Fix
4
+
5
+ - fix(babel-plugin-rn-stylename-to-style): change the default extensions to compile to .cssx.css and .cssx.styl (cray0000@gmail.com)
6
+
7
+ #### Authors: 1
8
+
9
+ - Pavel Zhukov (cray0000@gmail.com)
10
+
11
+ ---
12
+
13
+ # v0.2.16 (Sun Nov 09 2025)
14
+
15
+ #### 🚀 Enhancement
16
+
17
+ - feat(babel-plugin-rn-stylename-to-style): Support compiling css file imports in Babel itself ([@cray0000](https://github.com/cray0000))
18
+
19
+ #### Authors: 1
20
+
21
+ - Pavel Zhukov ([@cray0000](https://github.com/cray0000))
22
+
23
+ ---
24
+
1
25
  # v0.2.15 (Sun Nov 09 2025)
2
26
 
3
27
  #### 🐛 Bug Fix
package/README.md CHANGED
@@ -103,7 +103,7 @@ You must give one or more file extensions inside an array in the plugin options.
103
103
 
104
104
  #### `extensions`
105
105
 
106
- **Required**
106
+ **Default** `['cssx.css', 'cssx.styl']`
107
107
 
108
108
  List of css extensions to process (`css`, `styl`, `sass`, etc.)
109
109
 
@@ -113,12 +113,19 @@ List of css extensions to process (`css`, `styl`, `sass`, etc.)
113
113
 
114
114
  Whether to generate ESM `import` instead of CJS `require`.
115
115
 
116
- #### `parseJson`
116
+ #### `compileCssImports`
117
117
 
118
- **Default:** `false`
118
+ **Default:** `true`
119
+
120
+ Whether to pre-process the css file imports, like `import './index.styl'` by this babel
121
+ plugin itself, instead of passing it further to the bundler to compile.
122
+ Note that if Babel is responsible for compiling these files then the changes in then
123
+ are not gonna be reactive and to see changes made to the separate CSS file
124
+ you would need to restart the whole bundling with an option to clear the Babel cache.
119
125
 
120
- Whether the imported css is expected to be a JSON string or an object.
121
- If this flag is specified then JSON string is expected and it will do `JSON.parse` on it.
126
+ Storing styles in separate files should be avoided though, you should try to only
127
+ use it when importing some 3rd party libraries or for you global theme definitions,
128
+ so these files shouldn't frequently change.
122
129
 
123
130
  #### `cache`
124
131
 
package/index.js CHANGED
@@ -1,11 +1,15 @@
1
1
  const nodePath = require('path')
2
+ const fs = require('fs')
2
3
  const t = require('@babel/types')
3
4
  const template = require('@babel/template').default
5
+ const parser = require('@babel/parser')
4
6
  const { GLOBAL_NAME, LOCAL_NAME } = require('@cssxjs/runtime/constants')
5
7
  const { addNamed } = require('@babel/helper-module-imports')
6
8
 
7
- const COMPILERS = ['css', 'styl', 'pug'] // used in rn-stylename-inline. TODO: move to a shared place
9
+ const COMPILERS = require('@cssxjs/loaders/compilers')
8
10
  const RUNTIME_LIBRARY = 'cssxjs/runtime'
11
+ const DEFAULT_PLATFORM = 'web'
12
+ const DEFAULT_EXTENSIONS = ['cssx.css', 'cssx.styl']
9
13
  const STYLE_NAME_REGEX = /(?:^s|S)tyleName$/
10
14
  const STYLE_REGEX = /(?:^s|S)tyle$/
11
15
  const ROOT_STYLE_PROP_NAME = 'style'
@@ -21,18 +25,19 @@ const buildSafeVar = template.expression(`
21
25
  typeof %%variable%% !== 'undefined' && %%variable%%
22
26
  `)
23
27
 
24
- const buildJsonParse = template(`
25
- const %%name%% = JSON.parse(%%jsonStyle%%)
26
- `)
27
-
28
28
  const buildRuntimeVar = template(`
29
29
  const %%name%% = %%imported%%
30
30
  `)
31
31
 
32
+ const buildConst = template(`
33
+ const %%variable%% = %%value%%
34
+ `)
35
+
32
36
  module.exports = function (babel) {
33
37
  let styleHash = {}
34
38
  let cssIdentifier
35
39
  let hasObserver
40
+ let hasFrameworkImport
36
41
  let $program
37
42
  let usedCompilers
38
43
  let runtime
@@ -267,6 +272,7 @@ module.exports = function (babel) {
267
272
  styleHash = {}
268
273
  cssIdentifier = undefined
269
274
  hasObserver = undefined
275
+ hasFrameworkImport = undefined
270
276
  $program = undefined
271
277
  usedCompilers = undefined
272
278
  runtime = undefined
@@ -282,29 +288,31 @@ module.exports = function (babel) {
282
288
  // 2. Run early traversal of everything
283
289
  $this.traverse({
284
290
  ImportDeclaration ($this, state) {
291
+ // refactor this to check if we have the magic import and observer in Program:enter
292
+ // since there is now a race condition - if observer import is after css file import
293
+ // then it won't be detected
285
294
  if (!hasObserver) hasObserver = checkObserverImport($this, state)
295
+ if (!hasFrameworkImport) hasFrameworkImport = checkHasFrameworkImport($this, state)
286
296
 
287
- const extensions =
288
- Array.isArray(state.opts.extensions) &&
289
- state.opts.extensions
297
+ const extensions = state.opts.extensions ?? DEFAULT_EXTENSIONS
290
298
 
291
- if (!extensions) {
292
- throw new Error(
293
- 'You have not specified any extensions in the plugin options.'
294
- )
299
+ if (!Array.isArray(extensions)) {
300
+ throw Error(`
301
+ You have not specified any extensions in the plugin options.
302
+ The 'extensions' option must be an array of strings like ['styl', 'css'].
303
+ If you don't want to handle any CSS file imports then specify an empty array.
304
+ `)
295
305
  }
296
306
 
297
- const node = $this.node
307
+ const source = $this.node.source.value
308
+ if (!extensions.some(ext => source.endsWith(`.${ext}`))) return
309
+ const compilerName = source.split('.').pop()
298
310
 
299
- if (extensions.indexOf(getExt(node)) === -1) {
300
- return
301
- }
302
-
303
- const anonymousImports = $this.container.filter(n => {
311
+ const anonymousImports = $this.container.filter(node => {
304
312
  return (
305
- t.isImportDeclaration(n) &&
306
- n.specifiers.length === 0 &&
307
- extensions.indexOf(getExt(n)) > -1
313
+ t.isImportDeclaration(node) &&
314
+ node.specifiers.length === 0 &&
315
+ extensions.some(ext => node.source.value.endsWith(`.${ext}`))
308
316
  )
309
317
  })
310
318
 
@@ -314,35 +322,50 @@ module.exports = function (babel) {
314
322
  )
315
323
  }
316
324
 
317
- let specifier = node.specifiers[0]
325
+ let specifier = $this.node.specifiers[0]
318
326
 
319
327
  if (!specifier) {
320
328
  specifier = t.ImportDefaultSpecifier(
321
329
  $this.scope.generateUidIdentifier('css')
322
330
  )
323
- node.specifiers = [specifier]
331
+ $this.node.specifiers = [specifier]
324
332
  }
325
333
 
326
- cssIdentifier = specifier.local
327
-
328
- // Do JSON.parse() on the css file if we receive it as a json string:
329
- // import css from './index.styl'
330
- // v v v
331
- // import jsonCss from './index.styl'
332
- // const css = JSON.parse(jsonCss)
333
- if (state.opts.parseJson) {
334
- const lastImportOrRequire = $program
335
- .get('body')
336
- .filter(p => p.isImportDeclaration() || isRequire(p.node))
337
- .pop()
338
- const tempCssIdentifier = $this.scope.generateUidIdentifier('jsonCss')
339
- node.specifiers[0].local = tempCssIdentifier
340
- lastImportOrRequire.insertAfter(
341
- buildJsonParse({
342
- name: cssIdentifier,
343
- jsonStyle: tempCssIdentifier
344
- })
334
+ const compileCssImports = state.opts.compileCssImports ?? true
335
+ // if we compile css imports, we need to replace the import with a variable declaration
336
+ if (compileCssImports) {
337
+ const localName = specifier.local.name
338
+ const filename = state.file?.opts?.filename
339
+ const platform = state.opts?.platform || state.file?.opts?.caller?.platform || DEFAULT_PLATFORM
340
+ // resolve the full path to the style file relative to the current file
341
+ const styleFilepath = nodePath.resolve(nodePath.dirname(filename), source)
342
+ // read the style file content
343
+ const styleFileContent = fs.readFileSync(styleFilepath, 'utf8')
344
+ // find the appropriate compiler
345
+ const compiler = COMPILERS[compilerName]
346
+ if (!compiler) {
347
+ throw $this.buildCodeFrameError(
348
+ `No compiler found for imported extension: "${source}"`
349
+ )
350
+ }
351
+ const compiledString = compiler(
352
+ styleFileContent,
353
+ styleFilepath,
354
+ { platform }
345
355
  )
356
+ const compiledExpression = parser.parseExpression(compiledString)
357
+
358
+ cssIdentifier = t.identifier(localName)
359
+ const varDeclaration = buildConst({
360
+ variable: cssIdentifier,
361
+ value: compiledExpression
362
+ })
363
+ insertAfterImports($program, varDeclaration)
364
+ // remove the original import and insert the variable declaration instead
365
+ $this.remove()
366
+ } else {
367
+ // otherwise just keep the import as is
368
+ cssIdentifier = specifier.local
346
369
  }
347
370
  },
348
371
  JSXOpeningElement: {
@@ -412,14 +435,6 @@ module.exports = function (babel) {
412
435
  }
413
436
  }
414
437
 
415
- function isRequire (node) {
416
- return node?.declarations?.[0]?.init?.callee?.name === 'require'
417
- }
418
-
419
- function getExt (node) {
420
- return nodePath.extname(node.source.value).replace(/^\./, '')
421
- }
422
-
423
438
  function convertStyleName (name) {
424
439
  return name.replace(/Name$/, '')
425
440
  }
@@ -515,6 +530,11 @@ function checkObserverImport ($import, state) {
515
530
  }
516
531
  }
517
532
 
533
+ function checkHasFrameworkImport ($import, state) {
534
+ const magicImports = state.opts.magicImports || DEFAULT_MAGIC_IMPORTS
535
+ return magicImports.includes($import.node.source.value)
536
+ }
537
+
518
538
  // find topmost function (which is not a lowercase named one).
519
539
  // .getFunctionParent() returns undefined when we reach Program
520
540
  function findReactFnComponent ($jsxAttribute) {
@@ -537,7 +557,6 @@ function findReactFnComponent ($jsxAttribute) {
537
557
  return $potentialComponentFn
538
558
  }
539
559
 
540
- // Get compilers from the magic import
541
560
  function getUsedCompilers ($program, state) {
542
561
  const res = new Map()
543
562
  const magicImports = state.opts.magicImports || DEFAULT_MAGIC_IMPORTS
@@ -547,8 +566,9 @@ function getUsedCompilers ($program, state) {
547
566
  for (const $specifier of $import.get('specifiers')) {
548
567
  if (!$specifier.isImportSpecifier()) continue
549
568
  const { local, imported } = $specifier.node
550
- if (COMPILERS.includes(imported.name)) {
551
- res.set(local.name, true)
569
+ // it's important to use hasOwnProperty here to avoid prototype pollution issues, like 'toString'
570
+ if (Object.prototype.hasOwnProperty.call(COMPILERS, imported.name)) {
571
+ res.set(local.name, COMPILERS[imported.name])
552
572
  $specifier.remove()
553
573
  }
554
574
  }
@@ -591,3 +611,16 @@ function addNamedImport ($program, name, sourceName) {
591
611
  importPosition: 'after'
592
612
  })
593
613
  }
614
+
615
+ function insertAfterImports ($program, expressionStatement) {
616
+ const lastImport = $program
617
+ .get('body')
618
+ .filter($i => $i.isImportDeclaration())
619
+ .pop()
620
+
621
+ if (lastImport) {
622
+ lastImport.insertAfter(expressionStatement)
623
+ } else {
624
+ $program.unshift(expressionStatement)
625
+ }
626
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cssxjs/babel-plugin-rn-stylename-to-style",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -24,15 +24,16 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@babel/helper-module-imports": "^7.0.0",
27
+ "@babel/parser": "^7.0.0",
27
28
  "@babel/template": "^7.4.0",
28
29
  "@babel/types": "^7.0.0",
29
- "@cssxjs/runtime": "^0.2.15"
30
+ "@cssxjs/runtime": "^0.2.17"
30
31
  },
31
32
  "devDependencies": {
32
33
  "@babel/plugin-syntax-jsx": "^7.0.0",
33
- "@cssxjs/babel-plugin-react-pug": "^0.2.15",
34
+ "@cssxjs/babel-plugin-react-pug": "^0.2.17",
34
35
  "babel-plugin-tester": "^9.1.0",
35
36
  "jest": "^30.0.4"
36
37
  },
37
- "gitHead": "3ab2ccbdfdd935546be993322c645f216e4768e3"
38
+ "gitHead": "02b76ae074674c67f8d50a85b091e1190648449d"
38
39
  }