@symbiote-native/css-parser 0.2.0 → 0.2.2

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,16 +1,16 @@
1
1
  // Generates a real on-disk `.d.ts` for a `.module.css` (or `.module.scss`/`.module.less`/
2
- // `.module.styl`) file — the follow-up the symbiote-sfc-style-compiler skill records as
3
- // deliberately deferred when CSS Modules shipped. Unlike Volar's built-in `<style module>`
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`/
7
7
  // `vue-tsc`, not a silent runtime miss. Named `<file>.d.ts` (full original filename, extension
8
8
  // appended rather than replaced — e.g. `Card.module.css.d.ts`) so TypeScript's own module
9
- // resolution picks it up for `import styles from './Card.module.css'` without a separate
9
+ // resolution picks it up for a default import of `Card.module.css` without a separate
10
10
  // registration step, the same convention typed-css-modules uses.
11
- import { parseCSS } from "./parser.js";
12
- import { compile, detectLanguage } from "./preprocessors.js";
13
- import { isCssModuleFile } from "./metro-css-module.js";
11
+ import { parseCSS } from "../parser/index.js";
12
+ import { compile, detectLanguage } from "../preprocessors/index.js";
13
+ import { isCssModuleFile } from "../metro-css-module/index.js";
14
14
  const IDENTIFIER_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
15
15
  function formatKey(className) {
16
16
  return IDENTIFIER_RE.test(className) ? className : JSON.stringify(className);
@@ -14,9 +14,9 @@
14
14
  // `--watch` mode for live autocomplete while actively editing styles.
15
15
  import * as fs from 'node:fs/promises';
16
16
  import * as path from 'node:path';
17
- import { isStyleFile } from "./preprocessors.js";
18
- import { isCssModuleFile } from "./metro-css-module.js";
19
- import { generateModuleDts } from "./generate-dts.js";
17
+ import { isStyleFile } from "./preprocessors/index.js";
18
+ import { isCssModuleFile } from "./metro-css-module/index.js";
19
+ import { generateModuleDts } from "./generate-dts/index.js";
20
20
  const SKIPPED_DIR_NAMES = new Set(['node_modules', 'build', '.git']);
21
21
  async function collectModuleStyleFiles(root) {
22
22
  const stat = await fs.stat(root);
@@ -7,7 +7,7 @@
7
7
  // exempt these names, so it re-derives it here with its own minimal regex, independent of the
8
8
  // full CSS-to-style pipeline. Only the single-class form (`:global(.name)`) is recognized,
9
9
  // matching extractClassName's own documented narrower gap for partial/nested :global() wrapping.
10
- import { kebabToCamel } from "./parser.js";
10
+ import { kebabToCamel } from "./parser/index.js";
11
11
  const GLOBAL_SELECTOR_PATTERN = /:global\(\s*\.([a-zA-Z0-9_-]+)\s*\)/g;
12
12
  export function globalClassNamesIn(css) {
13
13
  const names = new Set();
package/build/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- export { parseCSS, extractClassName, kebabToCamel } from './parser.ts';
2
- export type { ICssParserOptions } from './parser.ts';
1
+ export { parseCSS, extractClassName, kebabToCamel } from './parser/index.ts';
2
+ export type { ICssParserOptions } from './parser/index.ts';
3
3
  export { globalClassNamesIn } from './global-selectors.ts';
4
4
  export { hashFilePath } from './file-scope-id.ts';
5
- export { compileCssFile, isCssModuleFile } from './metro-css-module.ts';
6
- export type { ICompiledCssFile } from './metro-css-module.ts';
7
- export { classNamesToDtsSource, generateModuleDts } from './generate-dts.ts';
8
- export { createCssMetroTransformer, resolveUpstreamTransformer } from './metro-transformer.ts';
9
- export type { IMetroTransformer, IMetroTransformParams } from './metro-transformer.ts';
10
- export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from './preprocessors.ts';
11
- export type { IPreprocessorLanguage } from './preprocessors.ts';
5
+ export { compileCssFile, isCssModuleFile } from './metro-css-module/index.ts';
6
+ export type { ICompiledCssFile } from './metro-css-module/index.ts';
7
+ export { classNamesToDtsSource, generateModuleDts } from './generate-dts/index.ts';
8
+ export { createCssMetroTransformer, resolveUpstreamTransformer, } from './metro-transformer/index.ts';
9
+ export type { IMetroTransformer, IMetroTransformParams } from './metro-transformer/index.ts';
10
+ export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from './preprocessors/index.ts';
11
+ export type { IPreprocessorLanguage } from './preprocessors/index.ts';
package/build/index.js CHANGED
@@ -1,7 +1,7 @@
1
- export { parseCSS, extractClassName, kebabToCamel } from "./parser.js";
1
+ export { parseCSS, extractClassName, kebabToCamel } from "./parser/index.js";
2
2
  export { globalClassNamesIn } from "./global-selectors.js";
3
3
  export { hashFilePath } from "./file-scope-id.js";
4
- export { compileCssFile, isCssModuleFile } from "./metro-css-module.js";
5
- export { classNamesToDtsSource, generateModuleDts } from "./generate-dts.js";
6
- export { createCssMetroTransformer, resolveUpstreamTransformer } from "./metro-transformer.js";
7
- export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from "./preprocessors.js";
4
+ export { compileCssFile, isCssModuleFile } from "./metro-css-module/index.js";
5
+ export { classNamesToDtsSource, generateModuleDts } from "./generate-dts/index.js";
6
+ export { createCssMetroTransformer, resolveUpstreamTransformer, } from "./metro-transformer/index.js";
7
+ export { compileScss, compileSass, compileLess, compileStylus, compile, detectLanguage, isStyleFile, } from "./preprocessors/index.js";
@@ -1,4 +1,4 @@
1
- import { type ICssParserOptions } from './parser.ts';
1
+ import { type ICssParserOptions } from '../parser/index.ts';
2
2
  export interface ICompiledCssFile {
3
3
  code: string;
4
4
  }
@@ -1,8 +1,8 @@
1
1
  // Compiles a standalone .css/.scss/.sass/.less/.styl (and their .module.* twins) file into a
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
- // `import styles from './Card.module.scss'` works the same from a React .tsx, a Vue <script>, or
5
- // an Angular .ts. See the symbiote-sfc-style-compiler skill.
4
+ // a default import of `Card.module.scss` works the same from a React .tsx, a Vue <script>, or an
5
+ // 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.*`
@@ -20,10 +20,10 @@
20
20
  // logic is entirely language-agnostic, it only ever sees `parseCSS`'s plain-CSS output, same as
