@platformatic/generators 1.13.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/LICENSE +201 -0
- package/README.md +67 -0
- package/index.d.ts +8 -0
- package/index.js +10 -0
- package/lib/base-generator.d.ts +105 -0
- package/lib/base-generator.js +426 -0
- package/lib/create-gitignore.js +42 -0
- package/lib/create-plugin.d.ts +13 -0
- package/lib/create-plugin.js +252 -0
- package/lib/errors.js +11 -0
- package/lib/file-generator.d.ts +29 -0
- package/lib/file-generator.js +90 -0
- package/lib/utils.d.ts +12 -0
- package/lib/utils.js +69 -0
- package/package.json +27 -0
- package/test/base-generator.test.js +459 -0
- package/test/file-generator.test.js +106 -0
- package/test/helpers.js +43 -0
- package/test/runner.js +20 -0
- package/test/utils.test.js +89 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { join } = require('path')
|
|
4
|
+
|
|
5
|
+
const JS_PLUGIN_WITH_TYPES_SUPPORT = `\
|
|
6
|
+
/// <reference path="../global.d.ts" />
|
|
7
|
+
'use strict'
|
|
8
|
+
/** @param {import('fastify').FastifyInstance} fastify */
|
|
9
|
+
module.exports = async function (fastify, opts) {
|
|
10
|
+
fastify.decorate('example', 'foobar')
|
|
11
|
+
}
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
const TS_PLUGIN_WITH_TYPES_SUPPORT = `\
|
|
15
|
+
/// <reference path="../global.d.ts" />
|
|
16
|
+
import { FastifyInstance, FastifyPluginOptions } from 'fastify'
|
|
17
|
+
|
|
18
|
+
export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
|
|
19
|
+
fastify.decorate('example', 'foobar')
|
|
20
|
+
}
|
|
21
|
+
`
|
|
22
|
+
|
|
23
|
+
const JS_ROUTES_WITH_TYPES_SUPPORT = `\
|
|
24
|
+
/// <reference path="../global.d.ts" />
|
|
25
|
+
'use strict'
|
|
26
|
+
/** @param {import('fastify').FastifyInstance} fastify */
|
|
27
|
+
module.exports = async function (fastify, opts) {
|
|
28
|
+
fastify.get('/example', async (request, reply) => {
|
|
29
|
+
return { hello: fastify.example }
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
`
|
|
33
|
+
|
|
34
|
+
const TS_ROUTES_WITH_TYPES_SUPPORT = `\
|
|
35
|
+
/// <reference path="../global.d.ts" />
|
|
36
|
+
import { FastifyInstance, FastifyPluginOptions } from 'fastify'
|
|
37
|
+
|
|
38
|
+
declare module 'fastify' {
|
|
39
|
+
interface FastifyInstance {
|
|
40
|
+
example: string
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default async function (fastify: FastifyInstance, opts: FastifyPluginOptions) {
|
|
45
|
+
fastify.get('/example', async (request, reply) => {
|
|
46
|
+
return { hello: fastify.example }
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
function testHelperJS (mod, customization = { pre: '', post: '', config: '' }) {
|
|
52
|
+
return `\
|
|
53
|
+
'use strict'
|
|
54
|
+
|
|
55
|
+
const { join } = require('node:path')
|
|
56
|
+
const { readFile } = require('node:fs/promises')
|
|
57
|
+
const { buildServer } = require('@platformatic/${mod}')
|
|
58
|
+
${customization.requires || ''}
|
|
59
|
+
|
|
60
|
+
async function getServer (t) {
|
|
61
|
+
${customization.pre || ''}
|
|
62
|
+
const config = JSON.parse(await readFile(join(__dirname, '..', 'platformatic.${mod}.json'), 'utf8'))
|
|
63
|
+
// Add your config customizations here. For example you want to set
|
|
64
|
+
// all things that are set in the config file to read from an env variable
|
|
65
|
+
config.server.logger.level = 'warn'
|
|
66
|
+
config.watch = false
|
|
67
|
+
${customization.config || ''}
|
|
68
|
+
// Add your config customizations here
|
|
69
|
+
const server = await buildServer(config)
|
|
70
|
+
t.after(() => server.close())
|
|
71
|
+
${customization.post || ''}
|
|
72
|
+
return server
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports.getServer = getServer
|
|
76
|
+
`
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const TEST_ROUTES_JS = `\
|
|
80
|
+
'use strict'
|
|
81
|
+
|
|
82
|
+
const test = require('node:test')
|
|
83
|
+
const assert = require('node:assert')
|
|
84
|
+
const { getServer } = require('../helper')
|
|
85
|
+
|
|
86
|
+
test('example', async (t) => {
|
|
87
|
+
const server = await getServer(t)
|
|
88
|
+
const res = await server.inject({
|
|
89
|
+
method: 'GET',
|
|
90
|
+
url: '/example'
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
assert.strictEqual(res.statusCode, 200)
|
|
94
|
+
assert.deepStrictEqual(res.json(), {
|
|
95
|
+
hello: 'foobar'
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
`
|
|
99
|
+
|
|
100
|
+
const TEST_PLUGIN_JS = `\
|
|
101
|
+
'use strict'
|
|
102
|
+
|
|
103
|
+
const test = require('node:test')
|
|
104
|
+
const assert = require('node:assert')
|
|
105
|
+
const { getServer } = require('../helper')
|
|
106
|
+
|
|
107
|
+
test('example decorator', async (t) => {
|
|
108
|
+
const server = await getServer(t)
|
|
109
|
+
|
|
110
|
+
assert.strictEqual(server.example, 'foobar')
|
|
111
|
+
})
|
|
112
|
+
`
|
|
113
|
+
|
|
114
|
+
function testHelperTS (mod, customizations = { pre: '', post: '', config: '', requires: '' }) {
|
|
115
|
+
return `\
|
|
116
|
+
import { join } from 'node:path'
|
|
117
|
+
import { readFile } from 'node:fs/promises'
|
|
118
|
+
import { buildServer } from '@platformatic/${mod}'
|
|
119
|
+
import { test } from 'node:test'
|
|
120
|
+
${customizations.requires}
|
|
121
|
+
|
|
122
|
+
type testfn = Parameters<typeof test>[0]
|
|
123
|
+
type TestContext = Parameters<Exclude<testfn, undefined>>[0]
|
|
124
|
+
|
|
125
|
+
export async function getServer (t: TestContext) {
|
|
126
|
+
${customizations.pre}
|
|
127
|
+
// We go up two folder because this files executes in the dist folder
|
|
128
|
+
const config = JSON.parse(await readFile(join(__dirname, '..', '..', 'platformatic.${mod}.json'), 'utf8'))
|
|
129
|
+
// Add your config customizations here. For example you want to set
|
|
130
|
+
// all things that are set in the config file to read from an env variable
|
|
131
|
+
config.server.logger.level = 'warn'
|
|
132
|
+
config.watch = false
|
|
133
|
+
${customizations.config}
|
|
134
|
+
// Add your config customizations here
|
|
135
|
+
const server = await buildServer(config)
|
|
136
|
+
t.after(() => server.close())
|
|
137
|
+
${customizations.post}
|
|
138
|
+
return server
|
|
139
|
+
}
|
|
140
|
+
`
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const TEST_ROUTES_TS = `\
|
|
144
|
+
import test from 'node:test'
|
|
145
|
+
import assert from 'node:assert'
|
|
146
|
+
import { getServer } from '../helper'
|
|
147
|
+
|
|
148
|
+
test('root', async (t) => {
|
|
149
|
+
const server = await getServer(t)
|
|
150
|
+
const res = await server.inject({
|
|
151
|
+
method: 'GET',
|
|
152
|
+
url: '/example'
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
assert.strictEqual(res.statusCode, 200)
|
|
156
|
+
assert.deepStrictEqual(res.json(), {
|
|
157
|
+
hello: 'foobar'
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
`
|
|
161
|
+
|
|
162
|
+
const TEST_PLUGIN_TS = `\
|
|
163
|
+
import test from 'node:test'
|
|
164
|
+
import assert from 'node:assert'
|
|
165
|
+
import { getServer } from '../helper'
|
|
166
|
+
|
|
167
|
+
test('example decorator', async (t) => {
|
|
168
|
+
const server = await getServer(t)
|
|
169
|
+
|
|
170
|
+
assert.strictEqual(server.example, 'foobar')
|
|
171
|
+
})
|
|
172
|
+
`
|
|
173
|
+
|
|
174
|
+
function generatePluginWithTypesSupport (typescript) {
|
|
175
|
+
const pluginTemplate = typescript
|
|
176
|
+
? TS_PLUGIN_WITH_TYPES_SUPPORT
|
|
177
|
+
: JS_PLUGIN_WITH_TYPES_SUPPORT
|
|
178
|
+
const pluginName = typescript
|
|
179
|
+
? 'example.ts'
|
|
180
|
+
: 'example.js'
|
|
181
|
+
return {
|
|
182
|
+
path: 'plugins',
|
|
183
|
+
file: pluginName,
|
|
184
|
+
contents: pluginTemplate
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function generateRouteWithTypesSupport (typescript) {
|
|
189
|
+
const routesTemplate = typescript
|
|
190
|
+
? TS_ROUTES_WITH_TYPES_SUPPORT
|
|
191
|
+
: JS_ROUTES_WITH_TYPES_SUPPORT
|
|
192
|
+
const routesName = typescript
|
|
193
|
+
? 'root.ts'
|
|
194
|
+
: 'root.js'
|
|
195
|
+
return {
|
|
196
|
+
path: 'routes',
|
|
197
|
+
file: routesName,
|
|
198
|
+
contents: routesTemplate
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function generateTests (typescript, type, customizations) {
|
|
203
|
+
const output = []
|
|
204
|
+
if (typescript) {
|
|
205
|
+
output.push({
|
|
206
|
+
path: 'test',
|
|
207
|
+
file: 'helper.ts',
|
|
208
|
+
contents: testHelperTS(type, customizations)
|
|
209
|
+
})
|
|
210
|
+
output.push({
|
|
211
|
+
path: join('test', 'plugins'),
|
|
212
|
+
file: 'example.test.ts',
|
|
213
|
+
contents: TEST_PLUGIN_TS
|
|
214
|
+
})
|
|
215
|
+
output.push({
|
|
216
|
+
path: join('test', 'routes'),
|
|
217
|
+
file: 'root.test.ts',
|
|
218
|
+
contents: TEST_ROUTES_TS
|
|
219
|
+
})
|
|
220
|
+
} else {
|
|
221
|
+
output.push({
|
|
222
|
+
path: 'test',
|
|
223
|
+
file: 'helper.js',
|
|
224
|
+
contents: testHelperJS(type, customizations)
|
|
225
|
+
})
|
|
226
|
+
output.push({
|
|
227
|
+
path: join('test', 'plugins'),
|
|
228
|
+
file: 'example.test.js',
|
|
229
|
+
contents: TEST_PLUGIN_JS
|
|
230
|
+
})
|
|
231
|
+
output.push({
|
|
232
|
+
path: join('test', 'routes'),
|
|
233
|
+
file: 'root.test.js',
|
|
234
|
+
contents: TEST_ROUTES_JS
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
return output
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function generatePlugins (typescript) {
|
|
241
|
+
const files = []
|
|
242
|
+
files.push(generatePluginWithTypesSupport(typescript))
|
|
243
|
+
files.push(generateRouteWithTypesSupport(typescript))
|
|
244
|
+
return files
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
module.exports = {
|
|
248
|
+
generatePluginWithTypesSupport,
|
|
249
|
+
generateRouteWithTypesSupport,
|
|
250
|
+
generatePlugins,
|
|
251
|
+
generateTests
|
|
252
|
+
}
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const createError = require('@fastify/error')
|
|
4
|
+
|
|
5
|
+
const ERROR_PREFIX = 'PLT_GEN'
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
NoQuestionsError: createError(`${ERROR_PREFIX}_NO_QUESTIONS_ERROR`, 'No questions added.'),
|
|
9
|
+
PrepareError: createError(`${ERROR_PREFIX}_PREPARE_ERROR`, 'Error while generating the files: %s.'),
|
|
10
|
+
MissingEnvVariable: createError(`${ERROR_PREFIX}_MISSING_ENV_VAR`, 'Env variable %s is defined in config file %s, but not in config.env object.')
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseLogger } from 'pino'
|
|
2
|
+
|
|
3
|
+
export namespace FileGenerator {
|
|
4
|
+
export type FileGeneratorOptions = {
|
|
5
|
+
logger?: BaseLogger
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type FileObject = {
|
|
9
|
+
path: string,
|
|
10
|
+
file: string,
|
|
11
|
+
contents: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export class FileGenerator {
|
|
15
|
+
files: FileObject[]
|
|
16
|
+
targetDirectory: string
|
|
17
|
+
|
|
18
|
+
constructor(opts?: FileGeneratorOptions)
|
|
19
|
+
|
|
20
|
+
setTargetDirectory(dir: string): void
|
|
21
|
+
addFile(file: FileObject): void
|
|
22
|
+
appendfile(file: FileObject): void
|
|
23
|
+
reset(): void
|
|
24
|
+
writeFiles(): Promise<void>
|
|
25
|
+
listFiles(): FileObject
|
|
26
|
+
getFileObject(file: string, path?: string): FileObject
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const { safeMkdir } = require('./utils')
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const { writeFile } = require('node:fs/promises')
|
|
5
|
+
|
|
6
|
+
/* c8 ignore start */
|
|
7
|
+
const fakeLogger = {
|
|
8
|
+
info: () => {},
|
|
9
|
+
warn: () => {},
|
|
10
|
+
debug: () => {},
|
|
11
|
+
trace: () => {},
|
|
12
|
+
error: () => {}
|
|
13
|
+
}
|
|
14
|
+
/* c8 ignore start */
|
|
15
|
+
|
|
16
|
+
class FileGenerator {
|
|
17
|
+
constructor (opts = {}) {
|
|
18
|
+
this.files = []
|
|
19
|
+
this.logger = opts.logger || fakeLogger
|
|
20
|
+
this.targetDirectory = opts.targetDirectory || null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setTargetDirectory (dir) {
|
|
24
|
+
this.targetDirectory = dir
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
addFile ({ path, file, contents }) {
|
|
28
|
+
const fileObject = this.getFileObject(file, path)
|
|
29
|
+
if (path.startsWith('/')) {
|
|
30
|
+
path = path.substring(1)
|
|
31
|
+
}
|
|
32
|
+
if (fileObject) {
|
|
33
|
+
fileObject.contents = contents
|
|
34
|
+
} else {
|
|
35
|
+
this.files.push({ path, file, contents })
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
appendfile ({ path, file, contents }) {
|
|
40
|
+
if (path.startsWith('/')) {
|
|
41
|
+
path = path.substring(1)
|
|
42
|
+
}
|
|
43
|
+
const fileObject = this.getFileObject(file, path)
|
|
44
|
+
if (fileObject) {
|
|
45
|
+
fileObject.contents += `\n${contents}`
|
|
46
|
+
} else {
|
|
47
|
+
this.files.push({ path, file, contents })
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async writeFiles () {
|
|
52
|
+
if (!this.targetDirectory) {
|
|
53
|
+
throw new Error('No target directory set.')
|
|
54
|
+
}
|
|
55
|
+
await safeMkdir(this.targetDirectory)
|
|
56
|
+
for (const fileToWrite of this.files) {
|
|
57
|
+
if (fileToWrite.contents.length === 0) {
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
const baseDir = join(this.targetDirectory, fileToWrite.path)
|
|
61
|
+
if (fileToWrite.path !== '') {
|
|
62
|
+
await safeMkdir(baseDir)
|
|
63
|
+
}
|
|
64
|
+
const fullFilePath = join(baseDir, fileToWrite.file)
|
|
65
|
+
await writeFile(fullFilePath, fileToWrite.contents)
|
|
66
|
+
this.logger.info(`${fullFilePath} written!`)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getFileObject (name, path = '') {
|
|
71
|
+
const output = this.files.find((file) => {
|
|
72
|
+
return file.path === path && file.file === name
|
|
73
|
+
})
|
|
74
|
+
if (!output) { return null }
|
|
75
|
+
return output
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
listFiles () {
|
|
79
|
+
return this.files.map((fileObject) => {
|
|
80
|
+
return join(fileObject.path, fileObject.file)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
reset () {
|
|
85
|
+
this.files = []
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = FileGenerator
|
|
90
|
+
module.exports.FileGenerator = FileGenerator
|
package/lib/utils.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type Env = {
|
|
2
|
+
[key: string]: string
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export namespace GeneratorUtils {
|
|
6
|
+
export function safeMkdir(dir: string): Promise<void>
|
|
7
|
+
export function stripVersion(version: string): string
|
|
8
|
+
export function convertServiceNameToPrefix(serviceName: string): string
|
|
9
|
+
export function addPrefixToEnv(env: Env, prefix: string): Env
|
|
10
|
+
export function envObjectToString(env: Env): string
|
|
11
|
+
export function extractEnvVariablesFromText(text: string): string[]
|
|
12
|
+
}
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { mkdir } = require('node:fs/promises')
|
|
4
|
+
|
|
5
|
+
async function safeMkdir (dir) {
|
|
6
|
+
try {
|
|
7
|
+
await mkdir(dir, { recursive: true })
|
|
8
|
+
/* c8 ignore next 3 */
|
|
9
|
+
} catch (err) {
|
|
10
|
+
// do nothing
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Strip all extra characters from a simple semver version string
|
|
16
|
+
* @param {string} version
|
|
17
|
+
* @returns string
|
|
18
|
+
*/
|
|
19
|
+
function stripVersion (version) {
|
|
20
|
+
const match = version.match(/(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)/)
|
|
21
|
+
if (match) {
|
|
22
|
+
return match[0]
|
|
23
|
+
}
|
|
24
|
+
return version
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function convertServiceNameToPrefix (serviceName) {
|
|
28
|
+
return serviceName.replace(/-/g, '_').toUpperCase()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function addPrefixToEnv (env, prefix) {
|
|
32
|
+
const newEnv = {}
|
|
33
|
+
const prefixRegExp = new RegExp(`^PLT_${prefix}_`)
|
|
34
|
+
Object.entries(env).forEach((kv) => {
|
|
35
|
+
if (!kv[0].match(prefixRegExp)) {
|
|
36
|
+
newEnv[`PLT_${prefix}_${kv[0]}`] = kv[1]
|
|
37
|
+
} else {
|
|
38
|
+
newEnv[kv[0]] = kv[1]
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
return newEnv
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function envObjectToString (env) {
|
|
45
|
+
const output = []
|
|
46
|
+
Object.entries(env).forEach((kv) => {
|
|
47
|
+
output.push(`${kv[0]}=${kv[1]}`)
|
|
48
|
+
})
|
|
49
|
+
return output.join('\n')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function extractEnvVariablesFromText (text) {
|
|
53
|
+
const match = text.match(/\{[a-zA-Z0-9-_]*\}/g)
|
|
54
|
+
if (match) {
|
|
55
|
+
return match
|
|
56
|
+
.map((found) => found.replace('{', '').replace('}', ''))
|
|
57
|
+
.filter((found) => found !== '')
|
|
58
|
+
}
|
|
59
|
+
return []
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
addPrefixToEnv,
|
|
64
|
+
convertServiceNameToPrefix,
|
|
65
|
+
envObjectToString,
|
|
66
|
+
extractEnvVariablesFromText,
|
|
67
|
+
safeMkdir,
|
|
68
|
+
stripVersion
|
|
69
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@platformatic/generators",
|
|
3
|
+
"version": "1.13.0",
|
|
4
|
+
"description": "Main classes and utils for generators.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": [],
|
|
7
|
+
"author": "",
|
|
8
|
+
"license": "Apache-2.0",
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"@fastify/error": "^3.4.1",
|
|
11
|
+
"boring-name-generator": "^1.0.3",
|
|
12
|
+
"fastify": "^4.24.3",
|
|
13
|
+
"pino": "^8.16.1"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/inquirer": "^9.0.7",
|
|
17
|
+
"c8": "^8.0.1",
|
|
18
|
+
"glob": "^10.3.10",
|
|
19
|
+
"snazzy": "^9.0.0",
|
|
20
|
+
"standard": "^17.1.0",
|
|
21
|
+
"typescript": "^5.2.2"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"lint": "standard | snazzy",
|
|
25
|
+
"test": "pnpm run lint && c8 --100 -x fixtures -x test node ./test/runner.js"
|
|
26
|
+
}
|
|
27
|
+
}
|