coralite-scripts 0.0.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/README.md +124 -0
- package/bin/coralite-scripts.js +185 -0
- package/package.json +51 -0
- package/src/build-html.js +60 -0
- package/src/build-sass.js +56 -0
- package/src/build-utils.js +39 -0
- package/src/config.js +50 -0
- package/src/index.js +1 -0
- package/src/load-config.js +27 -0
- package/types/index.js +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Coralite Development Environment Guide
|
|
2
|
+
|
|
3
|
+
Welcome to **Coralite starter script**, a lightweight Static Site Generator (SSG) built for rapid development and clean output. This guide walks you through setting up your local development environment using the provided `coralite-scripts` package and configuration files.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
Ensure you have:
|
|
10
|
+
- Node.js ≥ 20.x
|
|
11
|
+
- npm or pnpm installed
|
|
12
|
+
|
|
13
|
+
> Coralite uses experimental ES modules (`--experimental-vm-modules`) — make sure your Node version supports it.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Project Structure
|
|
18
|
+
|
|
19
|
+
Coralite expects a standard folder layout:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
my-coralite-site/
|
|
23
|
+
├── src/
|
|
24
|
+
│ ├── pages/ # Your page templates (e.g., `about.html`, `index.html`)
|
|
25
|
+
│ ├── scss/ # SCSS/Sass styles
|
|
26
|
+
│ └── templates/ # Reusable template files
|
|
27
|
+
├── public/ # Static assets (CSS, JS, images)
|
|
28
|
+
├── dist/ # Output directory for built site (auto-generated)
|
|
29
|
+
├── coralite.config.js # Configuration file
|
|
30
|
+
└── package.json # Scripts & dependencies
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Step 1: Configure `coralite.config.js`
|
|
36
|
+
|
|
37
|
+
Create or update your config file with the following:
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
import { defineConfig } from 'coralite-scripts'
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
output: 'dist',
|
|
44
|
+
public: 'public',
|
|
45
|
+
pages: 'src/pages',
|
|
46
|
+
templates: 'src/templates',
|
|
47
|
+
sass: {
|
|
48
|
+
input: 'src/scss'
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
> This tells Coralite where to find your source files, compile CSS from SCSS, and serve static assets.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Step 2: Start the Development Server
|
|
58
|
+
|
|
59
|
+
Update your `package.json` scripts to include:
|
|
60
|
+
|
|
61
|
+
```json package.json
|
|
62
|
+
{
|
|
63
|
+
"scripts": {
|
|
64
|
+
"start": "coralite-script"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Then start the dev server:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm run start
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> ✅ The server runs on `http://localhost:3000` by default.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Live Development Features
|
|
80
|
+
|
|
81
|
+
Coralite provides real-time development workflows out of the box:
|
|
82
|
+
|
|
83
|
+
| Feature | How It Works |
|
|
84
|
+
|-------|-------------|
|
|
85
|
+
| **Live Reload** | Automatically reloads browser when any `.html`, `.scss`, or `.sass` file changes. |
|
|
86
|
+
| **Hot CSS Updates** | Sass/SCSS files are compiled instantly and injected into your page via Server-Sent Events (SSE). |
|
|
87
|
+
| **File Watching** | Monitors `src/pages`, `src/scss`, `public`, and `src/templates`. |
|
|
88
|
+
| **Dev Logs** | Shows real-time build times, file changes, and status codes in terminal. |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## How it works under the hood
|
|
93
|
+
|
|
94
|
+
- **Routing**: `/` → `index.html`, `/about` → `about.html`
|
|
95
|
+
- **HTML Compilation**: Pages are compiled with embedded live reload scripts.
|
|
96
|
+
- **Sass Support**: `.scss`/`.sass` files are auto-compiled to CSS in `dist/css`.
|
|
97
|
+
- **Server-Sent Events (SSE)**: Used for real-time updates without full page refresh.
|
|
98
|
+
|
|
99
|
+
> No extra tooling needed — everything is built-in!
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Example usage
|
|
104
|
+
|
|
105
|
+
1. Create a new file at `src/pages/about.html`:
|
|
106
|
+
```html
|
|
107
|
+
<!DOCTYPE html>
|
|
108
|
+
<html lang="en">
|
|
109
|
+
<head><title>About</title></head>
|
|
110
|
+
<body><h1>Welcome to Coralite!</h1></body>
|
|
111
|
+
</html>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
2. Visit `http://localhost:3000/about` in your browser — it loads instantly.
|
|
115
|
+
|
|
116
|
+
3. Edit the file → see auto-reload!
|
|
117
|
+
|
|
118
|
+
4. Add a new SCSS file at `src/scss/style.scss`, and import it into an HTML page via `<link rel="stylesheet" href="/css/style.css">`.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
> **Feedback?** Found a bug or want a feature? Open an issue!
|
|
123
|
+
|
|
124
|
+
Happy building with Coralite!
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --experimental-vm-modules --experimental-import-meta-resolve
|
|
2
|
+
|
|
3
|
+
import express from 'express'
|
|
4
|
+
import colours from 'kleur'
|
|
5
|
+
import localAccess from 'local-access'
|
|
6
|
+
import chokidar from 'chokidar'
|
|
7
|
+
import loadConfig from '../src/load-config.js'
|
|
8
|
+
import html from '../src/build-html.js'
|
|
9
|
+
import buildSass from '../src/build-sass.js'
|
|
10
|
+
import { toCode, toMS, toTime } from '../src/build-utils.js'
|
|
11
|
+
import { extname, join } from 'path'
|
|
12
|
+
import { readFile, access, constants } from 'fs/promises'
|
|
13
|
+
|
|
14
|
+
const config = await loadConfig()
|
|
15
|
+
const app = express()
|
|
16
|
+
const port = config.server?.port || 3000
|
|
17
|
+
// track active connections.
|
|
18
|
+
const clients = new Set()
|
|
19
|
+
|
|
20
|
+
const buildHTML = await html(config)
|
|
21
|
+
|
|
22
|
+
const watchPath = [
|
|
23
|
+
config.public,
|
|
24
|
+
config.pages,
|
|
25
|
+
config.templates
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
// middleware to log request information including response time and status code
|
|
29
|
+
app.use(function (req, res, next){
|
|
30
|
+
const start = process.hrtime()
|
|
31
|
+
|
|
32
|
+
// when the response is finished, calculate duration and log details
|
|
33
|
+
res.on('finish', function (){
|
|
34
|
+
const dash = colours.gray(' ─ ')
|
|
35
|
+
const duration = process.hrtime(start)
|
|
36
|
+
const uri = req.originalUrl || req.url
|
|
37
|
+
|
|
38
|
+
// log the response time and status code
|
|
39
|
+
process.stdout.write(toTime() + toCode(res.statusCode) + dash + toMS(duration) + dash + uri + '\n')
|
|
40
|
+
})
|
|
41
|
+
next()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// check if Sass is configured and add its input directory to watchPath for file changes.
|
|
45
|
+
if (config.sass && config.sass.input) {
|
|
46
|
+
watchPath.push(config.sass.input)
|
|
47
|
+
|
|
48
|
+
app.use('/css', express.static(join(config.output, 'css'), {
|
|
49
|
+
cacheControl: false
|
|
50
|
+
}))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
app
|
|
54
|
+
.use(express.static(config.public, {
|
|
55
|
+
cacheControl: false
|
|
56
|
+
}))
|
|
57
|
+
.get('/_/rebuild', (req, res) => {
|
|
58
|
+
// set headers for SSE
|
|
59
|
+
res.writeHead(200, {
|
|
60
|
+
'Content-Type': 'text/event-stream',
|
|
61
|
+
'Cache-Control': 'no-cache',
|
|
62
|
+
Connection: 'keep-alive'
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// add client to tracking set
|
|
66
|
+
clients.add(res)
|
|
67
|
+
|
|
68
|
+
// send initial connection message
|
|
69
|
+
res.write('data: connected\n\n')
|
|
70
|
+
|
|
71
|
+
// clean up on client disconnect
|
|
72
|
+
req.on('close', () => {
|
|
73
|
+
clients.delete(res)
|
|
74
|
+
res.end()
|
|
75
|
+
})
|
|
76
|
+
})
|
|
77
|
+
.get(/(.*)/, async (req, res) => {
|
|
78
|
+
// extract the requested path and its extension.
|
|
79
|
+
let path = req.path
|
|
80
|
+
const extension = extname(path)
|
|
81
|
+
|
|
82
|
+
// if no extension is present, assume it's a HTML file and append '.html'.
|
|
83
|
+
if (!extension) {
|
|
84
|
+
if ('/' === path) {
|
|
85
|
+
path = 'index.html'
|
|
86
|
+
} else if (path.endsWith('/')) {
|
|
87
|
+
path = path.slice(0, path.length -1) + '.html'
|
|
88
|
+
} else {
|
|
89
|
+
path += '.html'
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// first attempt to read the file directly.
|
|
95
|
+
await access(path)
|
|
96
|
+
const data = await readFile(path, 'utf8')
|
|
97
|
+
|
|
98
|
+
res.send(data)
|
|
99
|
+
} catch {
|
|
100
|
+
try {
|
|
101
|
+
// if that fails, try reading from pages directory.
|
|
102
|
+
const filePath = join(config.pages, path)
|
|
103
|
+
|
|
104
|
+
// check if page source file exists and is readable
|
|
105
|
+
await access(filePath, constants.R_OK)
|
|
106
|
+
const start = process.hrtime()
|
|
107
|
+
let duration, dash = colours.gray(' ─ ')
|
|
108
|
+
|
|
109
|
+
// build the HTML for this page using the built-in compiler.
|
|
110
|
+
await buildHTML.compile(filePath)
|
|
111
|
+
const data = await readFile(filePath, 'utf8')
|
|
112
|
+
// inject a script to enable live reload via Server-Sent Events
|
|
113
|
+
const injectedHtml = data.replace(/<\/body>/i, `
|
|
114
|
+
<script>
|
|
115
|
+
const eventSource = new EventSource('/_/rebuild');
|
|
116
|
+
eventSource.onmessage = function(event) {
|
|
117
|
+
if (event.data === 'connected') return;
|
|
118
|
+
// Reload page when file changes
|
|
119
|
+
location.reload()
|
|
120
|
+
}
|
|
121
|
+
</script>
|
|
122
|
+
</body>`)
|
|
123
|
+
|
|
124
|
+
// prints time and path to the file that has been changed or added.
|
|
125
|
+
duration = process.hrtime(start)
|
|
126
|
+
process.stdout.write(toTime() + colours.bgGreen('Compiled HTML') + dash + toMS(duration) + dash + path + '\n')
|
|
127
|
+
res.send(injectedHtml)
|
|
128
|
+
} catch(error) {
|
|
129
|
+
// if all attempts fail, respond with a 404.
|
|
130
|
+
res.sendStatus(404)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// watch for file changes
|
|
136
|
+
const watcher = chokidar.watch(watchPath, {
|
|
137
|
+
persistent: true
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
watcher
|
|
141
|
+
.on('change', async (path) => {
|
|
142
|
+
if (path.endsWith('.scss') || path.endsWith('.sass')) {
|
|
143
|
+
const start = process.hrtime()
|
|
144
|
+
let duration, dash = colours.gray(' ─ ')
|
|
145
|
+
// rebuild CSS and send notification
|
|
146
|
+
await buildSass({
|
|
147
|
+
...config.sass,
|
|
148
|
+
output: join(config.output, 'css')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// prints time and path to the file that has been changed or added.
|
|
152
|
+
duration = process.hrtime(start)
|
|
153
|
+
process.stdout.write(toTime() + colours.bgGreen('Compiled SASS') + dash + toMS(duration) + dash + path + '\n')
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
clients.forEach(client => {
|
|
157
|
+
client.write(`data: reload\n\n`)
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
.on('add', async (path) => {
|
|
161
|
+
if (path.endsWith('.scss') || path.endsWith('.sass')) {
|
|
162
|
+
const start = process.hrtime()
|
|
163
|
+
let duration, dash = colours.gray(' ─ ')
|
|
164
|
+
// rebuild CSS and send notification
|
|
165
|
+
await buildSass({
|
|
166
|
+
...config.sass,
|
|
167
|
+
output: join(config.output, 'css')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// prints time and path to the file that has been changed or added.
|
|
171
|
+
duration = process.hrtime(start)
|
|
172
|
+
process.stdout.write(toTime() + colours.bgGreen('Compiled SASS') + dash + toMS(duration) + dash + path + '\n')
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
app.listen(port, () => {
|
|
177
|
+
// @ts-ignore
|
|
178
|
+
const { local } = localAccess({ port })
|
|
179
|
+
const PAD = ' '
|
|
180
|
+
const border = '─'.repeat(Math.min(process.stdout.columns, 36) / 2)
|
|
181
|
+
// print server status
|
|
182
|
+
process.stdout.write('\n' + PAD + colours.green('Coralite is ready! 🚀\n\n'))
|
|
183
|
+
process.stdout.write(PAD + `${colours.bold('- Local:')} ${local}\n\n`)
|
|
184
|
+
process.stdout.write(border + colours.inverse(' LOGS ') + border + '\n\n')
|
|
185
|
+
})
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "coralite-scripts",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Configuration and scripts for Create Coralite.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"coralite-run": "./bin/coralite-scripts.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"coralite",
|
|
11
|
+
"static-site-generator",
|
|
12
|
+
"ssg",
|
|
13
|
+
"configuration",
|
|
14
|
+
"scripts"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://coralite.io/docs/create-scripts",
|
|
17
|
+
"author": {
|
|
18
|
+
"name": "Thomas David",
|
|
19
|
+
"url": "https://thomasjackdavid.com"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://codeberg.org/tjdavid/coralite.git",
|
|
24
|
+
"directory": "packages/coralite-scripts"
|
|
25
|
+
},
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://codeberg.org/tjdavid/coralite/issues"
|
|
28
|
+
},
|
|
29
|
+
"imports": {
|
|
30
|
+
"#types": "./types/index.js"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"default": "./src/index.js",
|
|
35
|
+
"types": "./types/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./types": {
|
|
38
|
+
"default": "./types/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"license": "AGPL-3.0-only",
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"chokidar": "^4.0.3",
|
|
44
|
+
"express": "^5.1.0",
|
|
45
|
+
"html-validate": "^10.0.0",
|
|
46
|
+
"kleur": "^4.1.5",
|
|
47
|
+
"local-access": "^1.1.0",
|
|
48
|
+
"sass": "^1.91.0",
|
|
49
|
+
"coralite": "0.14.2"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import Coralite from 'coralite'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @import { CoralitePluginInstance } from 'coralite/types'
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Builds HTML files from Coralite templates and pages.
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} options
|
|
11
|
+
* @param {string} options.pages - Path to pages directory
|
|
12
|
+
* @param {string} options.templates - Path to templates directory
|
|
13
|
+
* @param {string} options.output - Output path for HTML files
|
|
14
|
+
* @param {string} options.output - Output path for HTML files
|
|
15
|
+
* @param {CoralitePluginInstance[]} [options.plugins=[]] - List of Coralite plugins.
|
|
16
|
+
*/
|
|
17
|
+
export default async function html ({
|
|
18
|
+
pages,
|
|
19
|
+
templates,
|
|
20
|
+
output,
|
|
21
|
+
plugins
|
|
22
|
+
}) {
|
|
23
|
+
const coralite = new Coralite({
|
|
24
|
+
templates,
|
|
25
|
+
pages,
|
|
26
|
+
plugins
|
|
27
|
+
})
|
|
28
|
+
await coralite.initialise()
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
/**
|
|
32
|
+
* Compiles the specified HTML pages using coralite and saves the output to the configured output path.
|
|
33
|
+
* @param {string | string[]} [paths] - Path to a single page or array of page paths relative to the pages directory. If omitted, compiles all pages.
|
|
34
|
+
*/
|
|
35
|
+
async compile (paths) {
|
|
36
|
+
let relativePathPages
|
|
37
|
+
|
|
38
|
+
if (Array.isArray(paths)) {
|
|
39
|
+
relativePathPages = []
|
|
40
|
+
|
|
41
|
+
for (let i = 0; i < paths.length; i++) {
|
|
42
|
+
const path = paths[i]
|
|
43
|
+
|
|
44
|
+
relativePathPages.push(path.replace(pages + '/', ''))
|
|
45
|
+
}
|
|
46
|
+
} else if (paths) {
|
|
47
|
+
relativePathPages = paths.replace(pages + '/', '')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (relativePathPages && relativePathPages[0] === '/') {
|
|
51
|
+
relativePathPages = relativePathPages.slice(1)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const document = await coralite.compile(relativePathPages)
|
|
55
|
+
|
|
56
|
+
await coralite.save(document, output)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import * as sass from 'sass'
|
|
2
|
+
import fs from 'fs/promises'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @import {Options} from 'sass'
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Compiles SCSS files to CSS with source maps
|
|
11
|
+
* @param {Object} options
|
|
12
|
+
* @param {string} options.input - The directory containing SCSS files to compile
|
|
13
|
+
* @param {string} options.output - The output directory for compiled CSS files
|
|
14
|
+
* @param {Options<'async'>} [options.options] - Sass compile options
|
|
15
|
+
* @returns {Promise<void>} Resolves when all files are compiled
|
|
16
|
+
*/
|
|
17
|
+
export default async function buildSass ({
|
|
18
|
+
input,
|
|
19
|
+
output,
|
|
20
|
+
options = {
|
|
21
|
+
sourceMap: true,
|
|
22
|
+
loadPaths: ['node_modules'],
|
|
23
|
+
silenceDeprecations: [
|
|
24
|
+
'color-functions',
|
|
25
|
+
'import',
|
|
26
|
+
'global-builtin'
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}) {
|
|
30
|
+
try {
|
|
31
|
+
// ensure output directory exists
|
|
32
|
+
await fs.mkdir(output, { recursive: true })
|
|
33
|
+
|
|
34
|
+
// read all files from src/scss directory
|
|
35
|
+
const scssFiles = await fs.readdir(input)
|
|
36
|
+
const filteredScssFiles = scssFiles.filter(file => file.endsWith('.scss') && file[0] !== '_')
|
|
37
|
+
|
|
38
|
+
for (const file of filteredScssFiles) {
|
|
39
|
+
const filePath = path.join(input, file)
|
|
40
|
+
const outputFile = path.join(output, file.replace('.scss', '.css'))
|
|
41
|
+
|
|
42
|
+
const result = await sass.compileAsync(filePath, options)
|
|
43
|
+
|
|
44
|
+
// write the compiled CSS
|
|
45
|
+
await fs.writeFile(outputFile, result.css)
|
|
46
|
+
|
|
47
|
+
// write source map if enabled
|
|
48
|
+
if (result.sourceMap) {
|
|
49
|
+
const sourceMapPath = outputFile + '.map'
|
|
50
|
+
await fs.writeFile(sourceMapPath, JSON.stringify(result.sourceMap))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
throw error
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import colours from 'kleur'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 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
|
|
5
|
+
* @returns {string} - Formatted timestamp to be used within a log message.
|
|
6
|
+
*/
|
|
7
|
+
export function toTime () {
|
|
8
|
+
const now = new Date()
|
|
9
|
+
const hours = now.getHours().toString().padStart(2, '0')
|
|
10
|
+
const minutes = now.getMinutes().toString().padStart(2, '0')
|
|
11
|
+
const seconds = now.getSeconds().toString().padStart(2, '0')
|
|
12
|
+
const milliseconds = now.getMilliseconds().toString().padStart(3, '0')
|
|
13
|
+
|
|
14
|
+
return '[' + colours.magenta(`${hours}:${minutes}:${seconds}.${milliseconds}`) + '] '
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Creates a formatted timestamp in milliseconds with ANSI colors and bold white string for better readability of logs or console output.
|
|
19
|
+
* @param {[number, number]} hrtime - High Resolution Time in microseconds since epoch, used to calculate time difference between two points of execution or the start/stopwatch function call respectively.
|
|
20
|
+
*/
|
|
21
|
+
export function toMS (hrtime) {
|
|
22
|
+
return colours.white().bold(`${(hrtime[1] / 1e6).toFixed(2)}ms`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Converts HTTP status code into a colourised text.
|
|
27
|
+
* @param {number} code - HTTP status code to convert into a colourised text.
|
|
28
|
+
*/
|
|
29
|
+
export function toCode (code) {
|
|
30
|
+
let fn = 'green'
|
|
31
|
+
|
|
32
|
+
if (code >= 400) {
|
|
33
|
+
fn = 'red'
|
|
34
|
+
} else if (code > 300) {
|
|
35
|
+
fn = 'yellow'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return colours[fn](code)
|
|
39
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {CoraliteScriptConfig} from '#types'
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {CoraliteScriptConfig} options
|
|
7
|
+
*/
|
|
8
|
+
export function defineConfig (options) {
|
|
9
|
+
// Validate required properties for CoraliteConfig
|
|
10
|
+
if (!options || typeof options !== 'object') {
|
|
11
|
+
throw new Error('Configuration must be a valid object')
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!options.output || typeof options.output !== 'string') {
|
|
15
|
+
throw new Error('Configuration must contain a valid "output" property')
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!options.templates || typeof options.templates !== 'string') {
|
|
19
|
+
throw new Error('Configuration must contain a valid "templates" property')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!options.pages || typeof options.pages !== 'string') {
|
|
23
|
+
throw new Error('Configuration must contain a valid "pages" property')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Validate optional server configuration
|
|
27
|
+
if (options.server && typeof options.server !== 'object') {
|
|
28
|
+
throw new Error('Configuration "server" must be an object')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (options.server?.port && (typeof options.server.port !== 'number' || options.server.port <= 0)) {
|
|
32
|
+
throw new Error('Configuration "server.port" must be a positive number')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Validate sass configuration
|
|
36
|
+
if (options.sass && typeof options.sass !== 'object') {
|
|
37
|
+
throw new Error('Configuration "sass" must be an object')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (options.sass?.input && typeof options.sass.input !== 'string') {
|
|
41
|
+
throw new Error('Configuration "sass.input" must be a string')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Validate assets path
|
|
45
|
+
if (!options.public || typeof options.public !== 'string') {
|
|
46
|
+
throw new Error('Configuration must contain a valid "public" property')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return options
|
|
50
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './config.js'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { resolve } from 'path'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @import {CoraliteScriptConfig} from '#types'
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Loads the configuration for the Coralite project.
|
|
9
|
+
*
|
|
10
|
+
* @returns {Promise<CoraliteScriptConfig>} The configuration object containing path settings or an empty promise if no config found
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```js
|
|
14
|
+
* import loadConfig from './loadConfig.js'
|
|
15
|
+
*
|
|
16
|
+
* const config = await loadConfig()
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export default async function loadConfig () {
|
|
20
|
+
try {
|
|
21
|
+
const config = await import(resolve('coralite.config.js'))
|
|
22
|
+
|
|
23
|
+
return config.default
|
|
24
|
+
} catch(error) {
|
|
25
|
+
throw error
|
|
26
|
+
}
|
|
27
|
+
}
|
package/types/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @import {CoraliteConfig} from 'coralite/types'
|
|
3
|
+
* @import {Options} from 'sass'
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @typedef {Object} CoraliteScriptBaseConfig
|
|
8
|
+
* @property {string} public - The path to the directory containing static assets.
|
|
9
|
+
* @property {Object} [server] - Server configuration options.
|
|
10
|
+
* @property {number} server.port - The port number on which the development server will run.
|
|
11
|
+
* @property {Object} [sass] - Sass compilation configuration.
|
|
12
|
+
* @property {string} sass.input - The path to the input Sass file or directory.
|
|
13
|
+
* @property {Options<'async'>} [sass.options] - Additional options passed to the Sass compiler.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {CoraliteScriptBaseConfig & CoraliteConfig} CoraliteScriptConfig
|
|
18
|
+
*/
|