@griffel/transform 1.1.0 → 1.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 CHANGED
@@ -1,12 +1,32 @@
1
1
  # Change Log - @griffel/transform
2
2
 
3
- This log was last generated on Mon, 03 Nov 2025 15:42:47 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 06 Mar 2026 08:15:28 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## 1.2.0
8
+
9
+ Fri, 06 Mar 2026 08:15:28 GMT
10
+
11
+ ### Minor changes
12
+
13
+ - feat: add AST evaluator plugin system with evaluationPlugins option (olfedias@microsoft.com)
14
+ - feat: wrap imported asset paths in <griffel-asset> tags for reliable CSS extraction (olfedias@microsoft.com)
15
+ - feat: add makeStaticStyles AOT/CSS extraction support (olfedias@microsoft.com)
16
+ - feat: hybrid evaluator that shakes ESM node_modules instead of ignoring them (olfedias@microsoft.com)
17
+ - feat: throw on non-ESM input in transformSync (olfedias@microsoft.com)
18
+ - Bump @griffel/core to v1.20.0
19
+
20
+ ### Patches
21
+
22
+ - refactor: use ScopeTracker from oxc-walker for scope-aware import resolution (olfedias@microsoft.com)
23
+ - refactor: extract dedupeCSSRules result to a variable in transformSync (olfedias@microsoft.com)
24
+ - refactor: internalize Linaria Module/EvalCache to remove @linaria/babel-preset dependency (olfedias@microsoft.com)
25
+ - perf: replace DeoptError with DEOPT sentinel symbol, optimize CSS rule dedup and lookups (olfedias@microsoft.com)
26
+
7
27
  ## 1.1.0
8
28
 
9
- Mon, 03 Nov 2025 15:42:47 GMT
29
+ Mon, 03 Nov 2025 15:43:56 GMT
10
30
 
11
31
  ### Minor changes
12
32
 
package/README.md CHANGED
@@ -6,12 +6,15 @@ A high-performance transformation package for Griffel that unifies CSS-in-JS tra
6
6
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
7
7
 
