@seyuna/postcss 1.0.0-canary.21 → 1.0.0-canary.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/at-rules/color-scheme.js +6 -12
- package/dist/at-rules/color.js +5 -9
- package/dist/at-rules/container.js +4 -11
- package/dist/at-rules/index.js +14 -20
- package/dist/config.d.ts +4 -0
- package/dist/config.js +46 -12
- package/dist/errors.js +2 -6
- package/dist/functions/color.js +10 -19
- package/dist/functions/index.js +10 -13
- package/dist/functions/theme.js +1 -4
- package/dist/helpers.js +8 -17
- package/dist/index.js +5 -7
- package/dist/parser.js +6 -12
- package/dist/plugin.js +11 -15
- package/dist/types.js +1 -2
- package/package.json +2 -1
- package/src/config.ts +45 -0
- package/src/plugin.ts +3 -3
- package/tsconfig.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
# [1.0.0-canary.23](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.22...v1.0.0-canary.23) (2026-01-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **esm:** prevent deadlock by making config load async ([e8b2d46](https://github.com/seyuna-corp/seyuna-postcss/commit/e8b2d461080bc773a552fdcf4847ee841708ca64))
|
|
7
|
+
|
|
8
|
+
# [1.0.0-canary.22](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.21...v1.0.0-canary.22) (2026-01-10)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **esm:** convert to esm and use lazy initialization to resolve deadlock ([4179e78](https://github.com/seyuna-corp/seyuna-postcss/commit/4179e786f3264a475ae89616b6078d80e51ba978))
|
|
14
|
+
|
|
1
15
|
# [1.0.0-canary.21](https://github.com/seyuna-corp/seyuna-postcss/compare/v1.0.0-canary.20...v1.0.0-canary.21) (2026-01-10)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.dark = exports.light = void 0;
|
|
7
|
-
const postcss_1 = __importDefault(require("postcss"));
|
|
1
|
+
import postcss from "postcss";
|
|
8
2
|
/**
|
|
9
3
|
* Custom PostCSS plugin handler factory for `@light` and `@dark` at-rules.
|
|
10
4
|
*/
|
|
@@ -20,7 +14,7 @@ function createColorSchemeHandler(scheme) {
|
|
|
20
14
|
/**
|
|
21
15
|
* Rule 1: [data-mode="scheme"] & { ... } (Explicit mode)
|
|
22
16
|
*/
|
|
23
|
-
const explicitRule = new
|
|
17
|
+
const explicitRule = new postcss.Rule({
|
|
24
18
|
selector: `[${modeAttribute}="${scheme}"] &`,
|
|
25
19
|
source: atRule.source,
|
|
26
20
|
});
|
|
@@ -28,12 +22,12 @@ function createColorSchemeHandler(scheme) {
|
|
|
28
22
|
/**
|
|
29
23
|
* Rule 2: @media (prefers-color-scheme: scheme) { [data-mode="system"] & { ... } } (System preference)
|
|
30
24
|
*/
|
|
31
|
-
const mediaAtRule = new
|
|
25
|
+
const mediaAtRule = new postcss.AtRule({
|
|
32
26
|
name: "media",
|
|
33
27
|
params: `(prefers-color-scheme: ${scheme})`,
|
|
34
28
|
source: atRule.source,
|
|
35
29
|
});
|
|
36
|
-
const systemRule = new
|
|
30
|
+
const systemRule = new postcss.Rule({
|
|
37
31
|
selector: `[${modeAttribute}="system"] &`,
|
|
38
32
|
source: atRule.source,
|
|
39
33
|
});
|
|
@@ -45,5 +39,5 @@ function createColorSchemeHandler(scheme) {
|
|
|
45
39
|
atRule.replaceWith(mediaAtRule, explicitRule);
|
|
46
40
|
};
|
|
47
41
|
}
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
export const light = createColorSchemeHandler('light');
|
|
43
|
+
export const dark = createColorSchemeHandler('dark');
|
package/dist/at-rules/color.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.eachStandardColor = eachStandardColor;
|
|
4
|
-
exports.eachFixedColor = eachFixedColor;
|
|
5
|
-
const helpers_js_1 = require("../helpers.js");
|
|
1
|
+
import { generateRules } from "../helpers.js";
|
|
6
2
|
/**
|
|
7
3
|
* Handler for @each-standard-color
|
|
8
4
|
*/
|
|
9
|
-
function eachStandardColor(atRule, context) {
|
|
5
|
+
export function eachStandardColor(atRule, context) {
|
|
10
6
|
const { config } = context;
|
|
11
7
|
const hueNames = config.ui ? Object.keys(config.ui.theme.hues) : [];
|
|
12
|
-
const rules =
|
|
8
|
+
const rules = generateRules(hueNames, atRule, context);
|
|
13
9
|
if (rules.length)
|
|
14
10
|
atRule.replaceWith(...rules);
|
|
15
11
|
else
|
|
@@ -18,7 +14,7 @@ function eachStandardColor(atRule, context) {
|
|
|
18
14
|
/**
|
|
19
15
|
* Handler for @each-fixed-color
|
|
20
16
|
*/
|
|
21
|
-
function eachFixedColor(atRule, context) {
|
|
17
|
+
export function eachFixedColor(atRule, context) {
|
|
22
18
|
const { config } = context;
|
|
23
19
|
const mergedNames = [
|
|
24
20
|
...new Set([
|
|
@@ -26,7 +22,7 @@ function eachFixedColor(atRule, context) {
|
|
|
26
22
|
...(config.ui ? Object.keys(config.ui.theme.dark.colors) : []),
|
|
27
23
|
]),
|
|
28
24
|
];
|
|
29
|
-
const rules =
|
|
25
|
+
const rules = generateRules(mergedNames, atRule, context);
|
|
30
26
|
if (rules.length)
|
|
31
27
|
atRule.replaceWith(...rules);
|
|
32
28
|
else
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.default = container;
|
|
7
|
-
const postcss_1 = __importDefault(require("postcss"));
|
|
1
|
+
import postcss from "postcss";
|
|
8
2
|
/**
|
|
9
3
|
* Custom PostCSS plugin handler for responsive at-rules.
|
|
10
4
|
*
|
|
@@ -21,8 +15,7 @@ const postcss_1 = __importDefault(require("postcss"));
|
|
|
21
15
|
* }
|
|
22
16
|
*
|
|
23
17
|
*/
|
|
24
|
-
function container(atRule, context) {
|
|
25
|
-
var _a, _b;
|
|
18
|
+
export default function container(atRule, context) {
|
|
26
19
|
const { config } = context;
|
|
27
20
|
// Default breakpoints
|
|
28
21
|
const defaultBreakpoints = {
|
|
@@ -36,7 +29,7 @@ function container(atRule, context) {
|
|
|
36
29
|
// Merge with config if available (assuming config.ui.breakpoints exists)
|
|
37
30
|
const breakpoints = {
|
|
38
31
|
...defaultBreakpoints,
|
|
39
|
-
...(
|
|
32
|
+
...(config.ui?.theme?.breakpoints || {}),
|
|
40
33
|
};
|
|
41
34
|
if (Object.keys(breakpoints).includes(atRule.name)) {
|
|
42
35
|
const minWidth = breakpoints[atRule.name];
|
|
@@ -44,7 +37,7 @@ function container(atRule, context) {
|
|
|
44
37
|
atRule.each((node) => {
|
|
45
38
|
clonedNodes.push(node.clone());
|
|
46
39
|
});
|
|
47
|
-
const containerAtRule = new
|
|
40
|
+
const containerAtRule = new postcss.AtRule({
|
|
48
41
|
name: "container",
|
|
49
42
|
params: `(min-width: ${minWidth})`,
|
|
50
43
|
source: atRule.source,
|
package/dist/at-rules/index.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.atRuleHandlers = void 0;
|
|
7
|
-
const color_js_1 = require("./color.js");
|
|
8
|
-
const container_js_1 = __importDefault(require("./container.js"));
|
|
9
|
-
const color_scheme_js_1 = require("./color-scheme.js");
|
|
1
|
+
import { eachStandardColor, eachFixedColor } from "./color.js";
|
|
2
|
+
import container from "./container.js";
|
|
3
|
+
import { light, dark } from "./color-scheme.js";
|
|
10
4
|
// Ordered array ensures execution order
|
|
11
|
-
|
|
12
|
-
{ name: "each-standard-color", handler:
|
|
13
|
-
{ name: "each-fixed-color", handler:
|
|
14
|
-
{ name: "light", handler:
|
|
15
|
-
{ name: "dark", handler:
|
|
16
|
-
{ name: "xs", handler:
|
|
17
|
-
{ name: "sm", handler:
|
|
18
|
-
{ name: "md", handler:
|
|
19
|
-
{ name: "lg", handler:
|
|
20
|
-
{ name: "xl", handler:
|
|
21
|
-
{ name: "2xl", handler:
|
|
5
|
+
export const atRuleHandlers = [
|
|
6
|
+
{ name: "each-standard-color", handler: eachStandardColor },
|
|
7
|
+
{ name: "each-fixed-color", handler: eachFixedColor },
|
|
8
|
+
{ name: "light", handler: light },
|
|
9
|
+
{ name: "dark", handler: dark },
|
|
10
|
+
{ name: "xs", handler: container },
|
|
11
|
+
{ name: "sm", handler: container },
|
|
12
|
+
{ name: "md", handler: container },
|
|
13
|
+
{ name: "lg", handler: container },
|
|
14
|
+
{ name: "xl", handler: container },
|
|
15
|
+
{ name: "2xl", handler: container },
|
|
22
16
|
];
|
package/dist/config.d.ts
CHANGED
|
@@ -4,3 +4,7 @@ export declare function loadConfig(options?: PluginOptions): {
|
|
|
4
4
|
config: SeyunaConfig;
|
|
5
5
|
options: Required<PluginOptions>;
|
|
6
6
|
};
|
|
7
|
+
export declare function loadConfigAsync(options?: PluginOptions): Promise<{
|
|
8
|
+
config: SeyunaConfig;
|
|
9
|
+
options: Required<PluginOptions>;
|
|
10
|
+
}>;
|
package/dist/config.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadConfig = loadConfig;
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
9
3
|
const DEFAULT_OPTIONS = {
|
|
10
4
|
configPath: 'seyuna.json',
|
|
11
5
|
modeAttribute: 'data-mode',
|
|
@@ -15,18 +9,57 @@ const DEFAULT_OPTIONS = {
|
|
|
15
9
|
};
|
|
16
10
|
let cachedConfig = null;
|
|
17
11
|
let cachedConfigPath = null;
|
|
18
|
-
function loadConfig(options = {}) {
|
|
12
|
+
export function loadConfig(options = {}) {
|
|
13
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
14
|
+
if (mergedOptions.config) {
|
|
15
|
+
return { config: mergedOptions.config, options: mergedOptions };
|
|
16
|
+
}
|
|
17
|
+
const configPath = path.resolve(process.cwd(), mergedOptions.configPath);
|
|
18
|
+
// Cache config if it's the same path
|
|
19
|
+
if (cachedConfig && cachedConfigPath === configPath) {
|
|
20
|
+
return { config: cachedConfig, options: mergedOptions };
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
if (!fs.existsSync(configPath)) {
|
|
24
|
+
if (mergedOptions.strict) {
|
|
25
|
+
throw new Error(`Seyuna config not found at ${configPath}`);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } },
|
|
29
|
+
options: mergedOptions,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
33
|
+
cachedConfig = data;
|
|
34
|
+
cachedConfigPath = configPath;
|
|
35
|
+
return { config: data, options: mergedOptions };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (mergedOptions.strict) {
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
console.warn(`[Seyuna PostCSS] Warning: Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
return {
|
|
43
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } },
|
|
44
|
+
options: mergedOptions,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function loadConfigAsync(options = {}) {
|
|
19
49
|
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
20
50
|
if (mergedOptions.config) {
|
|
21
51
|
return { config: mergedOptions.config, options: mergedOptions };
|
|
22
52
|
}
|
|
23
|
-
const configPath =
|
|
53
|
+
const configPath = path.resolve(process.cwd(), mergedOptions.configPath);
|
|
24
54
|
// Cache config if it's the same path
|
|
25
55
|
if (cachedConfig && cachedConfigPath === configPath) {
|
|
26
56
|
return { config: cachedConfig, options: mergedOptions };
|
|
27
57
|
}
|
|
28
58
|
try {
|
|
29
|
-
|
|
59
|
+
try {
|
|
60
|
+
await fs.promises.access(configPath);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
30
63
|
if (mergedOptions.strict) {
|
|
31
64
|
throw new Error(`Seyuna config not found at ${configPath}`);
|
|
32
65
|
}
|
|
@@ -35,7 +68,8 @@ function loadConfig(options = {}) {
|
|
|
35
68
|
options: mergedOptions,
|
|
36
69
|
};
|
|
37
70
|
}
|
|
38
|
-
const
|
|
71
|
+
const content = await fs.promises.readFile(configPath, 'utf-8');
|
|
72
|
+
const data = JSON.parse(content);
|
|
39
73
|
cachedConfig = data;
|
|
40
74
|
cachedConfigPath = configPath;
|
|
41
75
|
return { config: data, options: mergedOptions };
|
package/dist/errors.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.reportError = reportError;
|
|
4
|
-
exports.reportWarning = reportWarning;
|
|
5
|
-
function reportError(message, node, context, options = {}) {
|
|
1
|
+
export function reportError(message, node, context, options = {}) {
|
|
6
2
|
const { options: pluginOptions } = context;
|
|
7
3
|
const formattedMessage = `[Seyuna PostCSS] ${message}`;
|
|
8
4
|
if (pluginOptions.strict) {
|
|
@@ -12,7 +8,7 @@ function reportError(message, node, context, options = {}) {
|
|
|
12
8
|
reportWarning(formattedMessage, node);
|
|
13
9
|
}
|
|
14
10
|
}
|
|
15
|
-
function reportWarning(message, node) {
|
|
11
|
+
export function reportWarning(message, node) {
|
|
16
12
|
const result = node.root().toResult();
|
|
17
13
|
node.warn(result, `[Seyuna PostCSS] ${message}`);
|
|
18
14
|
}
|
package/dist/functions/color.js
CHANGED
|
@@ -1,21 +1,12 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sc = sc;
|
|
4
|
-
exports.fc = fc;
|
|
5
|
-
exports.alpha = alpha;
|
|
6
|
-
exports.lighten = lighten;
|
|
7
|
-
exports.darken = darken;
|
|
8
|
-
exports.contrast = contrast;
|
|
9
1
|
/**
|
|
10
2
|
* Resolves a color name to its CSS variables based on its type (standard or fixed)
|
|
11
3
|
*/
|
|
12
4
|
function getColorVariables(context, color, type) {
|
|
13
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
14
5
|
const { config } = context;
|
|
15
|
-
const hues =
|
|
16
|
-
const colors =
|
|
17
|
-
const lightColors =
|
|
18
|
-
const darkColors =
|
|
6
|
+
const hues = config?.ui?.theme?.hues || {};
|
|
7
|
+
const colors = config?.ui?.theme?.colors || {};
|
|
8
|
+
const lightColors = config?.ui?.theme?.light?.colors || {};
|
|
9
|
+
const darkColors = config?.ui?.theme?.dark?.colors || {};
|
|
19
10
|
const isStandard = color in hues;
|
|
20
11
|
const isFixed = color in colors || color in lightColors || color in darkColors;
|
|
21
12
|
if (type === 'sc' && !isStandard) {
|
|
@@ -40,33 +31,33 @@ function getColorVariables(context, color, type) {
|
|
|
40
31
|
}
|
|
41
32
|
throw new Error(`Color '${color}' not found in seyuna.json`);
|
|
42
33
|
}
|
|
43
|
-
function sc(context, name, alpha, lightness, chroma) {
|
|
34
|
+
export function sc(context, name, alpha, lightness, chroma) {
|
|
44
35
|
const vars = getColorVariables(context, name, 'sc');
|
|
45
36
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
46
37
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
47
38
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
|
48
39
|
return `oklch(${l} ${c} ${vars.h} / ${a})`;
|
|
49
40
|
}
|
|
50
|
-
function fc(context, name, alpha, lightness, chroma) {
|
|
41
|
+
export function fc(context, name, alpha, lightness, chroma) {
|
|
51
42
|
const vars = getColorVariables(context, name, 'fc');
|
|
52
43
|
const a = alpha && alpha !== "null" ? alpha : "1";
|
|
53
44
|
const l = lightness && lightness !== "null" ? lightness : vars.l;
|
|
54
45
|
const c = chroma && chroma !== "null" ? chroma : vars.c;
|
|
55
46
|
return `oklch(${l} ${c} ${vars.h} / ${a})`;
|
|
56
47
|
}
|
|
57
|
-
function alpha(context, color, value) {
|
|
48
|
+
export function alpha(context, color, value) {
|
|
58
49
|
const { l, c, h } = getColorVariables(context, color);
|
|
59
50
|
return `oklch(${l} ${c} ${h} / ${value})`;
|
|
60
51
|
}
|
|
61
|
-
function lighten(context, color, amount) {
|
|
52
|
+
export function lighten(context, color, amount) {
|
|
62
53
|
const { l, c, h } = getColorVariables(context, color);
|
|
63
54
|
return `oklch(calc(${l} + ${amount}) ${c} ${h} / 1)`;
|
|
64
55
|
}
|
|
65
|
-
function darken(context, color, amount) {
|
|
56
|
+
export function darken(context, color, amount) {
|
|
66
57
|
const { l, c, h } = getColorVariables(context, color);
|
|
67
58
|
return `oklch(calc(${l} - ${amount}) ${c} ${h} / 1)`;
|
|
68
59
|
}
|
|
69
|
-
function contrast(context, color) {
|
|
60
|
+
export function contrast(context, color) {
|
|
70
61
|
const { l } = getColorVariables(context, color);
|
|
71
62
|
return `oklch(calc((${l} - 0.6) * -1000) 0 0)`;
|
|
72
63
|
}
|
package/dist/functions/index.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
darken: color_js_1.darken,
|
|
12
|
-
contrast: color_js_1.contrast,
|
|
13
|
-
theme: theme_js_1.theme,
|
|
1
|
+
import { sc, fc, alpha, lighten, darken, contrast } from "./color.js";
|
|
2
|
+
import { theme } from "./theme.js";
|
|
3
|
+
export const functions = {
|
|
4
|
+
sc,
|
|
5
|
+
fc,
|
|
6
|
+
alpha,
|
|
7
|
+
lighten,
|
|
8
|
+
darken,
|
|
9
|
+
contrast,
|
|
10
|
+
theme,
|
|
14
11
|
};
|
package/dist/functions/theme.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.theme = theme;
|
|
4
1
|
/**
|
|
5
2
|
* Accesses values from the Seyuna configuration using dot notation
|
|
6
3
|
* Example: theme(ui.theme.breakpoints.tablet)
|
|
7
4
|
*/
|
|
8
|
-
function theme(context, path) {
|
|
5
|
+
export function theme(context, path) {
|
|
9
6
|
const parts = path.split('.');
|
|
10
7
|
let current = context.config;
|
|
11
8
|
for (const part of parts) {
|
package/dist/helpers.js
CHANGED
|
@@ -1,17 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.cloneNodes = cloneNodes;
|
|
7
|
-
exports.generateRules = generateRules;
|
|
8
|
-
const postcss_1 = __importDefault(require("postcss"));
|
|
9
|
-
const parser_js_1 = require("./parser.js");
|
|
1
|
+
import postcss from "postcss";
|
|
2
|
+
import { processFunctions } from "./parser.js";
|
|
10
3
|
/**
|
|
11
4
|
* Helper: clone nodes and replace {name} placeholders safely
|
|
12
5
|
* Returns only valid Rules or Declarations (never raw AtRules)
|
|
13
6
|
*/
|
|
14
|
-
function cloneNodes(nodes, name, context) {
|
|
7
|
+
export function cloneNodes(nodes, name, context) {
|
|
15
8
|
const { functions: fnMap } = context;
|
|
16
9
|
return nodes.flatMap((node) => {
|
|
17
10
|
const cloned = node.clone();
|
|
@@ -19,7 +12,7 @@ function cloneNodes(nodes, name, context) {
|
|
|
19
12
|
const decl = cloned;
|
|
20
13
|
let value = decl.value.replace(/\{name\}/g, name);
|
|
21
14
|
// Process functions using the robust parser
|
|
22
|
-
decl.value =
|
|
15
|
+
decl.value = processFunctions(value, fnMap, decl, context);
|
|
23
16
|
return decl;
|
|
24
17
|
}
|
|
25
18
|
if (cloned.type === "rule") {
|
|
@@ -40,18 +33,16 @@ function cloneNodes(nodes, name, context) {
|
|
|
40
33
|
/**
|
|
41
34
|
* Generate CSS rules from a list of names
|
|
42
35
|
*/
|
|
43
|
-
function generateRules(names, atRule, context) {
|
|
44
|
-
|
|
45
|
-
const nodes = (_a = atRule.nodes) !== null && _a !== void 0 ? _a : [];
|
|
36
|
+
export function generateRules(names, atRule, context) {
|
|
37
|
+
const nodes = atRule.nodes ?? [];
|
|
46
38
|
const generatedRules = [];
|
|
47
39
|
for (const name of names) {
|
|
48
|
-
const rule = new
|
|
40
|
+
const rule = new postcss.Rule({
|
|
49
41
|
selector: `&.${name}`,
|
|
50
42
|
source: atRule.source,
|
|
51
43
|
});
|
|
52
44
|
cloneNodes(nodes, name, context).forEach((n) => {
|
|
53
|
-
|
|
54
|
-
if (n.type === "rule" && n.selector && ((_a = n.nodes) === null || _a === void 0 ? void 0 : _a.length))
|
|
45
|
+
if (n.type === "rule" && n.selector && n.nodes?.length)
|
|
55
46
|
rule.append(n);
|
|
56
47
|
if (n.type === "decl")
|
|
57
48
|
rule.append(n);
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const plugin_js_1 = require("./plugin.js");
|
|
4
|
-
const index_js_1 = require("./functions/index.js");
|
|
1
|
+
import { dynamicFunctionsPlugin } from './plugin.js';
|
|
2
|
+
import { functions } from './functions/index.js';
|
|
5
3
|
// CommonJS-friendly export
|
|
6
|
-
const plugin = Object.assign(
|
|
4
|
+
const plugin = Object.assign(dynamicFunctionsPlugin, {
|
|
7
5
|
postcss: true,
|
|
8
|
-
functions
|
|
6
|
+
functions
|
|
9
7
|
});
|
|
10
|
-
|
|
8
|
+
export default plugin;
|
package/dist/parser.js
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.processFunctions = processFunctions;
|
|
7
|
-
const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
|
|
8
|
-
const errors_js_1 = require("./errors.js");
|
|
9
|
-
function processFunctions(value, fnMap, node, context) {
|
|
10
|
-
const parsed = (0, postcss_value_parser_1.default)(value);
|
|
1
|
+
import valueParser from 'postcss-value-parser';
|
|
2
|
+
import { reportError } from './errors.js';
|
|
3
|
+
export function processFunctions(value, fnMap, node, context) {
|
|
4
|
+
const parsed = valueParser(value);
|
|
11
5
|
// Helper to process nodes recursively (inner-first)
|
|
12
6
|
function processNode(parsedValue) {
|
|
13
7
|
parsedValue.walk((nodeIter) => {
|
|
@@ -37,7 +31,7 @@ function processFunctions(value, fnMap, node, context) {
|
|
|
37
31
|
currentArg = '';
|
|
38
32
|
}
|
|
39
33
|
else {
|
|
40
|
-
currentArg +=
|
|
34
|
+
currentArg += valueParser.stringify(argNode);
|
|
41
35
|
}
|
|
42
36
|
});
|
|
43
37
|
if (currentArg) {
|
|
@@ -52,7 +46,7 @@ function processFunctions(value, fnMap, node, context) {
|
|
|
52
46
|
nodeIter.nodes = []; // Clear children
|
|
53
47
|
}
|
|
54
48
|
catch (error) {
|
|
55
|
-
|
|
49
|
+
reportError(`Failed to process function "${nodeIter.value}": ${error instanceof Error ? error.message : String(error)}`, node, context);
|
|
56
50
|
}
|
|
57
51
|
}
|
|
58
52
|
}
|
package/dist/plugin.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const config_js_1 = require("./config.js");
|
|
7
|
-
const parser_js_1 = require("./parser.js");
|
|
8
|
-
const dynamicFunctionsPlugin = (opts = {}) => {
|
|
1
|
+
import { functions } from "./functions/index.js";
|
|
2
|
+
import { atRuleHandlers } from "./at-rules/index.js";
|
|
3
|
+
import { loadConfigAsync } from "./config.js";
|
|
4
|
+
import { processFunctions } from "./parser.js";
|
|
5
|
+
export const dynamicFunctionsPlugin = (opts = {}) => {
|
|
9
6
|
let context;
|
|
10
7
|
let fnMap;
|
|
11
8
|
return {
|
|
12
9
|
postcssPlugin: "postcss-dynamic-functions",
|
|
13
|
-
Once() {
|
|
14
|
-
const { config, options } =
|
|
15
|
-
fnMap = { ...
|
|
10
|
+
async Once() {
|
|
11
|
+
const { config, options } = await loadConfigAsync(opts);
|
|
12
|
+
fnMap = { ...functions, ...opts.functions };
|
|
16
13
|
context = {
|
|
17
14
|
config,
|
|
18
15
|
options,
|
|
@@ -22,14 +19,14 @@ const dynamicFunctionsPlugin = (opts = {}) => {
|
|
|
22
19
|
Declaration(decl) {
|
|
23
20
|
if (!context || !fnMap)
|
|
24
21
|
return;
|
|
25
|
-
decl.value =
|
|
22
|
+
decl.value = processFunctions(decl.value, fnMap, decl, context);
|
|
26
23
|
},
|
|
27
24
|
// Override AtRule handler to ensure ordered execution
|
|
28
25
|
AtRule(atRule) {
|
|
29
26
|
if (!context)
|
|
30
27
|
return;
|
|
31
28
|
// Iterate over handlers in order (array) instead of object spread
|
|
32
|
-
for (const { name, handler } of
|
|
29
|
+
for (const { name, handler } of atRuleHandlers) {
|
|
33
30
|
if (atRule.name === name) {
|
|
34
31
|
handler(atRule, context);
|
|
35
32
|
}
|
|
@@ -37,5 +34,4 @@ const dynamicFunctionsPlugin = (opts = {}) => {
|
|
|
37
34
|
},
|
|
38
35
|
};
|
|
39
36
|
};
|
|
40
|
-
|
|
41
|
-
exports.dynamicFunctionsPlugin.postcss = true;
|
|
37
|
+
dynamicFunctionsPlugin.postcss = true;
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
package/src/config.ts
CHANGED
|
@@ -57,3 +57,48 @@ export function loadConfig(options: PluginOptions = {}): { config: SeyunaConfig,
|
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
export async function loadConfigAsync(options: PluginOptions = {}): Promise<{ config: SeyunaConfig, options: Required<PluginOptions> }> {
|
|
62
|
+
const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
63
|
+
|
|
64
|
+
if (mergedOptions.config) {
|
|
65
|
+
return { config: mergedOptions.config, options: mergedOptions };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const configPath = path.resolve(process.cwd(), mergedOptions.configPath);
|
|
69
|
+
|
|
70
|
+
// Cache config if it's the same path
|
|
71
|
+
if (cachedConfig && cachedConfigPath === configPath) {
|
|
72
|
+
return { config: cachedConfig, options: mergedOptions };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
try {
|
|
77
|
+
await fs.promises.access(configPath);
|
|
78
|
+
} catch {
|
|
79
|
+
if (mergedOptions.strict) {
|
|
80
|
+
throw new Error(`Seyuna config not found at ${configPath}`);
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } } as any,
|
|
84
|
+
options: mergedOptions,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const content = await fs.promises.readFile(configPath, 'utf-8');
|
|
89
|
+
const data = JSON.parse(content);
|
|
90
|
+
cachedConfig = data;
|
|
91
|
+
cachedConfigPath = configPath;
|
|
92
|
+
|
|
93
|
+
return { config: data, options: mergedOptions };
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (mergedOptions.strict) {
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
console.warn(`[Seyuna PostCSS] Warning: Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
|
|
99
|
+
return {
|
|
100
|
+
config: { ui: { theme: { hues: {}, light: { colors: {} }, dark: { colors: {} } } } } as any,
|
|
101
|
+
options: mergedOptions,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/plugin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PluginCreator } from "postcss";
|
|
2
2
|
import { functions } from "./functions/index.js";
|
|
3
3
|
import { atRuleHandlers } from "./at-rules/index.js";
|
|
4
|
-
import { loadConfig } from "./config.js";
|
|
4
|
+
import { loadConfig, loadConfigAsync } from "./config.js";
|
|
5
5
|
import { PluginOptions, PluginContext, FunctionMap } from "./types.js";
|
|
6
6
|
import { processFunctions } from "./parser.js";
|
|
7
7
|
|
|
@@ -14,8 +14,8 @@ export const dynamicFunctionsPlugin: PluginCreator<PluginOptions> = (
|
|
|
14
14
|
return {
|
|
15
15
|
postcssPlugin: "postcss-dynamic-functions",
|
|
16
16
|
|
|
17
|
-
Once() {
|
|
18
|
-
const { config, options } =
|
|
17
|
+
async Once() {
|
|
18
|
+
const { config, options } = await loadConfigAsync(opts);
|
|
19
19
|
fnMap = { ...functions, ...opts.functions };
|
|
20
20
|
context = {
|
|
21
21
|
config,
|
package/tsconfig.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"target": "
|
|
4
|
-
"module": "
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "NodeNext",
|
|
5
5
|
"lib": ["ES2020"],
|
|
6
6
|
"declaration": true,
|
|
7
7
|
"outDir": "dist",
|
|
8
8
|
"strict": true,
|
|
9
|
-
"moduleResolution": "
|
|
9
|
+
"moduleResolution": "NodeNext",
|
|
10
10
|
"esModuleInterop": true,
|
|
11
11
|
"skipLibCheck": true
|
|
12
12
|
},
|