@gesslar/sassy 1.0.0 → 1.2.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.
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "gesslar",
6
6
  "url": "https://gesslar.dev"
7
7
  },
8
- "version": "1.0.0",
8
+ "version": "1.2.0",
9
9
  "license": "Unlicense",
10
10
  "homepage": "https://github.com/gesslar/sassy#readme",
11
11
  "repository": {
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@gesslar/colours": "^0.8.0",
47
- "@gesslar/toolkit": "^3.21.0",
47
+ "@gesslar/toolkit": "^3.29.0",
48
48
  "chokidar": "^5.0.0",
49
49
  "color-support": "^1.1.3",
50
50
  "commander": "^14.0.2",
@@ -54,13 +54,14 @@
54
54
  "yaml": "^2.8.2"
55
55
  },
56
56
  "devDependencies": {
57
- "@gesslar/uglier": "^1.0.0",
57
+ "@gesslar/uglier": "^1.2.0",
58
58
  "eslint": "^9.39.2",
59
59
  "typescript": "^5.9.3"
60
60
  },
61
61
  "scripts": {
62
62
  "clean": "rm -rfv ./dist",
63
63
  "build": "mkdir -pv ./dist && pnpm pack --pack-destination ./dist/",
64
+ "types": "node -e \"require('fs').rmSync('types',{recursive:true,force:true});\" && tsc -p tsconfig.types.json",
64
65
  "exec": "node ./src/cli.js",
65
66
  "lint": "eslint src/",
66
67
  "test": "node --test tests/**/*.test.js",
@@ -1,7 +1,7 @@
1
1
  import {EventEmitter} from "node:events"
2
2
  import process from "node:process"
3
3
 
4
- import {Sass, Term, Util} from "@gesslar/toolkit"
4
+ import {Promised, Sass, Term, Util} from "@gesslar/toolkit"
5
5
  import Command from "./Command.js"
6
6
  import Session from "./Session.js"
7
7
  import Theme from "./Theme.js"
@@ -36,6 +36,18 @@ export default class BuildCommand extends Command {
36
36
  })
37
37
  }
38
38
 
39
+ /**
40
+ * Emits an event asynchronously using the internal emitter.
41
+ * This method wraps Util.asyncEmit for convenience.
42
+ *
43
+ * @param {string} event - The event name to emit
44
+ * @param {...any} args - Arguments to pass to the event handlers
45
+ * @returns {Promise<void>} Resolves when all event handlers have completed
46
+ */
47
+ async asyncEmit(event, ...args) {
48
+ return await Util.asyncEmit(this.emitter, event, ...args)
49
+ }
50
+
39
51
  /**
40
52
  * Executes the build command for the provided theme files.
41
53
  * Processes each file in parallel, optionally watching for changes.
@@ -43,13 +55,21 @@ export default class BuildCommand extends Command {
43
55
  * @param {string[]} fileNames - Array of theme file paths to process
44
56
  * @param {object} options - Build options
45
57
  * @param {boolean} [options.watch] - Enable watch mode for file changes
46
- * @param {string} [options.output-dir] - Custom output directory path
47
- * @param {boolean} [options.dry-run] - Print JSON to stdout without writing files
48
- * @param {boolean} [options.silent] - Silent mode, only show errors or dry-run output
58
+ * @param {string} [options.outputDir] - Custom output directory path
59
+ * @param {boolean} [options.dryRun] - Print JSON to stdout without writing files
60
+ * @param {boolean} [options.silent] - Silent mode, only show errors or dry-run output
49
61
  * @returns {Promise<void>} Resolves when all files are processed
50
62
  * @throws {Error} When theme compilation fails
51
63
  */
