create-juisy 2.0.0-beta.9 → 2.1.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.
Files changed (47) hide show
  1. package/LICENSE +661 -0
  2. package/index.js +45 -17
  3. package/package.json +57 -59
  4. package/template/.env.example +1 -1
  5. package/template/COMMIT_CONVENTION.md +116 -0
  6. package/template/CONTRIBUTING.md +61 -0
  7. package/template/bin/cli/cli.js +11 -14
  8. package/template/bin/cli/cmds/index.js +4 -6
  9. package/template/bin/cli/cmds/private/docs/{generate-api.js → GenerateAPI.js} +28 -7
  10. package/template/bin/cli/cmds/private/docs/index.js +30 -11
  11. package/template/bin/cli/cmds/private/test.js +40 -25
  12. package/template/bin/cli/index.js +4 -2
  13. package/template/bin/scripts/commit-msg.js +13 -18
  14. package/template/bin/scripts/pre-commit.js +13 -11
  15. package/template/dev.config.js +37 -5
  16. package/template/dev.config.json +19 -1
  17. package/template/dev.config.ts +40 -1
  18. package/template/docs/.markdownlint-cli2.mjs +21 -0
  19. package/template/docs/cli/private/config.js +37 -0
  20. package/template/docs/cli/private/data.js +14 -0
  21. package/template/docs/cli/private/partials/child-command.md +26 -0
  22. package/template/docs/cli/private/template.md +26 -0
  23. package/template/docs/cli/public/config.js +21 -0
  24. package/template/docs/cli/public/template.md +19 -0
  25. package/template/docs/readme/config.js +24 -13
  26. package/template/docs/readme/data.js +45 -0
  27. package/template/docs/readme/template.md +37 -9
  28. package/template/eslint.config.js +47 -0
  29. package/template/package.json +9 -6
  30. package/template/project.globals.js +20 -29
  31. package/template/tests/unit/example.spec.ts +13 -0
  32. package/template/tests/unit/setup.unit.ts +14 -0
  33. package/template/tests/vitest.d.ts +16 -0
  34. package/template/tsconfig.json +18 -0
  35. package/template/vite.config.ts +22 -0
  36. package/template/bin/cli/cmds/private/changelog.js +0 -44
  37. package/template/bin/cli/cmds/private/docs/generate-cli.js +0 -11
  38. package/template/bin/cli/cmds/private/docs/generate-readme.js +0 -11
  39. package/template/bin/cli/cmds/private/docs/lint.js +0 -42
  40. package/template/bin/cli/cmds/private/git-hooks/index.js +0 -20
  41. package/template/bin/cli/cmds/private/git-hooks/reset.js +0 -48
  42. package/template/bin/cli/cmds/private/git-hooks/sync.js +0 -19
  43. package/template/bin/cli/cmds/private/release.js +0 -223
  44. package/template/bin/cli/lib/docs/generate-api-doc.js +0 -33
  45. package/template/bin/cli/lib/release/generate-release-note.js +0 -3
  46. package/template/bin/cli/lib/version/update-version.js +0 -51
  47. package/template/docs/readme/readme.js +0 -70
@@ -1,14 +1,17 @@
1
- const juisy = require('@hperchec/juisy')
1
+ import { InterfaceUtils, OutputUtils } from 'juisy/cli'
2
2
 
3
3
  const {
4
- $style,
5
4
  abort,
5
+ run
6
+ } = InterfaceUtils
7
+
8
+ const {
9
+ $style,
6
10
  log,
7
- rootDir,
11
+ error,
8
12
  step,
9
- substep,
10
- run
11
- } = juisy.utils
13
+ substep
14
+ } = OutputUtils
12
15
 
