@pikacss/core 0.0.56 → 0.0.58
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 +20 -0
- package/dist/index.d.mts +72 -47
- package/dist/index.mjs +182 -116
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -25,6 +25,26 @@ const css = await engine.renderAtomicStyles(true, { atomicStyleIds: ids })
|
|
|
25
25
|
|
|
26
26
|
See the [full documentation](https://pikacss.github.io/api/core).
|
|
27
27
|
|
|
28
|
+
## Diagnostics
|
|
29
|
+
|
|
30
|
+
`@pikacss/core` is platform-neutral and performs no console I/O by default. Explicitly install an instance-scoped handler when diagnostics should be surfaced:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
const engine = await createEngine(config, {
|
|
34
|
+
onDiagnostic(diagnostic) {
|
|
35
|
+
// Route to your host logger, editor UI, telemetry, or test assertions.
|
|
36
|
+
},
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Plugin lifecycle failures are reported and rethrown; warnings are delivered only through the configured handler.
|
|
41
|
+
|
|
42
|
+
Diagnostics and optional tracing are separate host-controlled channels, so configuring both does not duplicate the same runtime event.
|
|
43
|
+
|
|
44
|
+
## Optional tracing
|
|
45
|
+
|
|
46
|
+
The exported `log` and `createLogger()` APIs independently default to no-op output handlers. A host explicitly controls which debug, info, warning, and error sinks tracing uses.
|
|
47
|
+
|
|
28
48
|
## License
|
|
29
49
|
|
|
30
50
|
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -151,6 +151,46 @@ interface ResolvedKeyframesConfig {
|
|
|
151
151
|
autocomplete: string[];
|
|
152
152
|
}
|
|
153
153
|
//#endregion
|
|
154
|
+
//#region src/diagnostics.d.ts
|
|
155
|
+
/** Severity of a PikaCSS diagnostic. */
|
|
156
|
+
type DiagnosticLevel = 'warning' | 'error';
|
|
157
|
+
/**
|
|
158
|
+
* Structured diagnostic emitted by the PikaCSS engine or an engine plugin.
|
|
159
|
+
*
|
|
160
|
+
* @remarks Diagnostics are data only. The core package never assumes a console,
|
|
161
|
+
* logger, browser, or Node.js runtime. Hosts decide how diagnostics are displayed.
|
|
162
|
+
*/
|
|
163
|
+
interface Diagnostic {
|
|
164
|
+
/** Diagnostic severity. */
|
|
165
|
+
level: DiagnosticLevel;
|
|
166
|
+
/** Stable machine-readable identifier. */
|
|
167
|
+
code: string;
|
|
168
|
+
/** Human-readable explanation. */
|
|
169
|
+
message: string;
|
|
170
|
+
/** Original error or value related to the diagnostic. */
|
|
171
|
+
cause?: unknown;
|
|
172
|
+
/** Plugin that produced the diagnostic, when applicable. */
|
|
173
|
+
plugin?: string;
|
|
174
|
+
/** Plugin hook that produced the diagnostic, when applicable. */
|
|
175
|
+
hook?: string;
|
|
176
|
+
}
|
|
177
|
+
/** Callback used by a host to receive structured diagnostics. */
|
|
178
|
+
type DiagnosticHandler = (diagnostic: Diagnostic) => void;
|
|
179
|
+
/** Runtime-only options accepted by {@link createEngine}. */
|
|
180
|
+
interface CreateEngineOptions {
|
|
181
|
+
/**
|
|
182
|
+
* Receives warnings and errors produced by this engine instance.
|
|
183
|
+
*
|
|
184
|
+
* @default A no-op handler.
|
|
185
|
+
*/
|
|
186
|
+
onDiagnostic?: DiagnosticHandler;
|
|
187
|
+
}
|
|
188
|
+
/** Context passed to plugin hooks by the engine. */
|
|
189
|
+
interface EnginePluginContext {
|
|
190
|
+
/** Instance-scoped diagnostic handler. */
|
|
191
|
+
onDiagnostic: DiagnosticHandler;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
154
194
|
//#region src/resolver.d.ts
|
|
155
195
|
/**
|
|
156
196
|
* Wrapper holding a resolved value, used as the cache entry in resolver maps.
|
|
@@ -231,6 +271,7 @@ interface DynamicRule<T> {
|
|
|
231
271
|
* ```
|
|
232
272
|
*/
|
|
233
273
|
declare abstract class AbstractResolver<T> {
|
|
274
|
+
readonly onDiagnostic: DiagnosticHandler;
|
|
234
275
|
/** Cache of previously resolved input-string → result pairs. */
|
|
235
276
|
_resolvedResultsMap: Map<string, ResolvedResult<T>>;
|
|
236
277
|
/** Negative cache of input strings that matched no rule at all. Retryable-unresolved dynamic results (a matched dynamic rule whose value fn returned nullish) are never stored here. */
|
|
@@ -243,6 +284,9 @@ declare abstract class AbstractResolver<T> {
|
|
|
243
284
|
dynamicRulesMap: Map<string, DynamicRule<T>>;
|
|
244
285
|
/** Callback invoked after a successful resolution, receiving the input string, rule type, and result. */
|
|
245
286
|
onResolved: (string: string, type: 'static' | 'dynamic', result: ResolvedResult<T>) => void;
|
|
287
|
+
constructor(onDiagnostic?: DiagnosticHandler);
|
|
288
|
+
/** Reports through the host handler, falling back to the optional logger only for standalone resolvers. */
|
|
289
|
+
reportDiagnostic(diagnostic: Diagnostic): void;
|
|
246
290
|
get staticRules(): StaticRule<T>[];
|
|
247
291
|
get dynamicRules(): DynamicRule<T>[];
|
|
248
292
|
/**
|
|
@@ -1284,6 +1328,7 @@ type ExtractFn = (styleDefinition: InternalStyleDefinition) => Promise<Extracted
|
|
|
1284
1328
|
* Creates and initializes a PikaCSS engine with the given configuration.
|
|
1285
1329
|
*
|
|
1286
1330
|
* @param config - The engine configuration, including plugins, selectors, shortcuts, variables, keyframes, preflights, and layer settings.
|
|
1331
|
+
* @param options - Runtime-only host capabilities, including the instance-scoped diagnostic handler.
|
|
1287
1332
|
* @returns A fully initialized `Engine` instance.
|
|
1288
1333
|
*
|
|
1289
1334
|
* @remarks Core plugins (`important`, `variables`, `keyframes`, `selectors`, `shortcuts`) are prepended automatically. The function resolves plugins, runs all configuration hooks in sequence, and returns the ready-to-use engine.
|
|
@@ -1293,7 +1338,7 @@ type ExtractFn = (styleDefinition: InternalStyleDefinition) => Promise<Extracted
|
|
|
1293
1338
|
* const engine = await createEngine({ prefix: 'pk-', plugins: [myPlugin()] })
|
|
1294
1339
|
* ```
|
|
1295
1340
|
*/
|
|
1296
|
-
declare function createEngine(config?: EngineConfig): Promise<Engine>;
|
|
1341
|
+
declare function createEngine(config?: EngineConfig, options?: CreateEngineOptions): Promise<Engine>;
|
|
1297
1342
|
/**
|
|
1298
1343
|
* The PikaCSS engine: manages atomic style resolution, rendering, preflights, and plugin hooks.
|
|
1299
1344
|
*
|
|
@@ -1309,19 +1354,10 @@ declare function createEngine(config?: EngineConfig): Promise<Engine>;
|
|
|
1309
1354
|
declare class Engine {
|
|
1310
1355
|
/** The fully resolved engine configuration. */
|
|
1311
1356
|
config: ResolvedEngineConfig;
|
|
1312
|
-
/**
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
configureResolvedConfig: (plugins: EnginePlugin[], payload: ResolvedEngineConfig) => Promise<ResolvedEngineConfig>;
|
|
1317
|
-
configureEngine: (plugins: EnginePlugin[], payload: Engine) => Promise<Engine>;
|
|
1318
|
-
transformSelectors: (plugins: EnginePlugin[], payload: string[]) => Promise<string[]>;
|
|
1319
|
-
transformStyleItems: (plugins: EnginePlugin[], payload: StyleItem[]) => Promise<StyleItem[]>;
|
|
1320
|
-
transformStyleDefinitions: (plugins: EnginePlugin[], payload: StyleDefinition[]) => Promise<StyleDefinition[]>;
|
|
1321
|
-
preflightUpdated: (plugins: EnginePlugin[]) => void;
|
|
1322
|
-
atomicStyleAdded: (plugins: EnginePlugin[], payload: AtomicStyle) => AtomicStyle;
|
|
1323
|
-
autocompleteConfigUpdated: (plugins: EnginePlugin[]) => void;
|
|
1324
|
-
};
|
|
1357
|
+
/** Instance-scoped diagnostic handler supplied by the host. */
|
|
1358
|
+
readonly onDiagnostic: DiagnosticHandler;
|
|
1359
|
+
/** Reference to the instance-scoped plugin hook dispatcher. */
|
|
1360
|
+
pluginHooks: ReturnType<typeof createEngineHooks>;
|
|
1325
1361
|
/** The extraction function that decomposes style definitions into atomic style contents. */
|
|
1326
1362
|
extract: ExtractFn;
|
|
1327
1363
|
/** The engine's runtime store holding registered atomic styles and their ID mappings. */
|
|
@@ -1344,7 +1380,13 @@ declare class Engine {
|
|
|
1344
1380
|
* const engine = new Engine(resolvedConfig)
|
|
1345
1381
|
* ```
|
|
1346
1382
|
*/
|
|
1347
|
-
constructor(config: ResolvedEngineConfig);
|
|
1383
|
+
constructor(config: ResolvedEngineConfig, onDiagnostic?: DiagnosticHandler, pluginHooks?: ReturnType<typeof createEngineHooks>);
|
|
1384
|
+
/**
|
|
1385
|
+
* Reports a structured diagnostic to this engine instance's host handler.
|
|
1386
|
+
*
|
|
1387
|
+
* @param diagnostic - The structured warning or error to deliver.
|
|
1388
|
+
*/
|
|
1389
|
+
reportDiagnostic(diagnostic: Diagnostic): void;
|
|
1348
1390
|
/**
|
|
1349
1391
|
* Invokes a preflight function, memoizing the result in the given render-pass context.
|
|
1350
1392
|
*
|
|
@@ -1549,45 +1591,28 @@ type EngineHooksDefinition = DefineHooks<{
|
|
|
1549
1591
|
autocompleteConfigUpdated: ['sync', void];
|
|
1550
1592
|
}>;
|
|
1551
1593
|
type HookParams<H extends [type: 'sync' | 'async', payload: any, returnValue?: any]> = H[1] extends void ? [] : [payload: H[1]];
|
|
1552
|
-
type
|
|
1594
|
+
type PluginHookParams<H extends [type: 'sync' | 'async', payload: any, returnValue?: any]> = H[1] extends void ? [context?: EnginePluginContext] : [payload: H[1], context?: EnginePluginContext];
|
|
1595
|
+
type HookReturnType<H extends [type: 'sync' | 'async', payload: any, returnValue?: any]> = H extends [any, any, infer R] ? H[0] extends 'async' ? Promise<R> : R : H[0] extends 'async' ? Promise<H[1]> : H[1];
|
|
1596
|
+
type EngineHooks = { [K in keyof EngineHooksDefinition]: (plugins: EnginePlugin[], ...params: HookParams<EngineHooksDefinition[K]>) => HookReturnType<EngineHooksDefinition[K]> };
|
|
1553
1597
|
/**
|
|
1554
|
-
*
|
|
1555
|
-
*
|
|
1556
|
-
* @remarks Plugins implement optional hook methods corresponding to engine lifecycle events. Hooks run in plugin registration order, optionally reordered by the `order` property.
|
|
1598
|
+
* Creates an engine-local hook dispatcher bound to one diagnostic context.
|
|
1557
1599
|
*
|
|
1558
|
-
* @
|
|
1559
|
-
* ```ts
|
|
1560
|
-
* const myPlugin: EnginePlugin = {
|
|
1561
|
-
* name: 'my-plugin',
|
|
1562
|
-
* configureRawConfig: (config) => ({ ...config, important: { default: true } }),
|
|
1563
|
-
* }
|
|
1564
|
-
* ```
|
|
1600
|
+
* @internal
|
|
1565
1601
|
*/
|
|
1602
|
+
declare function createEngineHooks(context: EnginePluginContext): EngineHooks;
|
|
1603
|
+
type EnginePluginHooksOptions = { [K in keyof EngineHooksDefinition]?: EngineHooksDefinition[K][0] extends 'async' ? (...params: PluginHookParams<EngineHooksDefinition[K]>) => Awaitable<EngineHooksDefinition[K][1] | void> : (...params: PluginHookParams<EngineHooksDefinition[K]>) => EngineHooksDefinition[K][1] | void };
|
|
1604
|
+
/** Describes an engine plugin that can hook into the PikaCSS engine lifecycle. */
|
|
1566
1605
|
interface EnginePlugin extends EnginePluginHooksOptions {
|
|
1567
|
-
/** The unique human-readable name identifying this plugin in
|
|
1606
|
+
/** The unique human-readable name identifying this plugin in diagnostics. */
|
|
1568
1607
|
name: string;
|
|
1569
|
-
/**
|
|
1570
|
-
* Controls plugin execution order relative to other plugins.
|
|
1571
|
-
*
|
|
1572
|
-
* @default undefined (normal order)
|
|
1573
|
-
*/
|
|
1608
|
+
/** Controls execution order relative to other plugins. */
|
|
1574
1609
|
order?: 'pre' | 'post';
|
|
1575
1610
|
}
|
|
1576
1611
|
/**
|
|
1577
|
-
* Identity helper that
|
|
1578
|
-
*
|
|
1579
|
-
* @param plugin - The engine plugin definition.
|
|
1580
|
-
* @returns The same plugin object, unchanged.
|
|
1612
|
+
* Identity helper that provides type inference for an engine plugin definition.
|
|
1581
1613
|
*
|
|
1582
|
-
* @
|
|
1583
|
-
*
|
|
1584
|
-
* @example
|
|
1585
|
-
* ```ts
|
|
1586
|
-
* export default defineEnginePlugin({
|
|
1587
|
-
* name: 'my-plugin',
|
|
1588
|
-
* configureRawConfig: (config) => ({ ...config, important: { default: true } }),
|
|
1589
|
-
* })
|
|
1590
|
-
* ```
|
|
1614
|
+
* @param plugin - The plugin definition to return unchanged.
|
|
1615
|
+
* @returns The same plugin instance.
|
|
1591
1616
|
*/
|
|
1592
1617
|
declare function defineEnginePlugin(plugin: EnginePlugin): EnginePlugin;
|
|
1593
1618
|
//#endregion
|
|
@@ -37336,7 +37361,7 @@ interface ResolvedEngineConfig {
|
|
|
37336
37361
|
* @param prefix - Label prepended to every log message (e.g. `'[PikaCSS]'`).
|
|
37337
37362
|
* @returns A logger object with `debug`, `info`, `warn`, `error` methods and configuration setters.
|
|
37338
37363
|
*
|
|
37339
|
-
* @remarks
|
|
37364
|
+
* @remarks All output handlers are no-ops by default, and debug messages are additionally disabled. Hosts may install output functions through the `set*Fn` methods; engine warnings and errors are reported through `createEngine(..., { onDiagnostic })` instead.
|
|
37340
37365
|
*
|
|
37341
37366
|
* @example
|
|
37342
37367
|
* ```ts
|
|
@@ -37469,4 +37494,4 @@ declare function renderCSSStyleBlocks(blocks: CSSStyleBlocks, isFormatted: boole
|
|
|
37469
37494
|
*/
|
|
37470
37495
|
declare function defineEngineConfig<const T extends EngineConfig>(config: T): T;
|
|
37471
37496
|
//#endregion
|
|
37472
|
-
export { Arrayable, type AutocompleteConfig, type AutocompleteContribution, type AutocompletePatternsConfig, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type DefineAutocomplete, type Engine, type EngineConfig, type EnginePlugin, FromKebab, GetValue, ImportantConfig, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Preflight, type PreflightDefinition, type PreflightFn, type Properties, type PropertyValue, ResolveFrom, type ResolvedLayerName, type ResolvedPreflight, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleDefinitionMap, type StyleItem, ToKebab, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, appendAutocomplete, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, escapeRegExp, extractUsedVarNames, extractUsedVarNamesFromPreflightResult, important, isPlainObjectRecord, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, sortLayerNames, variables };
|
|
37497
|
+
export { Arrayable, type AutocompleteConfig, type AutocompleteContribution, type AutocompletePatternsConfig, Awaitable, type CSSProperty, type CSSSelector, type CSSStyleBlockBody, type CSSStyleBlocks, type CreateEngineOptions, type DefineAutocomplete, type Diagnostic, type DiagnosticHandler, type DiagnosticLevel, type Engine, type EngineConfig, type EnginePlugin, type EnginePluginContext, FromKebab, GetValue, ImportantConfig, IsEqual, IsNever, Keyframes, KeyframesConfig, KeyframesProgress, Nullish, type PikaAugment, type Preflight, type PreflightDefinition, type PreflightFn, type Properties, type PropertyValue, ResolveFrom, type ResolvedLayerName, type ResolvedPreflight, Selector, SelectorsConfig, Shortcut, ShortcutsConfig, Simplify, type StyleDefinition, type StyleDefinitionMap, type StyleItem, ToKebab, UnionString, UnionToIntersection, Variable, VariableAutocomplete, VariableObject, VariablesConfig, VariablesDefinition, appendAutocomplete, createEngine, createLogger, defineEngineConfig, defineEnginePlugin, escapeRegExp, extractUsedVarNames, extractUsedVarNamesFromPreflightResult, important, isPlainObjectRecord, keyframes, log, normalizeVariableName, renderCSSStyleBlocks, resolveSelectorConfig, selectors$1 as selectors, shortcuts, sortLayerNames, variables };
|
package/dist/index.mjs
CHANGED
|
@@ -1231,7 +1231,7 @@ function hasPropertyEffectOverlap(left, right) {
|
|
|
1231
1231
|
* @param prefix - Label prepended to every log message (e.g. `'[PikaCSS]'`).
|
|
1232
1232
|
* @returns A logger object with `debug`, `info`, `warn`, `error` methods and configuration setters.
|
|
1233
1233
|
*
|
|
1234
|
-
* @remarks
|
|
1234
|
+
* @remarks All output handlers are no-ops by default, and debug messages are additionally disabled. Hosts may install output functions through the `set*Fn` methods; engine warnings and errors are reported through `createEngine(..., { onDiagnostic })` instead.
|
|
1235
1235
|
*
|
|
1236
1236
|
* @example
|
|
1237
1237
|
* ```ts
|
|
@@ -1244,10 +1244,11 @@ function hasPropertyEffectOverlap(left, right) {
|
|
|
1244
1244
|
function createLogger(prefix) {
|
|
1245
1245
|
let currentPrefix = prefix;
|
|
1246
1246
|
let enabledDebug = false;
|
|
1247
|
-
|
|
1248
|
-
let
|
|
1249
|
-
let
|
|
1250
|
-
let
|
|
1247
|
+
const noop = (_prefix, ..._args) => {};
|
|
1248
|
+
let _debug = noop;
|
|
1249
|
+
let _info = noop;
|
|
1250
|
+
let _warn = noop;
|
|
1251
|
+
let _error = noop;
|
|
1251
1252
|
return {
|
|
1252
1253
|
debug: (...args) => {
|
|
1253
1254
|
if (!enabledDebug) return;
|
|
@@ -1927,6 +1928,20 @@ function replaceAtomicStyleIdPlaceholder(selector, atomicStyleId) {
|
|
|
1927
1928
|
return transformOutsideQuotes(selector, (segment) => segment.replace(ATOMIC_STYLE_ID_PLACEHOLDER_RE_GLOBAL, () => atomicStyleId));
|
|
1928
1929
|
}
|
|
1929
1930
|
//#endregion
|
|
1931
|
+
//#region src/diagnostics.ts
|
|
1932
|
+
/** Default diagnostic handler used by the platform-neutral core. */
|
|
1933
|
+
const noopDiagnosticHandler = (_diagnostic) => {};
|
|
1934
|
+
/**
|
|
1935
|
+
* Delivers a diagnostic without allowing a faulty host handler to alter engine execution.
|
|
1936
|
+
*
|
|
1937
|
+
* @internal
|
|
1938
|
+
*/
|
|
1939
|
+
function emitDiagnostic(handler, diagnostic) {
|
|
1940
|
+
try {
|
|
1941
|
+
handler(diagnostic);
|
|
1942
|
+
} catch {}
|
|
1943
|
+
}
|
|
1944
|
+
//#endregion
|
|
1930
1945
|
//#region src/extractor.ts
|
|
1931
1946
|
function replaceBySplitAndJoin(str, split, mapFn, join) {
|
|
1932
1947
|
let splitted = str.split(split);
|
|
@@ -2092,10 +2107,15 @@ function createExtractFn(options) {
|
|
|
2092
2107
|
}
|
|
2093
2108
|
//#endregion
|
|
2094
2109
|
//#region src/plugin.ts
|
|
2110
|
+
const VOID_HOOKS = new Set(["preflightUpdated", "autocompleteConfigUpdated"]);
|
|
2111
|
+
const DEFAULT_PLUGIN_CONTEXT = { onDiagnostic: noopDiagnosticHandler };
|
|
2095
2112
|
function getPluginHook(plugin, hook) {
|
|
2096
2113
|
const hookFn = plugin[hook];
|
|
2097
2114
|
return typeof hookFn === "function" ? hookFn : null;
|
|
2098
2115
|
}
|
|
2116
|
+
function invokePluginHook(hookFn, hook, payload, context) {
|
|
2117
|
+
return VOID_HOOKS.has(hook) ? hookFn(context) : hookFn(payload, context);
|
|
2118
|
+
}
|
|
2099
2119
|
function applyHookPayload(current, next) {
|
|
2100
2120
|
return next ?? current;
|
|
2101
2121
|
}
|
|
@@ -2111,27 +2131,29 @@ function logPluginHookStart(plugin, hook) {
|
|
|
2111
2131
|
function logPluginHookEnd(plugin, hook) {
|
|
2112
2132
|
log.debug(` - Plugin "${plugin.name}" completed ${hook}`);
|
|
2113
2133
|
}
|
|
2114
|
-
function
|
|
2115
|
-
|
|
2134
|
+
function reportPluginHookError(context, plugin, hook, error) {
|
|
2135
|
+
const message = `Plugin "${plugin.name}" failed to execute hook "${hook}": ${error instanceof Error ? error.message : String(error)}`;
|
|
2136
|
+
if (context.onDiagnostic === noopDiagnosticHandler) {
|
|
2137
|
+
log.error(message, error);
|
|
2138
|
+
return;
|
|
2139
|
+
}
|
|
2140
|
+
emitDiagnostic(context.onDiagnostic, {
|
|
2141
|
+
level: "error",
|
|
2142
|
+
code: "plugin-hook-error",
|
|
2143
|
+
message,
|
|
2144
|
+
cause: error,
|
|
2145
|
+
plugin: plugin.name,
|
|
2146
|
+
hook
|
|
2147
|
+
});
|
|
2116
2148
|
}
|
|
2117
2149
|
/**
|
|
2118
|
-
* Executes an async hook across all plugins in order, piping the payload through each
|
|
2119
|
-
* @internal
|
|
2120
|
-
*
|
|
2121
|
-
* @typeParam P - The payload/return type flowing through the hook pipeline.
|
|
2122
|
-
* @param plugins - The ordered list of engine plugins to execute.
|
|
2123
|
-
* @param hook - The name of the async hook to invoke.
|
|
2124
|
-
* @param payload - The initial payload to pass into the first plugin.
|
|
2125
|
-
* @returns The final payload after all plugins have processed it.
|
|
2150
|
+
* Executes an async hook across all plugins in order, piping the payload through each handler.
|
|
2126
2151
|
*
|
|
2127
|
-
* @
|
|
2128
|
-
*
|
|
2129
|
-
*
|
|
2130
|
-
* ```ts
|
|
2131
|
-
* const config = await execAsyncHook(plugins, 'configureRawConfig', rawConfig)
|
|
2132
|
-
* ```
|
|
2152
|
+
* @internal
|
|
2153
|
+
* @remarks A thrown plugin error is reported through the supplied diagnostic context and then
|
|
2154
|
+
* rethrown. The engine never converts a failed lifecycle into a silently partial result.
|
|
2133
2155
|
*/
|
|
2134
|
-
async function execAsyncHook(plugins, hook, payload) {
|
|
2156
|
+
async function execAsyncHook(plugins, hook, payload, context = DEFAULT_PLUGIN_CONTEXT) {
|
|
2135
2157
|
logHookStart("Async", hook);
|
|
2136
2158
|
let current = payload;
|
|
2137
2159
|
for (const plugin of plugins) {
|
|
@@ -2139,33 +2161,24 @@ async function execAsyncHook(plugins, hook, payload) {
|
|
|
2139
2161
|
if (hookFn == null) continue;
|
|
2140
2162
|
try {
|
|
2141
2163
|
logPluginHookStart(plugin, hook);
|
|
2142
|
-
current = applyHookPayload(current, await hookFn
|
|
2164
|
+
current = applyHookPayload(current, await invokePluginHook(hookFn, hook, current, context));
|
|
2143
2165
|
logPluginHookEnd(plugin, hook);
|
|
2144
2166
|
} catch (error) {
|
|
2145
|
-
|
|
2167
|
+
reportPluginHookError(context, plugin, hook, error);
|
|
2168
|
+
throw error;
|
|
2146
2169
|
}
|
|
2147
2170
|
}
|
|
2148
2171
|
logHookEnd("Async", hook);
|
|
2149
2172
|
return current;
|
|
2150
2173
|
}
|
|
2151
2174
|
/**
|
|
2152
|
-
* Executes a synchronous hook across all plugins in order, piping the payload through each
|
|
2153
|
-
* @internal
|
|
2175
|
+
* Executes a synchronous hook across all plugins in order, piping the payload through each handler.
|
|
2154
2176
|
*
|
|
2155
|
-
* @
|
|
2156
|
-
* @
|
|
2157
|
-
*
|
|
2158
|
-
* @param payload - The initial payload to pass into the first plugin.
|
|
2159
|
-
* @returns The final payload after all plugins have processed it.
|
|
2160
|
-
*
|
|
2161
|
-
* @remarks Functions identically to `execAsyncHook` but without awaiting. Used for notification-style hooks like `preflightUpdated` or `atomicStyleAdded`.
|
|
2162
|
-
*
|
|
2163
|
-
* @example
|
|
2164
|
-
* ```ts
|
|
2165
|
-
* execSyncHook(plugins, 'atomicStyleAdded', atomicStyle)
|
|
2166
|
-
* ```
|
|
2177
|
+
* @internal
|
|
2178
|
+
* @remarks A thrown plugin error is reported through the supplied diagnostic context and then
|
|
2179
|
+
* rethrown. Notification hooks therefore cannot fail silently.
|
|
2167
2180
|
*/
|
|
2168
|
-
function execSyncHook(plugins, hook, payload) {
|
|
2181
|
+
function execSyncHook(plugins, hook, payload, context = DEFAULT_PLUGIN_CONTEXT) {
|
|
2169
2182
|
logHookStart("Sync", hook);
|
|
2170
2183
|
let current = payload;
|
|
2171
2184
|
for (const plugin of plugins) {
|
|
@@ -2173,78 +2186,55 @@ function execSyncHook(plugins, hook, payload) {
|
|
|
2173
2186
|
if (hookFn == null) continue;
|
|
2174
2187
|
try {
|
|
2175
2188
|
logPluginHookStart(plugin, hook);
|
|
2176
|
-
current = applyHookPayload(current, hookFn
|
|
2189
|
+
current = applyHookPayload(current, invokePluginHook(hookFn, hook, current, context));
|
|
2177
2190
|
logPluginHookEnd(plugin, hook);
|
|
2178
2191
|
} catch (error) {
|
|
2179
|
-
|
|
2192
|
+
reportPluginHookError(context, plugin, hook, error);
|
|
2193
|
+
throw error;
|
|
2180
2194
|
}
|
|
2181
2195
|
}
|
|
2182
2196
|
logHookEnd("Sync", hook);
|
|
2183
2197
|
return current;
|
|
2184
2198
|
}
|
|
2185
2199
|
/**
|
|
2186
|
-
*
|
|
2187
|
-
* @internal
|
|
2188
|
-
*
|
|
2189
|
-
* @remarks Provides a convenient, type-safe interface for calling any engine hook by name without manually selecting between `execAsyncHook` and `execSyncHook`. Used throughout the `Engine` class.
|
|
2200
|
+
* Creates an engine-local hook dispatcher bound to one diagnostic context.
|
|
2190
2201
|
*
|
|
2191
|
-
* @
|
|
2192
|
-
* ```ts
|
|
2193
|
-
* const config = await hooks.configureRawConfig(plugins, rawConfig)
|
|
2194
|
-
* hooks.preflightUpdated(plugins)
|
|
2195
|
-
* ```
|
|
2202
|
+
* @internal
|
|
2196
2203
|
*/
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2204
|
+
function createEngineHooks(context) {
|
|
2205
|
+
return {
|
|
2206
|
+
configureRawConfig: (plugins, config) => execAsyncHook(plugins, "configureRawConfig", config, context),
|
|
2207
|
+
rawConfigConfigured: (plugins, config) => execSyncHook(plugins, "rawConfigConfigured", config, context),
|
|
2208
|
+
configureResolvedConfig: (plugins, resolvedConfig) => execAsyncHook(plugins, "configureResolvedConfig", resolvedConfig, context),
|
|
2209
|
+
configureEngine: (plugins, engine) => execAsyncHook(plugins, "configureEngine", engine, context),
|
|
2210
|
+
transformSelectors: (plugins, selectors) => execAsyncHook(plugins, "transformSelectors", selectors, context),
|
|
2211
|
+
transformStyleItems: (plugins, styleItems) => execAsyncHook(plugins, "transformStyleItems", styleItems, context),
|
|
2212
|
+
transformStyleDefinitions: (plugins, styleDefinitions) => execAsyncHook(plugins, "transformStyleDefinitions", styleDefinitions, context),
|
|
2213
|
+
preflightUpdated: (plugins) => execSyncHook(plugins, "preflightUpdated", void 0, context),
|
|
2214
|
+
atomicStyleAdded: (plugins, atomicStyle) => execSyncHook(plugins, "atomicStyleAdded", atomicStyle, context),
|
|
2215
|
+
autocompleteConfigUpdated: (plugins) => execSyncHook(plugins, "autocompleteConfigUpdated", void 0, context)
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
createEngineHooks(DEFAULT_PLUGIN_CONTEXT);
|
|
2209
2219
|
const orderMap = new Map([
|
|
2210
2220
|
[void 0, 1],
|
|
2211
2221
|
["pre", 0],
|
|
2212
2222
|
["post", 2]
|
|
2213
2223
|
]);
|
|
2214
2224
|
/**
|
|
2215
|
-
* Sorts
|
|
2216
|
-
* @internal
|
|
2217
|
-
*
|
|
2218
|
-
* @param plugins - The unordered array of engine plugins.
|
|
2219
|
-
* @returns A new array sorted by execution order.
|
|
2220
|
-
*
|
|
2221
|
-
* @remarks The original array is not mutated. Plugins with the same order retain their relative insertion order (stable sort).
|
|
2225
|
+
* Sorts plugins by `pre`, default, then `post` order without mutating the input.
|
|
2222
2226
|
*
|
|
2223
|
-
* @
|
|
2224
|
-
* ```ts
|
|
2225
|
-
* const ordered = resolvePlugins([postPlugin, prePlugin, normalPlugin])
|
|
2226
|
-
* // [prePlugin, normalPlugin, postPlugin]
|
|
2227
|
-
* ```
|
|
2227
|
+
* @internal
|
|
2228
2228
|
*/
|
|
2229
2229
|
function resolvePlugins(plugins) {
|
|
2230
2230
|
return [...plugins].sort((a, b) => orderMap.get(a.order) - orderMap.get(b.order));
|
|
2231
2231
|
}
|
|
2232
2232
|
/* c8 ignore start */
|
|
2233
2233
|
/**
|
|
2234
|
-
* Identity helper that
|
|
2235
|
-
*
|
|
2236
|
-
* @param plugin - The engine plugin definition.
|
|
2237
|
-
* @returns The same plugin object, unchanged.
|
|
2238
|
-
*
|
|
2239
|
-
* @remarks This is a compile-time-only helper; it has no runtime effect. Using it ensures type checking and IDE autocompletion for hook names and payloads.
|
|
2234
|
+
* Identity helper that provides type inference for an engine plugin definition.
|
|
2240
2235
|
*
|
|
2241
|
-
* @
|
|
2242
|
-
*
|
|
2243
|
-
* export default defineEnginePlugin({
|
|
2244
|
-
* name: 'my-plugin',
|
|
2245
|
-
* configureRawConfig: (config) => ({ ...config, important: { default: true } }),
|
|
2246
|
-
* })
|
|
2247
|
-
* ```
|
|
2236
|
+
* @param plugin - The plugin definition to return unchanged.
|
|
2237
|
+
* @returns The same plugin instance.
|
|
2248
2238
|
*/
|
|
2249
2239
|
function defineEnginePlugin(plugin) {
|
|
2250
2240
|
return plugin;
|
|
@@ -2436,6 +2426,19 @@ var AbstractResolver = class {
|
|
|
2436
2426
|
dynamicRulesMap = /* @__PURE__ */ new Map();
|
|
2437
2427
|
/** Callback invoked after a successful resolution, receiving the input string, rule type, and result. */
|
|
2438
2428
|
onResolved = () => {};
|
|
2429
|
+
constructor(onDiagnostic = noopDiagnosticHandler) {
|
|
2430
|
+
this.onDiagnostic = onDiagnostic;
|
|
2431
|
+
}
|
|
2432
|
+
/** Reports through the host handler, falling back to the optional logger only for standalone resolvers. */
|
|
2433
|
+
reportDiagnostic(diagnostic) {
|
|
2434
|
+
if (this.onDiagnostic === noopDiagnosticHandler) {
|
|
2435
|
+
const args = diagnostic.cause == null ? [] : [diagnostic.cause];
|
|
2436
|
+
if (diagnostic.level === "error") log.error(diagnostic.message, ...args);
|
|
2437
|
+
else log.warn(diagnostic.message, ...args);
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
emitDiagnostic(this.onDiagnostic, diagnostic);
|
|
2441
|
+
}
|
|
2439
2442
|
get staticRules() {
|
|
2440
2443
|
return [...this.staticRulesMap.values()];
|
|
2441
2444
|
}
|
|
@@ -2483,7 +2486,12 @@ var AbstractResolver = class {
|
|
|
2483
2486
|
removeStaticRule(key) {
|
|
2484
2487
|
const rule = this.staticRulesMap.get(key);
|
|
2485
2488
|
if (rule == null) {
|
|
2486
|
-
|
|
2489
|
+
const message = `Static rule not found for removal: ${key}`;
|
|
2490
|
+
this.reportDiagnostic({
|
|
2491
|
+
level: "warning",
|
|
2492
|
+
code: "resolver-static-rule-not-found",
|
|
2493
|
+
message
|
|
2494
|
+
});
|
|
2487
2495
|
return this;
|
|
2488
2496
|
}
|
|
2489
2497
|
log.debug(`Removing static rule: ${key}`);
|
|
@@ -2542,7 +2550,12 @@ var AbstractResolver = class {
|
|
|
2542
2550
|
*/
|
|
2543
2551
|
removeDynamicRule(key) {
|
|
2544
2552
|
if (this.dynamicRulesMap.get(key) == null) {
|
|
2545
|
-
|
|
2553
|
+
const message = `Dynamic rule not found for removal: ${key}`;
|
|
2554
|
+
this.reportDiagnostic({
|
|
2555
|
+
level: "warning",
|
|
2556
|
+
code: "resolver-dynamic-rule-not-found",
|
|
2557
|
+
message
|
|
2558
|
+
});
|
|
2546
2559
|
return this;
|
|
2547
2560
|
}
|
|
2548
2561
|
log.debug(`Removing dynamic rule: ${key}`);
|
|
@@ -2663,12 +2676,25 @@ var RecursiveResolver = class extends AbstractResolver {
|
|
|
2663
2676
|
async resolve(string, _visited) {
|
|
2664
2677
|
const visited = _visited ?? /* @__PURE__ */ new Set();
|
|
2665
2678
|
if (visited.has(string)) {
|
|
2666
|
-
|
|
2679
|
+
const message = `Circular reference detected for "${string}", returning as-is`;
|
|
2680
|
+
this.reportDiagnostic({
|
|
2681
|
+
level: "warning",
|
|
2682
|
+
code: "resolver-circular-reference",
|
|
2683
|
+
message
|
|
2684
|
+
});
|
|
2685
|
+
log.warn(message);
|
|
2667
2686
|
return [string];
|
|
2668
2687
|
}
|
|
2669
2688
|
visited.add(string);
|
|
2670
2689
|
const resolved = await this._resolve(string).catch((error) => {
|
|
2671
|
-
|
|
2690
|
+
const message = `Failed to resolve "${string}": ${error instanceof Error ? error.message : String(error)}`;
|
|
2691
|
+
this.reportDiagnostic({
|
|
2692
|
+
level: "warning",
|
|
2693
|
+
code: "resolver-resolution-error",
|
|
2694
|
+
message,
|
|
2695
|
+
cause: error
|
|
2696
|
+
});
|
|
2697
|
+
log.warn(message, error);
|
|
2672
2698
|
});
|
|
2673
2699
|
if (resolved == null) return [string];
|
|
2674
2700
|
const result = [];
|
|
@@ -2763,7 +2789,7 @@ function selectors() {
|
|
|
2763
2789
|
configureEngine(_engine) {
|
|
2764
2790
|
engine = _engine;
|
|
2765
2791
|
engine.selectors = {
|
|
2766
|
-
resolver: new SelectorResolver(),
|
|
2792
|
+
resolver: new SelectorResolver(engine.onDiagnostic),
|
|
2767
2793
|
add: (...list) => {
|
|
2768
2794
|
list.forEach((config) => {
|
|
2769
2795
|
const resolved = resolveSelectorConfig(config);
|
|
@@ -2832,7 +2858,7 @@ function shortcuts() {
|
|
|
2832
2858
|
configureEngine(_engine) {
|
|
2833
2859
|
engine = _engine;
|
|
2834
2860
|
engine.shortcuts = {
|
|
2835
|
-
resolver: new ShortcutResolver(),
|
|
2861
|
+
resolver: new ShortcutResolver(engine.onDiagnostic),
|
|
2836
2862
|
add: (...list) => {
|
|
2837
2863
|
list.forEach((config) => {
|
|
2838
2864
|
const resolved = resolveShortcutConfig(config);
|
|
@@ -2911,8 +2937,11 @@ function variables() {
|
|
|
2911
2937
|
let safeSet;
|
|
2912
2938
|
return defineEnginePlugin({
|
|
2913
2939
|
name: "core:variables",
|
|
2914
|
-
rawConfigConfigured(config) {
|
|
2915
|
-
resolveVariables = createResolveVariablesFn({
|
|
2940
|
+
rawConfigConfigured(config, context) {
|
|
2941
|
+
resolveVariables = createResolveVariablesFn({
|
|
2942
|
+
pruneUnused: config.variables?.pruneUnused,
|
|
2943
|
+
onDiagnostic: context?.onDiagnostic
|
|
2944
|
+
});
|
|
2916
2945
|
rawVariables = normalizeVariablesConfig(config.variables);
|
|
2917
2946
|
safeSet = new Set(config.variables?.safeList ?? []);
|
|
2918
2947
|
},
|
|
@@ -3001,7 +3030,7 @@ function mergeVariablesDefinition(target, source) {
|
|
|
3001
3030
|
}
|
|
3002
3031
|
return target;
|
|
3003
3032
|
}
|
|
3004
|
-
function createResolveVariablesFn({ pruneUnused: defaultPruneUnused = true } = {}) {
|
|
3033
|
+
function createResolveVariablesFn({ pruneUnused: defaultPruneUnused = true, onDiagnostic = noopDiagnosticHandler } = {}) {
|
|
3005
3034
|
function _resolveVariables(variables, levels, result) {
|
|
3006
3035
|
for (const [key, value] of Object.entries(variables)) if (key.startsWith("--")) {
|
|
3007
3036
|
const { value: varValue, autocomplete = {}, pruneUnused = defaultPruneUnused } = isPlainObjectRecord(value) ? value : { value };
|
|
@@ -3017,7 +3046,13 @@ function createResolveVariablesFn({ pruneUnused: defaultPruneUnused = true } = {
|
|
|
3017
3046
|
});
|
|
3018
3047
|
} else {
|
|
3019
3048
|
if (!isPlainObjectRecord(value)) {
|
|
3020
|
-
|
|
3049
|
+
const message = `Invalid variables scope for selector "${key}". Expected a nested object, received ${typeof value}. Skipping.`;
|
|
3050
|
+
if (onDiagnostic === noopDiagnosticHandler) log.warn(message);
|
|
3051
|
+
else emitDiagnostic(onDiagnostic, {
|
|
3052
|
+
level: "warning",
|
|
3053
|
+
code: "variables-invalid-scope",
|
|
3054
|
+
message
|
|
3055
|
+
});
|
|
3021
3056
|
continue;
|
|
3022
3057
|
}
|
|
3023
3058
|
_resolveVariables(value, [...levels, key], result);
|
|
@@ -3147,6 +3182,7 @@ const DEFAULT_LAYERS = {
|
|
|
3147
3182
|
* Creates and initializes a PikaCSS engine with the given configuration.
|
|
3148
3183
|
*
|
|
3149
3184
|
* @param config - The engine configuration, including plugins, selectors, shortcuts, variables, keyframes, preflights, and layer settings.
|
|
3185
|
+
* @param options - Runtime-only host capabilities, including the instance-scoped diagnostic handler.
|
|
3150
3186
|
* @returns A fully initialized `Engine` instance.
|
|
3151
3187
|
*
|
|
3152
3188
|
* @remarks Core plugins (`important`, `variables`, `keyframes`, `selectors`, `shortcuts`) are prepended automatically. The function resolves plugins, runs all configuration hooks in sequence, and returns the ready-to-use engine.
|
|
@@ -3156,7 +3192,10 @@ const DEFAULT_LAYERS = {
|
|
|
3156
3192
|
* const engine = await createEngine({ prefix: 'pk-', plugins: [myPlugin()] })
|
|
3157
3193
|
* ```
|
|
3158
3194
|
*/
|
|
3159
|
-
async function createEngine(config = {}) {
|
|
3195
|
+
async function createEngine(config = {}, options = {}) {
|
|
3196
|
+
const hostOnDiagnostic = options.onDiagnostic ?? noopDiagnosticHandler;
|
|
3197
|
+
const onDiagnostic = (diagnostic) => emitDiagnostic(hostOnDiagnostic, diagnostic);
|
|
3198
|
+
const pluginHooks = createEngineHooks({ onDiagnostic });
|
|
3160
3199
|
log.debug("Creating engine with config:", config);
|
|
3161
3200
|
const corePlugins = [
|
|
3162
3201
|
variables(),
|
|
@@ -3172,18 +3211,18 @@ async function createEngine(config = {}) {
|
|
|
3172
3211
|
plugins
|
|
3173
3212
|
};
|
|
3174
3213
|
log.debug(`Total plugins resolved: ${plugins.length}`);
|
|
3175
|
-
config = await
|
|
3176
|
-
|
|
3214
|
+
config = await pluginHooks.configureRawConfig(config.plugins, config);
|
|
3215
|
+
pluginHooks.rawConfigConfigured(resolvePlugins(config.plugins), config);
|
|
3177
3216
|
let resolvedConfig = await resolveEngineConfig(config);
|
|
3178
3217
|
log.debug("Engine config resolved with prefix:", resolvedConfig.prefix);
|
|
3179
|
-
resolvedConfig = await
|
|
3180
|
-
let engine = new Engine(resolvedConfig);
|
|
3218
|
+
resolvedConfig = await pluginHooks.configureResolvedConfig(resolvedConfig.plugins, resolvedConfig);
|
|
3219
|
+
let engine = new Engine(resolvedConfig, hostOnDiagnostic, pluginHooks);
|
|
3181
3220
|
engine.appendAutocomplete({
|
|
3182
3221
|
extraProperties: "__layer",
|
|
3183
3222
|
properties: { __layer: "Autocomplete['Layer']" }
|
|
3184
3223
|
});
|
|
3185
3224
|
log.debug("Engine instance created");
|
|
3186
|
-
engine = await
|
|
3225
|
+
engine = await pluginHooks.configureEngine(engine.config.plugins, engine);
|
|
3187
3226
|
log.debug("Engine initialized successfully");
|
|
3188
3227
|
return engine;
|
|
3189
3228
|
}
|
|
@@ -3202,8 +3241,10 @@ async function createEngine(config = {}) {
|
|
|
3202
3241
|
var Engine = class {
|
|
3203
3242
|
/** The fully resolved engine configuration. */
|
|
3204
3243
|
config;
|
|
3205
|
-
/**
|
|
3206
|
-
|
|
3244
|
+
/** Instance-scoped diagnostic handler supplied by the host. */
|
|
3245
|
+
onDiagnostic;
|
|
3246
|
+
/** Reference to the instance-scoped plugin hook dispatcher. */
|
|
3247
|
+
pluginHooks;
|
|
3207
3248
|
/** The extraction function that decomposes style definitions into atomic style contents. */
|
|
3208
3249
|
extract;
|
|
3209
3250
|
/** The engine's runtime store holding registered atomic styles and their ID mappings. */
|
|
@@ -3226,16 +3267,27 @@ var Engine = class {
|
|
|
3226
3267
|
* const engine = new Engine(resolvedConfig)
|
|
3227
3268
|
* ```
|
|
3228
3269
|
*/
|
|
3229
|
-
constructor(config) {
|
|
3270
|
+
constructor(config, onDiagnostic = noopDiagnosticHandler, pluginHooks) {
|
|
3271
|
+
const safeOnDiagnostic = (diagnostic) => emitDiagnostic(onDiagnostic, diagnostic);
|
|
3230
3272
|
this.config = config;
|
|
3273
|
+
this.onDiagnostic = safeOnDiagnostic;
|
|
3274
|
+
this.pluginHooks = pluginHooks ?? createEngineHooks({ onDiagnostic: safeOnDiagnostic });
|
|
3231
3275
|
this.extract = createExtractFn({
|
|
3232
3276
|
defaultSelector: this.config.defaultSelector,
|
|
3233
|
-
transformSelectors: (selectors) =>
|
|
3234
|
-
transformStyleItems: (styleItems) =>
|
|
3235
|
-
transformStyleDefinitions: (styleDefinitions) =>
|
|
3277
|
+
transformSelectors: (selectors) => this.pluginHooks.transformSelectors(this.config.plugins, selectors),
|
|
3278
|
+
transformStyleItems: (styleItems) => this.pluginHooks.transformStyleItems(this.config.plugins, styleItems),
|
|
3279
|
+
transformStyleDefinitions: (styleDefinitions) => this.pluginHooks.transformStyleDefinitions(this.config.plugins, styleDefinitions)
|
|
3236
3280
|
});
|
|
3237
3281
|
}
|
|
3238
3282
|
/**
|
|
3283
|
+
* Reports a structured diagnostic to this engine instance's host handler.
|
|
3284
|
+
*
|
|
3285
|
+
* @param diagnostic - The structured warning or error to deliver.
|
|
3286
|
+
*/
|
|
3287
|
+
reportDiagnostic(diagnostic) {
|
|
3288
|
+
emitDiagnostic(this.onDiagnostic, diagnostic);
|
|
3289
|
+
}
|
|
3290
|
+
/**
|
|
3239
3291
|
* Invokes a preflight function, memoizing the result in the given render-pass context.
|
|
3240
3292
|
*
|
|
3241
3293
|
* @param fn - The preflight function to invoke.
|
|
@@ -3286,7 +3338,7 @@ var Engine = class {
|
|
|
3286
3338
|
* ```
|
|
3287
3339
|
*/
|
|
3288
3340
|
notifyPreflightUpdated() {
|
|
3289
|
-
|
|
3341
|
+
this.pluginHooks.preflightUpdated(this.config.plugins);
|
|
3290
3342
|
}
|
|
3291
3343
|
/**
|
|
3292
3344
|
* Fires the `atomicStyleAdded` hook to notify plugins that a new atomic style was registered.
|
|
@@ -3301,7 +3353,7 @@ var Engine = class {
|
|
|
3301
3353
|
* ```
|
|
3302
3354
|
*/
|
|
3303
3355
|
notifyAtomicStyleAdded(atomicStyle) {
|
|
3304
|
-
|
|
3356
|
+
this.pluginHooks.atomicStyleAdded(this.config.plugins, atomicStyle);
|
|
3305
3357
|
}
|
|
3306
3358
|
/**
|
|
3307
3359
|
* Fires the `autocompleteConfigUpdated` hook to notify plugins that autocomplete entries changed.
|
|
@@ -3315,7 +3367,7 @@ var Engine = class {
|
|
|
3315
3367
|
* ```
|
|
3316
3368
|
*/
|
|
3317
3369
|
notifyAutocompleteConfigUpdated() {
|
|
3318
|
-
|
|
3370
|
+
this.pluginHooks.autocompleteConfigUpdated(this.config.plugins);
|
|
3319
3371
|
}
|
|
3320
3372
|
/**
|
|
3321
3373
|
* Merges an autocomplete contribution into the resolved autocomplete config.
|
|
@@ -3385,7 +3437,7 @@ var Engine = class {
|
|
|
3385
3437
|
log.debug(`Processing ${itemList.length} style items`);
|
|
3386
3438
|
const { unknown, contents } = await resolveStyleItemList({
|
|
3387
3439
|
itemList,
|
|
3388
|
-
transformStyleItems: (styleItems) =>
|
|
3440
|
+
transformStyleItems: (styleItems) => this.pluginHooks.transformStyleItems(this.config.plugins, styleItems),
|
|
3389
3441
|
extractStyleDefinition: (styleDefinition) => this.extract(styleDefinition)
|
|
3390
3442
|
});
|
|
3391
3443
|
const resolvedIds = [];
|
|
@@ -3484,6 +3536,7 @@ var Engine = class {
|
|
|
3484
3536
|
const { atomicStyleIds = null, isPreview = false } = options;
|
|
3485
3537
|
const atomicStyles = atomicStyleIds == null ? [...this.store.atomicStyles.values()] : atomicStyleIds.map((id) => this.store.atomicStyles.get(id)).filter(isNotNullish);
|
|
3486
3538
|
log.debug(`Rendering ${atomicStyles.length} atomic styles (preview: ${isPreview})`);
|
|
3539
|
+
reportUnknownAtomicStyleLayers(this, atomicStyles);
|
|
3487
3540
|
return renderAtomicStyles({
|
|
3488
3541
|
atomicStyles,
|
|
3489
3542
|
isPreview,
|
|
@@ -3601,6 +3654,20 @@ function splitLayerSelector(selector) {
|
|
|
3601
3654
|
function prependLayerSelector(selector, layer) {
|
|
3602
3655
|
return [`${LAYER_SELECTOR_PREFIX}${layer}`, ...selector];
|
|
3603
3656
|
}
|
|
3657
|
+
function reportUnknownAtomicStyleLayers(engine, styles) {
|
|
3658
|
+
const knownLayers = new Set(Object.keys(engine.config.layers));
|
|
3659
|
+
const reportedLayers = /* @__PURE__ */ new Set();
|
|
3660
|
+
for (const style of styles) {
|
|
3661
|
+
const { layer } = splitLayerSelector(style.content.selector);
|
|
3662
|
+
if (layer == null || knownLayers.has(layer) || reportedLayers.has(layer)) continue;
|
|
3663
|
+
reportedLayers.add(layer);
|
|
3664
|
+
engine.reportDiagnostic({
|
|
3665
|
+
level: "warning",
|
|
3666
|
+
code: "atomic-style-unknown-layer",
|
|
3667
|
+
message: `Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`
|
|
3668
|
+
});
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3604
3671
|
function groupAtomicStylesByLayer({ styles, layerOrder, defaultUtilitiesLayer }) {
|
|
3605
3672
|
const unlayeredStyles = [];
|
|
3606
3673
|
const layerGroups = new Map(layerOrder.map((name) => [name, []]));
|
|
@@ -3613,7 +3680,6 @@ function groupAtomicStylesByLayer({ styles, layerOrder, defaultUtilitiesLayer })
|
|
|
3613
3680
|
continue;
|
|
3614
3681
|
}
|
|
3615
3682
|
if (layer != null) {
|
|
3616
|
-
log.warn(`Unknown layer "${layer}" encountered in atomic style; falling back to unlayered output.`);
|
|
3617
3683
|
unlayeredStyles.push(style);
|
|
3618
3684
|
continue;
|
|
3619
3685
|
}
|
|
@@ -3859,7 +3925,7 @@ function renderAtomicStyles(payload) {
|
|
|
3859
3925
|
* @param options.blocks - Optional accumulator map reused during recursive descent.
|
|
3860
3926
|
* @returns The accumulated `CSSStyleBlocks` map.
|
|
3861
3927
|
*
|
|
3862
|
-
* @remarks Each key in the definition is either a CSS property (when its value is a property value) or a nested selector scope (when its value is an object). Selector keys are expanded through `
|
|
3928
|
+
* @remarks Each key in the definition is either a CSS property (when its value is a property value) or a nested selector scope (when its value is an object). Selector keys are expanded through the engine-local `pluginHooks.transformSelectors` dispatcher. The resulting blocks map is consumable by `renderCSSStyleBlocks`.
|
|
3863
3929
|
*
|
|
3864
3930
|
* @example
|
|
3865
3931
|
* ```ts
|
|
@@ -3870,7 +3936,7 @@ async function _renderPreflightDefinition({ engine, preflightDefinition, blocks
|
|
|
3870
3936
|
for (const [selector, propertiesOrDefinition] of Object.entries(preflightDefinition)) {
|
|
3871
3937
|
if (propertiesOrDefinition == null) continue;
|
|
3872
3938
|
const selectors = normalizeSelectors({
|
|
3873
|
-
selectors: await
|
|
3939
|
+
selectors: await engine.pluginHooks.transformSelectors(engine.config.plugins, [selector]),
|
|
3874
3940
|
defaultSelector: ""
|
|
3875
3941
|
}).filter(Boolean);
|
|
3876
3942
|
if (selectors.length === 0) continue;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikacss/core",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.58",
|
|
5
5
|
"author": "DevilTea <ch19980814@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://pikacss.github.io",
|
|
@@ -36,9 +36,6 @@
|
|
|
36
36
|
"files": [
|
|
37
37
|
"dist"
|
|
38
38
|
],
|
|
39
|
-
"engines": {
|
|
40
|
-
"node": ">=22"
|
|
41
|
-
},
|
|
42
39
|
"scripts": {
|
|
43
40
|
"build": "tsdown",
|
|
44
41
|
"build:watch": "tsdown --watch",
|