@seyuna/postcss 1.0.0-canary.37 → 1.0.0-canary.39

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +444 -156
  3. package/dist/at-rules/color-scheme.d.ts +3 -2
  4. package/dist/at-rules/color-scheme.js +6 -7
  5. package/dist/at-rules/color.d.ts +5 -4
  6. package/dist/at-rules/color.js +5 -4
  7. package/dist/at-rules/config.d.ts +2 -1
  8. package/dist/at-rules/config.js +44 -13
  9. package/dist/at-rules/container.d.ts +2 -1
  10. package/dist/at-rules/container.js +4 -6
  11. package/dist/at-rules/import.d.ts +3 -2
  12. package/dist/at-rules/import.js +107 -139
  13. package/dist/at-rules/index.d.ts +2 -1
  14. package/dist/at-rules/index.js +3 -4
  15. package/dist/config.js +70 -28
  16. package/dist/errors.d.ts +3 -5
  17. package/dist/errors.js +2 -4
  18. package/dist/functions/color.d.ts +4 -4
  19. package/dist/functions/color.js +4 -4
  20. package/dist/functions/index.js +5 -7
  21. package/dist/helpers.d.ts +4 -6
  22. package/dist/helpers.js +26 -22
  23. package/dist/index.d.ts +8 -1
  24. package/dist/index.js +1 -0
  25. package/dist/parser.js +36 -49
  26. package/dist/plugin.d.ts +3 -1
  27. package/dist/plugin.js +15 -19
  28. package/dist/types.d.ts +6 -1
  29. package/dist/types.js +0 -2
  30. package/package.json +20 -3
  31. package/.github/workflows/release.yml +0 -41
  32. package/.vscode/settings.json +0 -4
  33. package/dist/functions/theme.d.ts +0 -6
  34. package/dist/functions/theme.js +0 -17
  35. package/release.config.mjs +0 -37
  36. package/src/at-rules/color-scheme.ts +0 -54
  37. package/src/at-rules/color.ts +0 -33
  38. package/src/at-rules/config.ts +0 -78
  39. package/src/at-rules/container.ts +0 -58
  40. package/src/at-rules/import.ts +0 -196
  41. package/src/at-rules/index.ts +0 -29
  42. package/src/config.ts +0 -98
  43. package/src/errors.ts +0 -27
  44. package/src/functions/color.ts +0 -123
  45. package/src/functions/index.ts +0 -22
  46. package/src/functions/theme.ts +0 -20
  47. package/src/helpers.ts +0 -75
  48. package/src/index.ts +0 -10
  49. package/src/parser.ts +0 -81
  50. package/src/plugin.ts +0 -58
  51. package/src/styles/seyuna-global.css +0 -94
  52. package/src/types.ts +0 -71
  53. package/tests/plugin.test.ts +0 -244
  54. package/tsconfig.json +0 -14
