create-juisy 2.0.0-beta.10

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 (33) hide show
  1. package/LICENSE +661 -0
  2. package/index.js +162 -0
  3. package/package.json +63 -0
  4. package/template/.env.example +4 -0
  5. package/template/CHANGELOG.md +0 -0
  6. package/template/bin/cli/cli.js +27 -0
  7. package/template/bin/cli/cmds/index.js +13 -0
  8. package/template/bin/cli/cmds/private/changelog.js +44 -0
  9. package/template/bin/cli/cmds/private/docs/generate-api.js +22 -0
  10. package/template/bin/cli/cmds/private/docs/generate-cli.js +11 -0
  11. package/template/bin/cli/cmds/private/docs/generate-readme.js +11 -0
  12. package/template/bin/cli/cmds/private/docs/index.js +20 -0
  13. package/template/bin/cli/cmds/private/docs/lint.js +42 -0
  14. package/template/bin/cli/cmds/private/git-hooks/index.js +20 -0
  15. package/template/bin/cli/cmds/private/git-hooks/reset.js +48 -0
  16. package/template/bin/cli/cmds/private/git-hooks/sync.js +19 -0
  17. package/template/bin/cli/cmds/private/release.js +223 -0
  18. package/template/bin/cli/cmds/private/test.js +33 -0
  19. package/template/bin/cli/index.js +7 -0
  20. package/template/bin/cli/lib/docs/generate-api-doc.js +33 -0
  21. package/template/bin/cli/lib/release/generate-release-note.js +3 -0
  22. package/template/bin/cli/lib/version/update-version.js +51 -0
  23. package/template/bin/scripts/commit-msg.js +42 -0
  24. package/template/bin/scripts/pre-commit.js +32 -0
  25. package/template/dev.config.js +34 -0
  26. package/template/dev.config.json +27 -0
  27. package/template/dev.config.ts +28 -0
  28. package/template/docs/api/docs.config.js +10 -0
  29. package/template/docs/readme/config.js +22 -0
  30. package/template/docs/readme/readme.js +70 -0
  31. package/template/docs/readme/template.md +53 -0
  32. package/template/package.json +25 -0
  33. package/template/project.globals.js +33 -0
