coralite-scripts 0.36.3 → 0.37.1

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/bin/index.js CHANGED
@@ -8,7 +8,7 @@ import pkg from '../package.json' with { type: 'json' }
8
8
  import buildStyles from '../libs/build-styles.js'
9
9
  import { join, relative, dirname } from 'node:path'
10
10
  import { deleteDirectoryRecursive, copyDirectory, toMS, toTime, displayError, displayWarning, displayInfo } from '../libs/build-utils.js'
11
- import { Coralite } from 'coralite'
11
+ import { createCoralite } from 'coralite'
12
12
  import { mkdir, writeFile } from 'node:fs/promises'
13
13
  import ora from 'ora'
14
14
 
@@ -58,10 +58,8 @@ if (mode === 'dev') {
58
58
  // delete old output files
59
59
  deleteDirectoryRecursive(config.output)
60
60
 
61
- const start = process.hrtime()
62
-
63
61
  // start coralite
64
- const coralite = new Coralite({
62
+ const coralite = await createCoralite({
65
63
  components: config.components,
66
64
  pages: config.pages,
67
65
  plugins: config.plugins,
@@ -83,10 +81,10 @@ if (mode === 'dev') {
83
81
  }
84
82
  }
85
83
  })
86
- await coralite.initialise()
87
84
 
88
85
  let spinner
89
86
  let pageCount = 0
87
+ let skippedCount = 0
90
88
 
91
89
  try {
92
90
  let componentCount = 0
@@ -95,8 +93,24 @@ if (mode === 'dev') {
95
93
  spinner = ora('Building pages...').start()
96
94
  }
97
95
 
96
+ const updateSpinnerText = () => {
97
+ if (skippedCount > 0) {
98
+ spinner.text = `Building pages... (${pageCount} completed, ${skippedCount} skipped)`
99
+ } else {
100
+ spinner.text = `Building pages... (${pageCount} completed)`
101
+ }
102
+ }
103
+
98
104
  // compile website
99
105
  await coralite.build(async (result) => {
106
+ if (result.status === 'skipped') {
107
+ skippedCount++
108
+ if (!options.verbose) {
109
+ updateSpinnerText()
110
+ }
111
+ return
112
+ }
113
+
100
114
  const relativeDir = relative(config.pages, result.path.dirname)
101
115
  const outDir = join(config.output, relativeDir)
102
116
  const outFile = join(outDir, result.path.filename)
@@ -108,7 +122,7 @@ if (mode === 'dev') {
108
122
  process.stdout.write(toTime() + toMS(result.duration) + dash + result.path.pathname + '\n')
109
123
  } else {
110
124
  pageCount++
111
- spinner.text = `Building pages... (${pageCount} completed)`
125
+ updateSpinnerText()
112
126
  }
113
127
  })
114
128
 
@@ -130,7 +144,11 @@ if (mode === 'dev') {
130
144
  }
131
145
 
132
146
  if (!options.verbose) {
133
- spinner.succeed(`Pages built (${pageCount} completed)`)
147
+ if (skippedCount > 0) {
148
+ spinner.succeed(`Pages built (${pageCount} completed, ${skippedCount} skipped)`)
149
+ } else {
150
+ spinner.succeed(`Pages built (${pageCount} completed)`)
151
+ }
134
152
  if (componentCount > 0) {
135
153
  ora(`Components built (${componentCount} completed)`).succeed()
136
154
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../libs/config.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,sCAzBW,oBAAoB,GAClB,oBAAoB,CAmJhC;0CA7JsC,mBAAmB"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../libs/config.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,sCAzBW,oBAAoB,GAClB,oBAAoB,CAoJhC;0CA9JsC,mBAAmB"}
@@ -11,6 +11,9 @@ export type CoraliteScriptBaseConfig = {
11
11
  server?: {
12
12
  port: number;
13
13
  };
14
+ /**
15
+ * - The configuration options for style processing.
16
+ */
14
17
  styles?: {
15
18
  input?: string[];
16
19
  processors?: {
@@ -41,4 +44,5 @@ export type CoraliteScriptOptions = {
41
44
  verbose?: boolean;
42
45
  };
43
46
  import type { Options } from 'sass';
47
+ import type { CoraliteConfig } from 'coralite/types';
44
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.js"],"names":[],"mappings":";;;;;;YAOc,MAAM;;;;aAEjB;QAA0B,IAAI,EAAnB,MAAM;KACjB;aACA;QAA6B,KAAK,GAAvB,MAAM,EAAE;QACQ,UAAU,GACrC;YAAgD,IAAI,GAAzC,QAAQ,OAAO,CAAC;YACW,OAAO,GAC7C;gBAA0E,OAAO,GAAtE,OAAO,SAAS,EAAE,cAAc,EAAE;aAC7C;SAAA;KAAA;;;;WAAW,YAAY,GAAG,aAAa;;mCAI7B,wBAAwB,iBAAiB;;;;;UAKxC,OAAO;;;;YACP,OAAO;;;;cACP,OAAO;;6BAzBK,MAAM"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.js"],"names":[],"mappings":";;;;;;YAOc,MAAM;;;;aAEjB;QAA0B,IAAI,EAAnB,MAAM;KACjB;;;;aACA;QAA6B,KAAK,GAAvB,MAAM,EAAE;QACQ,UAAU,GACrC;YAAgD,IAAI,GAAzC,QAAQ,OAAO,CAAC;YACW,OAAO,GAC7C;gBAA0E,OAAO,GAAtE,OAAO,SAAS,EAAE,cAAc,EAAE;aAC7C;SAAA;KAAA;;;;WAAW,YAAY,GAAG,aAAa;;mCAI7B,wBAAwB,GAAG,cAAc;;;;;UAKxC,OAAO;;;;YACP,OAAO;;;;cACP,OAAO;;6BAzBK,MAAM;oCADC,gBAAgB"}
@@ -12,13 +12,10 @@ import path from 'path'
12
12
 
13
13
  /**
14
14
  * Compiles SCSS and CSS files with optional PostCSS processing
15
- * @param {Object} options
15
+ * @param {Object} options - The configuration options for building styles.
16
16
  * @param {string[]} options.input - Array of input file paths
17
17
  * @param {string} options.output - Output directory for compiled CSS files
18
18
  * @param {Object} [options.processors] - Processor configurations
19
- * @param {import('sass').Options<'async'>} [options.processors.scss] - Sass options
20
- * @param {Object} [options.processors.postcss] - PostCSS options
21
- * @param {import('postcss').AcceptedPlugin[]} [options.processors.postcss.plugins] - PostCSS plugins
22
19
  * @returns {Promise<BuildStylesResult[]>}
23
20
  */
24
21
  async function buildStyles ({
@@ -29,6 +26,7 @@ async function buildStyles ({
29
26
  const scssOptions = {
30
27
  sourceMap: true,
31
28
  loadPaths: ['node_modules'],
29
+ // @ts-ignore
32
30
  silenceDeprecations: [
33
31
  'color-functions',
34
32
  'import',
@@ -50,6 +48,7 @@ async function buildStyles ({
50
48
  let map
51
49
 
52
50
  if (ext === '.scss' || ext === '.sass') {
51
+ // @ts-ignore
53
52
  const result = await sass.compileAsync(filePath, scssOptions)
54
53
  css = result.css
55
54
  map = result.sourceMap
@@ -2,6 +2,7 @@ import colours from 'kleur'
2
2
  import fs from 'node:fs'
3
3
  import path from 'node:path'
4
4
  import { cp } from 'node:fs/promises'
5
+ import { fileURLToPath } from 'node:url'
5
6
 
6
7
  /**
7
8
  * Creates current time in format [HH:MM:SS].mmm (milliseconds), colored with ANSI colors, and formatted as bold white string for better readability of logs or console output
@@ -111,6 +112,49 @@ export function displayError (message, error) {
111
112
  }
112
113
 
113
114
  if (isCoraliteError) {
115
+ const displayFile = targetError.stackFile || targetError.filePath
116
+ if (displayFile) {
117
+ let absolutePath = displayFile
118
+ if (absolutePath.startsWith('file://')) {
119
+ try {
120
+ absolutePath = fileURLToPath(absolutePath)
121
+ } catch {
122
+ }
123
+ }
124
+
125
+ const relativePath = path.relative(process.cwd(), absolutePath)
126
+ let location = relativePath
127
+ if (targetError.line) {
128
+ location += `:${targetError.line}`
129
+ if (targetError.column) {
130
+ location += `:${targetError.column}`
131
+ }
132
+ }
133
+
134
+ process.stdout.write(colours.bold(`> ${location}: `) + colours.red('error: ') + targetError.message + '\n')
135
+
136
+ if (fs.existsSync(absolutePath) && targetError.line) {
137
+ try {
138
+ const content = fs.readFileSync(absolutePath, 'utf8')
139
+ const lines = content.split('\n')
140
+ const errorLine = lines[targetError.line - 1]
141
+ if (errorLine !== undefined) {
142
+ const gutter = ` ${targetError.line} | `
143
+ process.stdout.write(colours.grey(gutter) + errorLine + '\n')
144
+ if (targetError.column) {
145
+ // To handle tabs correctly, we take the prefix of the line up to the error column
146
+ // and replace all non-whitespace characters with spaces.
147
+ const prefix = errorLine.substring(0, targetError.column - 1)
148
+ const padding = ' '.repeat(gutter.length) + prefix.replace(/\S/g, ' ')
149
+ process.stdout.write(padding + colours.cyan('~') + '\n')
150
+ }
151
+ }
152
+ } catch {
153
+ }
154
+ }
155
+ process.stdout.write('\n')
156
+ }
157
+
114
158
  process.stdout.write(indent + colours.magenta('Component context:') + '\n')
115
159
  if (targetError.componentId) {
116
160
  process.stdout.write(indent + ' ' + colours.cyan('ID: ') + targetError.componentId + '\n')
@@ -129,15 +173,17 @@ export function displayError (message, error) {
129
173
 
130
174
  let errorDetails = ''
131
175
 
132
- if (error instanceof Error ||
133
- (error !== null
134
- && typeof error === 'object'
135
- && 'message' in error
136
- && 'stack' in error
176
+ const errorToStack = error.cause && error.cause.stack ? error.cause : error
177
+
178
+ if (errorToStack instanceof Error ||
179
+ (errorToStack !== null
180
+ && typeof errorToStack === 'object'
181
+ && 'message' in errorToStack
182
+ && 'stack' in errorToStack
137
183
  )
138
184
  ) {
139
185
  // @ts-ignore
140
- errorDetails = error.stack || error.message
186
+ errorDetails = errorToStack.stack || errorToStack.message
141
187
  } else if (typeof error === 'string') {
142
188
  errorDetails = error
143
189
  } else if (typeof error === 'object' && error !== null) {
package/libs/config.js CHANGED
@@ -91,6 +91,7 @@ export function defineConfig (options) {
91
91
  }
92
92
  }
93
93
 
94
+ // @ts-ignore
94
95
  if (options.styles.type) {
95
96
  throw new Error('Coralite Config Error: The "styles" configuration has been upgraded. "input" must now be an array, and "type" has been replaced by the "processors" object. Please update your coralite.config.js.')
96
97
  }
package/libs/server.js CHANGED
@@ -6,8 +6,8 @@ import buildStyles from './build-styles.js'
6
6
  import { displayError, displayInfo, displayWarning, displaySuccess, toCode, toMS, toTime, deleteDirectoryRecursive } from './build-utils.js'
7
7
  import { dirname, extname, join, normalize, relative, sep } from 'path'
8
8
  import { access, constants, mkdir, readFile, writeFile } from 'fs/promises'
9
- import Coralite from 'coralite'
10
- import { existsSync, mkdirSync } from 'fs'
9
+ import { createCoralite } from 'coralite'
10
+ import { existsSync } from 'fs'
11
11
  import portfinder from 'portfinder'
12
12
 
13
13
  /**
@@ -15,7 +15,7 @@ import portfinder from 'portfinder'
15
15
  */
16
16
 
17
17
  /**
18
- * Resolves the requested path to a physical file or a virtual page.
18
+ * Resolves the requested path to a file or a virtual page.
19
19
  *
20
20
  * @param {string} reqPath - The requested URL path.
21
21
  * @param {string} extension - The extension of the requested path.
@@ -26,35 +26,56 @@ import portfinder from 'portfinder'
26
26
  */
27
27
  export async function resolveSource (reqPath, extension, config, coralite, memoryPageSource) {
28
28
  const candidates = []
29
+ const pagesRoot = normalize(config.pages)
30
+ const isPathInsideRoot = (rootPath, candidatePath) => {
31
+ const rel = relative(rootPath, candidatePath)
32
+ return rel !== '..' && !rel.startsWith(`..${sep}`) && rel !== '' ? true : candidatePath === rootPath
33
+ }
29
34
 
30
35
  // Ensure relative path doesn't start with / for joining
31
36
  const relPath = reqPath.startsWith('/') ? reqPath.slice(1) : reqPath
32
37
 
33
38
  if (reqPath.endsWith('/')) {
34
39
  const key = join(relPath, 'index.html')
35
- candidates.push({
36
- path: join(config.pages, key),
37
- key
38
- })
40
+ const candidatePath = normalize(join(config.pages, key))
41
+
42
+ if (isPathInsideRoot(pagesRoot, candidatePath)) {
43
+ candidates.push({
44
+ path: candidatePath,
45
+ key
46
+ })
47
+ }
39
48
  } else if (extension === '.html') {
40
49
  const key = relPath
41
- candidates.push({
42
- path: join(config.pages, key),
43
- key
44
- })
50
+ const candidatePath = normalize(join(config.pages, key))
51
+
52
+ if (isPathInsideRoot(pagesRoot, candidatePath)) {
53
+ candidates.push({
54
+ path: candidatePath,
55
+ key
56
+ })
57
+ }
45
58
  } else {
46
59
  // No extension, no trailing slash
47
60
  const key1 = relPath + '.html'
48
- candidates.push({
49
- path: join(config.pages, key1),
50
- key: key1
51
- })
61
+ const candidatePath1 = normalize(join(config.pages, key1))
62
+
63
+ if (isPathInsideRoot(pagesRoot, candidatePath1)) {
64
+ candidates.push({
65
+ path: candidatePath1,
66
+ key: key1
67
+ })
68
+ }
52
69
 
53
70
  const key2 = join(relPath, 'index.html')
54
- candidates.push({
55
- path: join(config.pages, key2),
56
- key: key2
57
- })
71
+ const candidatePath2 = normalize(join(config.pages, key1))
72
+
73
+ if (isPathInsideRoot(pagesRoot, candidatePath2)) {
74
+ candidates.push({
75
+ path: candidatePath2,
76
+ key: key2
77
+ })
78
+ }
58
79
  }
59
80
 
60
81
  for (const candidate of candidates) {
@@ -137,7 +158,7 @@ async function server (config, options) {
137
158
 
138
159
  try {
139
160
  await access(configPath, constants.F_OK)
140
- } catch (err) {
161
+ } catch {
141
162
  return
142
163
  }
143
164
 
@@ -157,7 +178,7 @@ async function server (config, options) {
157
178
  }
158
179
  }
159
180
  }
160
- } catch (error) {
181
+ } catch {
161
182
  // ignore any other unexpected errors during reading/parsing
162
183
  }
163
184
  }
@@ -185,7 +206,7 @@ async function server (config, options) {
185
206
 
186
207
  pageCache.clear()
187
208
 
188
- coralite = new Coralite({
209
+ coralite = await createCoralite({
189
210
  components: currentConfig.components,
190
211
  pages: currentConfig.pages,
191
212
  plugins: currentConfig.plugins,
@@ -210,7 +231,6 @@ async function server (config, options) {
210
231
  }
211
232
  })
212
233
 
213
- await coralite.initialise()
214
234
 
215
235
  displaySuccess('Coralite initialized successfully')
216
236
 
@@ -225,6 +245,7 @@ async function server (config, options) {
225
245
 
226
246
  for (const plugin of currentConfig.plugins) {
227
247
  if (typeof plugin.server === 'function') {
248
+ // @ts-ignore
228
249
  await plugin.server(app, coralite)
229
250
  }
230
251
  }
@@ -255,9 +276,8 @@ async function server (config, options) {
255
276
 
256
277
  // middleware to log request information including response time and status code
257
278
  app.use(function (req, res, next) {
258
- const start = process.hrtime()
259
-
260
279
  if (options.verbose) {
280
+ const start = process.hrtime()
261
281
  // when the response is finished, calculate duration and log details
262
282
  res.on('finish', function () {
263
283
  const dash = colours.gray(' ─ ')
@@ -294,14 +314,11 @@ async function server (config, options) {
294
314
  cacheControl: false
295
315
  }))
296
316
 
297
- const start = process.hrtime()
298
-
299
317
  // rebuild CSS and send notification
300
318
  const results = await buildStyles({
301
319
  input: config.styles.input,
302
320
  output: join(config.output, 'assets', 'css'),
303
- processors: config.styles.processors,
304
- start
321
+ processors: config.styles.processors
305
322
  })
306
323
 
307
324
  const dash = colours.gray(' ─ ')
@@ -376,7 +393,7 @@ async function server (config, options) {
376
393
  // Only set item if it's not already in the collection (virtual pages are pre-registered)
377
394
  const item = coralite.pages.getItem(pathname)
378
395
 
379
- if (!item || item.physical !== false) {
396
+ if (!item || item.virtual !== true) {
380
397
  await coralite.pages.setItem(pathname)
381
398
  }
382
399
 
@@ -470,6 +487,7 @@ async function server (config, options) {
470
487
  // Helper function to debounce compilations
471
488
  const debounceCompile = () => {
472
489
  if (compileTimeout) {
490
+ // @ts-ignore
473
491
  clearTimeout(compileTimeout)
474
492
  }
475
493
  compileTimeout = setTimeout(async () => {
@@ -478,9 +496,9 @@ async function server (config, options) {
478
496
  }
479
497
 
480
498
  pageCache.clear()
499
+ coralite.clearCache()
481
500
 
482
501
  isCompiling = true
483
- const start = process.hrtime()
484
502
  let dash = colours.gray(' ─ ')
485
503
 
486
504
  // Process all pending changes
@@ -533,8 +551,7 @@ async function server (config, options) {
533
551
  const results = await buildStyles({
534
552
  input: currentConfig.styles.input,
535
553
  processors: currentConfig.styles.processors,
536
- output: join(config.output, 'assets', 'css'),
537
- start
554
+ output: join(config.output, 'assets', 'css')
538
555
  })
539
556
 
540
557
  for (const result of results) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coralite-scripts",
3
- "version": "0.36.3",
3
+ "version": "0.37.1",
4
4
  "description": "Configuration and scripts for Create Coralite.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -61,7 +61,7 @@
61
61
  "portfinder": "^1.0.38",
62
62
  "postcss": "^8.5.6",
63
63
  "sass": "^1.91.0",
64
- "coralite": "0.36.3"
64
+ "coralite": "0.37.1"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "premove dist && pnpm build-types",
package/types/index.js CHANGED
@@ -8,11 +8,11 @@
8
8
  * @property {string} public - The path to the directory containing static assets.
9
9
  * @property {Object} [server] - Server configuration options.
10
10
  * @property {number} server.port - The port number on which the development server will run.
11
- * @property {Object} [styles]
11
+ * @property {Object} [styles] - The configuration options for style processing.
12
12
  * @property {string[]} [styles.input] - Array of inputs, mixing scss and css
13
- * @property {Object} [styles.processors]
13
+ * @property {Object} [styles.processors] - The configuration for style processors like Sass or PostCSS.
14
14
  * @property {Options<'async'>} [styles.processors.scss] - Native Dart Sass options
15
- * @property {Object} [styles.processors.postcss]
15
+ * @property {Object} [styles.processors.postcss] - The configuration for PostCSS.
16
16
  * @property {import('postcss').AcceptedPlugin[]} [styles.processors.postcss.plugins] - Native PostCSS plugins
17
17
  * @property {'production' | 'development'} [mode='production'] - Set build mode for the coralite instance.
18
18
  */