@@ -1,78 +0,0 @@
1
- import { PluginContext } from "../types.js";
2
-
3
- /**
4
- * Handler for @config "seyuna"
5
- * Parses the configuration defined directly in CSS.
6
- */
7
- export function handleConfig(atRule: any, context: PluginContext) {
8
- const params = atRule.params.replace(/['"]/g, "");
9
-
10
- if (params === "seyuna") {
11
- const { config } = context;
12
- if (!config.ui) {
13
- config.ui = {
14
- theme: {
15
- hues: {},
16
- colors: {},
17
- light: {
18
- chroma: 0,
19
- lightness: 0,
20
- background: { lightness: 0, chroma: 0, hue: 0 },
21
- text: { lightness: 0, chroma: 0, hue: 0 },
22
- colors: {},
23
- },
24
- dark: {
25
- chroma: 0,
26
- lightness: 0,
27
- background: { lightness: 0, chroma: 0, hue: 0 },
28
- text: { lightness: 0, chroma: 0, hue: 0 },
29
- colors: {},
30
- },
31
- },
32
- };
33
- }
34
-
35
- const theme = config.ui.theme;
36
-
37
- atRule.walkDecls((decl: any) => {
38
- const prop = decl.prop;
39
- const value = decl.value;
40
-
41
- // Hues: --hue-alpha: 0;
42
- if (prop.startsWith("--hue-")) {
43
- const name = prop.replace("--hue-", "");
44
- theme.hues[name] = parseFloat(value);
45
- }
46
-
47
- // Fixed Colors: --color-primary: 0.66 0.26 240;
48
- else if (prop.startsWith("--color-")) {
49
- const name = prop.replace("--color-", "");
50
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
51
- theme.colors[name] = { lightness: l, chroma: c, hue: h };
52
- }
53
-
54
- // Theme Palettes: --light-lightness: 0.66;
55
- else if (prop.startsWith("--light-") || prop.startsWith("--dark-")) {
56
- const isLight = prop.startsWith("--light-");
57
- const palette = isLight ? theme.light : theme.dark;
58
- const key = prop.replace(isLight ? "--light-" : "--dark-", "");
59
-
60
- if (key === "lightness") palette.lightness = parseFloat(value);
61
- else if (key === "chroma") palette.chroma = parseFloat(value);
62
- else if (key === "background" || key === "text") {
63
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
64
- (palette as any)[key] = { lightness: l, chroma: c, hue: h };
65
- } else {
66
- // Custom colors in palette: --light-surface: 1 0 0;
67
- // Also supports overrides like --light-color-primary: 0.8 0.1 240;
68
- const cleanKey = key.replace(/^color-/, "");
69
- const [l, c, h] = value.split(/\s+/).map(parseFloat);
70
- palette.colors[cleanKey] = { lightness: l, chroma: c, hue: h };
71
- }
72
- }
73
- });
74
-
75
- // Remove the at-rule from CSS output
76
- atRule.remove();
77
- }
78
- }
@@ -1,58 +0,0 @@
1
- import AtRule from "postcss/lib/at-rule";
2
- // import type { ChildNode } from "postcss"; // AtRule is now a value import
3
- import { PluginContext } from "../types.js";
4
-
5
- /**
6
- * Custom PostCSS plugin handler for responsive at-rules.
7
- *
8
- * Example:
9
- *
10
- * @xs {
11
- * .box { color: red; }
12
- * }
13
- *
14
- * Into:
15
- *
16
- * @xs (min-width: 234px) {
17
- * .box { color: red; }
18
- * }
19
- *
20
- */
21
- export default function container(atRule: any, context: PluginContext) {
22
- const { config } = context;
23
-
24
- // Default breakpoints
25
- const defaultBreakpoints: Record<string, string> = {
26
- xs: "20rem",
27
- sm: "40rem",
28
- md: "48rem",
29
- lg: "64rem",
30
- xl: "80rem",
31
- "2xl": "96rem",
32
- };
33
-
34
- // Merge with config if available (assuming config.ui.breakpoints exists)
35
- const breakpoints = {
36
- ...defaultBreakpoints,
37
- ...((config as any).ui?.theme?.breakpoints || {}),
38
- };
39
-
40
- if (Object.keys(breakpoints).includes(atRule.name)) {
41
- const minWidth = breakpoints[atRule.name];
42
-
43
- const clonedNodes: any[] = [];
44
- atRule.each((node: any) => {
45
- clonedNodes.push(node.clone());
46
- });
47
-
48
- const containerAtRule = new AtRule({
49
- name: "container",
50
- params: `(min-width: ${minWidth})`,
51
- source: atRule.source,
52
- });
53
-
54
- clonedNodes.forEach((node) => containerAtRule.append(node));
55
-
56
- atRule.replaceWith(containerAtRule);
57
- }
58
- }
@@ -1,196 +0,0 @@
1
- import Rule from "postcss/lib/rule";
2
- import Declaration from "postcss/lib/declaration";
3
- import AtRule from "postcss/lib/at-rule";
4
- import { PluginContext } from "../types.js";
5
- import fs from "fs";
6
- import path from "path";
7
- import { fileURLToPath } from "url";
8
- import postcss from "postcss";
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = path.dirname(__filename);
12
-
13
- /**
14
- * Handler for @import "seyuna"
15
- * Injects the core Seyuna Design System variables and base styles
16
- */
17
- export function handleImport(atRule: any, context: PluginContext) {
18
- // Support both @seyuna; and the previous @import "seyuna" logic
19
- // Since this handler is now registered to @seyuna, we just check params or just run it.
20
- const params = atRule.params.replace(/['"]/g, "").trim();
21
-
22
- // If it's @seyuna; the params will be empty.
23
- // If it's @import "seyuna", this handler wouldn't be called unless we kept the name "import".
24
- // But we want this to run for @seyuna;
25
- if (atRule.name === "seyuna") {
26
- const { config, options } = context;
27
- if (!config.ui) {
28
- atRule.remove();
29
- return;
30
- }
31
-
32
- const { theme } = config.ui;
33
- const modeAttribute = options.modeAttribute;
34
- const nodes: any[] = [];
35
-
36
- // 1. Ingest Global Base Styles (Reset, Layers, etc.)
37
- try {
38
- const globalStylesPath = path.resolve(
39
- __dirname,
40
- "../styles/seyuna-global.css",
41
- );
42
- if (fs.existsSync(globalStylesPath)) {
43
- const globalCss = fs.readFileSync(globalStylesPath, "utf-8");
44
- const parsed = postcss.parse(globalCss);
45
-
46
- // Push all nodes from the global styles (reset, layers, etc.)
47
- parsed.nodes.forEach((node) => {
48
- nodes.push(node.clone());
49
- });
50
- } else {
51
- nodes.push(
52
- new AtRule({
53
- name: "layer",
54
- params: "reset, base, components, utilities",
55
- }),
56
- );
57
- }
58
- } catch (e) {
59
- console.warn("[Seyuna PostCSS] Could not load global base styles:", e);
60
- }
61
-
62
- // 2. Global Hues and Base Colors (:root)
63
- const rootRule = new Rule({ selector: ":root", source: atRule.source });
64
-
65
- // Process all hues from config
66
- if (theme.hues) {
67
- for (const [name, value] of Object.entries(theme.hues)) {
68
- rootRule.append(
69
- new Declaration({ prop: `--${name}-hue`, value: String(value) }),
70
- );
71
- }
72
- }
73
-
74
- // Add shared colors from theme.colors
75
- if (theme.colors) {
76
- for (const [name, color] of Object.entries(theme.colors)) {
77
- rootRule.append(
78
- new Declaration({
79
- prop: `--${name}-lightness`,
80
- value: String(color.lightness),
81
- }),
82
- );
83
- rootRule.append(
84
- new Declaration({
85
- prop: `--${name}-chroma`,
86
- value: String(color.chroma),
87
- }),
88
- );
89
- rootRule.append(
90
- new Declaration({ prop: `--${name}-hue`, value: String(color.hue) }),
91
- );
92
- }
93
- }
94
- nodes.push(rootRule);
95
-
96
- // Helper to generate palette declarations for a specific mode
97
- const getPaletteDecls = (palette: any) => {
98
- const decls: Declaration[] = [];
99
-
100
- if (palette.lightness !== undefined) {
101
- decls.push(
102
- new Declaration({
103
- prop: "--lightness",
104
- value: String(palette.lightness),
105
- }),
106
- );
107
- }
108
- if (palette.chroma !== undefined) {
109
- decls.push(
110
- new Declaration({ prop: "--chroma", value: String(palette.chroma) }),
111
- );
112
- }
113
-
114
- // Standard background/text if they exist
115
- if (palette.background) {
116
- decls.push(
117
- new Declaration({
118
- prop: "--background",
119
- value: `oklch(${palette.background.lightness} ${palette.background.chroma} ${palette.background.hue})`,
120
- }),
121
- );
122
- }
123
- if (palette.text) {
124
- decls.push(
125
- new Declaration({
126
- prop: "--text",
127
- value: `oklch(${palette.text.lightness} ${palette.text.chroma} ${palette.text.hue})`,
128
- }),
129
- );
130
- }
131
-
132
- if (palette.colors) {
133
- for (const [name, color] of Object.entries(palette.colors)) {
134
- const c = color as any;
135
- decls.push(
136
- new Declaration({
137
- prop: `--${name}-lightness`,
138
- value: String(c.lightness),
139
- }),
140
- );
141
- decls.push(
142
- new Declaration({
143
- prop: `--${name}-chroma`,
144
- value: String(c.chroma),
145
- }),
146
- );
147
- decls.push(
148
- new Declaration({ prop: `--${name}-hue`, value: String(c.hue) }),
149
- );
150
- }
151
- }
152
- return decls;
153
- };
154
-
155
- // 3. Explicit Mode Selectors ([data-mode="..."])
156
- if (theme.light) {
157
- const lightRule = new Rule({
158
- selector: `[${modeAttribute}="light"]`,
159
- source: atRule.source,
160
- });
161
- lightRule.append(...getPaletteDecls(theme.light));
162
- nodes.push(lightRule);
163
- }
164
-
165
- if (theme.dark) {
166
- const darkRule = new Rule({
167
- selector: `[${modeAttribute}="dark"]`,
168
- source: atRule.source,
169
- });
170
- darkRule.append(...getPaletteDecls(theme.dark));
171
- nodes.push(darkRule);
172
- }
173
-
174
- // 4. System Preference Support
175
- const createSystemMedia = (scheme: "light" | "dark", palette: any) => {
176
- const media = new AtRule({
177
- name: "media",
178
- params: `(prefers-color-scheme: ${scheme})`,
179
- source: atRule.source,
180
- });
181
- const rule = new Rule({
182
- selector: `[${modeAttribute}="system"]`,
183
- source: atRule.source,
184
- });
185
- rule.append(...getPaletteDecls(palette));
186
- media.append(rule);
187
- return media;
188
- };
189
-
190
- if (theme.light) nodes.push(createSystemMedia("light", theme.light));
191
- if (theme.dark) nodes.push(createSystemMedia("dark", theme.dark));
192
-
193
- // Replace the @import rule with our generated CSS
194
- atRule.replaceWith(...nodes);
195
- }
196
- }
@@ -1,29 +0,0 @@
1
- // import type { AtRule } from "postcss";
2
- import { eachStandardColor, eachFixedColor } from "./color.js";
3
- import container from "./container.js";
4
- import { light, dark } from "./color-scheme.js";
5
- import { handleImport } from "./import.js";
6
- import { handleConfig } from "./config.js";
7
- import { PluginContext } from "../types.js";
8
-
9
- // Each handler has a name (matches the at-rule) and the function
10
- export interface AtRuleHandler {
11
- name: string;
12
- handler: (atRule: any, context: PluginContext) => void;
13
- }
14
-
15
- // Ordered array ensures execution order
16
- export const atRuleHandlers: AtRuleHandler[] = [
17
- { name: "config", handler: handleConfig },
18
- { name: "seyuna", handler: handleImport },
19
- { name: "each-standard-color", handler: eachStandardColor },
20
- { name: "each-fixed-color", handler: eachFixedColor },
21
- { name: "light", handler: light },
22
- { name: "dark", handler: dark },
23
- { name: "xs", handler: container },
24
- { name: "sm", handler: container },
25
- { name: "md", handler: container },
26
- { name: "lg", handler: container },
27
- { name: "xl", handler: container },
28
- { name: "2xl", handler: container },
29
- ];
package/src/config.ts DELETED
@@ -1,98 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import {
4
- SeyunaConfig,
5
- PluginOptions,
6
- PluginContext,
7
- FunctionMap,
8
- } from "./types.js";
9
-
10
- // Re-export types for backwards compatibility
11
- export type { PluginOptions, PluginContext, FunctionMap } from "./types.js";
12
-
13
- const DEFAULT_HUES = {
14
- alpha: 15,
15
- beta: 30,
16
- gamma: 45,
17
- delta: 60,
18
- epsilon: 75,
19
- zeta: 90,
20
- eta: 105,
21
- theta: 120,
22
- iota: 135,
23
- kappa: 150,
24
- lambda: 165,
25
- mu: 180,
26
- nu: 195,
27
- xi: 210,
28
- omicron: 225,
29
- pi: 240,
30
- rho: 255,
31
- sigma: 270,
32
- tau: 285,
33
- upsilon: 300,
34
- phi: 315,
35
- chi: 330,
36
- psi: 345,
37
- omega: 360,
38
- };
39
-
40
- const DEFAULT_OPTIONS: Required<PluginOptions> = {
41
- config: undefined as any,
42
- functions: undefined as any,
43
- };
44
-
45
- export function loadConfig(options: PluginOptions = {}): {
46
- config: SeyunaConfig;
47
- options: Required<PluginOptions> & { modeAttribute: string };
48
- } {
49
- const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
50
-
51
- const baseConfig: SeyunaConfig = {
52
- ui: {
53
- theme: {
54
- hues: { ...DEFAULT_HUES },
55
- colors: {},
56
- light: {
57
- chroma: 0,
58
- lightness: 0,
59
- background: { lightness: 0, chroma: 0, hue: 0 },
60
- text: { lightness: 0, chroma: 0, hue: 0 },
61
- colors: {},
62
- },
63
- dark: {
64
- chroma: 0,
65
- lightness: 0,
66
- background: { lightness: 0, chroma: 0, hue: 0 },
67
- text: { lightness: 0, chroma: 0, hue: 0 },
68
- colors: {},
69
- },
70
- },
71
- },
72
- };
73
-
74
- if (mergedOptions.config) {
75
- // Deep merge or at least merge hues
76
- const config = mergedOptions.config;
77
- if (config.ui?.theme) {
78
- config.ui.theme.hues = { ...DEFAULT_HUES, ...config.ui.theme.hues };
79
- }
80
- return {
81
- config: config,
82
- options: { ...mergedOptions, modeAttribute: "data-mode" },
83
- };
84
- }
85
-
86
- // Return base config with defaults
87
- return {
88
- config: baseConfig,
89
- options: { ...mergedOptions, modeAttribute: "data-mode" },
90
- };
91
- }
92
-
93
- export async function loadConfigAsync(options: PluginOptions = {}): Promise<{
94
- config: SeyunaConfig;
95
- options: Required<PluginOptions> & { modeAttribute: string };
96
- }> {
97
- return loadConfig(options);
98
- }
package/src/errors.ts DELETED
@@ -1,27 +0,0 @@
1
- // import type { Node } from 'postcss';
2
- import { PluginContext } from "./types.js";
3
-
4
- export function reportError(
5
- message: string,
6
- node: any,
7
- context: PluginContext,
8
- options: { word?: string; index?: number } = {},
9
- ) {
10
- const { options: pluginOptions } = context;
11
- const formattedMessage = `[Seyuna PostCSS] ${message}`;
12
-
13
- reportWarning(formattedMessage, node, context);
14
- }
15
-
16
- export function reportWarning(
17
- message: string,
18
- node: any,
19
- context?: PluginContext,
20
- ) {
21
- if (context?.result) {
22
- node.warn(context.result, `[Seyuna PostCSS] ${message}`);
23
- } else {
24
- // Fallback if no result is available (should not happen in main flow)
25
- console.warn(`[Seyuna PostCSS Warning] ${message}`);
26
- }
27
- }
@@ -1,123 +0,0 @@
1
- import { PluginContext } from "../types.js";
2
-
3
- /**
4
- * Resolves a color name to its CSS variables based on its type (standard or fixed)
5
- */
6
- function getColorVariables(
7
- context: PluginContext,
8
- color: string,
9
- type?: "sc" | "fc",
10
- ) {
11
- const { config } = context;
12
- const hues = config?.ui?.theme?.hues || {};
13
- const colors = config?.ui?.theme?.colors || {};
14
- const lightColors = config?.ui?.theme?.light?.colors || {};
15
- const darkColors = config?.ui?.theme?.dark?.colors || {};
16
-
17
- // If explicitly typed, trust the type and generate appropriate variables
18
- if (type === "sc") {
19
- return {
20
- l: "var(--lightness)",
21
- c: "var(--chroma)",
22
- h: `var(--${color}-hue)`,
23
- };
24
- }
25
- if (type === "fc") {
26
- return {
27
- l: `var(--${color}-lightness)`,
28
- c: `var(--${color}-chroma)`,
29
- h: `var(--${color}-hue)`,
30
- };
31
- }
32
-
33
- // Auto-detect based on config
34
- const isStandard = color in hues;
35
- const isFixed =
36
- color in colors || color in lightColors || color in darkColors;
37
-
38
- if (isStandard && !isFixed) {
39
- return {
40
- l: "var(--lightness)",
41
- c: "var(--chroma)",
42
- h: `var(--${color}-hue)`,
43
- };
44
- }
45
-
46
- if (isFixed && !isStandard) {
47
- return {
48
- l: `var(--${color}-lightness)`,
49
- c: `var(--${color}-chroma)`,
50
- h: `var(--${color}-hue)`,
51
- };
52
- }
53
-
54
- // Resilient fallback (graceful degradation for multi-file scenarios or name collisions)
55
- // Use specific color variable if it exists, otherwise fall back to theme defaults
56
- return {
57
- l: `var(--${color}-lightness, var(--lightness))`,
58
- c: `var(--${color}-chroma, var(--chroma))`,
59
- h: `var(--${color}-hue)`,
60
- };
61
- }
62
-
63
- export function SeyunaStandardColor(
64
- context: PluginContext,
65
- name: string,
66
- alpha?: string,
67
- lightness?: string,
68
- chroma?: string,
69
- ) {
70
- const vars = getColorVariables(context, name, "sc");
71
- const a = alpha && alpha !== "null" ? alpha : "1";
72
- const l = lightness && lightness !== "null" ? lightness : vars.l;
73
- const c = chroma && chroma !== "null" ? chroma : vars.c;
74
-
75
- return `oklch(${l} ${c} ${vars.h} / ${a})`;
76
- }
77
-
78
- export function SeyunaFixedColor(
79
- context: PluginContext,
80
- name: string,
81
- alpha?: string,
82
- lightness?: string,
83
- chroma?: string,
84
- ) {
85
- const vars = getColorVariables(context, name, "fc");
86
- const a = alpha && alpha !== "null" ? alpha : "1";
87
- const l = lightness && lightness !== "null" ? lightness : vars.l;
88
- const c = chroma && chroma !== "null" ? chroma : vars.c;
89
-
90
- return `oklch(${l} ${c} ${vars.h} / ${a})`;
91
- }
92
-
93
- export function SeyunaAlpha(
94
- context: PluginContext,
95
- color: string,
96
- value: string,
97
- ) {
98
- const { l, c, h } = getColorVariables(context, color);
99
- return `oklch(${l} ${c} ${h} / ${value})`;
100
- }
101
-
102
- export function SeyunaLighten(
103
- context: PluginContext,
104
- color: string,
105
- amount: string,
106
- ) {
107
- const { l, c, h } = getColorVariables(context, color);
108
- return `oklch(calc(${l} + ${amount}) ${c} ${h} / 1)`;
109
- }
110
-
111
- export function SeyunaDarken(
112
- context: PluginContext,
113
- color: string,
114
- amount: string,
115
- ) {
116
- const { l, c, h } = getColorVariables(context, color);
117
- return `oklch(calc(${l} - ${amount}) ${c} ${h} / 1)`;
118
- }
119
-
120
- export function SeyunaContrast(context: PluginContext, color: string) {
121
- const { l } = getColorVariables(context, color);
122
- return `oklch(calc((${l} - 0.6) * -1000) 0 0)`;
123
- }
@@ -1,22 +0,0 @@
1
- import {
2
- SeyunaStandardColor,
3
- SeyunaFixedColor,
4
- SeyunaAlpha,
5
- SeyunaLighten,
6
- SeyunaDarken,
7
- SeyunaContrast,
8
- } from "./color.js";
9
- import { SeyunaTheme } from "./theme.js";
10
- import { PluginContext } from "../types.js";
11
-
12
- export type FnHandler = (context: PluginContext, ...args: string[]) => string;
13
-
14
- export const functions: Record<string, FnHandler> = {
15
- SeyunaStandardColor,
16
- SeyunaFixedColor,
17
- SeyunaAlpha,
18
- SeyunaLighten,
19
- SeyunaDarken,
20
- SeyunaContrast,
21
- SeyunaTheme,
22
- };
@@ -1,20 +0,0 @@
1
- import { PluginContext } from "../types.js";
2
-
3
- /**
4
- * Accesses values from the Seyuna configuration using dot notation
5
- * Example: theme(ui.theme.breakpoints.tablet)
6
- */
7
- export function SeyunaTheme(context: PluginContext, path: string): string {
8
- const parts = path.split('.');
9
- let current: any = context.config;
10
-
11
- for (const part of parts) {
12
- if (current && typeof current === 'object' && part in current) {
13
- current = current[part];
14
- } else {
15
- return path; // Return original path if not found
16
- }
17
- }
18
-
19
- return String(current);
20
- }