52
64
  async execute(fileNames, options) {
65
+
66
+ /**
67
+ * @typedef {object} BuildCommandOptions
68
+ * @property {boolean} [watch] Enable watch mode for file changes
69
+ * @property {string} [outputDir] Custom output directory path
70
+ * @property {boolean} [dryRun] Print JSON to stdout without writing files
71
+ * @property {boolean} [silent] Silent mode, only show errors or dry-run output
72
+ */
53
73
  const cwd = this.getCwd()
54
74
 
55
75
  if(options.watch) {
@@ -64,7 +84,7 @@ export default class BuildCommand extends Command {
64
84
  this.emitter.on("printPrompt", () => this.#printPrompt())
65
85
  }
66
86
 
67
- const sessionResults = await Promise.allSettled(
87
+ const sessionResults = await Promised.settle(
68
88
  fileNames.map(async fileName => {
69
89
  const fileObject = await this.resolveThemeFileName(fileName, cwd)
70
90
  const theme = new Theme(fileObject, cwd, options)
@@ -74,24 +94,25 @@ export default class BuildCommand extends Command {
74
94
  })
75
95
  )
76
96
 
77
- if(sessionResults.some(theme => theme.status === "rejected")) {
78
- const rejected = sessionResults.filter(result => result.status === "rejected")
97
+ if(Promised.hasRejected(sessionResults))
98
+ Promised.throw("Creating sessions.", sessionResults)
79
99
 
80
- rejected.forEach(item => Term.error(item.reason))
81
- process.exit(1)
82
- }
100
+ // if(sessionResults.some(theme => theme.status === "rejected")) {
101
+ // const rejected = sessionResults.filter(result => result.status === "rejected")
83
102
 
84
- const sessions = sessionResults.map(result => result.value)
85
- const firstRun = await Promise.allSettled(sessions.map(
86
- async session => await session.run()))
87
- const rejected = firstRun.filter(reject => reject.status === "rejected")
103
+ // rejected.forEach(item => {
104
+ // const sassError = Sass.new("Creating session for theme file.", item.reason)
105
+ // sassError.report(options.nerd)
106
+ // })
107
+ // process.exit(1)
108
+ // }
88
109
 
89
- if(rejected.length > 0) {
90
- rejected.forEach(reject => Term.error(reject.reason))
110
+ const sessions = Promised.values(sessionResults)
111
+ const firstRun = await Promised.settle(sessions.map(
112
+ async session => await session.run()))
91
113
 
92
- if(firstRun.length === rejected.length)
93
- await Util.asyncEmit(this.emitter, "quit")
94
- }
114
+ if(Promised.hasRejected(firstRun))
115
+ Promised.throw("Executing sessions.", firstRun)
95
116
  }
96
117
 
97
118
  /**
package/src/Colour.js CHANGED
@@ -13,7 +13,12 @@ import {
13
13
  parse
14
14
  } from "culori"
15
15
 
16
- import {Util, Sass} from "@gesslar/toolkit"
16
+ import {Sass, Util} from "@gesslar/toolkit"
17
+
18
+ /**
19
+ * @import {ThemeToken} from "./ThemeToken.js"
20
+ */
21
+
17
22
  // Cache for parsed colours to improve performance
18
23
  const _colourCache = new Map()
19
24
 
package/src/Command.js CHANGED
@@ -1,4 +1,10 @@
1
- import {Sass, FileObject} from "@gesslar/toolkit"
1
+ import {FileSystem, Sass} from "@gesslar/toolkit"
2
+
3
+ /**
4
+ * @import {DirectoryObject} from "@gesslar/toolkit"
5
+ * @import {FileObject} from "@gesslar/toolkit"
6
+ * @import {Cache} from "@gesslar/toolkit"
7
+ */
2
8
 
3
9
  /**
4
10
  * Base class for command-line interface commands.
@@ -17,11 +23,10 @@ export default class Command {
17
23
  /**
18
24
  * Creates a new Command instance.
19
25
  *
20
- * @param {object} config - Configuration object
21
26
  * @param {DirectoryObject} config.cwd - Current working directory object
22
27
  * @param {object} config.packageJson - Package.json data
23
28
  */
24
- constructor({cwd,packageJson}) {
29
+ constructor({cwd, packageJson}) {
25
30
  this.#cwd = cwd
26
31
  this.#packageJson = packageJson
27
32
  }
@@ -221,17 +226,18 @@ export default class Command {
221
226
  * Resolves a theme file name to a FileObject and validates its existence.
222
227
  *
223
228
  * @param {string} fileName - The theme file name or path
224
- * @param {object} cwd - The current working directory object
229
+ * @param {DirectoryObject} cwd - The current working directory object
225
230
  * @returns {Promise<FileObject>} The resolved and validated FileObject
226
231
  * @throws {Sass} If the file does not exist
227
232
  */
228
233
  async resolveThemeFileName(fileName, cwd) {
229
- const fileObject = new FileObject(fileName, cwd)
234
+ fileName = FileSystem.relativeOrAbsolutePath(cwd.path, fileName)
235
+
236
+ const fileObject = cwd.getFile(fileName)
230
237
 
231
238
  if(!await fileObject.exists)
232
- throw Sass.new(`No such file 🤷: ${fileObject.path}`)
239
+ throw Sass.new(`No such file 🤷: ${fileObject.relativeTo(cwd)}`)
233
240
 
234
241
  return fileObject
235
242
  }
236
-
237
243
  }
package/src/Compiler.js CHANGED
@@ -11,9 +11,14 @@
11
11
  * Supports extension points for custom phases and output formats.
12
12
  */
13
13
 
14
- import {Collection, Data, FileObject, Sass, Term, Util} from "@gesslar/toolkit"
14
+ import {Collection, Data, Sass, Term, Util} from "@gesslar/toolkit"
15
+
15
16
  import Evaluator from "./Evaluator.js"
16
17
 
18
+ /**
19
+ * @import {Theme} from "./Theme.js"
20
+ */
21
+
17
22
  /**
18
23
  * Main compiler class for processing theme source files.
19
24
  * Handles the complete compilation pipeline from source to VS Code theme output.
@@ -39,6 +44,7 @@ export default class Compiler {
39
44
  const config = this.#decomposeObject(sourceConfig)
40
45
 
41
46
  evaluate(config)
47
+
42
48
  const recompConfig = this.#composeObject(config)
43
49
 
44
50
  const header = {
@@ -49,12 +55,11 @@ export default class Compiler {
49
55
 
50
56
  // Let's get all of the imports!
51
57
  const imports = recompConfig.import ?? []
52
- const {imported,importByFile} =
53
- await this.#import(imports, theme)
58
+ const {imported,importByFile} = await this.#import(imports, theme)
54
59
 
55
- importByFile.forEach((themeData,file) => {
56
- theme.addDependency(file,themeData)
57
- })
60
+ importByFile.forEach(
61
+ (themeData, file) => theme.addDependency(file,themeData)
62
+ )
58
63
 
59
64
  // Handle tokenColors separately - imports first, then main source
60
65
  // (append-only)
@@ -149,15 +154,18 @@ export default class Compiler {
149
154
  : imports
150
155
 
151
156
  if(!Collection.isArrayUniform(imports, "string"))
152
- throw new Sass(
157
+ throw Sass.new(
153
158
  `All import entries must be strings. Got ${JSON.stringify(imports)}`
154
159
  )
155
160
 
156
161
  const loaded = new Map()
157
162
 
163
+ const themeSource = theme.getSourceFile()
164
+ const themeDirectory = themeSource.parent
165
+
158
166
  for(const importing of imports) {
159
167
  try {
160
- const file = new FileObject(importing, theme.getSourceFile().directory)
168
+ const file = themeDirectory.getFile(importing)
161
169
 
162
170
  // Get the cached version or a new version. Who knows? I don't know.
163
171
  const {result, cost} = await Util.time(async() => {
@@ -165,10 +173,11 @@ export default class Compiler {
165
173
  })
166
174
 
167
175
  if(theme.getOptions().nerd) {
176
+ const cwd = theme.getCwd()
168
177
  Term.status([
169
178
  ["muted", Util.rightAlignText(`${cost.toLocaleString()}ms`, 10), ["[","]"]],
170
179
  "",
171
- ["muted", `${file.toString()}`],
180
+ ["muted", `${file.relativeTo(cwd)}`],
172
181
  ["muted", `${theme.getName()}`,["(",")"]],
173
182
  ], theme.getOptions())
174
183
  }
@@ -23,6 +23,10 @@ import Evaluator from "./Evaluator.js"
23
23
  import Theme from "./Theme.js"
24
24
  import {Term} from "@gesslar/toolkit"
25
25
 
26
+ /**
27
+ * @import {ThemePool} from "./ThemePool.js"
28
+ */
29
+
26
30
  // oops, need to have @gesslar/colours support this, too!
27
31
  // ansiColors.enabled = colorSupport.hasBasic
28
32
 
package/src/Session.js CHANGED
@@ -1,6 +1,12 @@
1
1
  import chokidar from "chokidar"
2
+ import path from "node:path"
2
3
 
3
- import {Sass, Term, Util} from "@gesslar/toolkit"
4
+ import {Promised, Sass, Term, Util} from "@gesslar/toolkit"
5
+
6
+ /**
7
+ * @import {Command} from "./Command.js"
8
+ * @import {Theme} from "./Theme.js"
9
+ */
4
10
 
5
11
  /**
6
12
  * @typedef {object} SessionOptions
@@ -19,6 +25,11 @@ import {Sass, Term, Util} from "@gesslar/toolkit"
19
25
  * @property {string} [error] - Error message when success is false
20
26
  */
21
27
 
28
+ /**
29
+ * @import {Theme} from "./Theme.js"
30
+ * @import {Command} from "./Command.js"
31
+ */
32
+
22
33
  export default class Session {
23
34
  /**
24
35
  * The theme instance managed by this session.
@@ -170,8 +181,9 @@ export default class Session {
170
181
  async run() {
171
182
 
172
183
  this.#building = true
184
+
173
185
  await this.#command.asyncEmit("building")
174
- this.#command.asyncEmit("recordBuildStart", this.#theme)
186
+ await this.#command.asyncEmit("recordBuildStart", this.#theme)
175
187
  await this.#buildPipeline()
176
188
 
177
189
  // This must come after, or you will fuck up the watching!
@@ -224,6 +236,7 @@ export default class Session {
224
236
  `${this.#theme.getName()} loaded`,
225
237
  ["info", `${bytes.toLocaleString()} bytes`, ["[","]"]]
226
238
  ], this.#options)
239
+
227
240
  /**
228
241
  * ****************************************************************
229
242
  * Have the theme build itself.
@@ -236,31 +249,24 @@ export default class Session {
236
249
  .map(d => d.getSourceFile())
237
250
  .filter(f => f != null) // Filter out any null/undefined files
238
251
 
239
- const compileResult = await Promise
240
- .allSettled(dependencyFiles.map(async fileObject => {
241
- if(!fileObject) {
242
- throw new Error("Invalid dependency file object")
243
- }
244
-
245
- const fileName = fileObject.toString()
246
- const fileSize = await fileObject.size()
252
+ const cwd = this.#theme.getCwd()
253
+ const settled = await Promised
254
+ .settle(dependencyFiles.map(async fileObject => {
255
+ if(!fileObject)
256
+ throw Sass.new("Invalid dependency file object")
247
257
 
248
- return [fileName, fileSize]
258
+ return [fileObject.relativeTo(cwd), await fileObject.size()]
249
259
  }))
250
260
 
251
- const rejected = compileResult.filter(result => result.status === "rejected")
261
+ if(Promised.hasRejected(settled))
262
+ throw Sass.new("Compiling dependencies.", settled)
252
263
 
253
- if(rejected.length > 0) {
254
- rejected.forEach(reject => Term.error(reject.reason))
255
- throw new Error("Compilation failed")
256
- }
257
-
258
- const dependencies = compileResult
264
+ const dependencies = Promised.values(settled)
259
265
  .slice(1)
260
266
  .map(dep => dep?.value)
261
267
  .filter(Boolean)
262
268
 
263
- const totalBytes = compileResult.reduce(
269
+ const totalBytes = settled.reduce(
264
270
  (acc,curr) => acc + (curr?.value[1] ?? 0), 0
265
271
  )
266
272
 
@@ -271,7 +277,7 @@ export default class Session {
271
277
  ["[","]"]
272
278
  ],
273
279
  `${this.#theme.getName()} compiled`,
274
- ["success", `${compileResult[0].value[1].toLocaleString()} bytes`, ["[","]"]],
280
+ ["success", `${settled[0].value[1].toLocaleString()} bytes`, ["[","]"]],
275
281
  ["info", `${totalBytes.toLocaleString()} total bytes`, ["(",")"]],
276
282
  ], this.#options)
277
283
 
@@ -303,7 +309,7 @@ export default class Session {
303
309
  file: outputFile,
304
310
  bytes: writeBytes
305
311
  } = writeResult.result
306
- const outputFilename = outputFile.toString()
312
+ const outputFilename = outputFile.relativeTo(cwd)
307
313
  const status = [
308
314
  [
309
315
  "success",
@@ -327,7 +333,7 @@ export default class Session {
327
333
  Term.status(status, this.#options)
328
334
 
329
335
  // Track successful build
330
- this.#command.asyncEmit("recordBuildSucceed", this.#theme)
336
+ await this.#command.asyncEmit("recordBuildSucceed", this.#theme)
331
337
  this.#history.push({
332
338
  timestamp: buildStart,
333
339
  loadTime: loadCost,
@@ -348,36 +354,47 @@ export default class Session {
348
354
  error: error.message
349
355
  })
350
356
 
351
- Sass.new("Build process failed.", error).report(this.#options.nerd)
357
+ throw Sass.new("Build process failed.", error)
352
358
  } finally {
353
359
  this.#building = false
354
- this.#command.asyncEmit("finishedBuilding")
360
+ await this.#command.asyncEmit("finishedBuilding")
355
361
  }
356
362
  }
357
363
 
358
364
  /**
359
365
  * Handles a file change event and triggers a rebuild for the theme.
360
366
  *
361
- * @param {string} changed - Path to the changed file
367
+ * @param {string} changed - Path to the changed file (from chokidar)
362
368
  * @param {object} _stats - OS-level file stat information
363
369
  * @returns {Promise<void>}
364
370
  */
365
371
  async #handleFileChange(changed, _stats) {
372
+ let startedPipeline = false
373
+
366
374
  try {
367
375
  if(this.#building)
368
376
  return
369
377
 
370
378
  this.#building = true
371
- this.#command.asyncEmit("building")
379
+ await this.#command.asyncEmit("building")
380
+
381
+ // Normalize the changed path from chokidar for comparison
382
+ const normalizedChanged = path.resolve(changed)
372
383
 
373
384
  const changedFile = Array.from(this.#theme.getDependencies()).find(
374
- dep => dep.getSourceFile().path === changed
385
+ dep => {
386
+ const depPath = dep.getSourceFile().path
387
+ const normalizedDepPath = path.resolve(depPath)
388
+
389
+ return normalizedDepPath === normalizedChanged
390
+ }
375
391
  )?.getSourceFile()
376
392
 
377
393
  if(!changedFile)
378
394
  return
379
395
 
380
- const fileName = changedFile.toString()
396
+ const cwd = this.#theme.getCwd()
397
+ const fileName = changedFile.relativeTo(cwd)
381
398
 
382
399
  const message = [
383
400
  ["info", "REBUILDING", ["[","]"]],
@@ -390,17 +407,24 @@ export default class Session {
390
407
  Term.status(message)
391
408
 
392
409
  await this.#resetWatcher()
410
+ startedPipeline = true
393
411
  await this.#buildPipeline()
412
+ } catch(error) {
413
+ const sassError = Sass.new("Handling file change.", error)
414
+ sassError.report(this.#options?.nerd)
415
+
416
+ if(!startedPipeline)
417
+ await this.#command.asyncEmit("finishedBuilding")
394
418
  } finally {
395
419
  this.#building = false
396
420
  }
397
421
  }
398
422
 
399
423
  /**
400
- * Displays a formatted summary of the session's build statistics and performance.
401
- * Shows total builds, success/failure counts, success rate percentage, and timing
402
- * information from the most recent build. Used during session cleanup to provide
403
- * final statistics to the user.
424
+ * Displays a formatted summary of the session's build statistics and
425
+ * performance. Shows total builds, success/failure counts, success rate
426
+ * percentage, and timing information from the most recent build. Used during
427
+ * session cleanup to provide final statistics to the user.
404
428
  *
405
429
  * @returns {void}
406
430
  */
@@ -448,14 +472,16 @@ export default class Session {
448
472
  return
449
473
 
450
474
  try {
451
- this.#command.asyncEmit("recordBuildStart", this.#theme)
475
+ await this.#command.asyncEmit("recordBuildStart", this.#theme)
452
476
  this.#building = true
453
477
  await this.#resetWatcher()
454
- this.#command.asyncEmit("building")
478
+ await this.#command.asyncEmit("building")
455
479
  await this.#buildPipeline(true)
456
480
  } catch(error) {
457
481
  await this.#command.asyncEmit("recordBuildFail", this.#theme)
458
- throw Sass.new("Handling rebuild request.", error)
482
+ const sassError = Sass.new("Handling rebuild request.", error)
483
+ sassError.report(this.#options?.nerd)
484
+ throw sassError
459
485
  } finally {
460
486
  this.#building = false
461
487
  }
@@ -470,9 +496,15 @@ export default class Session {
470
496
  if(this.#watcher)
471
497
  await this.#watcher.close()
472
498
 
499
+ // Get real paths for chokidar (normalized for consistency)
473
500
  const dependencies = Array.from(this.#theme
474
501
  .getDependencies())
475
- .map(d => d.getSourceFile().path)
502
+ .map(d => {
503
+ const filePath = d.getSourceFile().path
504
+
505
+ // Normalize to absolute path for chokidar
506
+ return path.resolve(filePath)
507
+ })
476
508
 
477
509
  this.#watcher = chokidar.watch(dependencies, {
478
510
  // Prevent watching own output files
package/src/Theme.js CHANGED
@@ -13,10 +13,16 @@
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, DirectoryObject, FileObject, Term, Util} from "@gesslar/toolkit"
16
+ import {Sass, Term, Util} from "@gesslar/toolkit"
17
17
  import Compiler from "./Compiler.js"
18
18
  import ThemePool from "./ThemePool.js"
19
19
 
20
+ /**
21
+ * @import {Cache} from "@gesslar/toolkit"
22
+ * @import {DirectoryObject} from "@gesslar/toolkit"
23
+ * @import {FileObject} from "@gesslar/toolkit"
24
+ */
25
+
20
26
  const outputFileExtension = "color-theme.json"
21
27
  const obviouslyASentinelYouCantMissSoShutUpAboutIt = "kakadoodoo"
22
28
 
@@ -39,6 +45,7 @@ export default class Theme {
39
45
  #sourceFile = null
40
46
  #source = null
41
47
  #options = null
48
+
42
49
  /**
43
50
  * The dependencies of this theme.
44
51
  *
@@ -56,6 +63,8 @@ export default class Theme {
56
63
  #outputJson = null
57
64
  #outputFileName = null
58
65
  #outputHash = null
66
+ #outputFile = null
67
+ #outputDir = null
59
68
 
60
69
  #cwd = null
61
70
 
@@ -72,6 +81,16 @@ export default class Theme {
72
81
  this.#outputFileName = `${this.#name}.${outputFileExtension}`
73
82
  this.#options = options
74
83
  this.#cwd = cwd
84
+
85
+ // Let's create the output directory, since we're gonna needs it.
86
+ // If outputDir is not provided or is ".", use the cwd itself
87
+ const outputDir = options.outputDir && options.outputDir !== "."
88
+ ? cwd.getDirectory(options.outputDir)
89
+ : cwd
90
+ const outputFile = outputDir.getFile(this.#outputFileName)
91
+
92
+ this.#outputFile = outputFile
93
+ this.#outputDir = outputDir
75
94
  }
76
95
 
77
96
  /**
@@ -479,7 +498,7 @@ export default class Theme {
479
498
 
480
499
  if(!source[PropertyKey.CONFIG.description])
481
500
  throw Sass.new(
482
- `Source file does not contain '${PropertyKey.CONFIG.description}' property: ${this.#sourceFile.path}`
501
+ `Source file does not contain '${PropertyKey.CONFIG.description}' property: ${this.#sourceFile.relativeTo(this.#cwd)}`
483
502
  )
484
503
 
485
504
  this.#source = source
@@ -497,7 +516,6 @@ export default class Theme {
497
516
  */
498
517
  async build() {
499
518
  const compiler = new Compiler()
500
-
501
519
  await compiler.compile(this)
502
520
 
503
521
  return this
@@ -512,8 +530,7 @@ export default class Theme {
512
530
  */
513
531
  async write(force=false) {
514
532
  const output = this.#outputJson
515
- const outputDir = new DirectoryObject(this.#options.outputDir)
516
- const file = new FileObject(this.#outputFileName, outputDir)
533
+ const file = this.#outputFile
517
534
 
518
535
  if(this.#options.dryRun) {
519
536
  Term.log(this.#outputJson)
@@ -533,8 +550,8 @@ export default class Theme {
533
550
  }
534
551
 
535
552
  // Real write (timed)
536
- if(!await outputDir.exists)
537
- await outputDir.assureExists()
553
+ if(!await this.#outputDir.exists)
554
+ await this.#outputDir.assureExists()
538
555
 
539
556
  await file.write(output)
540
557
 
package/src/cli.js CHANGED
@@ -36,7 +36,7 @@ import process from "node:process"
36
36
  import url from "node:url"
37
37
  import c from "@gesslar/colours"
38
38
 
39
- import {Cache, Sass, DirectoryObject, FileObject, Term} from "@gesslar/toolkit"
39
+ import {Cache, DirectoryObject, FileObject, Sass, Term} from "@gesslar/toolkit"
40
40
  import BuildCommand from "./BuildCommand.js"
41
41
  import LintCommand from "./LintCommand.js"
42
42
  import ResolveCommand from "./ResolveCommand.js"
@@ -74,9 +74,11 @@ void (async function main() {
74
74
  c.alias.set("modified-bracket", "{F165}")
75
75
  c.alias.set("muted", "{F240}")
76
76
  c.alias.set("muted-bracket", "{F244}")
77
+
77
78
  // Lint command
78
79
  c.alias.set("context", "{F159}")
79
80
  c.alias.set("loc", "{F148}")
81
+
80
82
  // Resolve command
81
83
  c.alias.set("head", "{F220}")
82
84
  c.alias.set("leaf", "{F151}")
@@ -89,11 +91,12 @@ void (async function main() {
89
91
  c.alias.set("arrow", "{F033}")
90
92
 
91
93
  const cache = new Cache()
92
- const cr = new DirectoryObject(url.fileURLToPath(new url.URL("..", import.meta.url)))
93
- const cwd = new DirectoryObject(process.cwd())
94
- const packageJson = new FileObject("package.json", cr)
95
- const pkgJsonResult = await cache.loadCachedData(packageJson)
96
- const pkgJson = pkgJsonResult
94
+ const cwd = DirectoryObject.fromCwd()
95
+ const packageJson = new FileObject(
96
+ "package.json",
97
+ url.fileURLToPath(new url.URL("..", import.meta.url))
98
+ )
99
+ const pkgJson = await packageJson.loadData()
97
100
 
98
101
  // These are available to all subcommands in addition to whatever they
99
102
  // provide.
@@ -116,36 +119,13 @@ void (async function main() {
116
119
  command.addCliOptions(alwaysAvailable, false)
117
120
  }
118
121
 
119
- // // Add the build subcommand
120
- // const buildCommand = new BuildCommand({cwd, packageJson: pkgJson})
121
-
122
- // buildCommand.cache = cache
123
-
124
- // void(await buildCommand.buildCli(program))
125
- // .addCliOptions(alwaysAvailable, false)
126
-
127
- // // Add the resolve subcommand
128
- // const resolveCommand = new ResolveCommand({cwd, packageJson: pkgJson})
129
-
130
- // resolveCommand.cache = cache
131
-
132
- // void(await resolveCommand.buildCli(program))
133
- // .addCliOptions(alwaysAvailable, false)
134
-
135
- // // Add the lint subcommand
136
- // const lintCommand = new LintCommand({cwd, packageJson: pkgJson})
137
-
138
- // lintCommand.cache = cache
139
-
140
- // void(await lintCommand.buildCli(program))
141
- // .addCliOptions(alwaysAvailable, false)
142
-
143
122
  // Let'er rip, bitches! VROOM VROOM, motherfucker!!
144
123
  await program.parseAsync()
145
124
 
146
125
  } catch(error) {
147
- Sass.new("Starting Sassy.", error)
148
- .report(sassyOptions.nerd || true)
126
+ Sass
127
+ .from(error, "Starting Sassy.")
128
+ .report(sassyOptions.nerd ?? false)
149
129
 
150
130
  process.exit(1)
151
131
  }