13
16
  /**
14
17
  * commit-msg git hook
@@ -17,26 +20,18 @@ const {
17
20
  step('Git hook: commit-msg')
18
21
 
19
22
  // Get git commit msg path from args
20
- const args = process.argv.slice(2)
21
- const gitMsgPath = args[0]
23
+ // We call this script as: node ./bin/scripts/commit-msg $1
24
+ const gitMsgPath = process.argv[2]
22
25
 
23
26
  try {
24
- // original is: npx --no -- commitlint --edit ${1}
25
- // we replace "${1}" by gitMsgPath arg
26
- await run('npx', [
27
- '--no',
28
- '--',
29
- 'commitlint',
30
- '--edit',
31
- gitMsgPath
32
- ], { cwd: rootDir })
27
+ await run('node', [ './bin/cli', 'lint:commit', '--edit', gitMsgPath ])
33
28
  } catch (e) {
34
29
  substep($style.red('❌ Git hook: "commit-msg" failed. Please check ./COMMIT_CONVENTION.md for more informations.'), { last: true })
30
+ error('Error:', e)
35
31
  abort(1) // Abort with error
36
32
  }
37
33
 
38
34
  // Everything is okay
39
35
  substep($style.green('✔ Git hook: "commit-msg" passed'), { last: true })
40
-
41
36
  log() // blank line
42
37
  })()
@@ -1,14 +1,17 @@
1
- const juisy = require('@hperchec/juisy')
1
+ import { InterfaceUtils, OutputUtils } from 'juisy/cli'
2
+
3
+ const {
4
+ abort,
5
+ run
6
+ } = InterfaceUtils
2
7
 
3
8
  const {
4
9
  $style,
5
- error,
6
10
  log,
7
- rootDir,
11
+ error,
8
12
  step,
9
- substep,
10
- run
11
- } = juisy.utils
13
+ substep
14
+ } = OutputUtils
12
15
 
13
16
  /**
14
17
  * Pre commit git hook
@@ -17,12 +20,11 @@ const {
17
20
  step('Git hook: pre-commit')
18
21
 
19
22
  try {
20
- // npx lint-staged
21
- await run('npx', [
22
- 'lint-staged'
23
- ], { stdio: 'pipe', cwd: rootDir })
23
+ await run('node', [ './bin/cli', 'lint:staged' ])
24
24
  } catch (e) {
25
- error('Git hook: "commit-msg" error: ', e)
25
+ substep($style.red('Git hook: "pre-commit" failed.'), { last: true })
26
+ error('Error:', e)
27
+ abort(1) // Abort with error
26
28
  }
27
29
 
28
30
  // Everything is okay
@@ -18,17 +18,49 @@ export default {
18
18
  'commit-msg': 'node ./bin/scripts/commit-msg.js ${1}'
19
19
  },
20
20
  lint: {
21
+ default: {
22
+ config: 'eslint.config.js'
23
+ },
24
+ commit: {
25
+ // See also: https://github.com/conventional-changelog/commitlint
26
+ extends: [
27
+ '@commitlint/config-conventional'
28
+ ]
29
+ },
30
+ markdown: [
31
+ {
32
+ globs: [ 'README.md' ],
33
+ config: './docs/.markdownlint-cli2.mjs'
34
+ },
35
+ {
36
+ globs: [ 'cli.private.md', 'cli.public.md' ],
37
+ config: './docs/.markdownlint-cli2.mjs'
38
+ }
39
+ ],
21
40
  staged: {
22
41
  '*.{js,cjs,ts}': [
23
- 'eslint --fix'
42
+ 'node ./bin/cli lint --fix'
24
43
  ]
25
44
  }
26
45
  },
27
46
  release: {
28
- git: {
29
- commitMessage: 'chore(release): v${version}',
30
- requireBranch: 'main',
31
- tagAnnotation: 'v${version}'
47
+ /**
48
+ * See: https://github.com/release-it/release-it?tab=readme-ov-file#hooks
49
+ */
50
+ hooks: {
51
+ 'before:init': [
52
+ // Lint and run tests
53
+ 'node ./bin/cli lint --fix',
54
+ 'node ./bin/cli test'
55
+ ],
56
+ 'after:bump': [
57
+ // Build code and generate docs
58
+ 'vite build',
59
+ 'node ./bin/cli docs generate:api',
60
+ 'node ./bin/cli docs generate:readme',
61
+ 'node ./bin/cli docs generate:cli -c ./docs/cli/private/config.js',
62
+ 'node ./bin/cli docs generate:cli -c ./docs/cli/public/config.js'
63
+ ]
32
64
  }
33
65
  }
34
66
  }
@@ -18,9 +18,27 @@
18
18
  "commit-msg": "node ./bin/scripts/commit-msg.js ${1}"
19
19
  },
