@cssxjs/babel-plugin-rn-stylename-inline 0.2.0

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 ADDED
@@ -0,0 +1,15 @@
1
+ # v0.2.0 (Tue Nov 04 2025)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - feat: refactor all babel plugins to perform early transformation of all code in Program.enter block ([@cray0000](https://github.com/cray0000))
6
+ - feat: make it work for pure web through a babel plugin [#2](https://github.com/startupjs/cssx/pull/2) ([@cray0000](https://github.com/cray0000))
7
+ - feat: move over styles-related packages from startupjs ([@cray0000](https://github.com/cray0000))
8
+
9
+ #### 🐛 Bug Fix
10
+
11
+ - fix(babel-plugin-rn-stylename-to-stylename-inline): fix import aliases support, update tests ([@cray0000](https://github.com/cray0000))
12
+
13
+ #### Authors: 1
14
+
15
+ - Pavel Zhukov ([@cray0000](https://github.com/cray0000))
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @cssxjs/babel-plugin-rn-stylename-inline
2
+
3
+ Adds support for in-JS template strings `css\`\`` and `styl\`\``
4
+ for CSS styles for react-native.
5
+
6
+ Must be used together with `@cssxjs/babel-plugin-rn-stylename-to-style` library.
7
+
8
+ ## Options
9
+
10
+ - `platform` -- what platform the compilation is on. This is passed down to the underlying compiler (for example in Stylus it defines global variables `$PLATFORM = "web"` and `__WEB__ = true`). Example: `"web"` or `"ios"` or `"android"`. Default: `'web'`.
11
+ - `magicImports` -- an array of magic imports to use. Example: `["cssxjs", "startupjs"]`. Default: `["cssxjs"]`.
12
+
13
+ ## Example
14
+
15
+ ### File-level scope (global to file)
16
+
17
+ ```jsx
18
+ import React from 'react'
19
+ import { View } from 'react-native'
20
+ import { css } from 'cssxjs'
21
+
22
+ export default function Card () {
23
+ return <View styleName='card active'><Line /></View>
24
+ }
25
+ function Line () {
26
+ return <View styleName='line' />
27
+ }
28
+ css`
29
+ .card {
30
+ padding: 8px 16px;
31
+ }
32
+ .line {
33
+ margin-top: 16px;
34
+ border-radius: 8px;
35
+ }
36
+ .active {
37
+ background-color: red;
38
+ }
39
+ `
40
+ ```
41
+
42
+ ### Local component scope (inside particular react component function)
43
+
44
+ ```jsx
45
+ import React from 'react'
46
+ import { View } from 'react-native'
47
+ import { css, styl } from 'cssxjs'
48
+
49
+ export default function Card () {
50
+ return <View styleName='root active'><Line /></View>
51
+ // .root will be scoped only to this specific component
52
+ styl`
53
+ .root
54
+ padding: 8px 16px
55
+ `
56
+ }
57
+ function Line () {
58
+ return <View styleName='root' />
59
+ // .root will be scoped only to this specific component
60
+ css`
61
+ .root {
62
+ margin-top: 16px;
63
+ border-radius: 8px;
64
+ }
65
+ `
66
+ }
67
+ // you can use global- and local- scoped styles together
68
+ styl`
69
+ .active
70
+ background-color red
71
+ `
72
+ ```
73
+
74
+ ## License
75
+
76
+ MIT
@@ -0,0 +1,13 @@
1
+ // TODO: Move loaders into standalone libs
2
+ const cssLoader = require('@cssxjs/bundler/lib/cssToReactNativeLoader')
3
+ const callLoader = require('@cssxjs/bundler/lib/callLoader')
4
+ const { stripExport } = require('./helpers')
5
+
6
+ module.exports = function compileCss (src) {
7
+ return stripExport(
8
+ callLoader(
9
+ cssLoader,
10
+ src
11
+ )
12
+ )
13
+ }
@@ -0,0 +1,3 @@
1
+ exports.stripExport = function stripExport (source) {
2
+ return source.replace(/^(?:export\s+default\s*|module\.exports\s*=\s*)/, '')
3
+ }
@@ -0,0 +1,7 @@
1
+ const css = require('./css')
2
+ const styl = require('./styl')
3
+
4
+ module.exports = {
5
+ css,
6
+ styl
7
+ }
@@ -0,0 +1,14 @@
1
+ // TODO: Move loaders into standalone libs
2
+ const stylLoader = require('@cssxjs/bundler/lib/stylusToCssLoader')
3
+ const callLoader = require('@cssxjs/bundler/lib/callLoader')
4
+ const compileCss = require('./css')
5
+
6
+ module.exports = function compileStyl (src, filename, options) {
7
+ src = callLoader(
8
+ stylLoader,
9
+ src,
10
+ filename,
11
+ options
12
+ )
13
+ return compileCss(src)
14
+ }
package/index.js ADDED
@@ -0,0 +1,126 @@
1
+ const { GLOBAL_NAME, LOCAL_NAME } =
2
+ require('@cssxjs/runtime/constants')
3
+ const template = require('@babel/template').default
4
+ const parser = require('@babel/parser')
5
+ const t = require('@babel/types')
6
+ const compilers = require('./compilers')
7
+ const DEFAULT_MAGIC_IMPORTS = ['cssxjs']
8
+ const DEFAULT_PLATFORM = 'web'
9
+
10
+ const buildConst = template(`
11
+ const %%variable%% = %%value%%
12
+ `)
13
+
14
+ module.exports = () => ({
15
+ visitor: {
16
+ Program: {
17
+ enter ($this, state) {
18
+ const usedCompilers = getUsedCompilers($this, state)
19
+ $this.traverse(getVisitor({ $program: $this, usedCompilers }), state)
20
+ }
21
+ }
22
+ }
23
+ })
24
+
25
+ const getVisitor = ({ $program, usedCompilers }) => ({
26
+ TaggedTemplateExpression: ($this, state) => {
27
+ // 0. process only templates which are in usedCompilers (imported from our library)
28
+ if (!shouldProcess($this, usedCompilers)) return
29
+
30
+ // I. validate template
31
+ validateTemplate($this, usedCompilers)
32
+
33
+ const compiler = usedCompilers[$this.node.tag.name]
34
+
35
+ // II. compile template
36
+ const source = $this.node.quasi.quasis[0]?.value?.raw || ''
37
+ const filename = state.file?.opts?.filename
38
+ const platform = state.opts?.platform || DEFAULT_PLATFORM
39
+ const compiledString = compiler(source, filename, { platform })
40
+ const compiledExpression = parser.parseExpression(compiledString)
41
+
42
+ // III. find parent function or program
43
+ const $function = $this.getFunctionParent()
44
+
45
+ // IV. LOCAL. if parent is function -- handle local
46
+ if ($function) {
47
+ // 1. define a `const` variable at the top of the file
48
+ // with the unique identifier
49
+ const localIdentifier = $program.scope.generateUidIdentifier('localCssInstance')
50
+ insertAfterImports($program, buildConst({
51
+ variable: localIdentifier,
52
+ value: compiledExpression
53
+ }))
54
+
55
+ // 2. reassign this unique identifier to a constant LOCAL_NAME
56
+ // in the scope of current function
57
+ $function.get('body').unshiftContainer('body', buildConst({
58
+ variable: t.identifier(LOCAL_NAME),
59
+ value: localIdentifier
60
+ }))
61
+
62
+ // V. GLOBAL. if parent is program -- handle global
63
+ } else {
64
+ // 1. define a `const` variable at the top of the file
65
+ // with the constant GLOBAL_NAME
66
+ insertAfterImports($program, buildConst({
67
+ variable: t.identifier(GLOBAL_NAME),
68
+ value: compiledExpression
69
+ }))
70
+ }
71
+
72
+ // VI. Remove template expression after processing
73
+ $this.remove()
74
+
75
+ // TODO: Throw error if global styles were already added or
76
+ // local styles were already added to the same function scope
77
+ }
78
+ })
79
+
80
+ function insertAfterImports ($program, expressionStatement) {
81
+ const lastImport = $program
82
+ .get('body')
83
+ .filter($i => $i.isImportDeclaration())
84
+ .pop()
85
+
86
+ if (lastImport) {
87
+ lastImport.insertAfter(expressionStatement)
88
+ } else {
89
+ $program.unshift(expressionStatement)
90
+ }
91
+ }
92
+
93
+ function shouldProcess ($template, usedCompilers = {}) {
94
+ if (!$template.get('tag').isIdentifier()) return
95
+ if (!usedCompilers[$template.node.tag.name]) return
96
+ return true
97
+ }
98
+
99
+ function validateTemplate ($template, usedCompilers = {}) {
100
+ const { node: { quasi } } = $template
101
+
102
+ if (quasi.expressions.length > 0) {
103
+ throw $template.buildCodeFrameError(`
104
+ [@cssxjs/babel-plugin-rn-stylename-inline] Expression interpolations are not supported in css\`\` and styl\`\`.
105
+ `)
106
+ }
107
+ }
108
+
109
+ function getUsedCompilers ($program, state) {
110
+ const res = {}
111
+ const magicImports = state.opts.magicImports || DEFAULT_MAGIC_IMPORTS
112
+ for (const $import of $program.get('body')) {
113
+ if (!$import.isImportDeclaration()) continue
114
+ if (!magicImports.includes($import.node.source.value)) continue
115
+ for (const $specifier of $import.get('specifiers')) {
116
+ if (!$specifier.isImportSpecifier()) continue
117
+ const { local, imported } = $specifier.node
118
+ if (compilers[imported.name]) {
119
+ res[local.name] = compilers[imported.name]
120
+ $specifier.remove()
121
+ }
122
+ }
123
+ if ($import.get('specifiers').length === 0) $import.remove()
124
+ }
125
+ return res
126
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@cssxjs/babel-plugin-rn-stylename-inline",
3
+ "version": "0.2.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Use styleName attributes with inline css and styl template strings",
8
+ "keywords": [
9
+ "babel",
10
+ "babel-plugin",
11
+ "react",
12
+ "lazy",
13
+ "import"
14
+ ],
15
+ "main": "index.js",
16
+ "scripts": {
17
+ "test": "jest"
18
+ },
19
+ "author": "Pavel Zhukov",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "https://github.com/startupjs/startupjs"
24
+ },
25
+ "dependencies": {
26
+ "@babel/parser": "^7.0.0",
27
+ "@babel/template": "^7.4.0",
28
+ "@babel/types": "^7.0.0",
29
+ "@cssxjs/bundler": "^0.2.0",
30
+ "@cssxjs/runtime": "^0.2.0"
31
+ },
32
+ "devDependencies": {
33
+ "@babel/plugin-syntax-jsx": "^7.0.0",
34
+ "babel-plugin-tester": "^9.1.0",
35
+ "jest": "^30.0.4"
36
+ },
37
+ "gitHead": "a80a44b4d14c116871ca03997ce772b6beabf5d8"
38
+ }