8
8
  - [Overview](#overview)
9
- - [Features](#features)
10
9
  - [Install](#install)
11
10
  - [Usage](#usage)
12
11
  - [Basic Transformation](#basic-transformation)
13
12
  - [API Reference](#api-reference)
14
13
  - [transformSync(sourceCode, options)](#transformsyncsourcecode-options)
14
+ - [Evaluation Plugins](#evaluation-plugins)
15
+ - [Built-in Plugins](#built-in-plugins)
16
+ - [`fluentTokensPlugin`](#fluenttokensplugin)
17
+ - [Custom Plugins](#custom-plugins)
15
18
 
16
19
  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
17
20
 
@@ -76,3 +79,60 @@ Transforms source code containing `makeStyles` or `makeResetStyles` calls.
76
79
  - `modules?` (string[]): Module sources to process
77
80
  - `babelOptions?` (object): Babel configuration for complex evaluations
78
81
  - `evaluationRules?` (array): Rules for determining evaluation strategy
82
+ - `astEvaluationPlugins?` (AstEvaluatorPlugin[]): Plugins for extending AST evaluation with custom node handling (default: `[fluentTokensPlugin]`)
83
+
84
+ ## Evaluation Plugins
85
+
86
+ The AST evaluator supports a plugin system that allows extending static evaluation to handle additional AST node types. Plugins are tried in order when the base evaluator encounters a node type it doesn't handle (i.e., anything beyond `Literal`, `ObjectExpression`, and simple `TemplateLiteral` without expressions).
87
+
88
+ ### Built-in Plugins
89
+
90
+ #### `fluentTokensPlugin`
91
+
92
+ Handles Fluent UI design token expressions, transforming `tokens.propertyName` into `var(--propertyName)`. Enabled by default — no configuration needed.
93
+
94
+ To disable it, pass an empty array:
95
+
96
+ ```typescript
97
+ const result = transformSync(sourceCode, {
98
+ filename: 'styles.ts',
99
+ astEvaluationPlugins: [],
100
+ });
101
+ ```
102
+
103
+ This plugin handles:
104
+
105
+ - `MemberExpression`: `tokens.colorBrandBackground` → `var(--colorBrandBackground)`
106
+ - `TemplateLiteral`: `` `${tokens.spacingVerticalS} 0` `` → `var(--spacingVerticalS) 0`
107
+
108
+ ### Custom Plugins
109
+
110
+ You can create custom plugins by implementing the `AstEvaluatorPlugin` interface:
111
+
112
+ ```typescript
113
+ import { type AstEvaluatorPlugin, DEOPT } from '@griffel/transform';
114
+
115
+ const myPlugin: AstEvaluatorPlugin = {
116
+ name: 'myPlugin',
117
+ evaluateNode(node, context) {
118
+ // Handle specific node types
119
+ if (node.type === 'MemberExpression') {
120
+ // Custom evaluation logic...
121
+ return 'some-value';
122
+ }
123
+
124
+ // Return DEOPT to signal "can't handle this node" and let the next plugin try
125
+ return DEOPT;
126
+ },
127
+ };
128
+
129
+ const result = transformSync(sourceCode, {
130
+ filename: 'styles.ts',
131
+ astEvaluationPlugins: [myPlugin],
132
+ });
133
+ ```
134
+
135
+ The `context` parameter provides:
136
+
137
+ - `programAst`: The full program AST for cross-referencing
138
+ - `evaluateNode(node)`: Recursive evaluator callback that goes through base evaluation + all plugins
@@ -0,0 +1,2 @@
1
+ export declare const ASSET_TAG_OPEN = "<griffel-asset>";
2
+ export declare const ASSET_TAG_CLOSE = "</griffel-asset>";
@@ -1,5 +1,11 @@
1
- import { Node } from 'oxc-parser';
2
- import { EvaluationResult } from './types.mjs';
1
+ import { Node, Program } from 'oxc-parser';
2
+ import { EvaluationResult, AstEvaluatorPlugin } from './types.mjs';
3
+ /**
4
+ * Sentinel value returned by plugins and evaluateNode to signal "can't handle this node".
5
+ * Using a symbol avoids the cost of Error construction and stack trace capture.
6
+ */
7
+ export declare const DEOPT: unique symbol;
8
+ export type Deopt = typeof DEOPT;
3
9
  /**
4
10
  * Simple static evaluator for object expressions with nested objects.
5
11
  * Based on Babel's evaluation approach but simplified for our specific use case.
@@ -8,5 +14,7 @@ import { EvaluationResult } from './types.mjs';
8
14
  * - Objects with nested objects: { root: { color: 'red', padding: 0 } }
9
15
  * - String literals, numeric literals, boolean literals, null
10
16
  * - Simple property access
17
+ *
18
+ * Plugins can extend evaluation to handle additional node types.
11
19
  */
12
- export declare function astEvaluator(node: Node): EvaluationResult;
20
+ export declare function astEvaluator(node: Node, programAst: Program, plugins?: AstEvaluatorPlugin[]): EvaluationResult;
@@ -1,11 +1,12 @@
1
- import { StrictOptions } from '@linaria/babel-preset';
1
+ import { Program } from 'oxc-parser';
2
+ import { StrictOptions, AstEvaluatorPlugin } from './types.mjs';
2
3
  import { StyleCall } from '../types.mjs';
3
4
  /**
4
5
  * Batch evaluates all style calls in a file for better performance.
5
6
  * Uses static evaluation first, then falls back to VM evaluation for complex expressions.
6
7
  * Optimizes VM evaluation by sharing module loading and parsing overhead.
7
8
  */
8
- export declare function batchEvaluator(sourceCode: string, filename: string, styleCalls: StyleCall[], babelOptions: NonNullable<StrictOptions['babelOptions']>, evaluationRules: NonNullable<StrictOptions['rules']>): {
9
+ export declare function batchEvaluator(sourceCode: string, filename: string, styleCalls: StyleCall[], babelOptions: NonNullable<StrictOptions['babelOptions']>, evaluationRules: NonNullable<StrictOptions['rules']>, programAst: Program, astEvaluationPlugins?: AstEvaluatorPlugin[]): {
9
10
  usedVMForEvaluation: boolean;
10
11
  evaluationResults: unknown[];
11
12
  };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Evaluation cache for module results.
3
+ * Copied from @linaria/babel-preset v3.0.0-beta.19, adapted to use `debug` package.
4
+ */
5
+ export declare const clear: () => void;
6
+ export declare const clearForFile: (filename: string) => void;
7
+ export declare const has: ([filename, ...exports]: string[], text: string) => boolean;
8
+ export declare const get: ([filename, ...exports]: string[], text: string) => unknown;
9
+ export declare const set: ([filename, ...exports]: string[], text: string, value: unknown) => void;
@@ -0,0 +1,2 @@
1
+ import { AstEvaluatorPlugin } from './types.mjs';
2
+ export declare const fluentTokensPlugin: AstEvaluatorPlugin;
@@ -0,0 +1,2 @@
1
+ import { Evaluator } from './types.mjs';
2
+ export declare function createHybridEvaluator(shakerEvaluator: Evaluator): Evaluator;
@@ -0,0 +1,29 @@
1
+ import { StrictOptions } from './types.mjs';
2
+ export declare class Module {
3
+ readonly id: string;
4
+ readonly filename: string;
5
+ readonly paths: readonly string[];
6
+ options: StrictOptions;
7
+ imports: Map<string, string[]> | null;
8
+ dependencies: string[] | null;
9
+ transform: ((code: string, filename: string) => string) | null;
10
+ exports: unknown;
11
+ extensions: string[];
12
+ private debug;
13
+ private debuggerDepth;
14
+ constructor(filename: string, options: StrictOptions, debuggerDepth?: number);
15
+ resolve: (rawId: string) => string;
16
+ require: ((id: string) => unknown) & {
17
+ ensure: () => void;
18
+ cache: Record<string, Module>;
19
+ resolve: (id: string) => string;
20
+ };
21
+ evaluate(text: string, only?: string[] | null): void;
22
+ static invalidate: () => void;
23
+ static invalidateEvalCache: () => void;
24
+ static _resolveFilename: (id: string, options: {
25
+ filename: string;
26
+ paths: readonly string[];
27
+ }) => string;
28
+ static _nodeModulePaths: (filename: string) => string[];
29
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Mocked `process` variable for the VM sandbox used in module evaluation.
3
+ * Copied from @linaria/babel-preset v3.0.0-beta.19.
4
+ */
5
+ export declare const nextTick: (fn: (...args: unknown[]) => void) => ReturnType<typeof setTimeout>;
6
+ export declare const platform = "browser";
7
+ export declare const arch = "browser";
8
+ export declare const execPath = "browser";
9
+ export declare const title = "browser";
10
+ export declare const pid = 1;
11
+ export declare const browser = true;
12
+ export declare const argv: string[];
13
+ export declare const binding: () => never;
14
+ export declare const cwd: () => string;
15
+ export declare const exit: () => void;
16
+ export declare const kill: () => void;
17
+ export declare const chdir: () => void;
18
+ export declare const umask: () => void;
19
+ export declare const dlopen: () => void;
20
+ export declare const uptime: () => void;
21
+ export declare const memoryUsage: () => void;
22
+ export declare const uvCounters: () => void;
23
+ export declare const features: {};
24
+ export declare const env: NodeJS.ProcessEnv;
@@ -1,5 +1,34 @@
1
+ import { Node, Program } from 'oxc-parser';
2
+ export type Evaluator = (filename: string, options: StrictOptions, text: string, only: string[] | null) => [string, Map<string, string[]> | null];
3
+ export type EvalRule = {
4
+ test?: RegExp | ((path: string) => boolean);
5
+ action: Evaluator | 'ignore' | string;
6
+ };
7
+ export type StrictOptions = {
8
+ displayName: boolean;
9
+ evaluate: boolean;
10
+ babelOptions: {
11
+ plugins?: unknown[];
12
+ presets?: unknown[];
13
+ [key: string]: unknown;
14
+ };
15
+ rules: EvalRule[];
16
+ };
1
17
  export interface EvaluationResult {
2
18
  confident: boolean;
3
19
  value?: unknown;
4
20
  error?: Error;
5
21
  }
22
+ export interface AstEvaluatorContext {
23
+ /** Full program AST */
24
+ programAst: Program;
25
+ /** Recursive evaluator callback (goes through base + all plugins) */
26
+ evaluateNode: (node: Node) => unknown;
27
+ }
28
+ export interface AstEvaluatorPlugin {
29
+ name: string;
30
+ /**
31
+ * Evaluate an AST node. Return DEOPT symbol to signal "can't handle this".
32
+ */
33
+ evaluateNode: (node: Node, context: AstEvaluatorContext) => unknown;
34
+ }
@@ -1,3 +1,2 @@
1
- import { StrictOptions } from '@linaria/babel-preset';
2
- import { EvaluationResult } from './types.mjs';
1
+ import { EvaluationResult, StrictOptions } from './types.mjs';
3
2
  export declare function vmEvaluator(sourceCode: string, filename: string, expressionCode: string, babelOptions: NonNullable<StrictOptions['babelOptions']>, evaluationRules: NonNullable<StrictOptions['rules']>): EvaluationResult;
package/index.d.mts CHANGED
@@ -1,4 +1,9 @@
1
1
  export { default as shakerEvaluator } from '@linaria/shaker';
2
- export { EvalCache, Module } from '@linaria/babel-preset';
3
- export type { Evaluator, EvalRule } from '@linaria/babel-preset';
2
+ export { Module } from './evaluation/module.mjs';
3
+ export * as EvalCache from './evaluation/evalCache.mjs';
4
+ export { ASSET_TAG_OPEN, ASSET_TAG_CLOSE } from './constants.mjs';
5
+ export type { Evaluator, EvalRule } from './evaluation/types.mjs';
4
6
  export { transformSync, type TransformOptions, type TransformResult } from './transformSync.mjs';
7
+ export { DEOPT, type Deopt } from './evaluation/astEvaluator.mjs';
8
+ export type { AstEvaluatorPlugin, AstEvaluatorContext } from './evaluation/types.mjs';
9
+ export { fluentTokensPlugin } from './evaluation/fluentTokensPlugin.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@griffel/transform",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "A package that performs build time transforms for Griffel",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -16,11 +16,11 @@
16
16
  "./package.json": "./package.json"
17
17
  },
18
18
  "dependencies": {
19
- "@griffel/core": "^1.19.2",
20
- "@linaria/babel-preset": "^3.0.0-beta.24",
19
+ "@griffel/core": "^1.20.0",
21
20
  "@linaria/shaker": "^3.0.0-beta.22",
21
+ "debug": "^4.3.0",
22
22
  "magic-string": "^0.30.19",
23
- "oxc-parser": "^0.90.0",
24
- "oxc-walker": "^0.5.2"
23
+ "oxc-parser": "^0.116.0",
24
+ "oxc-walker": "^0.7.0"
25
25
  }
26
26
  }
package/transform.js CHANGED
@@ -1,86 +1,428 @@
1
1
  import _shaker from "@linaria/shaker";
2
2
  import { default as default2 } from "@linaria/shaker";
3
- import { Module } from "@linaria/babel-preset";
4
- import { EvalCache, Module as Module2 } from "@linaria/babel-preset";
5
- import { parseSync } from "oxc-parser";
6
- import { walk } from "oxc-walker";
3
+ import fs from "node:fs";
4
+ import NativeModule from "node:module";
5
+ import path, { dirname, extname } from "node:path";
6
+ import vm from "node:vm";
7
+ import createDebug from "debug";
8
+ import { createHash } from "node:crypto";
9
+ import { rawTransferSupported, parseSync } from "oxc-parser";
10
+ import { ScopeTracker, walk } from "oxc-walker";
7
11
  import MagicString from "magic-string";
8
- import { resolveResetStyleRules, resolveStyleRulesForSlots, normalizeCSSBucketEntry } from "@griffel/core";
9
- class DeoptError extends Error {
10
- }
11
- function evaluateNode(node) {
12
- switch (node.type) {
13
- case "Literal":
14
- return node.value;
15
- case "ObjectExpression":
16
- return evaluateObjectExpression(node);
17
- case "TemplateLiteral":
18
- return evaluateTemplateLiteral(node);
19
- case "MemberExpression":
20
- return evaluateMemberExpression(node);
21
- default:
22
- throw new DeoptError(`Unsupported node type: ${node.type}`);
12
+ import { resolveStaticStyleRules, resolveResetStyleRules, resolveStyleRulesForSlots, normalizeCSSBucketEntry } from "@griffel/core";
13
+ const ASSET_TAG_OPEN = "<griffel-asset>";
14
+ const ASSET_TAG_CLOSE = "</griffel-asset>";
15
+ const debug$1 = createDebug("griffel:eval-cache");
16
+ const fileHashes = /* @__PURE__ */ new Map();
17
+ const evalCache = /* @__PURE__ */ new Map();
18
+ const fileKeys = /* @__PURE__ */ new Map();
19
+ const hash = (text) => createHash("sha1").update(text).digest("base64");
20
+ let lastText = "";
21
+ let lastHash = hash(lastText);
22
+ const memoizedHash = (text) => {
23
+ if (lastText !== text) {
24
+ lastHash = hash(text);
25
+ lastText = text;
23
26
  }
24
- }
25
- function evaluateObjectExpression(node) {
26
- const obj = {};
27
- for (const prop of node.properties) {
28
- if (prop.type !== "Property" || prop.kind !== "init") {
29
- throw new DeoptError("Only standard properties are supported");
27
+ return lastHash;
28
+ };
29
+ const toKey = (filename, exports$1) => exports$1.length > 0 ? `${filename}:${exports$1.join(",")}` : filename;
30
+ const clear = () => {
31
+ fileHashes.clear();
32
+ evalCache.clear();
33
+ fileKeys.clear();
34
+ };
35
+ const clearForFile = (filename) => {
36
+ const keys = fileKeys.get(filename) ?? [];
37
+ if (keys.length === 0) {
38
+ return;
39
+ }
40
+ debug$1("clear-for-file", filename);
41
+ keys.forEach((key) => {
42
+ fileHashes.delete(key);
43
+ evalCache.delete(key);
44
+ });
45
+ fileKeys.set(filename, []);
46
+ };
47
+ const has = ([filename, ...exports$1], text) => {
48
+ const key = toKey(filename, exports$1);
49
+ const textHash = memoizedHash(text);
50
+ debug$1("has", `${key} ${textHash}`);
51
+ return fileHashes.get(key) === textHash;
52
+ };
53
+ const get = ([filename, ...exports$1], text) => {
54
+ const key = toKey(filename, exports$1);
55
+ const textHash = memoizedHash(text);
56
+ debug$1("get", `${key} ${textHash}`);
57
+ if (fileHashes.get(key) !== textHash) {
58
+ return void 0;
59
+ }
60
+ return evalCache.get(key);
61
+ };
62
+ const set = ([filename, ...exports$1], text, value) => {
63
+ const key = toKey(filename, exports$1);
64
+ const textHash = memoizedHash(text);
65
+ debug$1("set", `${key} ${textHash}`);
66
+ fileHashes.set(key, textHash);
67
+ evalCache.set(key, value);
68
+ if (!fileKeys.has(filename)) {
69
+ fileKeys.set(filename, []);
70
+ }
71
+ fileKeys.get(filename).push(key);
72
+ };
73
+ const evalCache$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
74
+ __proto__: null,
75
+ clear,
76
+ clearForFile,
77
+ get,
78
+ has,
79
+ set
80
+ }, Symbol.toStringTag, { value: "Module" }));
81
+ const nextTick = (fn) => setTimeout(fn, 0);
82
+ const platform = "browser";
83
+ const arch = "browser";
84
+ const execPath = "browser";
85
+ const title = "browser";
86
+ const pid = 1;
87
+ const browser = true;
88
+ const argv = [];
89
+ const binding = function binding2() {
90
+ throw new Error("No such module. (Possibly not yet loaded)");
91
+ };
92
+ const cwd = () => "/";
93
+ const noop = () => {
94
+ };
95
+ const exit = noop;
96
+ const kill = noop;
97
+ const chdir = noop;
98
+ const umask = noop;
99
+ const dlopen = noop;
100
+ const uptime = noop;
101
+ const memoryUsage = noop;
102
+ const uvCounters = noop;
103
+ const features = {};
104
+ const env = process.env;
105
+ const mockProcess = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
106
+ __proto__: null,
107
+ arch,
108
+ argv,
109
+ binding,
110
+ browser,
111
+ chdir,
112
+ cwd,
113
+ dlopen,
114
+ env,
115
+ execPath,
116
+ exit,
117
+ features,
118
+ kill,
119
+ memoryUsage,
120
+ nextTick,
121
+ pid,
122
+ platform,
123
+ title,
124
+ umask,
125
+ uptime,
126
+ uvCounters
127
+ }, Symbol.toStringTag, { value: "Module" }));
128
+ const debug = createDebug("griffel:module");
129
+ const builtins = {
130
+ assert: true,
131
+ buffer: true,
132
+ child_process: false,
133
+ cluster: false,
134
+ console: true,
135
+ constants: true,
136
+ crypto: true,
137
+ dgram: false,
138
+ dns: false,
139
+ domain: true,
140
+ events: true,
141
+ fs: false,
142
+ http: true,
143
+ https: true,
144
+ module: false,
145
+ net: false,
146
+ os: true,
147
+ path: true,
148
+ punycode: true,
149
+ process: true,
150
+ querystring: true,
151
+ readline: false,
152
+ repl: false,
153
+ stream: true,
154
+ string_decoder: true,
155
+ sys: true,
156
+ timers: true,
157
+ tls: false,
158
+ tty: true,
159
+ url: true,
160
+ util: true,
161
+ vm: true,
162
+ zlib: true
163
+ };
164
+ let cache = {};
165
+ const NOOP = () => {
166
+ };
167
+ const createCustomDebug = (depth) => (namespaces, arg1, ...args) => {
168
+ const modulePrefix = depth === 0 ? "module" : `sub-module-${depth}`;
169
+ debug(`${modulePrefix}:${namespaces}`, arg1, ...args);
170
+ };
171
+ const BABEL_ESM = "/@babel/runtime/helpers/esm/";
172
+ const BABEL_CJS = "/@babel/runtime/helpers/";
173
+ const SWC_HELPERS_RE = /(@swc\/helpers\/)src(\/.+)\.mjs/;
174
+ const cookModuleId = (rawId) => {
175
+ const babelESMIndex = rawId.indexOf(BABEL_ESM);
176
+ if (babelESMIndex !== -1) {
177
+ return rawId.slice(0, babelESMIndex) + BABEL_CJS + rawId.slice(babelESMIndex + BABEL_ESM.length);
178
+ }
179
+ const swcHelpersIndex = rawId.indexOf("@swc/helpers/src/");
180
+ if (swcHelpersIndex === -1) {
181
+ return rawId.replace(SWC_HELPERS_RE, "$1lib$2.js");
182
+ }
183
+ return rawId;
184
+ };
185
+ class Module {
186
+ id;
187
+ filename;
188
+ options;
189
+ imports = null;
190
+ dependencies = null;
191
+ transform = null;
192
+ exports = {};
193
+ extensions;
194
+ debug;
195
+ debuggerDepth;
196
+ constructor(filename, options, debuggerDepth = 0) {
197
+ this.id = filename;
198
+ this.filename = filename;
199
+ this.options = options;
200
+ this.debuggerDepth = debuggerDepth;
201
+ this.debug = createCustomDebug(debuggerDepth);
202
+ Object.defineProperties(this, {
203
+ id: {
204
+ value: filename,
205
+ writable: false
206
+ },
207
+ filename: {
208
+ value: filename,
209
+ writable: false
210
+ },
211
+ paths: {
212
+ value: Object.freeze(
213
+ NativeModule._nodeModulePaths(
214
+ path.dirname(filename)
215
+ )
216
+ ),
217
+ writable: false
218
+ }
219
+ });
220
+ this.exports = {};
221
+ this.extensions = [".json", ".js", ".jsx", ".ts", ".tsx", ".cjs"];
222
+ this.debug("prepare", filename);
223
+ }
224
+ resolve = (rawId) => {
225
+ const id = cookModuleId(rawId);
226
+ const extensions = NativeModule._extensions;
227
+ const added = [];
228
+ try {
229
+ this.extensions.forEach((ext) => {
230
+ if (ext in extensions) {
231
+ return;
232
+ }
233
+ extensions[ext] = NOOP;
234
+ added.push(ext);
235
+ });
236
+ return Module._resolveFilename(id, this);
237
+ } finally {
238
+ added.forEach((ext) => delete extensions[ext]);
30
239
  }
31
- let key;
32
- if (prop.computed) {
33
- throw new DeoptError("Computed properties are not supported");
34
- } else if (prop.key.type === "Identifier") {
35
- key = prop.key.name;
36
- } else if (prop.key.type === "Literal") {
37
- const keyLiteral = prop.key;
38
- if (typeof keyLiteral.value === "string" || typeof keyLiteral.value === "number") {
39
- key = String(keyLiteral.value);
240
+ };
241
+ require = Object.assign(
242
+ (rawId) => {
243
+ const id = cookModuleId(rawId);
244
+ this.debug("require", id);
245
+ if (id in builtins) {
246
+ if (builtins[id]) {
247
+ return require(id);
248
+ }
249
+ return null;
250
+ }
251
+ const filename = this.resolve(id);
252
+ if (filename === id && !path.isAbsolute(id)) {
253
+ throw new Error(`Unable to import "${id}". Importing Node builtins is not supported in the sandbox.`);
254
+ }
255
+ this.dependencies?.push(id);
256
+ let cacheKey = filename;
257
+ let only = [];
258
+ if (this.imports?.has(id)) {
259
+ only = this.imports.get(id).sort();
260
+ if (only.length === 0) {
261
+ only = ["default"];
262
+ }
263
+ cacheKey += `:${only.join(",")}`;
264
+ }
265
+ let m = cache[cacheKey];
266
+ if (!m) {
267
+ this.debug("cached:not-exist", id);
268
+ m = new Module(filename, this.options, this.debuggerDepth + 1);
269
+ m.transform = this.transform;
270
+ cache[cacheKey] = m;
271
+ if (this.extensions.includes(path.extname(filename))) {
272
+ const code = fs.readFileSync(filename, "utf-8");
273
+ if (/\.json$/.test(filename)) {
274
+ m.exports = JSON.parse(code);
275
+ } else {
276
+ m.evaluate(code, only.includes("*") ? ["*"] : only);
277
+ }
278
+ } else {
279
+ m.exports = ASSET_TAG_OPEN + filename + ASSET_TAG_CLOSE;
280
+ }
40
281
  } else {
41
- throw new DeoptError("Unsupported literal key type");
282
+ this.debug("cached:exist", id);
283
+ }
284
+ return m.exports;
285
+ },
286
+ {
287
+ ensure: NOOP,
288
+ cache,
289
+ resolve: this.resolve
290
+ }
291
+ );
292
+ evaluate(text, only = null) {
293
+ const { filename } = this;
294
+ let action = "ignore";
295
+ for (let i = this.options.rules.length - 1; i >= 0; i--) {
296
+ const { test } = this.options.rules[i];
297
+ if (!test || (typeof test === "function" ? test(filename) : test instanceof RegExp && test.test(filename))) {
298
+ action = this.options.rules[i].action;
299
+ break;
42
300
  }
301
+ }
302
+ const cacheKey = [this.filename, ...only ?? []];
303
+ if (has(cacheKey, text)) {
304
+ this.exports = get(cacheKey, text);
305
+ return;
306
+ }
307
+ let code;
308
+ if (action === "ignore") {
309
+ this.debug("ignore", `${filename}`);
310
+ code = text;
43
311
  } else {
44
- throw new DeoptError("Unsupported key type");
312
+ const evaluator = typeof action === "function" ? action : require(require.resolve(action, {
313
+ paths: [dirname(this.filename)]
314
+ })).default;
315
+ let imports;
316
+ this.debug("prepare-evaluation", this.filename, "using", evaluator.name);
317
+ [code, imports] = evaluator(this.filename, this.options, text, only);
318
+ this.imports = imports;
319
+ this.debug("evaluate", `${this.filename} (only ${(only || []).join(", ")}):
320
+ ${code}`);
45
321
  }
46
- obj[key] = evaluateNode(prop.value);
322
+ const script = new vm.Script(`(function (exports) { ${code}
323
+ })(exports);`, {
324
+ filename: this.filename
325
+ });
326
+ script.runInContext(
327
+ vm.createContext({
328
+ clearImmediate: NOOP,
329
+ clearInterval: NOOP,
330
+ clearTimeout: NOOP,
331
+ setImmediate: NOOP,
332
+ setInterval: NOOP,
333
+ setTimeout: NOOP,
334
+ global,
335
+ process: mockProcess,
336
+ module: this,
337
+ exports: this.exports,
338
+ require: this.require,
339
+ __filename: this.filename,
340
+ __dirname: path.dirname(this.filename)
341
+ })
342
+ );
343
+ set(cacheKey, text, this.exports);
47
344
  }
48
- return obj;
345
+ static invalidate = () => {
346
+ cache = {};
347
+ };
348
+ static invalidateEvalCache = () => {
349
+ clear();
350
+ };
351
+ // Alias to resolve the module using node's resolve algorithm
352
+ // This static property can be overridden by the webpack loader
353
+ // This allows us to use webpack's module resolution algorithm
354
+ static _resolveFilename = (id, options) => NativeModule._resolveFilename(
355
+ id,
356
+ options
357
+ );
358
+ static _nodeModulePaths = (filename) => NativeModule._nodeModulePaths(filename);
49
359
  }
50
- function evaluateTemplateLiteral(node) {
51
- let result = "";
52
- for (let i = 0; i < node.quasis.length; i++) {
53
- result += node.quasis[i].value.cooked;
54
- if (i < node.expressions.length) {
55
- const expression = node.expressions[i];
56
- if (expression.type === "MemberExpression" && expression.object.type === "Identifier" && expression.object.name === "tokens" && expression.property.type === "Identifier" && !expression.computed) {
57
- result += `var(--${expression.property.name})`;
58
- } else {
59
- throw new DeoptError("Only tokens.propertyName expressions are supported in template literals");
360
+ const DEOPT = /* @__PURE__ */ Symbol("deopt");
361
+ function astEvaluator(node, programAst, plugins = []) {
362
+ const context = {
363
+ programAst,
364
+ evaluateNode
365
+ };
366
+ function evaluateNode(node2) {
367
+ switch (node2.type) {
368
+ case "Literal":
369
+ return node2.value;
370
+ case "ObjectExpression":
371
+ return evaluateObjectExpression(node2);
372
+ case "TemplateLiteral":
373
+ if (node2.expressions.length === 0) {
374
+ return node2.quasis[0].value.cooked;
375
+ }
376
+ break;
377
+ }
378
+ for (const plugin of plugins) {
379
+ const result2 = plugin.evaluateNode(node2, context);
380
+ if (result2 !== DEOPT) {
381
+ return result2;
60
382
  }
61
383
  }
384
+ return DEOPT;
62
385
  }
63
- return result;
64
- }
65
- function evaluateMemberExpression(node) {
66
- if (node.object.type === "Identifier" && node.object.name === "tokens" && node.property.type === "Identifier" && !node.computed) {
67
- return `var(--${node.property.name})`;
68
- } else {
69
- throw new DeoptError("Only tokens.propertyName member expressions are supported");
386
+ function evaluateObjectExpression(node2) {
387
+ const obj = {};
388
+ for (const prop of node2.properties) {
389
+ if (prop.type !== "Property" || prop.kind !== "init") {
390
+ return DEOPT;
391
+ }
392
+ let key;
393
+ if (prop.computed) {
394
+ return DEOPT;
395
+ } else if (prop.key.type === "Identifier") {
396
+ key = prop.key.name;
397
+ } else if (prop.key.type === "Literal") {
398
+ const keyLiteral = prop.key;
399
+ if (typeof keyLiteral.value === "string" || typeof keyLiteral.value === "number") {
400
+ key = String(keyLiteral.value);
401
+ } else {
402
+ return DEOPT;
403
+ }
404
+ } else {
405
+ return DEOPT;
406
+ }
407
+ const value = evaluateNode(prop.value);
408
+ if (value === DEOPT) {
409
+ return DEOPT;
410
+ }
411
+ obj[key] = value;
412
+ }
413
+ return obj;
70
414
  }
71
- }
72
- function astEvaluator(node) {
73
- try {
74
- return {
75
- confident: true,
76
- value: evaluateNode(node)
77
- };
78
- } catch {
415
+ const result = evaluateNode(node);
416
+ if (result === DEOPT) {
79
417
  return {
80
418
  confident: false,
81
419
  value: void 0
82
420
  };
83
421
  }
422
+ return {
423
+ confident: true,
424
+ value: result
425
+ };
84
426
  }
85
427
  function isError(e) {
86
428
  return Object.prototype.toString.call(e) === "[object Error]";
@@ -123,13 +465,13 @@ if (typeof module !== 'undefined' && module.exports) {
123
465
  return { confident: false, error: err };
124
466
  }
125
467
  }
126
- function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluationRules) {
468
+ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluationRules, programAst, astEvaluationPlugins = []) {
127
469
  const evaluationResults = new Array(styleCalls.length);
128
470
  const argumentsCode = new Array(styleCalls.length).fill(null);
129
471
  let vmEvaluationNeeded = false;
130
472
  for (let i = 0; i < styleCalls.length; i++) {
131
473
  const styleCall = styleCalls[i];
132
- const staticResult = astEvaluator(styleCall.argumentNode);
474
+ const staticResult = astEvaluator(styleCall.argumentNode, programAst, astEvaluationPlugins);
133
475
  if (staticResult.confident) {
134
476
  evaluationResults[i] = staticResult.value;
135
477
  continue;
@@ -163,22 +505,91 @@ function batchEvaluator(sourceCode, filename, styleCalls, babelOptions, evaluati
163
505
  evaluationResults
164
506
  };
165
507
  }
508
+ const CJS_EXTENSIONS = /* @__PURE__ */ new Set([".cjs", ".cts", ".json"]);
509
+ const ESM_EXTENSIONS = /* @__PURE__ */ new Set([".mjs", ".mts"]);
510
+ const useRawTransfer = rawTransferSupported();
511
+ const NODE_MODULES_RE = /[/\\]node_modules[/\\]/;
512
+ function createHybridEvaluator(shakerEvaluator2) {
513
+ return (filename, options, text, only) => {
514
+ if (!NODE_MODULES_RE.test(filename)) {
515
+ return shakerEvaluator2(filename, options, text, only);
516
+ }
517
+ const ext = extname(filename);
518
+ if (CJS_EXTENSIONS.has(ext)) {
519
+ return [text, null];
520
+ }
521
+ if (ESM_EXTENSIONS.has(ext)) {
522
+ return shakerEvaluator2(filename, options, text, only);
523
+ }
524
+ const parseResult = parseSync(filename, text, {
525
+ sourceType: "unambiguous",
526
+ ...useRawTransfer && { experimentalLazy: true }
527
+ });
528
+ const isESM = parseResult.module.hasModuleSyntax;
529
+ parseResult.dispose?.();
530
+ if (!isESM) {
531
+ return [text, null];
532
+ }
533
+ return shakerEvaluator2(filename, options, text, only);
534
+ };
535
+ }
536
+ function evaluateTemplateLiteralWithTokens(node) {
537
+ let result = "";
538
+ for (let i = 0; i < node.quasis.length; i++) {
539
+ result += node.quasis[i].value.cooked;
540
+ if (i < node.expressions.length) {
541
+ const expression = node.expressions[i];
542
+ if (expression.type === "MemberExpression" && expression.object.type === "Identifier" && expression.object.name === "tokens" && expression.property.type === "Identifier" && !expression.computed) {
543
+ result += `var(--${expression.property.name})`;
544
+ } else {
545
+ return DEOPT;
546
+ }
547
+ }
548
+ }
549
+ return result;
550
+ }
551
+ function evaluateTokensMemberExpression(node) {
552
+ if (node.object.type === "Identifier" && node.object.name === "tokens" && node.property.type === "Identifier" && !node.computed) {
553
+ return `var(--${node.property.name})`;
554
+ } else {
555
+ return DEOPT;
556
+ }
557
+ }
558
+ const fluentTokensPlugin = {
559
+ name: "fluentTokensPlugin",
560
+ evaluateNode(node) {
561
+ switch (node.type) {
562
+ case "TemplateLiteral":
563
+ return evaluateTemplateLiteralWithTokens(node);
564
+ case "MemberExpression":
565
+ return evaluateTokensMemberExpression(node);
566
+ default:
567
+ return DEOPT;
568
+ }
569
+ }
570
+ };
166
571
  function dedupeCSSRules(cssRulesByBucket) {
167
572
  return Object.fromEntries(
168
573
  Object.entries(cssRulesByBucket).map(([styleBucketName, cssBucketEntries]) => {
169
574
  if (styleBucketName === "m") {
170
- return [
171
- styleBucketName,
172
- cssBucketEntries.filter(
173
- (entryA, index, entries) => entries.findIndex((entryB) => entryA[0] === entryB[0]) === index
174
- )
175
- ];
575
+ const seen = /* @__PURE__ */ new Map();
576
+ for (const entry of cssBucketEntries) {
577
+ if (!seen.has(entry[0])) {
578
+ seen.set(entry[0], entry);
579
+ }
580
+ }
581
+ return [styleBucketName, Array.from(seen.values())];
176
582
  }
177
- return [styleBucketName, [...new Set(cssBucketEntries)]];
583
+ return [styleBucketName, Array.from(new Set(cssBucketEntries))];
178
584
  })
179
585
  );
180
586
  }
181
587
  const shakerEvaluator = _shaker.default || _shaker;
588
+ const RUNTIME_IDENTIFIERS = /* @__PURE__ */ new Map([
589
+ ["makeStyles", "__css"],
590
+ ["makeResetStyles", "__resetCSS"],
591
+ ["makeStaticStyles", "__staticCSS"]
592
+ ]);
182
593
  function buildCSSResetEntriesMetadata(cssResetEntries, cssRules, declaratorId) {
183
594
  const cssRulesByBucket = Array.isArray(cssRules) ? { d: cssRules } : cssRules;
184
595
  cssResetEntries[declaratorId] ??= [];
@@ -227,11 +638,15 @@ function buildCSSEntriesMetadata(cssEntries, classnamesMapping, cssRulesByBucket
227
638
  );
228
639
  }
229
640
  function concatCSSRulesByBucket(bucketA = {}, bucketB) {
230
- Object.entries(bucketB).forEach(([cssBucketName, cssBucketEntries]) => {
231
- bucketA[cssBucketName] = cssBucketEntries.concat(
232
- bucketA[cssBucketName] || []
233
- );
234
- });
641
+ for (const cssBucketName in bucketB) {
642
+ const bucketName = cssBucketName;
643
+ const bucketBEntries = bucketB[bucketName] ?? [];
644
+ if (bucketA[bucketName]) {
645
+ bucketA[bucketName].push(...bucketBEntries);
646
+ } else {
647
+ bucketA[bucketName] = bucketBEntries;
648
+ }
649
+ }
235
650
  return bucketA;
236
651
  }
237
652
  function transformSync(sourceCode, options) {
@@ -241,109 +656,96 @@ function transformSync(sourceCode, options) {
241
656
  classNameHashSalt = "",
242
657
  generateMetadata = false,
243
658
  modules = ["@griffel/core", "@griffel/react", "@fluentui/react-components"],
244
- evaluationRules = [
245
- { action: shakerEvaluator },
246
- {
247
- test: /[/\\]node_modules[/\\]/,
248
- action: "ignore"
249
- }
250
- ]
659
+ evaluationRules = [{ action: createHybridEvaluator(shakerEvaluator) }],
660
+ astEvaluationPlugins = [fluentTokensPlugin]
251
661
  } = options;
252
662
  if (!filename) {
253
663
  throw new Error('Transform error: "filename" option is required');
254
664
  }
255
665
  const parseResult = parseSync(filename, sourceCode);
256
- parseResult.module.staticImports;
257
666
  if (parseResult.errors.length > 0) {
258
667
  throw new Error(`Failed to parse "${filename}": ${parseResult.errors.map((e) => e.message).join(", ")}`);
259
668
  }
669
+ if (parseResult.program.body.length > 0 && !parseResult.module.hasModuleSyntax) {
670
+ throw new Error(
671
+ `Transform error: "${filename}" is not an ES module. @griffel/transform only supports ES modules (files using import/export syntax).`
672
+ );
673
+ }
260
674
  const magicString = new MagicString(sourceCode);
261
675
  const programAst = parseResult.program;
262
- const imports = [];
676
+ const hasGriffelImports = parseResult.module.staticImports.some(
677
+ (si) => modules.includes(si.moduleRequest.value) && si.entries.some((e) => e.importName.kind === "Name" && RUNTIME_IDENTIFIERS.has(e.importName.name))
678
+ );
679
+ if (!hasGriffelImports) {
680
+ return { code: sourceCode, usedProcessing: false, usedVMForEvaluation: false };
681
+ }
263
682
  const styleCalls = [];
264
683
  const cssEntries = {};
265
684
  const cssResetEntries = {};
266
685
  let cssRulesByBucket = {};
686
+ const scopeTracker = new ScopeTracker();
687
+ const matchedSpecifiers = /* @__PURE__ */ new Map();
267
688
  walk(programAst, {
689
+ scopeTracker,
268
690
  enter(node, parent) {
269
- if (node.type === "ImportDeclaration") {
270
- const moduleSource = node.source.value;
271
- if (modules.includes(moduleSource)) {
272
- const specifiers = node.specifiers.reduce((acc, spec) => {
273
- if (spec.type === "ImportSpecifier") {
274
- const importedName = spec.imported;
275
- if (importedName.type === "Identifier" && (importedName.name === "makeStyles" || importedName.name === "makeResetStyles")) {
276
- acc.push({
277
- imported: importedName.name,
278
- local: spec.local.name,
279
- start: spec.start,
280
- end: spec.end
281
- });
282
- }
283
- }
284
- return acc;
285
- }, []);
286
- if (specifiers.length > 0) {
287
- imports.push({
288
- source: moduleSource,
289
- specifiers,
290
- start: node.start,
291
- end: node.end
292
- });
293
- }
691
+ if (node.type === "CallExpression" && node.callee.type === "Identifier") {
692
+ const declaration = scopeTracker.getDeclaration(node.callee.name);
693
+ if (declaration?.type !== "Import" || declaration.node.type !== "ImportSpecifier") {
694
+ return;
294
695
  }
295
- }
296
- if (node.type === "CallExpression") {
297
- let functionKind = null;
298
- let importId;
299
- if (node.callee.type === "Identifier") {
300
- const calleeName = node.callee.name;
301
- for (const importInfo of imports) {
302
- const specifier = importInfo.specifiers.find((s) => s.local === calleeName);
303
- if (specifier) {
304
- if (node.arguments.length !== 1) {
305
- throw new Error(`${functionKind}() function accepts only a single param`);
306
- }
307
- functionKind = specifier.imported;
308
- importId = specifier.local;
309
- break;
310
- }
311
- }
696
+ const importSource = declaration.importNode.source.value;
697
+ if (!modules.includes(importSource)) {
698
+ return;
312
699
  }
313
- if (functionKind && importId) {
314
- let declaratorId = "unknownHook";
315
- let current = parent;
316
- while (current) {
317
- if (!current) {
318
- break;
319
- }
320
- if (current.type === "VariableDeclarator" && current.id.type === "Identifier") {
321
- declaratorId = current.id.name;
322
- break;
323
- }
324
- if ("parent" in current) {
325
- current = current.parent;
326
- continue;
327
- }
700
+ const imported = declaration.node.imported;
701
+ if (imported.type !== "Identifier") {
702
+ return;
703
+ }
704
+ const importedName = imported.name;
705
+ if (!RUNTIME_IDENTIFIERS.has(importedName)) {
706
+ return;
707
+ }
708
+ const functionKind = importedName;
709
+ if (node.arguments.length !== 1) {
710
+ throw new Error(`${functionKind}() function accepts only a single param`);
711
+ }
712
+ matchedSpecifiers.set(declaration.node.start, {
713
+ start: declaration.node.start,
714
+ end: declaration.node.end,
715
+ functionKind
716
+ });
717
+ let declaratorId = "unknownHook";
718
+ let current = parent;
719
+ while (current) {
720
+ if (!current) {
721
+ break;
722
+ }
723
+ if (current.type === "VariableDeclarator" && current.id.type === "Identifier") {
724
+ declaratorId = current.id.name;
328
725
  break;
329
726
  }
330
- const argument = node.arguments[0];
331
- styleCalls.push({
332
- declaratorId,
333
- functionKind,
334
- argumentStart: argument.start,
335
- argumentEnd: argument.end,
336
- argumentCode: sourceCode.slice(argument.start, argument.end),
337
- argumentNode: argument,
338
- callStart: node.start,
339
- callEnd: node.end,
340
- importId
341
- });
727
+ if ("parent" in current) {
728
+ current = current.parent;
729
+ continue;
730
+ }
731
+ break;
342
732
  }
733
+ const argument = node.arguments[0];
734
+ styleCalls.push({
735
+ declaratorId,
736
+ functionKind,
737
+ argumentStart: argument.start,
738
+ argumentEnd: argument.end,
739
+ argumentCode: sourceCode.slice(argument.start, argument.end),
740
+ argumentNode: argument,
741
+ callStart: node.start,
742
+ callEnd: node.end,
743
+ importId: node.callee.name
744
+ });
343
745
  }
344
746
  }
345
747
  });
346
- if (imports.length === 0 || styleCalls.length === 0) {
748
+ if (styleCalls.length === 0) {
347
749
  return {
348
750
  code: sourceCode,
349
751
  usedProcessing: false,
@@ -355,7 +757,9 @@ function transformSync(sourceCode, options) {
355
757
  filename,
356
758
  styleCalls,
357
759
  babelOptions,
358
- evaluationRules
760
+ evaluationRules,
761
+ programAst,
762
+ astEvaluationPlugins
359
763
  );
360
764
  for (let i = 0; i < styleCalls.length; i++) {
361
765
  const styleCall = styleCalls[i];
@@ -364,17 +768,13 @@ function transformSync(sourceCode, options) {
364
768
  case "makeStyles":
365
769
  {
366
770
  const stylesBySlots = evaluationResult;
367
- const [classnamesMapping, cssRulesByBucketA] = resolveStyleRulesForSlots(stylesBySlots, classNameHashSalt);
771
+ const [classnamesMapping, resolvedCSSRules] = resolveStyleRulesForSlots(stylesBySlots, classNameHashSalt);
772
+ const uniqueCSSRules = dedupeCSSRules(cssRulesByBucket);
368
773
  if (generateMetadata) {
369
- buildCSSEntriesMetadata(
370
- cssEntries,
371
- classnamesMapping,
372
- dedupeCSSRules(cssRulesByBucket),
373
- styleCall.declaratorId
374
- );
774
+ buildCSSEntriesMetadata(cssEntries, classnamesMapping, uniqueCSSRules, styleCall.declaratorId);
375
775
  }
376
776
  magicString.overwrite(styleCall.argumentStart, styleCall.argumentEnd, `${JSON.stringify(classnamesMapping)}`);
377
- cssRulesByBucket = concatCSSRulesByBucket(cssRulesByBucket, cssRulesByBucketA);
777
+ cssRulesByBucket = concatCSSRulesByBucket(cssRulesByBucket, resolvedCSSRules);
378
778
  }
379
779
  break;
380
780
  case "makeResetStyles":
@@ -395,22 +795,25 @@ function transformSync(sourceCode, options) {
395
795
  );
396
796
  }
397
797
  break;
798
+ case "makeStaticStyles":
799
+ {
800
+ const styles = evaluationResult;
801
+ const stylesSet = Array.isArray(styles) ? styles : [styles];
802
+ const cssRules = resolveStaticStyleRules(stylesSet);
803
+ magicString.overwrite(styleCall.argumentStart, styleCall.argumentEnd, JSON.stringify({ d: cssRules }));
804
+ cssRulesByBucket = concatCSSRulesByBucket(cssRulesByBucket, { d: cssRules });
805
+ }
806
+ break;
398
807
  }
399
808
  }
400
- for (const importInfo of imports) {
401
- for (const specifier of importInfo.specifiers) {
402
- if (specifier.imported === "makeStyles") {
403
- magicString.overwrite(specifier.start, specifier.end, "__css");
404
- } else if (specifier.imported === "makeResetStyles") {
405
- magicString.overwrite(specifier.start, specifier.end, "__resetCSS");
406
- }
407
- }
809
+ for (const specifier of matchedSpecifiers.values()) {
810
+ magicString.overwrite(specifier.start, specifier.end, RUNTIME_IDENTIFIERS.get(specifier.functionKind));
408
811
  }
409
812
  for (const styleCall of styleCalls) {
410
813
  magicString.overwrite(
411
814
  styleCall.callStart,
412
815
  styleCall.callStart + styleCall.importId.length,
413
- "__" + (styleCall.functionKind === "makeStyles" ? "css" : "resetCSS")
816
+ RUNTIME_IDENTIFIERS.get(styleCall.functionKind)
414
817
  );
415
818
  }
416
819
  return {
@@ -421,8 +824,12 @@ function transformSync(sourceCode, options) {
421
824
  };
422
825
  }
423
826
  export {
424
- EvalCache,
425
- Module2 as Module,
827
+ ASSET_TAG_CLOSE,
828
+ ASSET_TAG_OPEN,
829
+ DEOPT,
830
+ evalCache$1 as EvalCache,
831
+ Module,
832
+ fluentTokensPlugin,
426
833
  default2 as shakerEvaluator,
427
834
  transformSync
428
835
  };
@@ -1,4 +1,4 @@
1
- import { StrictOptions } from '@linaria/babel-preset';
1
+ import { StrictOptions, AstEvaluatorPlugin } from './evaluation/types.mjs';
2
2
  import { CSSRulesByBucket } from '@griffel/core';
3
3
  export type TransformOptions = {
4
4
  filename: string;
@@ -17,6 +17,8 @@ export type TransformOptions = {
17
17
  babelOptions?: Pick<StrictOptions['babelOptions'], 'plugins' | 'presets'>;
18
18
  /** The set of rules that defines how the matched files will be transformed during the evaluation. */
19
19
  evaluationRules?: StrictOptions['rules'];
20
+ /** Plugins for extending AST evaluation with custom node handling. */
21
+ astEvaluationPlugins?: AstEvaluatorPlugin[];
20
22
  };
21
23
  export type TransformResult = {
22
24
  code: string;
package/types.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Node } from 'oxc-parser';
2
2
  export interface StyleCall {
3
3
  declaratorId: string;
4
- functionKind: 'makeStyles' | 'makeResetStyles';
4
+ functionKind: 'makeStyles' | 'makeResetStyles' | 'makeStaticStyles';
5
5
  argumentStart: number;
6
6
  argumentEnd: number;
7
7
  argumentCode: string;