@teacss/engine 0.9.1 → 0.9.3
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 +50 -5
- package/binding.js +54 -54
- package/contract.d.ts +1 -1
- package/dist/config-view.d.ts +9 -0
- package/dist/config-view.js +38 -1
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +4 -0
- package/dist/generator.d.ts +10 -2
- package/dist/generator.js +51 -9
- package/dist/select.d.ts +9 -1
- package/dist/select.js +65 -4
- package/dist/ts-fallback.d.ts +10 -1
- package/dist/ts-fallback.js +3 -2
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -22,19 +22,64 @@ Every package needs Node.js 22.12.0 or later; the wasm package needs `>=22.13.0
|
|
|
22
22
|
|
|
23
23
|
## Engine selection
|
|
24
24
|
|
|
25
|
-
- `TEACSS_ENGINE=auto|rust|ts` overrides
|
|
26
|
-
- Otherwise the integration's `engine` option decides
|
|
27
|
-
- `package.json#engineCompat.defaultMode` sets what the option `"auto"` means.
|
|
28
|
-
- With `"auto"`, a configuration Rust cannot serve falls back to TypeScript with a machine-readable reason; with `"rust"`, the
|
|
25
|
+
- `TEACSS_ENGINE=auto|rust|ts` overrides the `engine` option. An unrecognized value is ignored, and the selection result carries it as `invalidEnv`.
|
|
26
|
+
- Otherwise the integration's `engine` option decides. `selectEngineRequest` with no option returns TypeScript; what an unset `engine` means is the teacss-ts hook's call.
|
|
27
|
+
- `package.json#engineCompat.defaultMode` sets what the option `"auto"` means. It is `"auto"`: `engine: "auto"`, which the first-party integrations pass, tries Rust and falls back to TypeScript when the configuration cannot run there. Releases up to 0.9.1 shipped `"opt-in"`, under which the option `"auto"` stayed on TypeScript and only `TEACSS_ENGINE=rust|auto` or `engine: "rust"` tried Rust.
|
|
28
|
+
- With `"auto"`, a configuration Rust cannot serve falls back to TypeScript with a machine-readable reason (see [Fallback reasons](#fallback-reasons)); with `"rust"`, the teacss-ts hook prints the same fallback as a warning, and throws instead when `TEACSS_ENGINE_STRICT=1` is set.
|
|
29
29
|
|
|
30
30
|
`selectEngineRequest` from `@teacss/engine/select` (which does not load the binding) stays on TypeScript in three cases: `mode: "ts"` (TypeScript chosen explicitly), `resolvedBy: "opt-in"` (the option `"auto"` while `defaultMode` is `"opt-in"`), and `reason: "engine-compat"` (the host `@teacss/core` is outside `engineCompat.core`).
|
|
31
31
|
|
|
32
|
+
## Fallback reasons
|
|
33
|
+
|
|
34
|
+
A fallback prints one line per reason and path per process: `[teacss] engine: falling back to the TypeScript engine (<reason> at <path>)`. In teacss-ts, `TEACSS_ENGINE_STATS=1` prints on exit how many generators ran on each engine and which reasons fell back. `TEACSS_ENGINE_DEBUG=1` makes this package print the translated request or the first failure to stderr. The facade stops at the first item it cannot translate, so fixing one reason can reveal the next.
|
|
35
|
+
|
|
36
|
+
To keep TypeScript for any configuration, set `TEACSS_ENGINE=ts` (it covers every integration), or write `engine: "ts"` in the configuration or in the host's defaults, for example `pluginTeacss(config, { engine: "ts" })`. A fallback is not an error: the TypeScript engine produces the same CSS it always has.
|
|
37
|
+
|
|
38
|
+
`<i>` is the preset's index after nested presets are flattened and ordered by `enforce`.
|
|
39
|
+
|
|
40
|
+
| Reason | Path | What it means and why | To run on Rust |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| `engine-unavailable` | `@teacss/engine` | Reported by the teacss-ts hook, not by this package: importing the facade failed, usually because no platform package matches the machine or the native binding did not load. | Install the platform package for your machine; see [Troubleshooting](#troubleshooting). `TEACSS_ENGINE=rust` throws with the loader's error instead of falling back. |
|
|
43
|
+
| `engine-compat` | `@teacss/core` | The host `@teacss/core` is outside `engineCompat.core`, so the pair was not tested together. `TEACSS_ENGINE=rust` throws `E_ENGINE_COMPAT` instead. | Align `@teacss/core` and `@teacss/engine`; check the lockfile for a second copy of either. |
|
|
44
|
+
| `unknown-key` | the key | A top-level config key the facade does not know, such as a typo or an option from a newer core. Rust cannot know what it means. | Remove or correct the key. |
|
|
45
|
+
| `rules`, `variants`, `extractors`, `extractorDefault`, `preflights`, `preprocess`, `postprocess`, `extendTheme`, `configResolved`, `autocomplete`, `cli` | the key | The key has a non-empty value. These hold functions or matchers that only JavaScript can run, and Rust does not execute JavaScript. | Remove the key from the configuration the integration loads, or express it statically with `shortcuts`, `theme`, `safelist` or a preset option. |
|
|
46
|
+
| `separators` | `separators` | Separators other than the default `[":", "-"]`; Rust parses only the default. | Remove `separators`. |
|
|
47
|
+
| `mergeSelectors` | `mergeSelectors` | `mergeSelectors: false`; Rust always merges selectors. | Remove it. |
|
|
48
|
+
| `details` | `details` | `details` is set; Rust does not support it. | Remove it. |
|
|
49
|
+
| `sortLayers` | `sortLayers` | A `sortLayers` function. | Remove it and order layers with `layers`. |
|
|
50
|
+
| `content` | `content` or `content.filesystem` | `content` is not an object, or `content.filesystem` is not an array of strings. | Use an array of glob strings. |
|
|
51
|
+
| `content.inline` | `content.inline` | Inline content sources, which only the TypeScript engine reads. | Move the content into files matched by `content.filesystem`. |
|
|
52
|
+
| `envMode` | `envMode` | A value other than `"dev"` or `"build"`. | Use one of the two. |
|
|
53
|
+
| `unmatched` | `unmatched` | A value other than `"warn"`, `"error"` or `"off"`. | Use one of the three. |
|
|
54
|
+
| `outputToCssLayers` | `outputToCssLayers` | Neither a boolean nor an object. | Use `true`, `false` or `{ allLayers }`. |
|
|
55
|
+
| `outputToCssLayers.cssLayerName` | `outputToCssLayers.cssLayerName` | A `cssLayerName` value; Rust does not support it. | Remove it. |
|
|
56
|
+
| `transformers` | `transformers` or `transformers[<n>]` | A transformer other than `@teacss/transformer-compile-class` and `@teacss/directives`, or a `transformers` value that is not an array. Other transformers run JavaScript over the source. | Remove the transformer, or keep TypeScript. |
|
|
57
|
+
| `transformers.compile-class` | `transformers[<n>]` | The config lists its own `transformerCompileClass()` and the last Standard preset does not enable `compileClass`, or there is no Standard preset. Its options live in a closure, and the classes it registers never reach Rust. | Enable compile-class through `presetStandard({ compileClass })`, or keep TypeScript. |
|
|
58
|
+
| `shortcuts`, `safelist`, `blocklist`, `theme`, `layers` | the key and the item inside it | A value that is not static data: a shortcut whose expansion is not a string, or that has a regular expression or meta; a `safelist` or `blocklist` item that is not a string; a theme leaf that is not a string or number, the removed `rolePalettes` or `themes` theme key, or a `defaultMode` or mode name that is empty or holds a NUL or a lone surrogate (Standard rejects these; the TypeScript engine raises its error); a layer order that is not a number. | Replace the item with static data. |
|
|
59
|
+
| `preset-not-instantiated` | `presets[<n>]` | A preset that is a function, a promise or not an object. | Call the factory (`presetStandard()`, not `presetStandard`) and await it before passing it. |
|
|
60
|
+
| `preset-cycle` | `presets[<n>]…` | A preset that contains itself through nested `presets`. | Break the cycle. |
|
|
61
|
+
| `accessor` | the key | A getter or setter on the config, the defaults or a preset. Translation would run it once and the TypeScript engine again. | Use plain data properties. |
|
|
62
|
+
| `standard.unknown-option` | `presets[<i>].options.<key>` | A Standard option other than `modeSelectors`, `containers`, `preflight`, `variablePrefix` and `compileClass`. | Remove the option. |
|
|
63
|
+
| `standard.compileClass.hashFn`, `standard.compileClass.trigger` | `presets[<i>].options.compileClass.…` | A custom hash function or trigger for compiled classes. | Remove it; `classPrefix`, `alwaysHash`, `keepUnknown` and `layer` are supported. |
|
|
64
|
+
| `icons.collections` | `presets[<i>].options.collections.<name>` | An icon collection other than the bundled `carbon`, `crypto`, `flagpack`, `logo` and `lucide`. | Use a bundled collection, or keep TypeScript. |
|
|
65
|
+
| `icons.customizations`, `icons.processor` | `presets[<i>].options.…` | Icon customizations or a processor, which run JavaScript. | Remove them. |
|
|
66
|
+
| `role-palettes-without-entry` | `presets[<i>]` | The `@teacss/config/role-palettes` preset in a configuration that did not come from an entry stylesheet. On Rust the preset needs the entry. | Load the configuration from its entry stylesheet through `@teacss/config`. |
|
|
67
|
+
| `preset.name` | `presets[<i>].name` | A preset without a string `name`. | Give the preset a name. |
|
|
68
|
+
| `preset.rules`, `preset.variants`, `preset.extractors`, `preset.preflights`, `preset.preprocess`, `preset.postprocess`, `preset.extendTheme`, `preset.configResolved`, `preset.transformers`, `preset.autocomplete`, `preset.extractorDefault` | `presets[<i>].<key>` | A preset that is not one of the built-in presets carries a dynamic field, as for the top-level keys above. | Remove the field from the preset, or keep TypeScript. |
|
|
69
|
+
| `preset.content` | `presets[<i>].content` | A preset's `content` holds something other than `pipeline`, such as `filesystem` or `inline`; Rust reads content globs only from the configuration. | Move the globs to the configuration's `content.filesystem`. |
|
|
70
|
+
| `preset.shortcuts`, `preset.safelist`, `preset.blocklist`, `preset.theme`, `preset.layers` | `presets[<i>].<key>…` | A preset field that is not static data, as for the top-level keys above. | Replace the item with static data. |
|
|
71
|
+
| `preset.enforce`, `preset.layer` | `presets[<i>].<key>` | `enforce` other than `"pre"` or `"post"`, or a `layer` that is not a string. | Correct the value. |
|
|
72
|
+
| `declarations-unsaved` | the declaration file | A declaration file whose text came from an unsaved editor buffer. Rust reads declaration files from disk. | Save the file. |
|
|
73
|
+
| `declarations-unavailable` | `content.filesystem` | Finding declaration files under `content.filesystem` failed: the `@teacss/config` source scanner could not be loaded, or it threw. | Install `@teacss/config`. |
|
|
74
|
+
|
|
75
|
+
`content.pipeline` never falls back, in the configuration or in a preset, whatever it holds (RegExp, functions or `false`). It only decides which modules the integration feeds in, so it stays on the facade's `config.content` and is not sent to Rust.
|
|
76
|
+
|
|
32
77
|
## Compatibility
|
|
33
78
|
|
|
34
79
|
| `engineCompat` field | Meaning |
|
|
35
80
|
| --- | --- |
|
|
36
81
|
| `core` | The `@teacss/core` versions this engine accepts, written as `>=A.B.C <X.Y.Z`; prereleases compare by SemVer, so `0.9.0-alpha.1 < 0.9.0` |
|
|
37
|
-
| `defaultMode` | What the option `"auto"` means: `"opt-in"` keeps TypeScript, `"auto"` tries Rust |
|
|
82
|
+
| `defaultMode` | What the option `"auto"` means: `"opt-in"` keeps TypeScript, `"auto"` (the current value) tries Rust |
|
|
38
83
|
| `oracle.teacssTs` / `oracle.commit` | The teacss-ts version and commit this release was compared against byte for byte |
|
|
39
84
|
|
|
40
85
|
| `@teacss/core` | `@teacss/engine` | `engineCompat.core` | Result |
|
package/binding.js
CHANGED
|
@@ -92,8 +92,8 @@ function requireNative() {
|
|
|
92
92
|
try {
|
|
93
93
|
const binding = require('@teacss/engine-android-arm64')
|
|
94
94
|
const bindingPackageVersion = require('@teacss/engine-android-arm64/package.json').version
|
|
95
|
-
if (bindingPackageVersion !== '0.9.
|
|
96
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
95
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
96
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
97
97
|
}
|
|
98
98
|
return binding
|
|
99
99
|
} catch (e) {
|
|
@@ -108,8 +108,8 @@ function requireNative() {
|
|
|
108
108
|
try {
|
|
109
109
|
const binding = require('@teacss/engine-android-arm-eabi')
|
|
110
110
|
const bindingPackageVersion = require('@teacss/engine-android-arm-eabi/package.json').version
|
|
111
|
-
if (bindingPackageVersion !== '0.9.
|
|
112
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
111
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
112
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
113
113
|
}
|
|
114
114
|
return binding
|
|
115
115
|
} catch (e) {
|
|
@@ -129,8 +129,8 @@ function requireNative() {
|
|
|
129
129
|
try {
|
|
130
130
|
const binding = require('@teacss/engine-win32-x64-gnu')
|
|
131
131
|
const bindingPackageVersion = require('@teacss/engine-win32-x64-gnu/package.json').version
|
|
132
|
-
if (bindingPackageVersion !== '0.9.
|
|
133
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
132
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
133
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
134
134
|
}
|
|
135
135
|
return binding
|
|
136
136
|
} catch (e) {
|
|
@@ -145,8 +145,8 @@ function requireNative() {
|
|
|
145
145
|
try {
|
|
146
146
|
const binding = require('@teacss/engine-win32-x64-msvc')
|
|
147
147
|
const bindingPackageVersion = require('@teacss/engine-win32-x64-msvc/package.json').version
|
|
148
|
-
if (bindingPackageVersion !== '0.9.
|
|
149
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
148
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
149
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
150
150
|
}
|
|
151
151
|
return binding
|
|
152
152
|
} catch (e) {
|
|
@@ -162,8 +162,8 @@ function requireNative() {
|
|
|
162
162
|
try {
|
|
163
163
|
const binding = require('@teacss/engine-win32-ia32-msvc')
|
|
164
164
|
const bindingPackageVersion = require('@teacss/engine-win32-ia32-msvc/package.json').version
|
|
165
|
-
if (bindingPackageVersion !== '0.9.
|
|
166
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
165
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
166
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
167
167
|
}
|
|
168
168
|
return binding
|
|
169
169
|
} catch (e) {
|
|
@@ -178,8 +178,8 @@ function requireNative() {
|
|
|
178
178
|
try {
|
|
179
179
|
const binding = require('@teacss/engine-win32-arm64-msvc')
|
|
180
180
|
const bindingPackageVersion = require('@teacss/engine-win32-arm64-msvc/package.json').version
|
|
181
|
-
if (bindingPackageVersion !== '0.9.
|
|
182
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
181
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
182
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
183
183
|
}
|
|
184
184
|
return binding
|
|
185
185
|
} catch (e) {
|
|
@@ -197,8 +197,8 @@ function requireNative() {
|
|
|
197
197
|
try {
|
|
198
198
|
const binding = require('@teacss/engine-darwin-universal')
|
|
199
199
|
const bindingPackageVersion = require('@teacss/engine-darwin-universal/package.json').version
|
|
200
|
-
if (bindingPackageVersion !== '0.9.
|
|
201
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
200
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
201
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
202
202
|
}
|
|
203
203
|
return binding
|
|
204
204
|
} catch (e) {
|
|
@@ -213,8 +213,8 @@ function requireNative() {
|
|
|
213
213
|
try {
|
|
214
214
|
const binding = require('@teacss/engine-darwin-x64')
|
|
215
215
|
const bindingPackageVersion = require('@teacss/engine-darwin-x64/package.json').version
|
|
216
|
-
if (bindingPackageVersion !== '0.9.
|
|
217
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
216
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
217
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
218
218
|
}
|
|
219
219
|
return binding
|
|
220
220
|
} catch (e) {
|
|
@@ -229,8 +229,8 @@ function requireNative() {
|
|
|
229
229
|
try {
|
|
230
230
|
const binding = require('@teacss/engine-darwin-arm64')
|
|
231
231
|
const bindingPackageVersion = require('@teacss/engine-darwin-arm64/package.json').version
|
|
232
|
-
if (bindingPackageVersion !== '0.9.
|
|
233
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
232
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
233
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
234
234
|
}
|
|
235
235
|
return binding
|
|
236
236
|
} catch (e) {
|
|
@@ -249,8 +249,8 @@ function requireNative() {
|
|
|
249
249
|
try {
|
|
250
250
|
const binding = require('@teacss/engine-freebsd-x64')
|
|
251
251
|
const bindingPackageVersion = require('@teacss/engine-freebsd-x64/package.json').version
|
|
252
|
-
if (bindingPackageVersion !== '0.9.
|
|
253
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
252
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
253
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
254
254
|
}
|
|
255
255
|
return binding
|
|
256
256
|
} catch (e) {
|
|
@@ -265,8 +265,8 @@ function requireNative() {
|
|
|
265
265
|
try {
|
|
266
266
|
const binding = require('@teacss/engine-freebsd-arm64')
|
|
267
267
|
const bindingPackageVersion = require('@teacss/engine-freebsd-arm64/package.json').version
|
|
268
|
-
if (bindingPackageVersion !== '0.9.
|
|
269
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
268
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
269
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
270
270
|
}
|
|
271
271
|
return binding
|
|
272
272
|
} catch (e) {
|
|
@@ -286,8 +286,8 @@ function requireNative() {
|
|
|
286
286
|
try {
|
|
287
287
|
const binding = require('@teacss/engine-linux-x64-musl')
|
|
288
288
|
const bindingPackageVersion = require('@teacss/engine-linux-x64-musl/package.json').version
|
|
289
|
-
if (bindingPackageVersion !== '0.9.
|
|
290
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
289
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
290
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
291
291
|
}
|
|
292
292
|
return binding
|
|
293
293
|
} catch (e) {
|
|
@@ -302,8 +302,8 @@ function requireNative() {
|
|
|
302
302
|
try {
|
|
303
303
|
const binding = require('@teacss/engine-linux-x64-gnu')
|
|
304
304
|
const bindingPackageVersion = require('@teacss/engine-linux-x64-gnu/package.json').version
|
|
305
|
-
if (bindingPackageVersion !== '0.9.
|
|
306
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
305
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
306
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
307
307
|
}
|
|
308
308
|
return binding
|
|
309
309
|
} catch (e) {
|
|
@@ -320,8 +320,8 @@ function requireNative() {
|
|
|
320
320
|
try {
|
|
321
321
|
const binding = require('@teacss/engine-linux-arm64-musl')
|
|
322
322
|
const bindingPackageVersion = require('@teacss/engine-linux-arm64-musl/package.json').version
|
|
323
|
-
if (bindingPackageVersion !== '0.9.
|
|
324
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
323
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
324
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
325
325
|
}
|
|
326
326
|
return binding
|
|
327
327
|
} catch (e) {
|
|
@@ -336,8 +336,8 @@ function requireNative() {
|
|
|
336
336
|
try {
|
|
337
337
|
const binding = require('@teacss/engine-linux-arm64-gnu')
|
|
338
338
|
const bindingPackageVersion = require('@teacss/engine-linux-arm64-gnu/package.json').version
|
|
339
|
-
if (bindingPackageVersion !== '0.9.
|
|
340
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
339
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
340
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
341
341
|
}
|
|
342
342
|
return binding
|
|
343
343
|
} catch (e) {
|
|
@@ -354,8 +354,8 @@ function requireNative() {
|
|
|
354
354
|
try {
|
|
355
355
|
const binding = require('@teacss/engine-linux-arm-musleabihf')
|
|
356
356
|
const bindingPackageVersion = require('@teacss/engine-linux-arm-musleabihf/package.json').version
|
|
357
|
-
if (bindingPackageVersion !== '0.9.
|
|
358
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
357
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
358
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
359
359
|
}
|
|
360
360
|
return binding
|
|
361
361
|
} catch (e) {
|
|
@@ -370,8 +370,8 @@ function requireNative() {
|
|
|
370
370
|
try {
|
|
371
371
|
const binding = require('@teacss/engine-linux-arm-gnueabihf')
|
|
372
372
|
const bindingPackageVersion = require('@teacss/engine-linux-arm-gnueabihf/package.json').version
|
|
373
|
-
if (bindingPackageVersion !== '0.9.
|
|
374
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
373
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
374
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
375
375
|
}
|
|
376
376
|
return binding
|
|
377
377
|
} catch (e) {
|
|
@@ -388,8 +388,8 @@ function requireNative() {
|
|
|
388
388
|
try {
|
|
389
389
|
const binding = require('@teacss/engine-linux-loong64-musl')
|
|
390
390
|
const bindingPackageVersion = require('@teacss/engine-linux-loong64-musl/package.json').version
|
|
391
|
-
if (bindingPackageVersion !== '0.9.
|
|
392
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
391
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
392
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
393
393
|
}
|
|
394
394
|
return binding
|
|
395
395
|
} catch (e) {
|
|
@@ -404,8 +404,8 @@ function requireNative() {
|
|
|
404
404
|
try {
|
|
405
405
|
const binding = require('@teacss/engine-linux-loong64-gnu')
|
|
406
406
|
const bindingPackageVersion = require('@teacss/engine-linux-loong64-gnu/package.json').version
|
|
407
|
-
if (bindingPackageVersion !== '0.9.
|
|
408
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
407
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
408
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
409
409
|
}
|
|
410
410
|
return binding
|
|
411
411
|
} catch (e) {
|
|
@@ -422,8 +422,8 @@ function requireNative() {
|
|
|
422
422
|
try {
|
|
423
423
|
const binding = require('@teacss/engine-linux-riscv64-musl')
|
|
424
424
|
const bindingPackageVersion = require('@teacss/engine-linux-riscv64-musl/package.json').version
|
|
425
|
-
if (bindingPackageVersion !== '0.9.
|
|
426
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
425
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
426
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
427
427
|
}
|
|
428
428
|
return binding
|
|
429
429
|
} catch (e) {
|
|
@@ -438,8 +438,8 @@ function requireNative() {
|
|
|
438
438
|
try {
|
|
439
439
|
const binding = require('@teacss/engine-linux-riscv64-gnu')
|
|
440
440
|
const bindingPackageVersion = require('@teacss/engine-linux-riscv64-gnu/package.json').version
|
|
441
|
-
if (bindingPackageVersion !== '0.9.
|
|
442
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
441
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
442
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
443
443
|
}
|
|
444
444
|
return binding
|
|
445
445
|
} catch (e) {
|
|
@@ -455,8 +455,8 @@ function requireNative() {
|
|
|
455
455
|
try {
|
|
456
456
|
const binding = require('@teacss/engine-linux-ppc64-gnu')
|
|
457
457
|
const bindingPackageVersion = require('@teacss/engine-linux-ppc64-gnu/package.json').version
|
|
458
|
-
if (bindingPackageVersion !== '0.9.
|
|
459
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
458
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
459
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
460
460
|
}
|
|
461
461
|
return binding
|
|
462
462
|
} catch (e) {
|
|
@@ -471,8 +471,8 @@ function requireNative() {
|
|
|
471
471
|
try {
|
|
472
472
|
const binding = require('@teacss/engine-linux-s390x-gnu')
|
|
473
473
|
const bindingPackageVersion = require('@teacss/engine-linux-s390x-gnu/package.json').version
|
|
474
|
-
if (bindingPackageVersion !== '0.9.
|
|
475
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
474
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
475
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
476
476
|
}
|
|
477
477
|
return binding
|
|
478
478
|
} catch (e) {
|
|
@@ -491,8 +491,8 @@ function requireNative() {
|
|
|
491
491
|
try {
|
|
492
492
|
const binding = require('@teacss/engine-openharmony-arm64')
|
|
493
493
|
const bindingPackageVersion = require('@teacss/engine-openharmony-arm64/package.json').version
|
|
494
|
-
if (bindingPackageVersion !== '0.9.
|
|
495
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
494
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
495
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
496
496
|
}
|
|
497
497
|
return binding
|
|
498
498
|
} catch (e) {
|
|
@@ -507,8 +507,8 @@ function requireNative() {
|
|
|
507
507
|
try {
|
|
508
508
|
const binding = require('@teacss/engine-openharmony-x64')
|
|
509
509
|
const bindingPackageVersion = require('@teacss/engine-openharmony-x64/package.json').version
|
|
510
|
-
if (bindingPackageVersion !== '0.9.
|
|
511
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
510
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
511
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
512
512
|
}
|
|
513
513
|
return binding
|
|
514
514
|
} catch (e) {
|
|
@@ -523,8 +523,8 @@ function requireNative() {
|
|
|
523
523
|
try {
|
|
524
524
|
const binding = require('@teacss/engine-openharmony-arm')
|
|
525
525
|
const bindingPackageVersion = require('@teacss/engine-openharmony-arm/package.json').version
|
|
526
|
-
if (bindingPackageVersion !== '0.9.
|
|
527
|
-
throw new Error(`Native binding package version mismatch, expected 0.9.
|
|
526
|
+
if (bindingPackageVersion !== '0.9.3' && process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
527
|
+
throw new Error(`Native binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
528
528
|
}
|
|
529
529
|
return binding
|
|
530
530
|
} catch (e) {
|
|
@@ -664,8 +664,8 @@ if (!nativeBinding || forceWasi) {
|
|
|
664
664
|
if (!candidateFailed) {
|
|
665
665
|
if (process.env.NAPI_RS_ENFORCE_VERSION_CHECK && process.env.NAPI_RS_ENFORCE_VERSION_CHECK !== '0') {
|
|
666
666
|
const bindingPackageVersion = require('@teacss/engine-wasm32-wasi/package.json').version
|
|
667
|
-
if (bindingPackageVersion !== '0.9.
|
|
668
|
-
throw new Error(`WASI binding package version mismatch, expected 0.9.
|
|
667
|
+
if (bindingPackageVersion !== '0.9.3') {
|
|
668
|
+
throw new Error(`WASI binding package version mismatch, expected 0.9.3 but got ${bindingPackageVersion}. You can reinstall dependencies to fix this issue.`)
|
|
669
669
|
}
|
|
670
670
|
}
|
|
671
671
|
wasiBinding = require('@teacss/engine-wasm32-wasi')
|
package/contract.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Mirror of docs/specs/v02.2-engine-contract.md §3 (spec-revision
|
|
1
|
+
// Mirror of docs/specs/v02.2-engine-contract.md §3 (spec-revision 13). Do not edit without bumping the spec revision.
|
|
2
2
|
export interface InspectEntryRequest {
|
|
3
3
|
/** 项目根(绝对路径)。相对 @source 以声明它的文件所在目录为基准。 */
|
|
4
4
|
root: string;
|
package/dist/config-view.d.ts
CHANGED
|
@@ -23,5 +23,14 @@ export interface ConfigViewArgs {
|
|
|
23
23
|
compileClassShortcuts(): unknown[];
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* The merged `content.pipeline` of the presets and the config, as `mergeContentOptions`
|
|
28
|
+
* (core/config.ts) builds it: `false` anywhere disables it, otherwise includes and excludes
|
|
29
|
+
* concatenate in source order without duplicates. The runtime builds its module filter from it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergePipeline(sources: readonly unknown[]): false | {
|
|
32
|
+
include?: Array<string | RegExp>;
|
|
33
|
+
exclude?: Array<string | RegExp>;
|
|
34
|
+
} | undefined;
|
|
26
35
|
export declare function createConfigView({ view, presets, merged, transformers, host, fallback, engine }: ConfigViewArgs): Record<string, unknown>;
|
|
27
36
|
//# sourceMappingURL=config-view.d.ts.map
|
package/dist/config-view.js
CHANGED
|
@@ -38,6 +38,40 @@ const RESOLVED_KEYS = Object.freeze([
|
|
|
38
38
|
"content",
|
|
39
39
|
"transformers",
|
|
40
40
|
]);
|
|
41
|
+
const ownValue = (source, key) => (source !== null && typeof source === "object" && Object.hasOwn(source, key) ? source[key] : undefined);
|
|
42
|
+
const flattenPatterns = (patterns) => [...new Set(patterns.flatMap((pattern) => (Array.isArray(pattern) ? pattern : pattern ? [pattern] : [])))];
|
|
43
|
+
/**
|
|
44
|
+
* The merged `content.pipeline` of the presets and the config, as `mergeContentOptions`
|
|
45
|
+
* (core/config.ts) builds it: `false` anywhere disables it, otherwise includes and excludes
|
|
46
|
+
* concatenate in source order without duplicates. The runtime builds its module filter from it.
|
|
47
|
+
*/
|
|
48
|
+
export function mergePipeline(sources) {
|
|
49
|
+
const includes = [];
|
|
50
|
+
const excludes = [];
|
|
51
|
+
let configured = false;
|
|
52
|
+
for (const content of new Set(sources.map((source) => ownValue(source, "content")).filter((content) => content !== undefined && content !== null))) {
|
|
53
|
+
const pipeline = ownValue(content, "pipeline");
|
|
54
|
+
if (pipeline === false)
|
|
55
|
+
return false;
|
|
56
|
+
if (pipeline === undefined)
|
|
57
|
+
continue;
|
|
58
|
+
configured = true;
|
|
59
|
+
const include = pipeline && ownValue(pipeline, "include");
|
|
60
|
+
const exclude = pipeline && ownValue(pipeline, "exclude");
|
|
61
|
+
if (include)
|
|
62
|
+
includes.push(include);
|
|
63
|
+
if (exclude)
|
|
64
|
+
excludes.push(exclude);
|
|
65
|
+
}
|
|
66
|
+
if (!configured)
|
|
67
|
+
return undefined;
|
|
68
|
+
const merged = {};
|
|
69
|
+
if (includes.length)
|
|
70
|
+
merged.include = flattenPatterns(includes);
|
|
71
|
+
if (excludes.length)
|
|
72
|
+
merged.exclude = flattenPatterns(excludes);
|
|
73
|
+
return merged;
|
|
74
|
+
}
|
|
41
75
|
export function createConfigView({ view, presets, merged, transformers, host, fallback, engine }) {
|
|
42
76
|
const config = {};
|
|
43
77
|
const data = (key, value) => Object.defineProperty(config, key, { value, enumerable: true, configurable: true, writable: true });
|
|
@@ -54,7 +88,10 @@ export function createConfigView({ view, presets, merged, transformers, host, fa
|
|
|
54
88
|
const extractors = host.core ? [host.core.extractorSplit] : [{ name: view.extractors?.[0]?.name ?? "@teacss/core/extractor-split" }];
|
|
55
89
|
const fields = {
|
|
56
90
|
presets: () => data("presets", presets),
|
|
57
|
-
content: () =>
|
|
91
|
+
content: () => {
|
|
92
|
+
const pipeline = mergePipeline([...presets, merged]);
|
|
93
|
+
data("content", pipeline === undefined ? (view.content ?? {}) : { pipeline, ...view.content });
|
|
94
|
+
},
|
|
58
95
|
transformers: () => data("transformers", transformers),
|
|
59
96
|
extractors: () => data("extractors", extractors),
|
|
60
97
|
extractorDefault: () => data("extractorDefault", extractors[0]),
|
package/dist/errors.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare class TeacssEngineError extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
/** v02.9 §2.1: the member needs `@teacss/core`, which is not installed. */
|
|
8
8
|
export declare function tsRequiredError(member: string): TeacssEngineError;
|
|
9
|
+
/** The generator was disposed; the native Engine reports the same code after its own `dispose()`. */
|
|
10
|
+
export declare function disposedError(member: string): TeacssEngineError;
|
|
9
11
|
/** v02.9 §3.3: the member needs the TypeScript engine, which has not been materialized. */
|
|
10
12
|
export declare function tsNotReadyError(member: string): TeacssEngineError;
|
|
11
13
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.js
CHANGED
|
@@ -11,6 +11,10 @@ export class TeacssEngineError extends Error {
|
|
|
11
11
|
export function tsRequiredError(member) {
|
|
12
12
|
return new TeacssEngineError("E_TS_REQUIRED", `[@teacss/engine] ${member} requires @teacss/core (optional peer) to be installed`, { member });
|
|
13
13
|
}
|
|
14
|
+
/** The generator was disposed; the native Engine reports the same code after its own `dispose()`. */
|
|
15
|
+
export function disposedError(member) {
|
|
16
|
+
return new TeacssEngineError("E_DISPOSED", `[@teacss/engine] ${member} called after dispose()`);
|
|
17
|
+
}
|
|
14
18
|
/** v02.9 §3.3: the member needs the TypeScript engine, which has not been materialized. */
|
|
15
19
|
export function tsNotReadyError(member) {
|
|
16
20
|
return new TeacssEngineError("E_TS_REQUIRED", `[@teacss/engine] ${member} needs the TypeScript engine; await generator[Symbol.for('@teacss/engine/materialize')]() first or set engine: 'ts'`, { member });
|
package/dist/generator.d.ts
CHANGED
|
@@ -19,7 +19,8 @@ export declare function engineStats(): {
|
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
21
|
* v02.9 §9: each reason and path prints once per process; the counter grows on every call. A
|
|
22
|
-
* host `report(reason, path, level)` (
|
|
22
|
+
* host `report(reason, path, level)` (core's `reportFallback`) gets every call and does both
|
|
23
|
+
* itself, so the counter is not touched here.
|
|
23
24
|
*/
|
|
24
25
|
export declare function reportFallback(reason: string, path: string, host?: FacadeHost, level?: "info" | "warn"): void;
|
|
25
26
|
export declare class FacadeGenerator {
|
|
@@ -121,6 +122,13 @@ export declare class FacadeGenerator {
|
|
|
121
122
|
userConfig: Record<string, unknown>;
|
|
122
123
|
version: number;
|
|
123
124
|
}): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Releases the Engine this generator owns; later `generate`, `parseToken`, `applyExtractors`,
|
|
127
|
+
* `prepareConfig` and `commitConfig` throw `E_DISPOSED`, and a second call does nothing. A
|
|
128
|
+
* candidate committed into another generator handed its Engine over and leaves it alone.
|
|
129
|
+
*/
|
|
130
|
+
dispose(): void;
|
|
131
|
+
[Symbol.dispose](): void;
|
|
124
132
|
}
|
|
125
133
|
/**
|
|
126
134
|
* v02.9 §3.1: a Rust facade, or the reason the configuration needs TypeScript. Errors from
|
|
@@ -140,7 +148,7 @@ export interface FacadeHost {
|
|
|
140
148
|
/** core/utils/warn.ts 的 warnOnce;传入时 shortcut 警告与 TS 引擎共用一个去重集合。 */
|
|
141
149
|
warnOnce?: (message: string) => void;
|
|
142
150
|
} | undefined;
|
|
143
|
-
/**
|
|
151
|
+
/** 挂钩注入的回退出口(core 的 reportFallback):每次回退都调用,由它计数并按 reason 与 path 去重打印;缺省时 facade 自己计数并写 process.stderr。 */
|
|
144
152
|
report?: (reason: string, path: string, level: "info" | "warn") => void;
|
|
145
153
|
}
|
|
146
154
|
export type FacadeCreateResult = {
|
package/dist/generator.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Engine } from "../binding.js";
|
|
|
6
6
|
import { createConfigView } from "./config-view.js";
|
|
7
7
|
import { ENGINE_INSTANCE, ENGINE_MATERIALIZE, ENGINE_PACKAGE_VERSION, ENGINE_STATS } from "./constants.js";
|
|
8
8
|
import { BoundedSet, BoundedTokenCache, CountableSet, copyCountableSet, expandInputGroups, isCountableSet, MAX_RUNTIME_CACHE_ENTRIES } from "./countable-set.js";
|
|
9
|
-
import { tsNotReadyError } from "./errors.js";
|
|
9
|
+
import { disposedError, tsNotReadyError } from "./errors.js";
|
|
10
10
|
import { buildMatched, createFacadeResult, describeUnmatched, fallbackIsTokenShaped, formatUnmatchedError, shortcutWarningMessages, splitMatched, toTuple } from "./result.js";
|
|
11
11
|
import { mergeDefinedConfig, translateConfig } from "./select.js";
|
|
12
12
|
import { createCompileClassTransformer } from "./transformer.js";
|
|
@@ -232,19 +232,21 @@ export function engineStats() {
|
|
|
232
232
|
const reported = new Set();
|
|
233
233
|
/**
|
|
234
234
|
* v02.9 §9: each reason and path prints once per process; the counter grows on every call. A
|
|
235
|
-
* host `report(reason, path, level)` (
|
|
235
|
+
* host `report(reason, path, level)` (core's `reportFallback`) gets every call and does both
|
|
236
|
+
* itself, so the counter is not touched here.
|
|
236
237
|
*/
|
|
237
238
|
export function reportFallback(reason, path, host = {}, level = "info") {
|
|
239
|
+
if (typeof host.report === "function") {
|
|
240
|
+
host.report(reason, path, level);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
238
243
|
const stats = engineStats();
|
|
239
244
|
stats.fallbacks[reason] = (stats.fallbacks[reason] ?? 0) + 1;
|
|
240
245
|
const key = `${reason}\0${path}`;
|
|
241
246
|
if (reported.has(key))
|
|
242
247
|
return;
|
|
243
248
|
reported.add(key);
|
|
244
|
-
|
|
245
|
-
host.report(reason, path, level);
|
|
246
|
-
else
|
|
247
|
-
process.stderr.write(`[teacss] engine: falling back to the TypeScript engine (${reason} at ${path})\n`);
|
|
249
|
+
process.stderr.write(`[teacss] engine: falling back to the TypeScript engine (${reason} at ${path})\n`);
|
|
248
250
|
}
|
|
249
251
|
/** array-internal.ts:7-13: ownership is rechecked before each read. */
|
|
250
252
|
function* ownArrayValues(array) {
|
|
@@ -301,7 +303,10 @@ export class FacadeGenerator {
|
|
|
301
303
|
disposeEngine(held.engine);
|
|
302
304
|
});
|
|
303
305
|
#backend;
|
|
306
|
+
#disposed = false;
|
|
304
307
|
#held = null;
|
|
308
|
+
/** A TS candidate's own commit, run when another generator commits it. */
|
|
309
|
+
#commitTs = null;
|
|
305
310
|
#host;
|
|
306
311
|
#tsFallback;
|
|
307
312
|
/** The compile-class transformer: created once and handed to every candidate (v02.9 §5.2). */
|
|
@@ -410,6 +415,7 @@ export class FacadeGenerator {
|
|
|
410
415
|
* tokens; a counted set adds each token's occurrences.
|
|
411
416
|
*/
|
|
412
417
|
async applyExtractors(code, id, extracted = new Set()) {
|
|
418
|
+
this.#assertLive("applyExtractors");
|
|
413
419
|
await Promise.resolve();
|
|
414
420
|
const backend = this.#backend;
|
|
415
421
|
if (backend.kind === "ts")
|
|
@@ -447,6 +453,7 @@ export class FacadeGenerator {
|
|
|
447
453
|
* runs `applyExtractors` on it, generator.ts:2378).
|
|
448
454
|
*/
|
|
449
455
|
async generate(input, options = {}) {
|
|
456
|
+
this.#assertLive("generate");
|
|
450
457
|
const backend = this.#backend;
|
|
451
458
|
if (backend.kind === "ts") {
|
|
452
459
|
// A rule may commit a new configuration through this facade while the TS backend runs; the
|
|
@@ -610,6 +617,7 @@ export class FacadeGenerator {
|
|
|
610
617
|
* already cached reads back as `null`. With an `alias` nothing is cached.
|
|
611
618
|
*/
|
|
612
619
|
async parseToken(raw, alias) {
|
|
620
|
+
this.#assertLive("parseToken");
|
|
613
621
|
await Promise.resolve();
|
|
614
622
|
const backend = this.#backend;
|
|
615
623
|
if (backend.kind === "ts")
|
|
@@ -727,6 +735,7 @@ export class FacadeGenerator {
|
|
|
727
735
|
* one. A configuration Rust cannot serve gets a TypeScript candidate.
|
|
728
736
|
*/
|
|
729
737
|
async prepareConfig(userConfig, defaults) {
|
|
738
|
+
this.#assertLive("prepareConfig");
|
|
730
739
|
await Promise.resolve();
|
|
731
740
|
const version = ++this.#configVersion;
|
|
732
741
|
const nextDefaults = defaults ?? this.defaults;
|
|
@@ -741,13 +750,14 @@ export class FacadeGenerator {
|
|
|
741
750
|
else {
|
|
742
751
|
this.#reportFallback(translated);
|
|
743
752
|
const ts = await this.#tsFallback.create(userConfig, nextDefaults);
|
|
744
|
-
candidate = new FacadeGenerator({ ts, userConfig, defaults: nextDefaults, host: this.#host });
|
|
753
|
+
candidate = new FacadeGenerator({ ts: ts.generator, userConfig, defaults: nextDefaults, host: this.#host });
|
|
754
|
+
candidate.#commitTs = ts.commit;
|
|
745
755
|
}
|
|
746
756
|
const prepared = Object.freeze({ config: candidate.config, defaults: nextDefaults, generator: candidate, userConfig, version });
|
|
747
757
|
this.#prepared.add(prepared);
|
|
748
758
|
const held = candidate.#backend.kind === "rust" ? { kind: "rust", engine: candidate.#backend.engine, committed: false } : { kind: "ts", committed: false };
|
|
749
759
|
candidate.#held = held;
|
|
750
|
-
FacadeGenerator.#registry.register(candidate, held);
|
|
760
|
+
FacadeGenerator.#registry.register(candidate, held, candidate);
|
|
751
761
|
return prepared;
|
|
752
762
|
}
|
|
753
763
|
/**
|
|
@@ -755,6 +765,7 @@ export class FacadeGenerator {
|
|
|
755
765
|
* superseded Rust candidate is disposed; so is the previous Engine once it is replaced.
|
|
756
766
|
*/
|
|
757
767
|
commitConfig(prepared) {
|
|
768
|
+
this.#assertLive("commitConfig");
|
|
758
769
|
if (!this.#prepared.delete(prepared))
|
|
759
770
|
return false;
|
|
760
771
|
const candidate = prepared.generator;
|
|
@@ -764,11 +775,18 @@ export class FacadeGenerator {
|
|
|
764
775
|
}
|
|
765
776
|
if (candidate.config !== prepared.config)
|
|
766
777
|
return false;
|
|
778
|
+
let next = candidate.#backend;
|
|
779
|
+
if (candidate.#commitTs) {
|
|
780
|
+
const committed = candidate.#commitTs();
|
|
781
|
+
if (!committed)
|
|
782
|
+
return false;
|
|
783
|
+
next = { kind: "ts", generator: committed };
|
|
784
|
+
}
|
|
767
785
|
const previous = this.#backend;
|
|
768
786
|
this.defaults = prepared.defaults;
|
|
769
787
|
this.userConfig = prepared.userConfig;
|
|
770
788
|
this.#clearRuntimeCaches();
|
|
771
|
-
this.#backend =
|
|
789
|
+
this.#backend = next;
|
|
772
790
|
if (candidate.#held)
|
|
773
791
|
candidate.#held.committed = true;
|
|
774
792
|
this.#tsFallback.invalidate(prepared.userConfig, prepared.defaults);
|
|
@@ -777,6 +795,30 @@ export class FacadeGenerator {
|
|
|
777
795
|
this.#dispatchConfig(this.config);
|
|
778
796
|
return true;
|
|
779
797
|
}
|
|
798
|
+
/**
|
|
799
|
+
* Releases the Engine this generator owns; later `generate`, `parseToken`, `applyExtractors`,
|
|
800
|
+
* `prepareConfig` and `commitConfig` throw `E_DISPOSED`, and a second call does nothing. A
|
|
801
|
+
* candidate committed into another generator handed its Engine over and leaves it alone.
|
|
802
|
+
*/
|
|
803
|
+
dispose() {
|
|
804
|
+
if (this.#disposed)
|
|
805
|
+
return;
|
|
806
|
+
this.#disposed = true;
|
|
807
|
+
FacadeGenerator.#registry.unregister(this);
|
|
808
|
+
const backend = this.#backend;
|
|
809
|
+
if (backend.kind !== "rust")
|
|
810
|
+
return;
|
|
811
|
+
const handedOver = this.#held?.committed === true && this.#held.engine === backend.engine;
|
|
812
|
+
if (!handedOver)
|
|
813
|
+
disposeEngine(backend.engine);
|
|
814
|
+
}
|
|
815
|
+
[Symbol.dispose]() {
|
|
816
|
+
this.dispose();
|
|
817
|
+
}
|
|
818
|
+
#assertLive(member) {
|
|
819
|
+
if (this.#disposed)
|
|
820
|
+
throw disposedError(member);
|
|
821
|
+
}
|
|
780
822
|
/** An explicit `engine: "rust"` asked for Rust, so its fallback is a warning. */
|
|
781
823
|
#reportFallback(failure) {
|
|
782
824
|
const explicit = this.defaults?.engine === "rust" || this.userConfig?.engine === "rust";
|
package/dist/select.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export declare function pick(obj: Record<string, unknown>, keys: Iterable<string
|
|
|
54
54
|
export declare function translateTaggedPreset(preset: object, path: string, ctx: {
|
|
55
55
|
hasEntry: boolean;
|
|
56
56
|
}): Success<object | null> | Failure | undefined;
|
|
57
|
-
/** Keys of an unmarked preset whose non-empty value means fallback
|
|
57
|
+
/** Keys of an unmarked preset whose non-empty value means fallback; `content` is checked by `hasContentBeyondPipeline`. */
|
|
58
58
|
export declare const PRESET_DYNAMIC_KEYS: readonly string[];
|
|
59
59
|
/**
|
|
60
60
|
* v02.9 §4.5: the static shortcut forms as `[name, expansion]` pairs. A shortcut meta (`[n, e, meta]`)
|
|
@@ -88,6 +88,14 @@ export declare const ALLOWED_TRANSFORMER_NAMES: Set<string>;
|
|
|
88
88
|
* checked per call (v02.9 §6.3), so none are read here.
|
|
89
89
|
*/
|
|
90
90
|
export declare function translateTransformers(list: unknown): Success<object[]> | Failure;
|
|
91
|
+
/**
|
|
92
|
+
* A config's own `transformerCompileClass(options)` keeps its options in a closure the facade
|
|
93
|
+
* cannot read, and it registers classes by pushing onto `config.shortcuts`, which never reaches
|
|
94
|
+
* the Engine. It is harmless only when the last Standard preset enables compileClass: the facade's
|
|
95
|
+
* Rust transformer then comes first and `uniqueNamed` drops it, as the oracle drops it after the
|
|
96
|
+
* preset's own. Otherwise it would run and its classes would generate no CSS, so it falls back.
|
|
97
|
+
*/
|
|
98
|
+
export declare function hostCompileClass(transformers: readonly object[], presetSpecs: readonly object[]): Failure | undefined;
|
|
91
99
|
export type EntryProvenance = {
|
|
92
100
|
base: string;
|
|
93
101
|
entryFile: string | undefined;
|
package/dist/select.js
CHANGED
|
@@ -223,11 +223,23 @@ export function translateTaggedPreset(preset, path, ctx) {
|
|
|
223
223
|
return ctx.hasEntry ? ok(null) : fail("role-palettes-without-entry", path);
|
|
224
224
|
return undefined;
|
|
225
225
|
}
|
|
226
|
-
/** Keys of an unmarked preset whose non-empty value means fallback
|
|
227
|
-
export const PRESET_DYNAMIC_KEYS = Object.freeze(["rules", "variants", "extractors", "preflights", "preprocess", "postprocess", "extendTheme", "configResolved", "transformers", "autocomplete", "extractorDefault"
|
|
226
|
+
/** Keys of an unmarked preset whose non-empty value means fallback; `content` is checked by `hasContentBeyondPipeline`. */
|
|
227
|
+
export const PRESET_DYNAMIC_KEYS = Object.freeze(["rules", "variants", "extractors", "preflights", "preprocess", "postprocess", "extendTheme", "configResolved", "transformers", "autocomplete", "extractorDefault"]);
|
|
228
228
|
const isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
229
229
|
/** Values `undefined` are left out. */
|
|
230
230
|
const defined = (entries) => Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== undefined));
|
|
231
|
+
/**
|
|
232
|
+
* `content.pipeline` only filters the modules an integration feeds in; generation never reads it
|
|
233
|
+
* (v02.2 §4), so it stays in the config view and never reaches Rust. Any other content field of a
|
|
234
|
+
* preset is not translated.
|
|
235
|
+
*/
|
|
236
|
+
function hasContentBeyondPipeline(content) {
|
|
237
|
+
if (!isNonEmpty(content))
|
|
238
|
+
return false;
|
|
239
|
+
if (!isPlainObject(content))
|
|
240
|
+
return true;
|
|
241
|
+
return Object.keys(content).some((key) => key !== "pipeline" && isNonEmpty(content[key]));
|
|
242
|
+
}
|
|
231
243
|
/**
|
|
232
244
|
* v02.9 §4.5: the static shortcut forms as `[name, expansion]` pairs. A shortcut meta (`[n, e, meta]`)
|
|
233
245
|
* has no place in `StaticPreset.shortcuts`, so any meta key falls back.
|
|
@@ -282,6 +294,26 @@ export function translateShortcuts(value, path, reasonOnFail) {
|
|
|
282
294
|
}
|
|
283
295
|
return ok(pairs.length > 0 ? pairs : undefined);
|
|
284
296
|
}
|
|
297
|
+
/** context.ts `isContextName` behind its falsy check: no NUL and no lone surrogate. */
|
|
298
|
+
function isContextName(value) {
|
|
299
|
+
if (!value)
|
|
300
|
+
return false;
|
|
301
|
+
if (typeof value !== "string")
|
|
302
|
+
return true;
|
|
303
|
+
for (let index = 0; index < value.length; index++) {
|
|
304
|
+
const code = value.charCodeAt(index);
|
|
305
|
+
if (code === 0)
|
|
306
|
+
return false;
|
|
307
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
308
|
+
const next = value.charCodeAt(++index);
|
|
309
|
+
if (!(next >= 0xdc00 && next <= 0xdfff))
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
else if (code >= 0xdc00 && code <= 0xdfff)
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
return true;
|
|
316
|
+
}
|
|
285
317
|
/**
|
|
286
318
|
* v02.9 §4.5: a theme as dotted keys to string leaves (numbers stringified); empty objects vanish.
|
|
287
319
|
*
|
|
@@ -299,6 +331,16 @@ export function flattenTheme(theme, path, reasonOnFail) {
|
|
|
299
331
|
if (isPlainObject(values) && Object.hasOwn(values, "rolePalettes"))
|
|
300
332
|
return fail(reasonOnFail, `${path}.modes.${mode}.rolePalettes`);
|
|
301
333
|
}
|
|
334
|
+
// Standard's `validateContextNames` (context.ts) throws on these. Flattening drops an empty
|
|
335
|
+
// object and the binding replaces lone surrogates, so Rust cannot see them.
|
|
336
|
+
if (Object.hasOwn(theme, "themes"))
|
|
337
|
+
return fail(reasonOnFail, `${path}.themes`);
|
|
338
|
+
if (Object.hasOwn(theme, "defaultMode") && !isContextName(theme.defaultMode))
|
|
339
|
+
return fail(reasonOnFail, `${path}.defaultMode`);
|
|
340
|
+
for (const [mode] of modes) {
|
|
341
|
+
if (!isContextName(mode))
|
|
342
|
+
return fail(reasonOnFail, `${path}.modes.${mode}`);
|
|
343
|
+
}
|
|
302
344
|
const flat = {};
|
|
303
345
|
const visit = (object, prefix) => {
|
|
304
346
|
for (const [key, value] of Object.entries(object)) {
|
|
@@ -354,6 +396,8 @@ export function translateStaticPreset(preset, path) {
|
|
|
354
396
|
if (isNonEmpty(preset[key]))
|
|
355
397
|
return fail(`preset.${key}`, `${path}.${key}`);
|
|
356
398
|
}
|
|
399
|
+
if (hasContentBeyondPipeline(preset.content))
|
|
400
|
+
return fail("preset.content", `${path}.content`);
|
|
357
401
|
const shortcuts = translateShortcuts(preset.shortcuts, `${path}.shortcuts`, "preset.shortcuts");
|
|
358
402
|
if (!shortcuts.ok)
|
|
359
403
|
return shortcuts;
|
|
@@ -401,8 +445,6 @@ export function translateInline(merged) {
|
|
|
401
445
|
if (merged.content !== undefined) {
|
|
402
446
|
if (!isPlainObject(merged.content))
|
|
403
447
|
return fail("content", "content");
|
|
404
|
-
if (Object.hasOwn(merged.content, "pipeline") && merged.content.pipeline !== undefined)
|
|
405
|
-
return fail("content.pipeline", "content.pipeline");
|
|
406
448
|
if (isNonEmpty(merged.content.inline))
|
|
407
449
|
return fail("content.inline", "content.inline");
|
|
408
450
|
const filesystem = merged.content.filesystem;
|
|
@@ -436,6 +478,22 @@ export function translateTransformers(list) {
|
|
|
436
478
|
}
|
|
437
479
|
return ok(kept);
|
|
438
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* A config's own `transformerCompileClass(options)` keeps its options in a closure the facade
|
|
483
|
+
* cannot read, and it registers classes by pushing onto `config.shortcuts`, which never reaches
|
|
484
|
+
* the Engine. It is harmless only when the last Standard preset enables compileClass: the facade's
|
|
485
|
+
* Rust transformer then comes first and `uniqueNamed` drops it, as the oracle drops it after the
|
|
486
|
+
* preset's own. Otherwise it would run and its classes would generate no CSS, so it falls back.
|
|
487
|
+
*/
|
|
488
|
+
export function hostCompileClass(transformers, presetSpecs) {
|
|
489
|
+
const index = transformers.findIndex((transformer) => transformer.name === "@teacss/transformer-compile-class");
|
|
490
|
+
if (index < 0)
|
|
491
|
+
return undefined;
|
|
492
|
+
const standard = presetSpecs.findLast((spec) => spec.kind === "standard");
|
|
493
|
+
if (standard && standard.options.compileClass !== false)
|
|
494
|
+
return undefined;
|
|
495
|
+
return fail("transformers.compile-class", `transformers[${index}]`);
|
|
496
|
+
}
|
|
439
497
|
export const scanners = {
|
|
440
498
|
load: null,
|
|
441
499
|
};
|
|
@@ -551,6 +609,9 @@ async function translate(userConfig, defaults) {
|
|
|
551
609
|
const transformers = translateTransformers(merged.transformers);
|
|
552
610
|
if (!transformers.ok)
|
|
553
611
|
return transformers;
|
|
612
|
+
const compileClass = hostCompileClass(transformers.value, presetSpecs);
|
|
613
|
+
if (compileClass)
|
|
614
|
+
return compileClass;
|
|
554
615
|
const inline = translateInline(merged);
|
|
555
616
|
if (!inline.ok)
|
|
556
617
|
return inline;
|
package/dist/ts-fallback.d.ts
CHANGED
|
@@ -16,7 +16,16 @@ export interface TsFallback {
|
|
|
16
16
|
invalidate(userConfig: object, defaults: object): void;
|
|
17
17
|
generator(member?: string): Promise<TsGenerator>;
|
|
18
18
|
peek(): TsGenerator | null;
|
|
19
|
-
create(userConfig: object, defaults: object): Promise<
|
|
19
|
+
create(userConfig: object, defaults: object): Promise<TsCandidate>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A prepared TS configuration. `commit` runs the base generator's own `commitConfig`, which
|
|
23
|
+
* re-reads in-place edits of the prepared config (generator.ts:2036-2063), and returns the
|
|
24
|
+
* generator that now serves it, or `null` when the TS generator refused the commit.
|
|
25
|
+
*/
|
|
26
|
+
export interface TsCandidate {
|
|
27
|
+
generator: TsGenerator;
|
|
28
|
+
commit(): TsGenerator | null;
|
|
20
29
|
}
|
|
21
30
|
/**
|
|
22
31
|
* `engine: "ts"` goes into the defaults, which take precedence over `config.engine`, so the TS
|
package/dist/ts-fallback.js
CHANGED
|
@@ -70,8 +70,9 @@ export function createTsFallback(host, committed) {
|
|
|
70
70
|
// translate it, so `createGenerator` resolves to TS and creates no Engine.
|
|
71
71
|
const base = await createTs(binding, typeof binding.createTsGenerator === "function" ? {} : userConfig, defaults);
|
|
72
72
|
if (ENGINE_INSTANCE in Object(base) || typeof base?.prepareConfig !== "function")
|
|
73
|
-
return base;
|
|
74
|
-
|
|
73
|
+
return { generator: base, commit: () => base };
|
|
74
|
+
const prepared = await base.prepareConfig(userConfig, tsDefaults);
|
|
75
|
+
return { generator: prepared.generator, commit: () => (base.commitConfig(prepared) ? base : null) };
|
|
75
76
|
},
|
|
76
77
|
};
|
|
77
78
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teacss/engine",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "In-process Rust engine for TeaCSS 0.9 (napi-rs binding and 0.8.x-compatible facade)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -65,21 +65,21 @@
|
|
|
65
65
|
},
|
|
66
66
|
"engineCompat": {
|
|
67
67
|
"core": ">=0.8.5 <0.10.0",
|
|
68
|
-
"defaultMode": "
|
|
68
|
+
"defaultMode": "auto",
|
|
69
69
|
"oracle": {
|
|
70
70
|
"teacssTs": "0.8.5",
|
|
71
71
|
"commit": "786b4d40"
|
|
72
72
|
}
|
|
73
73
|
},
|
|
74
74
|
"optionalDependencies": {
|
|
75
|
-
"@teacss/engine-darwin-arm64": "0.9.
|
|
76
|
-
"@teacss/engine-darwin-x64": "0.9.
|
|
77
|
-
"@teacss/engine-linux-arm64-gnu": "0.9.
|
|
78
|
-
"@teacss/engine-linux-arm64-musl": "0.9.
|
|
79
|
-
"@teacss/engine-linux-x64-gnu": "0.9.
|
|
80
|
-
"@teacss/engine-linux-x64-musl": "0.9.
|
|
81
|
-
"@teacss/engine-win32-arm64-msvc": "0.9.
|
|
82
|
-
"@teacss/engine-win32-x64-msvc": "0.9.
|
|
75
|
+
"@teacss/engine-darwin-arm64": "0.9.3",
|
|
76
|
+
"@teacss/engine-darwin-x64": "0.9.3",
|
|
77
|
+
"@teacss/engine-linux-arm64-gnu": "0.9.3",
|
|
78
|
+
"@teacss/engine-linux-arm64-musl": "0.9.3",
|
|
79
|
+
"@teacss/engine-linux-x64-gnu": "0.9.3",
|
|
80
|
+
"@teacss/engine-linux-x64-musl": "0.9.3",
|
|
81
|
+
"@teacss/engine-win32-arm64-msvc": "0.9.3",
|
|
82
|
+
"@teacss/engine-win32-x64-msvc": "0.9.3"
|
|
83
83
|
},
|
|
84
84
|
"peerDependencies": {
|
|
85
85
|
"@teacss/config": ">=0.8.5 <0.10.0 || >=0.9.0-alpha.0 <0.10.0",
|