20
20
  "lint": {
21
+ "default": {
22
+ "config": "eslint.config.js"
23
+ },
24
+ "commit": {
25
+ "extends": [
26
+ "@commitlint/config-conventional"
27
+ ]
28
+ },
29
+ "markdown": [
30
+ {
31
+ "globs": [ "README.md" ],
32
+ "config": "./docs/.markdownlint-cli2.mjs"
33
+ },
34
+ {
35
+ "globs": [ "cli.private.md", "cli.public.md" ],
36
+ "config": "./docs/.markdownlint-cli2.mjs"
37
+ }
38
+ ],
21
39
  "staged": {
22
40
  "*.{js,cjs,ts}": [
23
- "eslint --fix"
41
+ "node ./bin/cli lint --fix"
24
42
  ]
25
43
  }
26
44
  }
@@ -19,9 +19,48 @@ export default {
19
19
  'commit-msg': 'node ./bin/scripts/commit-msg.js ${1}'
20
20
  },
21
21
  lint: {
22
+ default: {
23
+ config: 'eslint.config.js'
24
+ },
25
+ commit: {
26
+ // See also: https://github.com/conventional-changelog/commitlint
27
+ extends: [
28
+ '@commitlint/config-conventional'
29
+ ]
30
+ },
31
+ markdown: [
32
+ {
33
+ globs: [ 'README.md' ],
34
+ config: './docs/.markdownlint-cli2.mjs'
35
+ },
36
+ {
37
+ globs: [ 'cli.private.md', 'cli.public.md' ],
38
+ config: './docs/.markdownlint-cli2.mjs'
39
+ }
40
+ ],
22
41
  staged: {
23
42
  '*.{js,cjs,ts}': [
24
- 'eslint --fix'
43
+ 'node ./bin/cli lint --fix'
44
+ ]
45
+ }
46
+ },
47
+ release: {
48
+ /**
49
+ * See: https://github.com/release-it/release-it?tab=readme-ov-file#hooks
50
+ */
51
+ hooks: {
52
+ 'before:init': [
53
+ // Lint and run tests
54
+ 'node ./bin/cli lint --fix',
55
+ 'node ./bin/cli test'
56
+ ],
57
+ 'after:bump': [
58
+ // Build code and generate docs
59
+ 'vite build',
60
+ 'node ./bin/cli docs generate:api',
61
+ 'node ./bin/cli docs generate:readme',
62
+ 'node ./bin/cli docs generate:cli -c ./docs/cli/private/config.js',
63
+ 'node ./bin/cli docs generate:cli -c ./docs/cli/public/config.js'
25
64
  ]
26
65
  }
27
66
  }
