@gesslar/sassy 0.21.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Evaluator class for resolving variables and colour tokens in theme objects.
3
+ * Handles recursive substitution of token references in arrays of objects
4
+ * with support for colour manipulation functions.
5
+ */
6
+ export default class Evaluator {
7
+ /**
8
+ * Regular expression used to locate variable substitution tokens. Supports:
9
+ * - POSIX-ish: $(variable.path)
10
+ * - Legacy: $variable.path
11
+ * - Braced: ${variable.path}
12
+ *
13
+ * Capturing groups allow extraction of the inner path variant irrespective
14
+ * of wrapping style. The pattern captures (entireMatch, posix, legacy,
15
+ * braced).
16
+ *
17
+ * @type {RegExp}
18
+ */
19
+ static sub: RegExp;
20
+ /**
21
+ * Regular expression for matching colour / transformation function calls
22
+ * within token strings, e.g. `darken($(std.accent), 10)`.
23
+ *
24
+ * @type {RegExp}
25
+ */
26
+ static func: RegExp;
27
+ /**
28
+ * Extracts a variable name from a string containing variable syntax.
29
+ * Supports $(var), $var, and ${var} patterns.
30
+ *
31
+ * @param {string} [str] - String that may contain a variable reference
32
+ * @returns {string|null} The variable name or null if none found
33
+ */
34
+ static extractVariableName(str?: string): string | null;
35
+ /**
36
+ * Extracts function name and arguments from a string containing function syntax.
37
+ * Supports functionName(args) patterns.
38
+ *
39
+ * @param {string} [str] - String that may contain a function call
40
+ * @returns {{func:string, args:string}|null} Object with {func, args} or null if none found
41
+ */
42
+ static extractFunctionCall(str?: string): {
43
+ func: string;
44
+ args: string;
45
+ } | null;
46
+ get pool(): ThemePool;
47
+ /**
48
+ * Resolve variables and theme token entries in two distinct passes to ensure
49
+ * deterministic scoping and to prevent partially-resolved values from
50
+ * leaking between stages:
51
+ *
52
+ * 1. Variable pass: each variable is resolved only with access to the
53
+ * variable set itself (no theme values yet). This ensures variables are
54
+ * self-contained building blocks.
55
+ * 2. Theme pass: theme entries are then resolved against the union of the
56
+ * fully-resolved variables plus (progressively) the theme entries. This
57
+ * allows theme keys to reference variables and other theme keys.
58
+ *
59
+ * Implementation details:
60
+ * - The internal lookup map persists for the lifetime of this instance; new
61
+ * entries overwrite prior values (last write wins) so previously resolved
62
+ * data can seed later evaluations without a rebuild.
63
+ * - Input array is mutated in-place (`value` fields change).
64
+ * - No return value. Evident by the absence of a return statement.
65
+ *
66
+ * @param {Array<{flatPath:string,value:unknown}>} decomposed - Variable entries to resolve.
67
+ * @example
68
+ * // Example decomposed input with variables and theme references
69
+ * const evaluator = new Evaluator();
70
+ * const decomposed = [
71
+ * { flatPath: 'vars.primary', value: '#3366cc' },
72
+ * { flatPath: 'theme.colors.background', value: '$(vars.primary)' },
73
+ * { flatPath: 'theme.colors.accent', value: 'lighten($(vars.primary), 20)' }
74
+ * ];
75
+ * evaluator.evaluate(decomposed);
76
+ * // After evaluation, values are resolved:
77
+ * // decomposed[1].value === '#3366cc'
78
+ * // decomposed[2].value === '#5588dd' (lightened color)
79
+ */
80
+ evaluate(decomposed: Array<{
81
+ flatPath: string;
82
+ value: unknown;
83
+ }>): void;
84
+ #private;
85
+ }
86
+ import ThemePool from "./ThemePool.js";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Command handler for linting theme files for potential issues.
3
+ * Validates tokenColors for duplicate scopes, undefined variables, unused
4
+ * variables, and precedence issues that could cause unexpected theme
5
+ * behaviour.
6
+ */
7
+ export default class LintCommand extends Command {
8
+ static SECTIONS: {
9
+ VARS: string;
10
+ COLORS: string;
11
+ TOKEN_COLORS: string;
12
+ SEMANTIC_TOKEN_COLORS: string;
13
+ };
14
+ static SEVERITY: {
15
+ HIGH: string;
16
+ MEDIUM: string;
17
+ LOW: string;
18
+ };
19
+ static ISSUE_TYPES: {
20
+ DUPLICATE_SCOPE: string;
21
+ UNDEFINED_VARIABLE: string;
22
+ UNUSED_VARIABLE: string;
23
+ PRECEDENCE_ISSUE: string;
24
+ };
25
+ static TEMPLATES: {
26
+ ENTRY_NAME: (index: any) => string;
27
+ OBJECT_NAME: (index: any) => string;
28
+ VARIABLE_PREFIX: string;
29
+ };
30
+ /**
31
+ * Creates a new LintCommand instance.
32
+ *
33
+ * @param {object} base - Base configuration containing cwd and packageJson
34
+ */
35
+ constructor(base: object);
36
+ /**
37
+ * Executes the lint command for a given theme file.
38
+ * Validates the theme and reports any issues found.
39
+ *
40
+ * @param {string} inputArg - Path to the theme file to lint
41
+ * @param {object} options - Linting options
42
+ * @returns {Promise<void>} Resolves when linting is complete
43
+ */
44
+ execute(inputArg: string, options?: object): Promise<void>;
45
+ /**
46
+ * Public method to lint a theme and return structured results for external
47
+ * consumption.
48
+ *
49
+ * Returns categorized lint results for tokenColors, semanticTokenColors, and colors.
50
+ *
51
+ * @param {Theme} theme - The compiled theme object
52
+ * @returns {Promise<object>} Object containing categorized lint results
53
+ */
54
+ lint(theme: Theme): Promise<object>;
55
+ #private;
56
+ }
57
+ import Command from "./Command.js";
58
+ import Theme from "./Theme.js";
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Command handler for resolving theme tokens and variables to their final values.
3
+ * Provides introspection into the theme resolution process and variable dependencies.
4
+ */
5
+ export default class ResolveCommand extends Command {
6
+ /**
7
+ * Creates a new ResolveCommand instance.
8
+ *
9
+ * @param {object} base - Base configuration containing cwd and packageJson
10
+ */
11
+ constructor(base: object);
12
+ /**
13
+ * Executes the resolve command for a given theme file and option.
14
+ * Validates mutual exclusivity of options and delegates to appropriate resolver.
15
+ *
16
+ * @param {string} inputArg - Path to the theme file to resolve
17
+ * @param {object} options - Resolution options (token, etc.)
18
+ * @returns {Promise<void>} Resolves when resolution is complete
19
+ */
20
+ execute(inputArg: string, options?: object): Promise<void>;
21
+ /**
22
+ * Resolves a specific color to its final value and displays the resolution trail.
23
+ * Shows the complete dependency chain for the requested color.
24
+ *
25
+ * @param {object} theme - The compiled theme object with pool
26
+ * @param {string} colorName - The color key to resolve
27
+ * @returns {void}
28
+ * @example
29
+ * // Resolve a color variable from a compiled theme
30
+ * await resolveCommand.resolveColor(theme, 'colors.primary');
31
+ * // Output:
32
+ * // colors.primary:
33
+ * // $(vars.accent)
34
+ * // → #3366cc
35
+ * // Resolution: #3366cc
36
+ */
37
+ resolveColor(theme: object, colorName: string): void;
38
+ /**
39
+ * Resolves a specific tokenColors scope to its final value and displays the resolution trail.
40
+ * Shows all matching scopes with disambiguation when multiple matches are found.
41
+ *
42
+ * @param {object} theme - The compiled theme object with output
43
+ * @param {string} scopeName - The scope to resolve (e.g., "entity.name.class" or "entity.name.class.1")
44
+ * @returns {void}
45
+ */
46
+ resolveTokenColor(theme: object, scopeName: string): void;
47
+ /**
48
+ * Resolves a specific semanticTokenColors scope to its final value.
49
+ * Uses the same logic as tokenColors since they have identical structure.
50
+ *
51
+ * @param {object} theme - The compiled theme object with output
52
+ * @param {string} scopeName - The scope to resolve (e.g., "keyword" or "keyword.1")
53
+ * @returns {void}
54
+ */
55
+ resolveSemanticTokenColor(theme: object, scopeName: string): void;
56
+ #private;
57
+ }
58
+ import Command from "./Command.js";
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @typedef {object} SessionOptions
3
+ * @property {boolean} [watch] - Whether to enable file watching
4
+ * @property {boolean} [nerd] - Whether to show verbose output
5
+ * @property {boolean} [dryRun] - Whether to skip file writes
6
+ */
7
+ /**
8
+ * @typedef {object} BuildRecord
9
+ * @property {number} timestamp - Epoch ms when the build started
10
+ * @property {number} loadTime - Time (ms) spent loading theme sources
11
+ * @property {number} buildTime - Time (ms) spent compiling the theme
12
+ * @property {number} writeTime - Time (ms) spent writing the output file
13
+ * @property {boolean} success - Whether the build completed successfully
14
+ * @property {string} [error] - Error message when success is false
15
+ */
16
+ export default class Session {
17
+ /**
18
+ * Creates a new Session instance for managing theme compilation lifecycle.
19
+ * Sessions provide persistent state across rebuilds, error tracking, and
20
+ * individual theme management within the build system.
21
+ *
22
+ * @param {Command} command - The parent build command instance
23
+ * @param {Theme} theme - The theme instance to manage
24
+ * @param {SessionOptions} options - Build configuration options
25
+ */
26
+ constructor(command: Command, theme: Theme, options: SessionOptions);
27
+ get theme(): Theme;
28
+ /**
29
+ * Gets the theme instance managed by this session.
30
+ *
31
+ * @returns {Theme} The theme instance
32
+ */
33
+ getTheme(): Theme;
34
+ /**
35
+ * Gets the command instance orchestrating this session.
36
+ *
37
+ * @returns {Command} The command instance
38
+ */
39
+ getCommand(): Command;
40
+ /**
41
+ * Gets the session options.
42
+ *
43
+ * @returns {SessionOptions} The session options
44
+ */
45
+ getOptions(): SessionOptions;
46
+ /**
47
+ * Gets the build history for this session.
48
+ *
49
+ * @returns {Array<BuildRecord>} Array of build records
50
+ */
51
+ getHistory(): Array<BuildRecord>;
52
+ /**
53
+ * Gets the build statistics for this session.
54
+ *
55
+ * @returns {{builds: number, failures: number}} Build statistics
56
+ */
57
+ getStats(): {
58
+ builds: number;
59
+ failures: number;
60
+ };
61
+ /**
62
+ * Checks if a build is currently in progress.
63
+ *
64
+ * @returns {boolean} True if building
65
+ */
66
+ isBuilding(): boolean;
67
+ /**
68
+ * Checks if watch mode is enabled.
69
+ *
70
+ * @returns {boolean} True if watching
71
+ */
72
+ isWatching(): boolean;
73
+ /**
74
+ * Checks if there's an active file watcher.
75
+ *
76
+ * @returns {boolean} True if watcher exists
77
+ */
78
+ hasWatcher(): boolean;
79
+ run(): Promise<void>;
80
+ /**
81
+ * Displays a formatted summary of the session's build statistics and performance.
82
+ * Shows total builds, success/failure counts, success rate percentage, and timing
83
+ * information from the most recent build. Used during session cleanup to provide
84
+ * final statistics to the user.
85
+ *
86
+ * @returns {void}
87
+ */
88
+ showSummary(): void;
89
+ #private;
90
+ }
91
+ export type SessionOptions = {
92
+ /**
93
+ * - Whether to enable file watching
94
+ */
95
+ watch?: boolean;
96
+ /**
97
+ * - Whether to show verbose output
98
+ */
99
+ nerd?: boolean;
100
+ /**
101
+ * - Whether to skip file writes
102
+ */
103
+ dryRun?: boolean;
104
+ };
105
+ export type BuildRecord = {
106
+ /**
107
+ * - Epoch ms when the build started
108
+ */
109
+ timestamp: number;
110
+ /**
111
+ * - Time (ms) spent loading theme sources
112
+ */
113
+ loadTime: number;
114
+ /**
115
+ * - Time (ms) spent compiling the theme
116
+ */
117
+ buildTime: number;
118
+ /**
119
+ * - Time (ms) spent writing the output file
120
+ */
121
+ writeTime: number;
122
+ /**
123
+ * - Whether the build completed successfully
124
+ */
125
+ success: boolean;
126
+ /**
127
+ * - Error message when success is false
128
+ */
129
+ error?: string;
130
+ };
131
+ import Theme from "./Theme.js";
132
+ import Command from "./Command.js";
@@ -0,0 +1,336 @@
1
+ import type { FileObject, DirectoryObject, Cache } from '@gesslar/toolkit';
2
+ /**
3
+ * Theme class: manages the lifecycle of a theme compilation unit.
4
+ * See file-level docstring for responsibilities.
5
+ */
6
+ export default class Theme {
7
+ /**
8
+ * Creates a new Theme instance.
9
+ *
10
+ * @param {FileObject} themeFile - The source theme file object
11
+ * @param {DirectoryObject} cwd - The project's directory.
12
+ * @param {object} options - Compilation options
13
+ */
14
+ constructor(themeFile: FileObject, cwd: DirectoryObject, options: object);
15
+ /**
16
+ * Resets the theme's compilation state, clearing output and lookup data.
17
+ * Used when recompiling in watch mode or clearing previous state.
18
+ */
19
+ reset(): void;
20
+ /**
21
+ * Gets the current working directory.
22
+ *
23
+ * @returns {DirectoryObject} The current working directory
24
+ */
25
+ getCwd(): DirectoryObject;
26
+ /**
27
+ * Gets the compilation options.
28
+ *
29
+ * @returns {object} The compilation options object
30
+ */
31
+ getOptions(): object;
32
+ /**
33
+ * Gets a specific compilation option.
34
+ *
35
+ * @param {string} option - The option name to retrieve
36
+ * @returns {unknown} The option value or undefined if not set
37
+ */
38
+ getOption(option: string): unknown;
39
+ /**
40
+ * Sets the cache instance for theme compilation.
41
+ *
42
+ * @param {Cache} cache - The cache instance to use for file operations
43
+ * @returns {this} Returns this instance for method chaining
44
+ */
45
+ setCache(cache: Cache): this;
46
+ /**
47
+ * Gets the cache instance.
48
+ *
49
+ * @returns {Cache|null} The cache instance or null if not set
50
+ */
51
+ getCache(): Cache | null;
52
+ /**
53
+ * Gets the theme name.
54
+ *
55
+ * @returns {string} The theme name derived from the source file
56
+ */
57
+ getName(): string;
58
+ /**
59
+ * Gets the output file name for the compiled theme.
60
+ *
61
+ * @returns {string} The output file name with extension
62
+ */
63
+ getOutputFileName(): string;
64
+ /**
65
+ * Gets the source file object.
66
+ *
67
+ * @returns {FileObject} The source theme file
68
+ */
69
+ getSourceFile(): FileObject;
70
+ /**
71
+ * Sets the compiled theme output object and updates derived JSON and hash.
72
+ *
73
+ * @param {object} data - The compiled theme output object
74
+ * @returns {this} Returns this instance for method chaining
75
+ */
76
+ setOutput(data: object): this;
77
+ /**
78
+ * Gets the compiled theme output object.
79
+ *
80
+ * @returns {object|null} The compiled theme output
81
+ */
82
+ getOutput(): object | null;
83
+ /**
84
+ * Checks if the source has colors defined.
85
+ *
86
+ * @returns {boolean} True if source has theme colors
87
+ */
88
+ sourceHasColors(): boolean;
89
+ /**
90
+ * Checks if the source has token colors defined.
91
+ *
92
+ * @returns {boolean} True if source has theme token colors
93
+ */
94
+ sourceHasTokenColors(): boolean;
95
+ /**
96
+ * Checks if the source has semantic token colors defined.
97
+ *
98
+ * @returns {boolean} True if source has theme semantic token colors
99
+ */
100
+ sourceHasSemanticTokenColors(): boolean;
101
+ /**
102
+ * Checks if the source has theme configuration.
103
+ *
104
+ * @returns {boolean} True if source has theme data
105
+ */
106
+ sourceHasTheme(): boolean;
107
+ /**
108
+ * Checks if the source has variables.
109
+ *
110
+ * @returns {boolean} True if source has vars section
111
+ */
112
+ sourceHasVars(): boolean;
113
+ /**
114
+ * Checks if the source has config section.
115
+ *
116
+ * @returns {boolean} True if source has config
117
+ */
118
+ sourceHasConfig(): boolean;
119
+ /**
120
+ * Gets the source colors data.
121
+ *
122
+ * @returns {object|null} The colors object or null if not defined
123
+ */
124
+ getSourceColors(): object | null;
125
+ /**
126
+ * Gets the source token colors data.
127
+ *
128
+ * @returns {Array|null} The token colors array or null if not defined
129
+ */
130
+ getSourceTokenColors(): any[] | null;
131
+ /**
132
+ * Gets the source semantic token colors data.
133
+ *
134
+ * @returns {object|null} The semantic token colors object or null if not defined
135
+ */
136
+ getSourceSemanticTokenColors(): object | null;
137
+ /**
138
+ * Gets the set of file dependencies.
139
+ *
140
+ * @returns {Set<Dependency>} Set of dependency files
141
+ */
142
+ getDependencies(): Set<Dependency>;
143
+ /**
144
+ * Adds a dependency to the theme with its source data.
145
+ *
146
+ * @param {FileObject} file - The dependency file object
147
+ * @param {object} source - The parsed source data from the file
148
+ * @returns {this} Returns this instance for method chaining
149
+ */
150
+ addDependency(file: FileObject, source: object): this;
151
+ /**
152
+ * Checks if the theme has any dependencies.
153
+ *
154
+ * @returns {boolean} True if theme has dependencies
155
+ */
156
+ hasDependencies(): boolean;
157
+ /**
158
+ * Gets the parsed source data from the theme file.
159
+ *
160
+ * @returns {object|null} The parsed source data
161
+ */
162
+ getSource(): object | null;
163
+ /**
164
+ * Gets the variable lookup data for theme compilation.
165
+ *
166
+ * @returns {object|null} The lookup data object
167
+ */
168
+ getLookup(): object | null;
169
+ /**
170
+ * Sets the variable lookup data for theme compilation.
171
+ *
172
+ * @param {object} data - The lookup data object
173
+ * @returns {this} Returns this instance for method chaining
174
+ */
175
+ setLookup(data: object): this;
176
+ /**
177
+ * Gets the pool data for variable resolution tracking or null if one has
178
+ * not been set.
179
+ *
180
+ * @returns {ThemePool|null} The pool for this theme.
181
+ */
182
+ getPool(): ThemePool | null;
183
+ /**
184
+ * Sets the pool data for variable resolution tracking. May not be over-
185
+ * written publicly. May only be reset
186
+ *
187
+ * @see reset
188
+ *
189
+ * @param {ThemePool} pool - The pool to assign to this theme
190
+ * @throws {Error} If there is already a pool.
191
+ * @returns {this} Returns this instance for method chaining
192
+ */
193
+ setPool(pool: ThemePool): this;
194
+ /**
195
+ * Method to return true or false if this theme has a pool.
196
+ *
197
+ * @returns {boolean} True if a pool has been set, false otherwise.
198
+ */
199
+ hasPool(): boolean;
200
+ /**
201
+ * Checks if the theme has compiled output.
202
+ *
203
+ * @returns {boolean} True if theme has been compiled
204
+ */
205
+ hasOutput(): boolean;
206
+ /**
207
+ * Checks if the theme has loaded source data.
208
+ *
209
+ * @returns {boolean} True if source data is available
210
+ */
211
+ hasSource(): boolean;
212
+ /**
213
+ * Checks if the theme has a cache instance.
214
+ *
215
+ * @returns {boolean} True if cache is available
216
+ */
217
+ hasCache(): boolean;
218
+ /**
219
+ * Checks if the theme has lookup data.
220
+ *
221
+ * @returns {boolean} True if lookup data exists
222
+ */
223
+ hasLookup(): boolean;
224
+ /**
225
+ * Checks if the theme is ready to be compiled.
226
+ * Requires source data and cache to be available.
227
+ *
228
+ * @returns {boolean} True if theme can be compiled
229
+ */
230
+ isReady(): boolean;
231
+ /**
232
+ * Checks if the theme has been fully compiled.
233
+ * Requires output, pool, and lookup data to be present.
234
+ *
235
+ * @returns {boolean} True if theme is fully compiled
236
+ */
237
+ isCompiled(): boolean;
238
+ /**
239
+ * Checks if the theme can be built/compiled.
240
+ * Same as isReady() but with more semantic naming.
241
+ *
242
+ * @returns {boolean} True if build can proceed
243
+ */
244
+ canBuild(): boolean;
245
+ /**
246
+ * Checks if the theme can be written to output.
247
+ * Requires the theme to be compiled.
248
+ *
249
+ * @returns {boolean} True if write can proceed
250
+ */
251
+ canWrite(): boolean;
252
+ /**
253
+ * Checks if the theme is in a valid state for operation.
254
+ * Basic validation that core properties are set.
255
+ *
256
+ * @returns {boolean} True if theme state is valid
257
+ */
258
+ isValid(): boolean;
259
+ /**
260
+ * Loads and parses the theme source file.
261
+ * Validates that the source contains required configuration.
262
+ * Skips loading if no cache is available (extension use case).
263
+ *
264
+ * @returns {Promise<this>} Returns this instance for method chaining
265
+ * @throws {Sass} If source file lacks required 'config' property
266
+ */
267
+ load(): Promise<this>;
268
+ /**
269
+ * Builds the theme by compiling source data into final output.
270
+ * Main entry point for theme compilation process.
271
+ *
272
+ * @returns {Promise<this>} Returns this instance for method chaining
273
+ */
274
+ build(): Promise<this>;
275
+ /**
276
+ * Writes the compiled theme output to a file or stdout.
277
+ * Handles dry-run mode, output directory creation, and duplicate write prevention.
278
+ *
279
+ * @param {boolean} [force] - Force a write. Used by the rebuild CLI option.
280
+ * @returns {Promise<void>} Resolves when write operation is complete
281
+ */
282
+ write(force?: boolean): Promise<void>;
283
+ #private;
284
+ }
285
+ /**
286
+ * Dependency class represents a theme file dependency.
287
+ * Manages the relationship between a file reference and its parsed source data.
288
+ */
289
+ export class Dependency {
290
+ /**
291
+ * Sets the file object for this dependency.
292
+ *
293
+ * @param {FileObject} file - The file object of this dependency.
294
+ * @returns {this} This.
295
+ */
296
+ setSourceFile(file: FileObject): this;
297
+ /**
298
+ * Get the file object for this depenency.
299
+ *
300
+ * @returns {FileObject} The file object of this dependency.
301
+ */
302
+ getSourceFile(): FileObject;
303
+ /**
304
+ * Sets the source object for this dependency.
305
+ *
306
+ * @param {object} source - The parsed JSON from the file after loading.
307
+ * @returns {this} This.
308
+ */
309
+ setSource(source: object): this;
310
+ /**
311
+ * Gets the parsed source data for this dependency.
312
+ *
313
+ * @returns {object|null} The parsed source data
314
+ */
315
+ getSource(): object | null;
316
+ /**
317
+ * Checks if the dependency has a source file.
318
+ *
319
+ * @returns {boolean} True if source file is set
320
+ */
321
+ hasSourceFile(): boolean;
322
+ /**
323
+ * Checks if the dependency has parsed source data.
324
+ *
325
+ * @returns {boolean} True if source data is available
326
+ */
327
+ hasSource(): boolean;
328
+ /**
329
+ * Checks if the dependency is fully initialized.
330
+ *
331
+ * @returns {boolean} True if both file and source are set
332
+ */
333
+ isComplete(): boolean;
334
+ #private;
335
+ }
336
+ import ThemePool from "./ThemePool.js";