21
21
  // it always did for a `.css` file.
22
22
  import * as path from 'node:path';
23
- import { parseCSS } from "./parser.js";
24
- import { globalClassNamesIn } from "./global-selectors.js";
25
- import { hashFilePath } from "./file-scope-id.js";
26
- import { compile, detectLanguage } from "./preprocessors.js";
23
+ import { parseCSS } from "../parser/index.js";
24
+ import { globalClassNamesIn } from "../global-selectors.js";
25
+ import { hashFilePath } from "../file-scope-id.js";
26
+ import { compile, detectLanguage } from "../preprocessors/index.js";
27
27
  export function isCssModuleFile(filename) {
28
28
  const ext = path.extname(filename);
29
29
  if (!ext)
@@ -6,7 +6,7 @@
6
6
  // package (@symbiote-native/react, @symbiote-native/vue, @symbiote-native/angular), so this is
7
7
  // transitively resolvable from any app that already depends on one of them — this repo's
8
8
  // shamefully-hoist pnpm config (.npmrc) makes that resolvable without the app adding
9
- // @symbiote-native/css-parser to its own package.json. See the symbiote-sfc-style-compiler skill.
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
@@ -23,8 +23,8 @@
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
25
  import { createRequire } from 'node:module';
26
- import { compileCssFile } from "./metro-css-module.js";
27
- import { isStyleFile } from "./preprocessors.js";
26
+ import { compileCssFile } from "../metro-css-module/index.js";
27
+ import { isStyleFile } from "../preprocessors/index.js";
28
28
  // @react-native/metro-babel-transformer is a real `dependency` of this package (not merely a
29
29
  // peer/dev dep), so it lands in css-parser's OWN resolvable node_modules under pnpm — no
30
30
  // hoisting or `paths`-anchored require.resolve trick needed, unlike the app-local workaround
@@ -1,14 +1,12 @@
1
- // CSS → React Native style-object compiler. Ported from wolf-tui's
2
- // `internal/css-parser/src/parser.ts`: `extractClassName` and the CSS-custom-property/`var()`
3
- // resolution machinery are framework/target-agnostic and carry over near-verbatim. `evaluateCalc`
4
- // drops wolf-tui's terminal-cell scaling (`1rem = 4 cells`, `4px = 1 cell`) — RN has no cell grid,
5
- // so `px` is identity and `rem`/`em` use the same {@link REM_TO_PX} constant as a bare value
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
- import { mapCSSProperty } from "./properties.js";
11
- import { REM_TO_PX } from "./values.js";
8
+ import { mapCSSProperty } from "../properties.js";
9
+ import { REM_TO_PX } from "../values.js";
12
10
  //#region Selector utilities
13
11
  // Exported: the SFC style compiler (metro-vue-transformer.js) reuses this exact conversion to
14
12
  // normalize a template's kebab-case class="section-label" authoring to the camelCase key this
@@ -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 the narrow shape of `calc()` wolf-tui supported (a single multiplication, or the
152
- * first numeric term as a fallback) — ported verbatim minus the terminal-cell unit scale.
153
- * `px` is identity; `rem`/`em` scale by {@link REM_TO_PX}, matching a bare dimension value.
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('))
@@ -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. Ported from
4
- // wolf-tui's `internal/css-parser/src/preprocessors.ts` (the SCSS/Less/Stylus shape only — that
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
@@ -1,8 +1,6 @@
1
- // CSS property → React Native ViewStyle/TextStyle prop mapping. Unlike wolf-tui's
2
- // `properties.ts` (which maps onto a terminal-cell `Styles` type with TUI-only concepts like
3
- // `borderStyle: 'round'`), RN's own style props already mirror CSS's shorthand model 1:1
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 (there is no terminal-cell or DP grid to scale onto, unlike wolf-tui's TUI target), so
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.2.0",
3
+ "version": "0.2.2",
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",
@@ -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
- // Ported from wolf-tui's `@wolf-tui/typescript-plugin` (wolf-tui/packages/typescript-plugin/
11
- // src/index.ts) — same core mechanism (override getScriptSnapshot + resolveModuleNameLiterals to
12
- // synthesize a virtual .d.ts for the import), fixing two real bugs found by reading that source
13
- // directly: (1) its class extractor never converts kebab-case to camelCase, so a suggested key
14
- // like `section-tight` does NOT match the ACTUAL exported key our runtime produces
15
- // (@symbiote-native/css-parser's parseCSS always camelCases — see src/generate-dts.ts's
16
- // classNamesToDtsSource, which this plugin's dts shape mirrors); (2) its dts cache never
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. Same accepted limitation
35
- // wolf-tui's own README documents for its regex approach ("complex selectors may not be
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 (see the symbiote-sfc-style-compiler skill's
40
- // "Distribution" section). tsserver loads a plugin via a synchronous `require()`, which cannot
41
- // load this package's own ESM build output; a `.cts` source was tried first and rejected because
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
File without changes