@@ -0,0 +1,21 @@
1
+ import { init } from '@github/markdownlint-github'
2
+
3
+ const options = {
4
+ // See also https://www.npmjs.com/package/@github/markdownlint-github
5
+ config: init({
6
+ // ... Custom overrides
7
+ }),
8
+ customRules: [
9
+ '@github/markdownlint-github'
10
+ ],
11
+ outputFormatters: [
12
+ [
13
+ 'markdownlint-cli2-formatter-pretty',
14
+ {
15
+ appendLink: true // ensures the error message includes a link to the rule documentation
16
+ }
17
+ ]
18
+ ]
19
+ }
20
+
21
+ export default options
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ReadmeTemplater configuration file
3
+ */
4
+
5
+ import path, { dirname } from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = dirname(__filename)
10
+
11
+ /** @type {import('juisy/templater').ReadmeTemplaterUserConfig} */
12
+ export default {
13
+ /**
14
+ * Output file name: 'README.md' by default
15
+ */
16
+ fileName: 'cli.private.md',
17
+ /**
18
+ * Change destination folder
19
+ */
20
+ destFolder: path.resolve(__dirname, '../../..'),
21
+ /**
22
+ * Template entry file path
23
+ */
24
+ templatePath: path.resolve(__dirname, './template.md'),
25
+ /**
26
+ * EJS data file
27
+ */
28
+ ejsDataPath: path.resolve(__dirname, './data.js'),
29
+ /**
30
+ * EJS options
31
+ */
32
+ ejsOptions: {
33
+ views: [
34
+ path.resolve(__dirname, './partials')
35
+ ]
36
+ }
37
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * ReadmeTemplater EJS data file
3
+ */
4
+
5
+ import stripAnsi from 'strip-ansi'
6
+ import cli from '../../../bin/cli/cli.js'
7
+
8
+ import { extractUsage } from 'juisy/cli'
9
+
10
+ export const rootDoclet = await extractUsage(cli, true) // recursively extract usage
11
+ // Add filters
12
+ export const $filters = {
13
+ stripAnsi
14
+ }
@@ -0,0 +1,26 @@
1
+ <%%
2
+ // Optional props
3
+ if (hLevel === undefined) { hLevel = 3 }
4
+ if (recursive === undefined) { recursive = true }
5
+ -%>
6
+ <%%= $utils.h(hLevel, '`' + cmdDoclet.args.join(' ') + '`') %>
7
+
8
+ ```
9
+ <%%- $filters.stripAnsi(cmdDoclet.rawUsage) %>
10
+ ```
11
+
12
+ <%%
13
+ if (recursive) {
14
+ for (const child in cmdDoclet.children) {
15
+ %>
16
+ <%%-
17
+ await include('child-command.md', {
18
+ cmdDoclet: cmdDoclet.children[child],
19
+ hLevel: hLevel + 1,
20
+ recursive: true
21
+ })
22
+ %>
23
+ <%%
24
+ }
25
+ }
26
+ %>
@@ -0,0 +1,26 @@
1
+ # CLI
2
+
3
+ ## Table of contents
4
+
5
+ <%%#
6
+ // Table of contents is automatically injected here by
7
+ // [remark-toc](https://github.com/remarkjs/remark-toc)
8
+ -%>
9
+
10
+ ## Usage
11
+
12
+ ```console
13
+ <%%- $filters.stripAnsi(rootDoclet.rawUsage) %>
14
+ ```
15
+
16
+ ## Commands
17
+
18
+ <%% for (const child in rootDoclet.children) { %>
19
+ <%%-
20
+ await include('child-command.md', {
21
+ cmdDoclet: rootDoclet.children[child],
22
+ hLevel: 3,
23
+ recursive: true
24
+ })
25
+ %>
26
+ <%% } %>
@@ -0,0 +1,21 @@
1
+ /**
2
+ * ReadmeTemplater configuration file
3
+ */
4
+
5
+ import path, { dirname } from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+
8
+ import baseConfig from '../private/config.js'
9
+
10
+ const __filename = fileURLToPath(import.meta.url)
11
+ const __dirname = dirname(__filename)
12
+
13
+ // Force process.env.CLI_ENV to "public"
14
+ process.env.CLI_ENV = 'public'
15
+
16
+ /** @type {import('juisy/templater').ReadmeTemplaterUserConfig} */
17
+ export default {
18
+ ...baseConfig,
19
+ fileName: 'cli.public.md',
20
+ templatePath: path.resolve(__dirname, './template.md')
21
+ }
@@ -0,0 +1,19 @@
1
+ # CLI
2
+
3
+ ## Usage
4
+
5
+ ```console
6
+ <%%- $filters.stripAnsi(rootDoclet.rawUsage) %>
7
+ ```
8
+
9
+ ## Commands
10
+
11
+ <%% for (const child in rootDoclet.children) { %>
12
+ <%%-
13
+ await include('child-command.md', {
14
+ cmdDoclet: rootDoclet.children[child],
15
+ hLevel: 3,
16
+ recursive: true
17
+ })
18
+ %>
19
+ <%% } %>
@@ -1,22 +1,33 @@
1
1
  /**
2
- * @hperchec/readme-generator Example configuration file
2
+ * ReadmeTemplater configuration file
3
3
  */
4
4
 
5
- const path = require('path')
5
+ import path, { dirname } from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
6
7
 
7
- // Export configuration
8
- module.exports = {
9
- // Template path
10
- templatePath: path.resolve(__dirname, './template.md'), // Default template file
11
- // Output path
12
- outputPath: path.resolve(__dirname, '../../'), // Your project root directory by default
13
- // Output file name
14
- outputName: 'README.md', // 'README.md' by default
15
- // Path to ejs data file
16
- ejsDataPath: path.resolve(__dirname, './readme.js'), // Default template ejs data file
8
+ const __filename = fileURLToPath(import.meta.url)
9
+ const __dirname = dirname(__filename)
10
+
11
+ /** @type {import('juisy/templater').ReadmeTemplaterUserConfig} */
12
+ export default {
13
+ /**
14
+ * Output file name: 'README.md' by default
15
+ */
16
+ fileName: 'README.md',
17
+ /**
18
+ * Change destination folder
19
+ */
20
+ destFolder: path.resolve(__dirname, '../..'),
21
+ /**
22
+ * Template entry file path
23
+ */
24
+ templatePath: path.resolve(__dirname, './template.md'),
25
+ /**
26
+ * EJS data file
27
+ */
28
+ ejsDataPath: path.resolve(__dirname, './data.js'),
17
29
  // EJS options (see https://www.npmjs.com/package/ejs#options)
18
30
  ejsOptions: {
19
- async: true
20
31
  /* your ejs options... */
21
32
  }
22
33
  }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ReadmeTemplater EJS data file
3
+ */
4
+
5
+ import { getPackageInfo } from 'juisy'
6
+
7
+ // Based on the package.json file, get some data and informations
8
+ const pkg = getPackageInfo()
9
+
10
+ /**
11
+ * Return author link
12
+ * @param {Object} author
13
+ * @return {string}
14
+ */
15
+ function getMdAuthor (author) {
16
+ return '[' + author.name + '](' + author.url + ')'
17
+ }
18
+
19
+ /**
20
+ * Return markdown list of persons
21
+ * @param {Array} contributors
22
+ * @return {String}
23
+ */
24
+ function getMdContributors (contributors) {
25
+ let mdString = ''
26
+ contributors.forEach((person) => {
27
+ mdString += '- [' + person.name + '](' + person.url + ')\n'
28
+ })
29
+ return mdString
30
+ }
31
+
32
+ /**
33
+ * Export data for readme file templating
34
+ */
35
+ export const packageName = pkg.name
36
+ export const packageUrl = `https://www.npmjs.com/package/${packageName}`
37
+ export const dependencies = pkg.dependencies || {}
38
+ export const devDependencies = pkg.devDependencies || {}
39
+ export const peerDependencies = pkg.peerDependencies || {}
40
+ export const projectUrl = pkg.repository.url.match(/^git\+(.*)\.git$/)[1] // find string between 'git+' and '.git'
41
+ export const projectPath = projectUrl.replace('https://gitlab.com/', '') // remove domain name
42
+ export const issuesUrl = pkg.bugs.url
43
+ export const license = pkg.license || 'Unknown'
44
+ export const author = getMdAuthor(pkg.author)
45
+ export const contributors = getMdContributors(pkg.contributors || [])
@@ -1,11 +1,17 @@
1
1
  # Awesome project
2
2
 
3
- [![author](https://img.shields.io/static/v1?label=&message=Author:&color=black)]()
3
+ [![author](https://img.shields.io/static/v1?label=&message=Author:&color=black)](http://herve-perchec.com/)
4
4
  [![herve-perchec](http://herve-perchec.com/badge.svg)](http://herve-perchec.com/)
5
5
 
6
- **Table of contents**:
6
+ > You can use [shields.io](https://shields.io/) to generate your own badges!
7
+
8
+ ## Table of contents
9
+
10
+ <%%#
11
+ // Table of contents is automatically injected here by
12
+ // [remark-toc](https://github.com/remarkjs/remark-toc)
13
+ -%>
7
14
 
8
- [[*TOC*]]
9
15
 
10
16
  ## 🚀 Get started
11
17
 
@@ -13,33 +19,51 @@
13
19
  # Let's go!
14
20
  ```
15
21
 
16
- ## 📙 Documentation
17
-
18
- Please check the [documentation](https://www.npmjs.com/package/@hperchec/juisy)
22
+ This project is made with [Juisy](https://www.npmjs.com/package/juisy).
23
+ Read the [documentation](https://hperchec.gitlab.io/juisy) to learn more!
19
24
 
20
25
  ## 🧱 Dependencies
21
26
 
22
27
  <details>
23
28
  <summary>Global</summary>
24
29
 
25
- <%%= dependencies %>
30
+ <%%-
31
+ $utils.table([
32
+ ['name', 'version'],
33
+ ...(Object.entries(dependencies))
34
+ ])
35
+ %>
26
36
 
27
37
  </details>
28
38
 
29
39
  <details>
30
40
  <summary>Dev</summary>
31
41
 
32
- <%%= devDependencies %>
42
+ <%%-
43
+ $utils.table([
44
+ ['name', 'version'],
45
+ ...(Object.entries(devDependencies))
46
+ ])
47
+ %>
33
48
 
34
49
  </details>
35
50
 
36
51
  <details>
37
52
  <summary>Peer</summary>
38
53
 
39
- <%%= peerDependencies %>
54
+ <%%-
55
+ $utils.table([
56
+ ['name', 'version'],
57
+ ...(Object.entries(peerDependencies))
58
+ ])
59
+ %>
40
60
 
41
61
  </details>
42
62
 
63
+ ## 🤝 Contribute
64
+
65
+ See the [CONTRIBUTING.md](./CONTRIBUTING.md) file.
66
+
43
67
  ## ✍ Author
44
68
 
45
69
  <%%= author %>
@@ -48,6 +72,10 @@ Please check the [documentation](https://www.npmjs.com/package/@hperchec/juisy)
48
72
 
49
73
  <%%= license %>
50
74
 
75
+ ## 🧬 Changelog
76
+
77
+ See all changes to this project in the [CHANGELOG.md](./CHANGELOG.md) file.
78
+
51
79
  ----
52
80
 
53
81
  Made with ❤ by <%%= author %>
@@ -0,0 +1,47 @@
1
+ import globals from 'globals'
2
+ import js from '@eslint/js'
3
+ import stylistic from '@stylistic/eslint-plugin'
4
+
5
+ /** @type {import('eslint').Linter.Config[]} */
6
+ export default [
7
+ {
8
+ languageOptions: {
9
+ globals: {
10
+ ...globals.node
11
+ }
12
+ }
13
+ },
14
+ /**
15
+ * See: https://eslint.style/packages/default
16
+ */
17
+ stylistic.configs.customize({
18
+ // ...
19
+ }),
20
+ /**
21
+ * Our rules configuration
22
+ */
23
+ {
24
+ rules: {
25
+ // @eslint/js
26
+ ...js.configs.recommended.rules,
27
+ 'no-unused-vars': [ 'error', {
28
+ args: 'none'
29
+ } ],
30
+ // @stylistic/eslint-plugin
31
+ '@stylistic/array-bracket-spacing': [ 'error', 'always' ],
32
+ '@stylistic/brace-style': [ 'error', '1tbs' ],
33
+ '@stylistic/comma-dangle': [ 'error', 'never' ],
34
+ '@stylistic/space-before-function-paren': [ 'error', 'always' ]
35
+ }
36
+ },
37
+ {
38
+ files: [
39
+ '**/bin/cli/**/*.js'
40
+ ],
41
+ languageOptions: {
42
+ globals: {
43
+ CLI: 'readonly'
44
+ }
45
+ }
46
+ }
47
+ ]
@@ -1,11 +1,9 @@
1
1
  {
2
- "name": "new-project",
2
+ "name": "<%= __PROJECT_NAME__ %>",
3
3
  "version": "1.0.0",
4
4
  "description": "New project based on Juisy template",
5
5
  "type": "module",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
6
+ "scripts": {},
9
7
  "repository": {
10
8
  "type": "git",
11
9
  "url": "git+https://gitlab.com/hperchec/juisy.git"
@@ -18,8 +16,13 @@
18
16
  "bugs": {
19
17
  "url": "https://gitlab.com/hperchec/juisy/issues"
20
18
  },
21
- "homepage": "https://gitlab.com/hperchec/juisy#readme",
19
+ "homepage": "<%= __JUISY_DOCS_HOMEPAGE__ %>",
22
20
  "dependencies": {
23
- "juisy": "^__JUISY_VERSION__"
21
+ "juisy": "^<%= __JUISY_VERSION__ %>"
22
+ },
23
+ "devDependencies": {
24
+ "@vitest/coverage-v8": "^3",
25
+ "@vitest/ui": "^3",
26
+ "vitest": "^3"
24
27
  }
25
28
  }