package/index.js ADDED
@@ -0,0 +1,162 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Create a new Juisy project
5
+ * @author Hervé Perchec
6
+ * @see https://github.com/hperchec/juisy
7
+ */
8
+
9
+ import fs from 'node:fs'
10
+ import path, { dirname } from 'node:path'
11
+ import { fileURLToPath } from 'node:url'
12
+ import mri from 'mri'
13
+ import { eject } from 'juisy'
14
+ import { InterfaceUtils, OutputUtils } from 'juisy/cli'
15
+
16
+ const __filename = fileURLToPath(import.meta.url)
17
+ const __dirname = dirname(__filename)
18
+
19
+ const {
20
+ run,
21
+ prompts
22
+ } = InterfaceUtils
23
+
24
+ const {
25
+ $style,
26
+ log,
27
+ step,
28
+ substep
29
+ } = OutputUtils
30
+
31
+ // Use `mri` library to parse command line arguments
32
+ // Usage: npm create juisy <project-name> -- [--template|-t <template>] [--force|-f]
33
+ const argv = mri(process.argv.slice(2), {
34
+ alias: { t: 'template', f: 'force' },
35
+ boolean: [ 'force' ],
36
+ string: [ 'template' ]
37
+ })
38
+
39
+ const cwd = process.cwd()
40
+
41
+ // Get juisy version from this package.json file
42
+ const { version: JUISY_VERSION } = JSON.parse(
43
+ fs.readFileSync(path.resolve(__dirname, './package.json'), 'utf-8')
44
+ )
45
+
46
+ const defaultTargetDir = 'juisy-project'
47
+
48
+ const rmTrailingSlashes = str => str.trim().replace(/\/+$/g, '') // remove trailing slashes
49
+
50
+ async function main () {
51
+ // Get target dir argument (optional)
52
+ let targetDir = argv._[0]
53
+ ? rmTrailingSlashes(String(argv._[0])) // remove trailing slashes
54
+ : undefined
55
+
56
+ let devConfigFormat = '.ts' // default is typescript config
57
+
58
+ // Project name (& directory name)
59
+ if (!targetDir) {
60
+ const promptsResult = await prompts([
61
+ {
62
+ type: 'text',
63
+ message: 'Project name (directory):',
64
+ initial: defaultTargetDir,
65
+ name: 'projectName'
66
+ }
67
+ ])
68
+ targetDir = rmTrailingSlashes(promptsResult.projectName)
69
+ }
70
+
71
+ // Dev config format
72
+ const promptsResult = await prompts([
73
+ {
74
+ type: 'select',
75
+ message: 'Dev config format:',
76
+ choices: [
77
+ { title: 'TypeScript', description: 'dev.config.ts', value: '.ts' },
78
+ { title: 'JavaScript', description: 'dev.config.js', value: '.js' },
79
+ { title: 'JSON', description: 'dev.config.json', value: '.json' }
80
+ ],
81
+ initial: 0,
82
+ name: 'devConfigFormat'
83
+ }
84
+ ])
85
+ devConfigFormat = promptsResult.devConfigFormat
86
+
87
+ /**
88
+ * Eject files from template
89
+ */
90
+ step('Copying files')
91
+
92
+ await eject(path.resolve(__dirname, './template'), '**/*', {
93
+ force: argv.force,
94
+ targetDir: path.resolve(cwd, targetDir),
95
+ ignoreFiles: [
96
+ 'dev.config.ts',
97
+ 'dev.config.js',
98
+ 'dev.config.json'
99
+ ].filter(identifier => !identifier.endsWith(devConfigFormat)), // don't ignore dev config file of chosen format
100
+ logLevel: 'warn',
101
+ processor: (content, identifier) => {
102
+ if (identifier === 'package.json') {
103
+ return content.replace(/__JUISY_VERSION__/g, JUISY_VERSION)
104
+ } else {
105
+ return content
106
+ }
107
+ }
108
+ })
109
+
110
+ substep($style.green(`✔ Successfuly copied`), { last: true })
111
+ log() // Blank line
112
+
113
+ const targetCliCommand = 'node ./bin/cli'
114
+
115
+ /**
116
+ * Update package.json file
117
+ */
118
+ const scripts = {
119
+ 'docs:api': `${targetCliCommand} docs generate -c ./docs/docs.config.js`,
120
+ 'docs:readme': `${targetCliCommand} docs generate:readme`,
121
+ 'docs:lint': `${targetCliCommand} docs lint`,
122
+ 'docs:lint:fix': 'npm run docs:lint -- --fix',
123
+ 'docs': 'npm run docs:readme && npm run docs:api && npm run docs:lint',
124
+ 'lint': `${targetCliCommand} lint`,
125
+ 'lint:fix': 'npm run lint -- --fix',
126
+ 'lint:markdown': 'npm run docs:lint',
127
+ 'lint:markdown:fix': 'npm run docs:lint:fix',
128
+ 'release': `${targetCliCommand} release`,
129
+ 'changelog': `${targetCliCommand} changelog`,
130
+ 'git-hooks:reset': `${targetCliCommand} git-hooks reset`,
131
+ 'git-hooks:sync': `${targetCliCommand} git-hooks sync`,
132
+ 'test': `${targetCliCommand} test`
133
+ }
134
+
135
+ step('Adding scripts to package.json')
136
+ const pkg = JSON.parse(
137
+ fs.readFileSync(path.join(path.resolve(cwd, targetDir), 'package.json'), 'utf-8')
138
+ )
139
+ pkg.scripts = pkg.scripts || {}
140
+
141
+ for (const scriptName of Object.keys(scripts)) {
142
+ // Is script already defined?
143
+ const setScript = pkg.scripts[scriptName]
144
+ ? argv.force
145
+ : true
146
+ const isLastStep = scriptName === Object.keys(scripts)[Object.keys(scripts).length - 1]
147
+ if (setScript) {
148
+ await run('npm', [ 'set-script', scriptName, scripts[scriptName] ], { stdio: 'pipe', cwd: path.resolve(cwd, targetDir) })
149
+ substep($style.green(`✔ Script "${scriptName}" successfuly added`), { last: isLastStep })
150
+ } else {
151
+ substep($style.yellow(`Script "${scriptName}" already set. Use --force option to overwrite`), { last: isLastStep })
152
+ }
153
+ }
154
+
155
+ log() // Blank line
156
+ log('You should now move into the created folder and run the following command:\n - npm install')
157
+ log() // Blank line
158
+ log('You can use feature of .env file by copying .env.example:\n - cp .env.example .env')
159
+ log() // Blank line
160
+ }
161
+
162
+ main()
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "create-juisy",
3
+ "version": "2.0.0-beta.10",
4
+ "description": "Juisy boilerplate for npm init",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-juisy": "index.js"
8
+ },
9
+ "files": [
10
+ "template",
11
+ "index.js"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "scripts": {
17
+ "release": "release-it",
18
+ "test": "echo No test found..."
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://gitlab.com/hperchec/juisy.git"
23
+ },
24
+ "keywords": [
25
+ "js",
26
+ "build",
27
+ "release",
28
+ "changelog",
29
+ "bin",
30
+ "cmd",
31
+ "easy"
32
+ ],
33
+ "author": {
34
+ "name": "Hervé Perchec",
35
+ "email": "contact@herve-perchec.com",
36
+ "url": "https://gitlab.com/herveperchec"
37
+ },
38
+ "license": "GPL-3.0-only",
39
+ "bugs": {
40
+ "url": "https://gitlab.com/hperchec/juisy/issues"
41
+ },
42
+ "homepage": "https://hperchec.gitlab.io/juisy",
43
+ "devDependencies": {
44
+ "juisy": "2.0.0-beta.10"
45
+ },
46
+ "dependencies": {
47
+ "execa": "^8",
48
+ "mri": "^1.2.0"
49
+ },
50
+ "release-it": {
51
+ "git": false,
52
+ "plugins": {
53
+ "@release-it/bumper": {
54
+ "out": {
55
+ "file": "package.json",
56
+ "path": [
57
+ "devDependencies.juisy"
58
+ ]
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,4 @@
1
+ NODE_ENV=development
2
+
3
+ # CLI specific environement variables
4
+ __JUISY_CLI_ENV__=private
File without changes
@@ -0,0 +1,27 @@
1
+ const { createCli, utils } = require('@hperchec/juisy')
2
+ const path = require('path')
3
+ const {
4
+ rootDir,
5
+ $style
6
+ } = utils
7
+ // Get package.json content
8
+ const packageJson = require(path.resolve(rootDir, './package.json'))
9
+
10
+ function getBanner () {
11
+ let str = ''
12
+ const title = $style.bold('CLI: ') + packageJson.name
13
+ const length = title.length - 9 // removes characters generated by $style.bold from length
14
+ str += $style.cyan('-'.repeat(length) + '\n')
15
+ str += $style.cyan(title + '\n')
16
+ str += $style.cyan('-'.repeat(length) + '\n')
17
+ str += $style.italic('Made with') + ' ' + $style.red('❤') + ' ' + $style.italic('by ') + $style.bold('Hervé Perchec <contact@herve-perchec.com') + '\n'
18
+ return str
19
+ }
20
+
21
+ // CLI
22
+ module.exports = createCli(cli => cli
23
+ .scriptName('./bin/cli')
24
+ .usage(`${getBanner()}\nUsage: $0 <command> [<options>]`)
25
+ .commandDir('cmds')
26
+ .demandCommand(1, ('Command is missing. See help to learn more.').red)
27
+ )
@@ -0,0 +1,13 @@
1
+ // Private commands
2
+ import docs from './private/docs/index.js'
3
+ import release from './private/release.js'
4
+ import test from './private/test.js'
5
+
6
+ export const commands = [
7
+ // Private commands
8
+ docs,
9
+ release,
10
+ test
11
+ // Public commands
12
+ // ...
13
+ ]
@@ -0,0 +1,44 @@
1
+ /** @type {import('juisy/cli').Command} */
2
+ export default new CLI.Command({
3
+ command: 'changelog',
4
+ describe: 'Generate CHANGELOG file',
5
+ meta: {
6
+ private: true
7
+ },
8
+ builder: function (cli) {
9
+ return cli.option('i', {
10
+ alias: 'infile',
11
+ type: 'string',
12
+ describe: 'Same as conventional-changelog option',
13
+ default: 'CHANGELOG.md',
14
+ requiresArg: true
15
+ })
16
+ },
17
+ async handler (argv) {
18
+ // Utils
19
+ const { $style, step, substep, error } = CLI.OutputUtils
20
+ const { run, wait } = CLI.InterfaceUtils
21
+ /**
22
+ * Generate changelog file
23
+ */
24
+ step('Generating changelog')
25
+ await wait('Generating', async () => {
26
+ try {
27
+ await run(
28
+ 'npx',
29
+ [
30
+ 'conventional-changelog',
31
+ '-p', 'angular',
32
+ '-i', argv.infile,
33
+ '-s' // same file to output
34
+ ],
35
+ { stdio: 'pipe' }
36
+ )
37
+ } catch (e) {
38
+ error('Unable to generate changelog', e)
39
+ }
40
+ })
41
+ substep($style.green('✔ Success'), { last: true })
42
+ this.log() // Blank line
43
+ }
44
+ })
@@ -0,0 +1,22 @@
1
+ /** @type {import('juisy/cli').Command} */
2
+ export default new CLI.Command({
3
+ command: 'generate:api',
4
+ describe: 'Generate API docs from source code',
5
+ builder (cli) {
6
+ cli
7
+ },
8
+ async handler (argv) {
9
+ // Utils
10
+ const { $style, step, substep } = CLI.OutputUtils
11
+
12
+ /**
13
+ * Generate api documentation
14
+ */
15
+ step('Generating API documentation')
16
+
17
+ substep($style.yellow('⚠ This command does nothing...'), { last: true })
18
+ this.log() // blank line
19
+ this.log($style.yellow('You can use JSDoc or TypeDoc for example. See documentation'))
20
+ this.log() // blank line
21
+ }
22
+ })
@@ -0,0 +1,11 @@
1
+ import { ReadmeTemplater } from 'juisy/templater'
2
+
3
+ /** @type {import('juisy/cli').Command} */
4
+ export default new CLI.Command({
5
+ command: 'generate:cli',
6
+ describe: 'Generate CLI docs',
7
+ async handler (argv) {
8
+ const templater = new ReadmeTemplater('./docs/cli/config.js')
9
+ await templater.generate()
10
+ }
11
+ })
@@ -0,0 +1,11 @@
1
+ import { ReadmeTemplater } from 'juisy/templater'
2
+
3
+ /** @type {import('juisy/cli').Command} */
4
+ export default new CLI.Command({
5
+ command: 'generate:readme',
6
+ describe: 'Generate README.md',
7
+ async handler (argv) {
8
+ const templater = new ReadmeTemplater('./docs/readme/config.js')
9
+ await templater.generate()
10
+ }
11
+ })
@@ -0,0 +1,20 @@
1
+ import generateAPI from './generate-api.js'
2
+
3
+ /** @type {import('juisy/cli').Command} */
4
+ export default new CLI.Command({
5
+ command: 'docs <command>',
6
+ describe: 'Manage project documentation',
7
+ meta: {
8
+ private: true
9
+ },
10
+ builder (cli) {
11
+ return cli
12
+ .command([
13
+ /**
14
+ * Default command are automatically injected here...
15
+ */
16
+ generateAPI
17
+ ])
18
+ },
19
+ handler (argv) {}
20
+ })
@@ -0,0 +1,42 @@
1
+ /** @type {import('juisy/cli').Command} */
2
+ export default new CLI.Command({
3
+ command: 'lint',
4
+ describe: 'Lint markdown with markdownlint',
5
+ builder: function (cli) {
6
+ cli.option('c', {
7
+ alias: 'config',
8
+ type: 'string',
9
+ describe: 'Path to custom markdownlint config file (relative to root folder)',
10
+ requiresArg: true
11
+ })
12
+ cli.option('f', {
13
+ alias: 'fix',
14
+ type: 'boolean',
15
+ describe: 'Auto fix by passing --fix option to markdownlint-cli2',
16
+ default: false
17
+ })
18
+ return cli
19
+ },
20
+ async handler (argv) {
21
+ const { abort, run } = CLI.InterfaceUtils
22
+ const configPath = argv.config || './docs/.markdownlint-cli2.cjs' // default relative to root folder
23
+
24
+ /**
25
+ * Call markdownlint command
26
+ */
27
+ try {
28
+ await run(
29
+ 'npx',
30
+ [
31
+ 'markdownlint-cli2',
32
+ '--config',
33
+ configPath,
34
+ ...(argv.fix ? [ '--fix' ] : [])
35
+ ],
36
+ { stdio: 'inherit' }
37
+ )
38
+ } catch (error) {
39
+ abort(error.exitCode)
40
+ }
41
+ }
42
+ })
@@ -0,0 +1,20 @@
1
+ import reset from './reset.js'
2
+ import sync from './sync.js'
3
+
4
+ /** @type {import('juisy/cli').Command} */
5
+ export default new CLI.Command({
6
+ command: 'git-hooks <command>',
7
+ describe: 'Git relative commands',
8
+ meta: {
9
+ private: true
10
+ },
11
+ builder: function (cli) {
12
+ return cli
13
+ .command([
14
+ reset,
15
+ sync
16
+ ])
17
+ .demandCommand(1, 'Command is missing. See help to learn more.')
18
+ },
19
+ handler: async function (argv) {}
20
+ })
@@ -0,0 +1,48 @@
1
+ import path from 'node:path'
2
+ import fs from 'fs-extra'
3
+
4
+ /** @type {import('juisy/cli').Command} */
5
+ export default new CLI.Command({
6
+ command: 'reset',
7
+ describe: 'Reset git hooks',
8
+ builder (cli) {
9
+ return cli
10
+ },
11
+ async handler (argv) {
12
+ // Utils
13
+ const { $style, step, substep } = CLI.OutputUtils
14
+ const { rootDir, run, abort } = CLI.InterfaceUtils
15
+ /**
16
+ * Reset git hooks
17
+ */
18
+ step('Reset git hooks')
19
+
20
+ // Create temporary empty configuration file
21
+ const tempConfigFilePath = './__TEMP_SIMPLE_GIT_HOOKS_CONFIG__.json' // relative to project root folder
22
+ fs.writeFileSync(path.resolve(rootDir, tempConfigFilePath), '{}')
23
+
24
+ // Run command with empty configuration
25
+ let commandError = false
26
+ try {
27
+ await run('npx', [
28
+ 'simple-git-hooks',
29
+ tempConfigFilePath
30
+ ], { stdio: 'pipe', cwd: rootDir })
31
+ } catch (e) {
32
+ commandError = e
33
+ }
34
+
35
+ // Don't forget to always remove temporary file
36
+ fs.unlinkSync(path.resolve(rootDir, tempConfigFilePath))
37
+
38
+ // If error
39
+ if (commandError) {
40
+ substep($style.red('❌ Unable to reset git hooks.'), { last: true })
41
+ abort(1) // Abort with error
42
+ } else {
43
+ // Everything is okay
44
+ substep($style.green('✔ Git hooks successfuly reset'), { last: true })
45
+ this.log() // blank line
46
+ }
47
+ }
48
+ })
@@ -0,0 +1,19 @@
1
+ /** @type {import('juisy/cli').Command} */
2
+ export default new CLI.Command({
3
+ command: 'sync',
4
+ describe: 'Sync git hooks',
5
+ builder (cli) {
6
+ return cli
7
+ },
8
+ async handler (argv) {
9
+ // Utils
10
+ const { step } = CLI.OutputUtils
11
+ const { run } = CLI.InterfaceUtils
12
+ /**
13
+ * Sync git hooks
14
+ */
15
+ step('Sync git hooks')
16
+
17
+ await run('npx', [ 'simple-git-hooks' ])
18
+ }
19
+ })