@symbiote-native/css-parser 0.1.1 → 0.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.
- package/README.md +10 -0
- package/build/generate-dts.js +2 -2
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/metro-css-module.js +1 -1
- package/build/metro-transformer.d.ts +2 -1
- package/build/metro-transformer.js +22 -9
- package/build/parser.js +8 -10
- package/build/preprocessors.js +2 -4
- package/build/properties.js +3 -5
- package/build/values.js +1 -2
- package/package.json +2 -1
- package/typescript-plugin.cjs +12 -18
package/README.md
CHANGED
|
@@ -14,6 +14,16 @@ CSS Modules all work identically regardless of source language.
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
Not installed directly by an app — each adapter package (`@symbiote-native/react`,
|
|
20
|
+
`@symbiote-native/vue`, `@symbiote-native/angular`) already depends on it and re-exports it via its
|
|
21
|
+
own `./metro-css-parser` subpath. Writing a Metro transformer for a new adapter yourself:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @symbiote-native/css-parser
|
|
25
|
+
```
|
|
26
|
+
|
|
17
27
|
## Who calls this, and how
|
|
18
28
|
|
|
19
29
|
**An app never imports this package directly.** It runs only inside a Metro transformer, on the
|
package/build/generate-dts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generates a real on-disk `.d.ts` for a `.module.css` (or `.module.scss`/`.module.less`/
|
|
2
|
-
// `.module.styl`) file
|
|
3
|
-
//
|
|
2
|
+
// `.module.styl`) file, giving CSS Modules imports real compile-time type checking.
|
|
3
|
+
// Unlike Volar's built-in `<style module>`
|
|
4
4
|
// typing for inline Vue SFC blocks (which synthesizes `Record<string, string> & {known keys}` —
|
|
5
5
|
// an index signature that still accepts any key, so it never catches a typo), the type emitted
|
|
6
6
|
// here has NO index signature: a typo in `styles.typo` is a genuine `error TS2339` under `tsc`/
|
package/build/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { hashFilePath } from './file-scope-id.ts';
|
|
|
5
5
|
export { compileCssFile, isCssModuleFile } from './metro-css-module.ts';
|
|
6
6
|
export type { ICompiledCssFile } from './metro-css-module.ts';
|
|
7
7
|
export { classNamesToDtsSource, generateModuleDts } from './generate-dts.ts';
|
|
8
|
-
export { createCssMetroTransformer } from './metro-transformer.ts';
|
|
8
|
+
export { createCssMetroTransformer, resolveUpstreamTransformer } from './metro-transformer.ts';
|
|
9
9
|
export type { IMetroTransformer, IMetroTransformParams } from './metro-transformer.ts';
|
|
10
10
|
export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from './preprocessors.ts';
|
|
11
11
|
export type { IPreprocessorLanguage } from './preprocessors.ts';
|
package/build/index.js
CHANGED
|
@@ -3,5 +3,5 @@ export { globalClassNamesIn } from "./global-selectors.js";
|
|
|
3
3
|
export { hashFilePath } from "./file-scope-id.js";
|
|
4
4
|
export { compileCssFile, isCssModuleFile } from "./metro-css-module.js";
|
|
5
5
|
export { classNamesToDtsSource, generateModuleDts } from "./generate-dts.js";
|
|
6
|
-
export { createCssMetroTransformer } from "./metro-transformer.js";
|
|
6
|
+
export { createCssMetroTransformer, resolveUpstreamTransformer } from "./metro-transformer.js";
|
|
7
7
|
export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from "./preprocessors.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// plain JS module — the framework-agnostic twin of a Vue SFC's inline <style>/<style module>
|
|
3
3
|
// block (examples/vue-sfc/metro-vue-transformer.js), usable from ANY adapter's own source file:
|
|
4
4
|
// `import styles from './Card.module.scss'` works the same from a React .tsx, a Vue <script>, or
|
|
5
|
-
// an Angular .ts.
|
|
5
|
+
// an Angular .ts.
|
|
6
6
|
//
|
|
7
7
|
// A plain style file registers its classes globally, exactly like an unscoped Vue <style>
|
|
8
8
|
// block — side-effect import only (`import './theme.scss'`), no default export. A `.module.*`
|
|
@@ -7,4 +7,5 @@ export interface IMetroTransformer {
|
|
|
7
7
|
transform: (params: IMetroTransformParams) => unknown;
|
|
8
8
|
getCacheKey?: (...args: unknown[]) => string;
|
|
9
9
|
}
|
|
10
|
-
export declare function
|
|
10
|
+
export declare function resolveUpstreamTransformer(): IMetroTransformer;
|
|
11
|
+
export declare function createCssMetroTransformer(upstreamTransformer?: IMetroTransformer): IMetroTransformer;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// A ready-made Metro babel transformer wrapper for .css/.scss/.sass/.less/.styl (+ their
|
|
2
|
-
// .module.* twins) support, so a consuming app's own metro.config.js needs only
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// is a regular `dependency` of every adapter
|
|
6
|
-
// @symbiote-native/angular), so this is
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
2
|
+
// .module.* twins) support, so a consuming app's own metro.config.js needs only
|
|
3
|
+
// `babelTransformerPath: require.resolve('@symbiote-native/<adapter>/metro-css-parser')` instead of
|
|
4
|
+
// hand-rolling the "compile a style file, delegate everything else to upstream" boilerplate once
|
|
5
|
+
// per adapter's example. @symbiote-native/css-parser is a regular `dependency` of every adapter
|
|
6
|
+
// package (@symbiote-native/react, @symbiote-native/vue, @symbiote-native/angular), so this is
|
|
7
|
+
// transitively resolvable from any app that already depends on one of them — this repo's
|
|
8
|
+
// shamefully-hoist pnpm config (.npmrc) makes that resolvable without the app adding
|
|
9
|
+
// @symbiote-native/css-parser to its own package.json.
|
|
10
10
|
//
|
|
11
11
|
// Sync vs async: `transform()` is async uniformly, for every recognized style extension
|
|
12
12
|
// including plain `.css`. Metro's own `metro-transform-worker` already does
|
|
@@ -22,9 +22,22 @@
|
|
|
22
22
|
// duplication. `return upstreamTransformer.transform(...)` as the last line of an async function
|
|
23
23
|
// forwards whatever it returns (Promise or not) as this function's own resolved value with no
|
|
24
24
|
// extra `await` needed; Metro awaits the whole chain regardless.
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
25
26
|
import { compileCssFile } from "./metro-css-module.js";
|
|
26
27
|
import { isStyleFile } from "./preprocessors.js";
|
|
27
|
-
|
|
28
|
+
// @react-native/metro-babel-transformer is a real `dependency` of this package (not merely a
|
|
29
|
+
// peer/dev dep), so it lands in css-parser's OWN resolvable node_modules under pnpm — no
|
|
30
|
+
// hoisting or `paths`-anchored require.resolve trick needed, unlike the app-local workaround
|
|
31
|
+
// this replaces (formerly duplicated in every adapter's example metro-css-transformer.js).
|
|
32
|
+
// Exported (not just used internally) so a per-framework Metro transformer that ALSO needs to
|
|
33
|
+
// delegate to the upstream RN transformer (the Vue SFC transformer, for its non-.vue passthrough
|
|
34
|
+
// branch) can reuse this instead of its own fragile direct `require('@react-native/metro-babel-
|
|
35
|
+
// transformer')`, which would only resolve for an external install by accident of hoisting.
|
|
36
|
+
export function resolveUpstreamTransformer() {
|
|
37
|
+
const require = createRequire(import.meta.url);
|
|
38
|
+
return require('@react-native/metro-babel-transformer');
|
|
39
|
+
}
|
|
40
|
+
export function createCssMetroTransformer(upstreamTransformer = resolveUpstreamTransformer()) {
|
|
28
41
|
return {
|
|
29
42
|
async transform(params) {
|
|
30
43
|
if (!isStyleFile(params.filename))
|
package/build/parser.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
// CSS → React Native style-object compiler.
|
|
2
|
-
// `
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// (see values.ts). `mapCSSProperty` (properties.ts) targets RN's `ViewStyle`/`TextStyle` instead
|
|
7
|
-
// of wolfie's `Styles`.
|
|
1
|
+
// CSS → React Native style-object compiler. `extractClassName` and the CSS-custom-property/
|
|
2
|
+
// `var()` resolution machinery are framework/target-agnostic. `evaluateCalc` treats `px` as
|
|
3
|
+
// identity (RN has no cell grid to scale against) and `rem`/`em` as scaled by the same
|
|
4
|
+
// {@link REM_TO_PX} constant as a bare value (see values.ts). `mapCSSProperty` (properties.ts)
|
|
5
|
+
// targets RN's `ViewStyle`/`TextStyle`.
|
|
8
6
|
import postcss from 'postcss';
|
|
9
7
|
import valueParser from 'postcss-value-parser';
|
|
10
8
|
import { mapCSSProperty } from "./properties.js";
|
|
@@ -148,9 +146,9 @@ function resolveVariables(value, variables) {
|
|
|
148
146
|
const CALC_TERM_PATTERN = /calc\(([^)]+)\)/g;
|
|
149
147
|
const NUMBER_WITH_UNIT_PATTERN = /(-?\d+(?:\.\d+)?)(rem|em|px)?/g;
|
|
150
148
|
/**
|
|
151
|
-
* Evaluates
|
|
152
|
-
*
|
|
153
|
-
*
|
|
149
|
+
* Evaluates a narrow shape of `calc()`: a single multiplication, or the first numeric term
|
|
150
|
+
* as a fallback. `px` is identity; `rem`/`em` scale by {@link REM_TO_PX}, matching a bare
|
|
151
|
+
* dimension value.
|
|
154
152
|
*/
|
|
155
153
|
function evaluateCalc(value) {
|
|
156
154
|
if (!value.includes('calc('))
|
package/build/preprocessors.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Optional SCSS/Sass, Less, and Stylus preprocessor support. Each compiler here only ever reduces
|
|
2
2
|
// its own syntax down to plain CSS text — parser.ts's `parseCSS()` is the single, UNCHANGED
|
|
3
|
-
// downstream consumer of that text, exactly as it always was for a plain `.css` file.
|
|
4
|
-
//
|
|
5
|
-
// file's Tailwind branch is a separate, out-of-scope concern here, see the
|
|
6
|
-
// symbiote-sfc-style-compiler skill).
|
|
3
|
+
// downstream consumer of that text, exactly as it always was for a plain `.css` file. Tailwind
|
|
4
|
+
// is a separate, out-of-scope concern and has no branch here.
|
|
7
5
|
//
|
|
8
6
|
// `sass`/`less`/`stylus` are lazy `import()`ed, never a top-level import, and are
|
|
9
7
|
// devDependencies of THIS package ONLY (never a `dependency`, see package.json) — a project that
|
package/build/properties.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
// CSS property → React Native ViewStyle/TextStyle prop mapping.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// (`margin`, `borderRadius`, `borderTopLeftRadius`, …), so this table is a flat kebab→camel
|
|
5
|
-
// rename plus a value-conversion kind — no shorthand expansion is needed.
|
|
1
|
+
// CSS property → React Native ViewStyle/TextStyle prop mapping. RN's own style props already
|
|
2
|
+
// mirror CSS's shorthand model 1:1 (`margin`, `borderRadius`, `borderTopLeftRadius`, …), so this
|
|
3
|
+
// table is a flat kebab→camel rename plus a value-conversion kind — no shorthand expansion is needed.
|
|
6
4
|
import { parseNumeric, parseNumericOrPercent, parseRawValue, parseTextShadow, warnOnce, } from "./values.js";
|
|
7
5
|
/**
|
|
8
6
|
* kebab-case CSS property → { RN camelCase prop, value-conversion kind }.
|
package/build/values.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// CSS → React Native value conversion. RN style props take plain numbers for `px` / unitless
|
|
2
|
-
// values
|
|
3
|
-
// unlike wolf-tui's `values.ts` there is no unit-to-cell division here — `px` is identity.
|
|
2
|
+
// values, so there is no unit conversion needed here beyond scaling `rem`/`em` — `px` is identity.
|
|
4
3
|
import valueParser from 'postcss-value-parser';
|
|
5
4
|
// symbiote has no root-font-size registry (a DOM `<html>` element would own one); we pick CSS's
|
|
6
5
|
// own default of a 16px root font size as the `rem` multiplier, so `2rem` reads as `32`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/css-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Build-time CSS/SCSS/Less/Stylus compiler for SymbioteNative — compiles stylesheets to React Native style objects, resolved at runtime via a cross-adapter class-name registry.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
+
"@react-native/metro-babel-transformer": "0.86.0",
|
|
42
43
|
"postcss": "^8.4.49",
|
|
43
44
|
"postcss-value-parser": "^4.2.0"
|
|
44
45
|
},
|
package/typescript-plugin.cjs
CHANGED
|
@@ -7,18 +7,13 @@
|
|
|
7
7
|
// live-editing case; generate-dts-cli.ts (`css-dts`, wired to `pretypecheck`) remains the
|
|
8
8
|
// separate, on-disk source of truth for `tsc`/`vue-tsc` CLI runs — plugins never load there.
|
|
9
9
|
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
// invalidates, so autocomplete goes stale after editing the CSS file until the IDE restarts
|
|
18
|
-
// tsserver — this version keys the cache on the file's mtime instead. wolf-tui's package.json
|
|
19
|
-
// also lists a real dependency on `@wolf-tui/css-parser` that its index.ts never actually
|
|
20
|
-
// imports — a leftover of an abandoned attempt to reuse it directly, for the same reason
|
|
21
|
-
// explained below.
|
|
10
|
+
// Core mechanism: override getScriptSnapshot + resolveModuleNameLiterals to synthesize a virtual
|
|
11
|
+
// .d.ts for the import. Two things worth calling out: (1) the class extractor converts kebab-case
|
|
12
|
+
// to camelCase, so a suggested key like `section-tight` matches the ACTUAL exported key our
|
|
13
|
+
// runtime produces (@symbiote-native/css-parser's parseCSS always camelCases — see
|
|
14
|
+
// src/generate-dts.ts's classNamesToDtsSource, which this plugin's dts shape mirrors); (2) the dts
|
|
15
|
+
// cache is keyed on the file's mtime, so autocomplete doesn't go stale after editing the CSS file
|
|
16
|
+
// and wait for the IDE to restart tsserver.
|
|
22
17
|
//
|
|
23
18
|
// SCOPE: plain `.module.css` only, not `.module.scss`/`.module.less`/`.module.styl` —
|
|
24
19
|
// getScriptSnapshot must be fully SYNCHRONOUS (tsserver's plugin protocol has no async hook), and
|
|
@@ -31,14 +26,13 @@
|
|
|
31
26
|
// SCOPE, second cut: only a SIMPLE `.foo { ... }` class selector is recognized correctly — a
|
|
32
27
|
// compound (`.btn.primary`) or descendant (`.card .title`) selector, which the real
|
|
33
28
|
// src/parser.ts's extractClassName merges into ONE key (`btnPrimary`/`cardTitle`), gets
|
|
34
|
-
// extracted here as TWO separate (wrong, non-existent) keys instead.
|
|
35
|
-
//
|
|
36
|
-
// detected").
|
|
29
|
+
// extracted here as TWO separate (wrong, non-existent) keys instead. This is an accepted
|
|
30
|
+
// limitation of the regex-based approach — complex selectors may not be detected correctly.
|
|
37
31
|
//
|
|
38
32
|
// Hand-written plain CommonJS, NOT compiled from a `.ts`/`.cts` source — same convention already
|
|
39
|
-
// used for each adapter's metro-css-parser.cjs shim
|
|
40
|
-
//
|
|
41
|
-
//
|
|
33
|
+
// used for each adapter's metro-css-parser.cjs shim. tsserver loads a plugin via a synchronous
|
|
34
|
+
// `require()`, which cannot load this package's own ESM build output; a `.cts` source was tried
|
|
35
|
+
// first and rejected because
|
|
42
36
|
// this package's shared tsconfig (`moduleResolution: "Bundler"`, needed for the rest of the
|
|
43
37
|
// package) doesn't apply the classic .cts→CJS format-forcing TypeScript otherwise gives Node16/
|
|
44
38
|
// NodeNext projects — carving out a second tsconfig/project reference just for one file was more
|