@gesslar/sassy 0.21.0 → 0.21.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,13 +2,10 @@ import c from "@gesslar/colours"
2
2
  // import colorSupport from "color-support"
3
3
 
4
4
  import Command from "./Command.js"
5
- import Sass from "./Sass.js"
5
+ import {Sass, Term, Util, Data} from "@gesslar/toolkit"
6
6
  import Colour from "./Colour.js"
7
7
  import Evaluator from "./Evaluator.js"
8
- import Term from "./Term.js"
9
8
  import Theme from "./Theme.js"
10
- import Util from "./Util.js"
11
- import Data from "./Data.js"
12
9
 
13
10
  // ansiColors.enabled = colorSupport.hasBasic
14
11
 
@@ -87,6 +84,14 @@ export default class ResolveCommand extends Command {
87
84
  * @param {object} theme - The compiled theme object with pool
88
85
  * @param {string} colorName - The color key to resolve
89
86
  * @returns {void}
87
+ * @example
88
+ * // Resolve a color variable from a compiled theme
89
+ * await resolveCommand.resolveColor(theme, 'colors.primary');
90
+ * // Output:
91
+ * // colors.primary:
92
+ * // $(vars.accent)
93
+ * // → #3366cc
94
+ * // Resolution: #3366cc
90
95
  */
91
96
  async resolveColor(theme, colorName) {
92
97
  const pool = theme.getPool()
@@ -243,6 +248,7 @@ export default class ResolveCommand extends Command {
243
248
 
244
249
  // Temporarily replace tokenColors with semanticTokenColors for resolution
245
250
  const themeOutput = theme.getOutput()
251
+
246
252
  if(themeOutput?.semanticTokenColors) {
247
253
  themeOutput.tokenColors = themeOutput.semanticTokenColors
248
254
  }
@@ -426,7 +432,12 @@ export default class ResolveCommand extends Command {
426
432
  }
427
433
 
428
434
  if(this.#func.test(value)) {
429
- const {func,args} = this.#func.exec(value).groups
435
+ const result = Evaluator.extractFunctionCall(value)
436
+
437
+ if(!result)
438
+ return [c`{leaf}${value}{/}`, "literal"]
439
+
440
+ const {func, args} = result
430
441
 
431
442
  return [
432
443
  c`{func}${func}{/}{parens}${"("}{/}{leaf}${args}{/}{parens}${")"}{/}`,
@@ -435,9 +446,9 @@ export default class ResolveCommand extends Command {
435
446
  }
436
447
 
437
448
  if(this.#sub.test(value)) {
449
+ const varValue = Evaluator.extractVariableName(value) || value
438
450
  const {parens,none,braces} = Evaluator.sub.exec(value)?.groups || {}
439
451
  const style = (braces && ["{","}"]) || (parens && ["(",")"]) || (none && ["",""])
440
- const varValue = braces || parens || none || value
441
452
 
442
453
  return [
443
454
  c`{func}{/}{parens}${style[0]}{/}{leaf}${varValue}{/}{parens}${style[1]}{/}`,
package/src/Session.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import chokidar from "chokidar"
2
2
 
3
3
  import Command from "./Command.js"
4
- import Sass from "./Sass.js"
5
- import File from "./File.js"
6
- import Term from "./Term.js"
4
+ import {Sass, File, Term, Util} from "@gesslar/toolkit"
7
5
  import Theme from "./Theme.js"
8
- import Util from "./Util.js"
9
6
 
10
7
  /**
11
8
  * @typedef {object} SessionOptions
@@ -481,7 +478,9 @@ export default class Session {
481
478
  if(this.#watcher)
482
479
  await this.#watcher.close()
483
480
 
484
- const dependencies = Array.from(this.#theme.getDependencies()).map(d => d.getSourceFile().path)
481
+ const dependencies = Array.from(this.#theme
482
+ .getDependencies())
483
+ .map(d => d.getSourceFile().path)
485
484
 
486
485
  this.#watcher = chokidar.watch(dependencies, {
487
486
  // Prevent watching own output files
package/src/Theme.js CHANGED
@@ -13,14 +13,9 @@
13
13
  * - Write output files, supporting dry-run and hash-based skip
14
14
  * - Support watch mode for live theme development
15
15
  */
16
- import Sass from "./Sass.js"
16
+ import {Sass, DirectoryObject, File, FileObject, Term, Util, Cache} from "@gesslar/toolkit"
17
17
  import Compiler from "./Compiler.js"
18
- import DirectoryObject from "./DirectoryObject.js"
19
- import File from "./File.js"
20
- import FileObject from "./FileObject.js"
21
- import Term from "./Term.js"
22
18
  import ThemePool from "./ThemePool.js"
23
- import Util from "./Util.js"
24
19
 
25
20
  const outputFileExtension = "color-theme.json"
26
21
  const obviouslyASentinelYouCantMissSoShutUpAboutIt = "kakadoodoo"
@@ -113,7 +108,7 @@ export default class Theme {
113
108
  * Gets a specific compilation option.
114
109
  *
115
110
  * @param {string} option - The option name to retrieve
116
- * @returns {*} The option value or undefined if not set
111
+ * @returns {unknown} The option value or undefined if not set
117
112
  */
118
113
  getOption(option) {
119
114
  return this.#options?.[option] ?? undefined
@@ -282,9 +277,9 @@ export default class Theme {
282
277
  }
283
278
 
284
279
  /**
285
- * Gets the array of file dependencies.
280
+ * Gets the set of file dependencies.
286
281
  *
287
- * @returns {Set<Dependency>} Array of dependency files
282
+ * @returns {Set<Dependency>} Set of dependency files
288
283
  */
289
284
  getDependencies() {
290
285
  return this.#dependencies
@@ -306,6 +301,11 @@ export default class Theme {
306
301
  return this
307
302
  }
308
303
 
304
+ /**
305
+ * Checks if the theme has any dependencies.
306
+ *
307
+ * @returns {boolean} True if theme has dependencies
308
+ */
309
309
  hasDependencies() {
310
310
  return this.#dependencies.size > 0
311
311
  }
@@ -484,7 +484,7 @@ export default class Theme {
484
484
 
485
485
  this.#source = source
486
486
 
487
- this.addDependency(this.#sourceFile, this.#source)
487
+ this.addDependency(this.#sourceFile, new Map(Object.entries(this.#source)))
488
488
 
489
489
  return this
490
490
  }
@@ -542,6 +542,10 @@ export default class Theme {
542
542
  }
543
543
  }
544
544
 
545
+ /**
546
+ * Dependency class represents a theme file dependency.
547
+ * Manages the relationship between a file reference and its parsed source data.
548
+ */
545
549
  export class Dependency {
546
550
  #sourceFile = null
547
551
  #source = null
@@ -581,6 +585,11 @@ export class Dependency {
581
585
  return this
582
586
  }
583
587
 
588
+ /**
589
+ * Gets the parsed source data for this dependency.
590
+ *
591
+ * @returns {object|null} The parsed source data
592
+ */
584
593
  getSource() {
585
594
  return this.#source
586
595
  }
package/src/ThemePool.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * Manages resolved values, raw resolutions, and token relationships during theme compilation.
7
7
  */
8
8
 
9
- import Sass from "./Sass.js"
9
+ import {Sass} from "@gesslar/toolkit"
10
10
  import ThemeToken from "./ThemeToken.js"
11
11
 
12
12
  /**
package/src/ThemeToken.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * management, pool integration, and serialization during theme compilation.
8
8
  */
9
9
 
10
- import Sass from "./Sass.js"
10
+ import {Sass} from "@gesslar/toolkit"
11
11
  import ThemePool from "./ThemePool.js"
12
12
 
13
13
  /**
package/src/cli.js CHANGED
@@ -36,14 +36,10 @@ import process from "node:process"
36
36
  import url from "node:url"
37
37
  import c from "@gesslar/colours"
38
38
 
39
- import Cache from "./Cache.js"
40
- import Sass from "./Sass.js"
39
+ import {Cache, Sass, DirectoryObject, FileObject, Term} from "@gesslar/toolkit"
41
40
  import BuildCommand from "./BuildCommand.js"
42
- import DirectoryObject from "./DirectoryObject.js"
43
- import FileObject from "./FileObject.js"
44
41
  import LintCommand from "./LintCommand.js"
45
42
  import ResolveCommand from "./ResolveCommand.js"
46
- import Term from "./Term.js"
47
43
 
48
44
  /**
49
45
  * Main application entry point.
@@ -111,9 +107,10 @@ void (async function main() {
111
107
  .version(pkgJson.version)
112
108
 
113
109
  const commands = [BuildCommand, ResolveCommand, LintCommand]
114
-
110
+
115
111
  for(const CommandClass of commands) {
116
112
  const command = new CommandClass({cwd, packageJson: pkgJson})
113
+
117
114
  command.setCache(cache)
118
115
  await command.buildCli(program)
119
116
  command.addCliOptions(alwaysAvailable, false)
package/src/index.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file API entry point for @gesslar/sassy
3
+ *
4
+ * Exports classes and utilities for programmatic use by other npm packages.
5
+ *
6
+ * This allows other projects to import and use Sassy's functionality
7
+ * programmatically.
8
+ *
9
+ * @example
10
+ * // Import specific classes
11
+ * import { Theme, LintCommand, Compiler } from '@gesslar/sassy'
12
+ *
13
+ * // Import everything
14
+ * import * as Sassy from '@gesslar/sassy'
15
+ *
16
+ * // Create and use a Theme programmatically
17
+ * const theme = new Theme(fileObject)
18
+ * await theme.load('./my-theme.json5')
19
+ * await theme.build()
20
+ */
21
+
22
+ // Core theme functionality
23
+ export {default as Theme} from "./Theme.js"
24
+ export {default as Compiler} from "./Compiler.js"
25
+ export {default as Evaluator} from "./Evaluator.js"
26
+
27
+ // Command classes for programmatic access
28
+ export {default as Command} from "./Command.js"
29
+ export {default as BuildCommand} from "./BuildCommand.js"
30
+ export {default as LintCommand} from "./LintCommand.js"
31
+ export {default as ResolveCommand} from "./ResolveCommand.js"
32
+
33
+ // Data handling and utilities
34
+ export {default as Session} from "./Session.js"
35
+
36
+ // Color utilities
37
+ export {default as Colour} from "./Colour.js"
38
+
39
+ // Note: CLI functionality remains in cli.js and is accessible via the 'sassy'
40
+ // command when installed globally or via npx
package/src/Cache.js DELETED
@@ -1,74 +0,0 @@
1
- import Sass from "./Sass.js"
2
- import File from "./File.js"
3
- import FileObject from "./FileObject.js"
4
-
5
- /**
6
- * File system cache for theme compilation data with automatic invalidation.
7
- * Provides intelligent caching of parsed JSON5/YAML files with mtime-based
8
- * cache invalidation to optimize parallel theme compilation performance.
9
- *
10
- * The cache eliminates redundant file reads and parsing when multiple themes
11
- * import the same dependency files, while ensuring data freshness through
12
- * modification time checking.
13
- */
14
- export default class Cache {
15
- /** @type {Map<string, Date>} Map of file paths to last modification times */
16
- #modifiedTimes = new Map()
17
- /** @type {Map<string, object>} Map of file paths to parsed file data */
18
- #dataCache = new Map()
19
-
20
- /**
21
- * Removes cached data for a specific file from both time and data maps.
22
- * Used when files are modified or when cache consistency needs to be
23
- * maintained.
24
- *
25
- * @private
26
- * @param {FileObject} file - The file object to remove from cache
27
- * @returns {void}
28
- */
29
- #cleanup(file) {
30
- this.#modifiedTimes.delete(file.path)
31
- this.#dataCache.delete(file.path)
32
- }
33
-
34
- /**
35
- * Loads and caches parsed file data with automatic invalidation based on
36
- * modification time.
37
- *
38
- * Implements a sophisticated caching strategy that checks file modification
39
- * times to determine whether cached data is still valid, ensuring data
40
- * freshness while optimizing performance for repeated file access during
41
- * parallel theme compilation.
42
- *
43
- * @param {FileObject} fileObject - The file object to load and cache
44
- * @returns {Promise<object>} The parsed file data (JSON5 or YAML)
45
- * @throws {Sass} If the file cannot be found or accessed
46
- */
47
- async loadCachedData(fileObject) {
48
- const lastModified = await File.fileModified(fileObject)
49
-
50
- if(lastModified === null)
51
- throw Sass.new(`Unable to find file '${fileObject.path}'`)
52
-
53
- if(this.#modifiedTimes.has(fileObject.path)) {
54
- const lastCached = this.#modifiedTimes.get(fileObject.path)
55
-
56
- if(lastModified > lastCached) {
57
- this.#cleanup(fileObject)
58
- } else {
59
- if(!(this.#dataCache.has(fileObject.path)))
60
- this.#cleanup(fileObject)
61
- else {
62
- return this.#dataCache.get(fileObject.path)
63
- }
64
- }
65
- }
66
-
67
- const data = await File.loadDataFile(fileObject)
68
-
69
- this.#modifiedTimes.set(fileObject.path, lastModified)
70
- this.#dataCache.set(fileObject.path, data)
71
-
72
- return data
73
- }
74
- }