coralite-scripts 0.38.6 → 0.39.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/bin/index.js +8 -161
- package/libs/commands/build.js +260 -0
- package/libs/load-config.js +3 -2
- package/package.json +2 -2
package/bin/index.js
CHANGED
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
import loadConfig from '../libs/load-config.js'
|
|
4
4
|
import { Command, Argument } from 'commander'
|
|
5
5
|
import server from '../libs/server.js'
|
|
6
|
-
import colours from 'kleur'
|
|
7
6
|
import pkg from '../package.json' with { type: 'json' }
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { createCoralite } from 'coralite'
|
|
12
|
-
import { mkdir, writeFile } from 'node:fs/promises'
|
|
13
|
-
import ora from 'ora'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
import { mkdir } from 'node:fs/promises'
|
|
9
|
+
import { buildCommand } from '../libs/commands/build.js'
|
|
14
10
|
|
|
15
11
|
// remove all Node warnings before doing anything else
|
|
16
12
|
process.removeAllListeners('warning')
|
|
@@ -22,7 +18,8 @@ program
|
|
|
22
18
|
.description(pkg.description)
|
|
23
19
|
.version(pkg.version)
|
|
24
20
|
.addArgument(new Argument('<mode>', 'Run mode: dev (development server) or build (production compilation)').choices(['dev', 'build']).default('dev'))
|
|
25
|
-
.option('-v --verbose', 'Enable verbose logging output')
|
|
21
|
+
.option('-v, --verbose', 'Enable verbose logging output')
|
|
22
|
+
.option('-c, --clean', 'Clear the output directory before building')
|
|
26
23
|
|
|
27
24
|
program.parse(process.argv)
|
|
28
25
|
program.on('error', (err) => {
|
|
@@ -31,7 +28,7 @@ program.on('error', (err) => {
|
|
|
31
28
|
|
|
32
29
|
const options = program.opts()
|
|
33
30
|
const mode = program.args[0]
|
|
34
|
-
const config = await loadConfig()
|
|
31
|
+
const config = await loadConfig(process.cwd())
|
|
35
32
|
|
|
36
33
|
if (!config) {
|
|
37
34
|
process.exit(1)
|
|
@@ -43,159 +40,9 @@ if (mode === 'dev') {
|
|
|
43
40
|
|
|
44
41
|
await server(config, options)
|
|
45
42
|
} else if (mode === 'build') {
|
|
46
|
-
const PAD = ' '
|
|
47
|
-
const border = '─'.repeat(Math.min(process.stdout.columns, 36) / 2)
|
|
48
|
-
const dash = colours.gray(' ─ ')
|
|
49
|
-
|
|
50
|
-
if (options.verbose) {
|
|
51
|
-
// log the response time and status code
|
|
52
|
-
process.stdout.write('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
53
|
-
process.stdout.write(border + colours.inverse(` LOGS `) + border + '\n\n')
|
|
54
|
-
} else {
|
|
55
|
-
process.stdout.write('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// delete old output files
|
|
59
|
-
deleteDirectoryRecursive(config.output)
|
|
60
|
-
|
|
61
|
-
// start coralite
|
|
62
|
-
const coralite = await createCoralite({
|
|
63
|
-
components: config.components,
|
|
64
|
-
pages: config.pages,
|
|
65
|
-
plugins: config.plugins,
|
|
66
|
-
assets: config.assets,
|
|
67
|
-
externalStyles: config.styles?.input?.map(input => {
|
|
68
|
-
const ext = input.split('.').pop()
|
|
69
|
-
return '/assets/css/' + input.split('/').pop().replace(`.${ext}`, '.css')
|
|
70
|
-
}),
|
|
71
|
-
baseURL: config.baseURL,
|
|
72
|
-
output: config.output,
|
|
73
|
-
mode: 'production',
|
|
74
|
-
onError: ({ level, message, error }) => {
|
|
75
|
-
if (level === 'ERR') {
|
|
76
|
-
displayError(message, error)
|
|
77
|
-
} else if (level === 'WARN') {
|
|
78
|
-
displayWarning(message)
|
|
79
|
-
} else {
|
|
80
|
-
displayInfo(message)
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
let spinner
|
|
86
|
-
let pageCount = 0
|
|
87
|
-
let skippedCount = 0
|
|
88
|
-
|
|
89
43
|
try {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (!options.verbose) {
|
|
93
|
-
spinner = ora('Building pages...').start()
|
|
94
|
-
}
|
|
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
|
-
|
|
104
|
-
// compile website
|
|
105
|
-
await coralite.build(async (result) => {
|
|
106
|
-
if (result.status === 'skipped') {
|
|
107
|
-
skippedCount++
|
|
108
|
-
if (!options.verbose) {
|
|
109
|
-
updateSpinnerText()
|
|
110
|
-
}
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const relativeDir = relative(config.pages, result.path.dirname)
|
|
115
|
-
const outDir = join(config.output, relativeDir)
|
|
116
|
-
const outFile = join(outDir, result.path.filename)
|
|
117
|
-
|
|
118
|
-
await mkdir(outDir, { recursive: true })
|
|
119
|
-
await writeFile(outFile, result.content)
|
|
120
|
-
|
|
121
|
-
if (options.verbose) {
|
|
122
|
-
process.stdout.write(toTime() + toMS(result.duration) + dash + result.path.pathname + '\n')
|
|
123
|
-
} else {
|
|
124
|
-
pageCount++
|
|
125
|
-
updateSpinnerText()
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
// Write ESM script assets generated during the build phase
|
|
130
|
-
if (coralite.outputFiles) {
|
|
131
|
-
const assetsDir = join(config.output, 'assets', 'js')
|
|
132
|
-
|
|
133
|
-
const assetWrites = Object.values(coralite.outputFiles).map(async (file) => {
|
|
134
|
-
const outFile = join(assetsDir, file.hashedPath)
|
|
135
|
-
await mkdir(dirname(outFile), { recursive: true })
|
|
136
|
-
await writeFile(outFile, file.text)
|
|
137
|
-
if (options.verbose) {
|
|
138
|
-
const dash = colours.gray(' ─ ')
|
|
139
|
-
process.stdout.write(toTime() + toMS(0) + dash + outFile + '\n')
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
await Promise.all(assetWrites)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (!options.verbose) {
|
|
147
|
-
if (skippedCount > 0) {
|
|
148
|
-
spinner.succeed(`Pages built (${pageCount} completed, ${skippedCount} skipped)`)
|
|
149
|
-
} else {
|
|
150
|
-
spinner.succeed(`Pages built (${pageCount} completed)`)
|
|
151
|
-
}
|
|
152
|
-
if (componentCount > 0) {
|
|
153
|
-
ora(`Components built (${componentCount} completed)`).succeed()
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const publicDir = config.public
|
|
158
|
-
|
|
159
|
-
if (publicDir) {
|
|
160
|
-
if (!options.verbose) {
|
|
161
|
-
spinner = ora('Copying public directory...').start()
|
|
162
|
-
}
|
|
163
|
-
await copyDirectory(publicDir, config.output)
|
|
164
|
-
if (!options.verbose) {
|
|
165
|
-
spinner.succeed('Public directory copied')
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (config.styles && config.styles.input) {
|
|
170
|
-
if (!options.verbose) {
|
|
171
|
-
spinner = ora('Building styles...').start()
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const results = await buildStyles({
|
|
175
|
-
input: config.styles.input,
|
|
176
|
-
output: join(config.output, 'assets', 'css'),
|
|
177
|
-
processors: config.styles.processors,
|
|
178
|
-
minify: mode === 'build',
|
|
179
|
-
sourcemap: mode !== 'build'
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
for (let i = 0; i < results.length; i++) {
|
|
183
|
-
const result = results[i]
|
|
184
|
-
|
|
185
|
-
if (options.verbose) {
|
|
186
|
-
process.stdout.write(toTime() + toMS(result.duration) + dash + result.output + '\n')
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (!options.verbose) {
|
|
191
|
-
spinner.succeed('Styles built')
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
} catch (error) {
|
|
195
|
-
if (spinner) {
|
|
196
|
-
spinner.fail('Build failed')
|
|
197
|
-
}
|
|
198
|
-
displayError('Build failed', error)
|
|
44
|
+
await buildCommand(config, options)
|
|
45
|
+
} catch {
|
|
199
46
|
process.exit(1)
|
|
200
47
|
}
|
|
201
48
|
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import colours from 'kleur'
|
|
2
|
+
import buildStyles from '../build-styles.js'
|
|
3
|
+
import { join, relative, dirname } from 'node:path'
|
|
4
|
+
import { existsSync, readdirSync, rmdirSync, statSync, unlinkSync } from 'node:fs'
|
|
5
|
+
import { deleteDirectoryRecursive, copyDirectory, toMS, toTime, displayError, displayWarning, displayInfo } from '../build-utils.js'
|
|
6
|
+
import { createCoralite } from 'coralite'
|
|
7
|
+
import { mkdir, writeFile } from 'node:fs/promises'
|
|
8
|
+
import ora from 'ora'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {import('../../types/index.js').CoraliteScriptConfig} config - The configuration object.
|
|
12
|
+
* @param {any} options - The CLI options.
|
|
13
|
+
* @param {any} logger - The logger object.
|
|
14
|
+
*/
|
|
15
|
+
export async function buildCommand (config, options, logger = null) {
|
|
16
|
+
const mode = 'build'
|
|
17
|
+
const PAD = ' '
|
|
18
|
+
const border = '─'.repeat(Math.min(process.stdout.columns || 36, 36) / 2)
|
|
19
|
+
const dash = colours.gray(' ─ ')
|
|
20
|
+
|
|
21
|
+
const log = (msg) => {
|
|
22
|
+
if (logger && logger.write) {
|
|
23
|
+
logger.write(msg)
|
|
24
|
+
} else {
|
|
25
|
+
process.stdout.write(msg)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const createSpinner = (text) => {
|
|
30
|
+
if (logger && logger.spinner) {
|
|
31
|
+
return logger.spinner(text)
|
|
32
|
+
}
|
|
33
|
+
return ora(text)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const internalLogger = {
|
|
37
|
+
info: (msg) => {
|
|
38
|
+
return logger && logger.info ? logger.info(msg) : displayInfo(msg)
|
|
39
|
+
},
|
|
40
|
+
warn: (msg) => {
|
|
41
|
+
return logger && logger.warn ? logger.warn(msg) : displayWarning(msg)
|
|
42
|
+
},
|
|
43
|
+
error: (msg, err) => {
|
|
44
|
+
return logger && logger.error ? logger.error(msg, err) : displayError(msg, err)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (options.verbose) {
|
|
49
|
+
log('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
50
|
+
log(border + colours.inverse(` LOGS `) + border + '\n\n')
|
|
51
|
+
} else {
|
|
52
|
+
log('\n' + PAD + colours.yellow('Compiling Coralite... \n\n'))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.clean) {
|
|
56
|
+
deleteDirectoryRecursive(config.output)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const validFiles = new Set()
|
|
60
|
+
|
|
61
|
+
const coralite = await createCoralite({
|
|
62
|
+
components: config.components,
|
|
63
|
+
pages: config.pages,
|
|
64
|
+
plugins: config.plugins,
|
|
65
|
+
assets: config.assets,
|
|
66
|
+
externalStyles: config.styles?.input?.map(input => {
|
|
67
|
+
const ext = input.split('.').pop()
|
|
68
|
+
return '/assets/css/' + input.split('/').pop().replace(`.${ext}`, '.css')
|
|
69
|
+
}),
|
|
70
|
+
baseURL: config.baseURL,
|
|
71
|
+
output: config.output,
|
|
72
|
+
mode: 'production',
|
|
73
|
+
onError: ({ level, message, error }) => {
|
|
74
|
+
if (level === 'ERR') {
|
|
75
|
+
internalLogger.error(message, error)
|
|
76
|
+
} else if (level === 'WARN') {
|
|
77
|
+
internalLogger.warn(message)
|
|
78
|
+
} else {
|
|
79
|
+
internalLogger.info(message)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
let spinner
|
|
85
|
+
let pageCount = 0
|
|
86
|
+
let skippedCount = 0
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const componentCount = 0
|
|
90
|
+
|
|
91
|
+
if (!options.verbose) {
|
|
92
|
+
spinner = createSpinner('Building pages...').start()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const updateSpinnerText = () => {
|
|
96
|
+
if (skippedCount > 0) {
|
|
97
|
+
spinner.text = `Building pages... (${pageCount} completed, ${skippedCount} skipped)`
|
|
98
|
+
} else {
|
|
99
|
+
spinner.text = `Building pages... (${pageCount} completed)`
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
await coralite.build(async (result) => {
|
|
104
|
+
const relativeDir = relative(config.pages, result.path.dirname)
|
|
105
|
+
const outDir = join(config.output, relativeDir)
|
|
106
|
+
const outFile = join(outDir, result.path.filename)
|
|
107
|
+
|
|
108
|
+
validFiles.add(outFile)
|
|
109
|
+
|
|
110
|
+
if (result.status === 'skipped') {
|
|
111
|
+
skippedCount++
|
|
112
|
+
if (!options.verbose) {
|
|
113
|
+
updateSpinnerText()
|
|
114
|
+
}
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
await mkdir(outDir, { recursive: true })
|
|
119
|
+
await writeFile(outFile, result.content)
|
|
120
|
+
|
|
121
|
+
if (options.verbose) {
|
|
122
|
+
log(toTime() + toMS(result.duration) + dash + result.path.pathname + '\n')
|
|
123
|
+
} else {
|
|
124
|
+
pageCount++
|
|
125
|
+
updateSpinnerText()
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
if (coralite.outputFiles) {
|
|
130
|
+
const assetsJsDir = join(config.output, 'assets', 'js')
|
|
131
|
+
const assetsCssDir = join(config.output, 'assets', 'css')
|
|
132
|
+
|
|
133
|
+
const assetWrites = Object.values(coralite.outputFiles).map(async (file) => {
|
|
134
|
+
const isCSS = (file.path || file.hashedPath)?.endsWith('.css')
|
|
135
|
+
const baseAssetsDir = isCSS ? assetsCssDir : assetsJsDir
|
|
136
|
+
const outFile = join(baseAssetsDir, file.hashedPath)
|
|
137
|
+
|
|
138
|
+
validFiles.add(outFile)
|
|
139
|
+
|
|
140
|
+
await mkdir(dirname(outFile), { recursive: true })
|
|
141
|
+
await writeFile(outFile, file.text)
|
|
142
|
+
if (options.verbose) {
|
|
143
|
+
const dash = colours.gray(' ─ ')
|
|
144
|
+
log(toTime() + toMS(0) + dash + outFile + '\n')
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
await Promise.all(assetWrites)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!options.verbose) {
|
|
152
|
+
if (skippedCount > 0) {
|
|
153
|
+
spinner.succeed(`Pages built (${pageCount} completed, ${skippedCount} skipped)`)
|
|
154
|
+
} else {
|
|
155
|
+
spinner.succeed(`Pages built (${pageCount} completed)`)
|
|
156
|
+
}
|
|
157
|
+
if (componentCount > 0) {
|
|
158
|
+
createSpinner(`Components built (${componentCount} completed)`).succeed()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const publicDir = config.public
|
|
163
|
+
|
|
164
|
+
if (publicDir) {
|
|
165
|
+
if (!options.verbose) {
|
|
166
|
+
spinner = createSpinner('Copying public directory...').start()
|
|
167
|
+
}
|
|
168
|
+
await copyDirectory(publicDir, config.output)
|
|
169
|
+
|
|
170
|
+
const trackPublicFiles = (dir, baseDir) => {
|
|
171
|
+
const files = readdirSync(dir)
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
const fullPath = join(dir, file)
|
|
174
|
+
const stat = statSync(fullPath)
|
|
175
|
+
|
|
176
|
+
if (stat.isDirectory()) {
|
|
177
|
+
trackPublicFiles(fullPath, baseDir)
|
|
178
|
+
} else {
|
|
179
|
+
const relativePath = relative(baseDir, fullPath)
|
|
180
|
+
validFiles.add(join(config.output, relativePath))
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
trackPublicFiles(publicDir, publicDir)
|
|
185
|
+
|
|
186
|
+
if (!options.verbose) {
|
|
187
|
+
spinner.succeed('Public directory copied')
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (config.styles && config.styles.input) {
|
|
192
|
+
if (!options.verbose) {
|
|
193
|
+
spinner = createSpinner('Building styles...').start()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const results = await buildStyles({
|
|
197
|
+
input: config.styles.input,
|
|
198
|
+
output: join(config.output, 'assets', 'css'),
|
|
199
|
+
processors: config.styles.processors,
|
|
200
|
+
minify: mode === 'build',
|
|
201
|
+
sourcemap: mode !== 'build'
|
|
202
|
+
})
|
|
203
|
+
|
|
204
|
+
for (let i = 0; i < results.length; i++) {
|
|
205
|
+
const result = results[i]
|
|
206
|
+
validFiles.add(result.output)
|
|
207
|
+
|
|
208
|
+
if (options.verbose) {
|
|
209
|
+
log(toTime() + toMS(result.duration) + dash + result.output + '\n')
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (!options.verbose) {
|
|
214
|
+
spinner.succeed('Styles built')
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (!options.clean) {
|
|
219
|
+
if (!options.verbose) {
|
|
220
|
+
spinner = createSpinner('Cleaning up stale files...').start()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const cleanupStaleFiles = (dir) => {
|
|
224
|
+
if (!existsSync(dir)) {
|
|
225
|
+
return
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const files = readdirSync(dir)
|
|
229
|
+
for (const file of files) {
|
|
230
|
+
const fullPath = join(dir, file)
|
|
231
|
+
const stat = statSync(fullPath)
|
|
232
|
+
|
|
233
|
+
if (stat.isDirectory()) {
|
|
234
|
+
cleanupStaleFiles(fullPath)
|
|
235
|
+
if (readdirSync(fullPath).length === 0) {
|
|
236
|
+
rmdirSync(fullPath)
|
|
237
|
+
}
|
|
238
|
+
} else if (!validFiles.has(fullPath)) {
|
|
239
|
+
unlinkSync(fullPath)
|
|
240
|
+
|
|
241
|
+
if (options.verbose) {
|
|
242
|
+
log(toTime() + colours.gray('Deleted stale file: ') + fullPath + '\n')
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
cleanupStaleFiles(config.output)
|
|
248
|
+
|
|
249
|
+
if (!options.verbose) {
|
|
250
|
+
spinner.succeed('Cleanup complete')
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {
|
|
254
|
+
if (spinner) {
|
|
255
|
+
spinner.fail('Build failed')
|
|
256
|
+
}
|
|
257
|
+
internalLogger.error('Build failed', error)
|
|
258
|
+
throw error
|
|
259
|
+
}
|
|
260
|
+
}
|
package/libs/load-config.js
CHANGED
|
@@ -19,9 +19,10 @@ import { defineConfig } from './config.js'
|
|
|
19
19
|
*
|
|
20
20
|
* const config = await loadConfig()
|
|
21
21
|
* ```
|
|
22
|
+
* @param {string} [cwd=process.cwd()] - The current working directory.
|
|
22
23
|
*/
|
|
23
|
-
async function loadConfig () {
|
|
24
|
-
const configPath = pathToFileURL(join(
|
|
24
|
+
async function loadConfig (cwd = process.cwd()) {
|
|
25
|
+
const configPath = pathToFileURL(join(cwd, 'coralite.config.js'))
|
|
25
26
|
|
|
26
27
|
try {
|
|
27
28
|
await access(configPath)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coralite-scripts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.0",
|
|
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.15",
|
|
63
63
|
"sass": "^1.101.0",
|
|
64
|
-
"coralite": "0.
|
|
64
|
+
"coralite": "0.39.0"
|
|
65
65
|
},
|
|
66
66
|
"scripts": {
|
|
67
67
|
"build": "premove dist && pnpm build-types",
|