@nutin/cli 1.1.0 → 1.2.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.
Files changed (92) hide show
  1. package/CHANGELOG.md +69 -6
  2. package/README.md +49 -2
  3. package/lib/index.mjs +9 -9
  4. package/lib/src/file-generator.mjs +24 -9
  5. package/lib/src/package-manager.mjs +72 -51
  6. package/lib/src/prompts.mjs +10 -10
  7. package/lib/src/utils.mjs +4 -1
  8. package/package.json +4 -3
  9. package/templates/base/.dockerignore.hbs +12 -2
  10. package/templates/base/README.md.hbs +23 -0
  11. package/templates/base/builder.config.js.hbs +28 -0
  12. package/templates/base/src/app/components/common/anchor/anchor.component.ts.hbs +11 -12
  13. package/templates/base/src/app/dom.test.js.hbs +8 -1
  14. package/templates/base/src/core/base-classes/base-component/base-component.ts.hbs +2 -1
  15. package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.ts.hbs +11 -11
  16. package/templates/base/src/core/base-classes/base-component/helpers/event.helper.ts.hbs +3 -0
  17. package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.ts.hbs +3 -0
  18. package/templates/base/src/core/base-classes/base-component/helpers/token.helper.ts.hbs +5 -4
  19. package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +55 -27
  20. package/templates/base/src/core/services/http-client/http-client.ts.hbs +24 -17
  21. package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +3 -3
  22. package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.ts.hbs +2 -2
  23. package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +25 -10
  24. package/templates/base/src/core/services/router/router.ts.hbs +1 -0
  25. package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.ts.hbs +4 -3
  26. package/templates/base/src/core/utils/button-manager/button-manager.utils.test.js.hbs +1 -1
  27. package/templates/base/src/index.html.hbs +2 -2
  28. package/templates/base/src/libs/popover/popover.ts.hbs +2 -1
  29. package/templates/base/src/styles/main.scss.hbs +4 -1
  30. package/templates/base/tools/builder/builder.js.hbs +19 -26
  31. package/templates/base/tools/builder/core/copy-static.js.hbs +41 -20
  32. package/templates/base/tools/builder/core/esbuild.js.hbs +26 -0
  33. package/templates/base/tools/builder/core/finalize-build.js.hbs +24 -0
  34. package/templates/base/tools/builder/core/minify-html.js.hbs +60 -0
  35. package/templates/base/tools/builder/core/paths.js.hbs +19 -0
  36. package/templates/base/tools/builder/core/sass.js.hbs +22 -0
  37. package/templates/base/tools/builder/core/tsc.js.hbs +12 -0
  38. package/templates/base/tools/builder/core/validate-html.js.hbs +32 -12
  39. package/templates/base/tools/deployment/Dockerfile.hbs +22 -0
  40. package/templates/base/tools/deployment/gzip.conf.hbs +19 -0
  41. package/templates/base/tools/deployment/nginx.conf.hbs +78 -0
  42. package/templates/base/tools/dev/dev-serve.js.hbs +32 -0
  43. package/templates/base/tools/dev/serve.js.hbs +23 -0
  44. package/templates/base/tools/{watcher.js.hbs → dev/watcher.js.hbs} +8 -8
  45. package/templates/base/tools/generator/generator.js.hbs +21 -6
  46. package/templates/base/tools/generator/handle-file.js.hbs +32 -2
  47. package/templates/base/tools/generator/templates/index.js.hbs +3 -0
  48. package/templates/base/tools/utils/export-flags.js.hbs +6 -0
  49. package/templates/base/tools/utils/get-files-recursive.js.hbs +1 -3
  50. package/templates/base/tools/utils/index.js.hbs +8 -1
  51. package/templates/base/tools/utils/prompt-boolean.js.hbs +15 -0
  52. package/templates/base/tools/utils/run-command.js.hbs +12 -0
  53. package/templates/base/tools/utils/run-script.js.hbs +22 -0
  54. package/templates/features/i18n/src/core/config.ts.hbs +3 -0
  55. package/templates/features/i18n/src/core/services/i18n/i18n.test.js.hbs +2 -0
  56. package/templates/features/i18n/src/core/services/i18n/i18n.ts.hbs +10 -1
  57. package/templates/features/i18n/src/core/services/i18n/languages.ts.hbs +7 -0
  58. package/templates/features/i18n/tools/builder/core/build-i18n.js.hbs +12 -17
  59. package/templates/features/i18n/tools/utils/languages.js.hbs +7 -0
  60. package/templates/features/stylinNutin/src/styles/_custom-classes.scss.hbs +1 -1
  61. package/templates/features/stylinNutin/src/styles/components/_index.scss.hbs +0 -0
  62. package/templates/features/stylinNutin/src/styles/views/_index.scss.hbs +0 -0
  63. package/templates/features/stylinNutin/tools/generator/templates/scss.template.js.hbs +4 -0
  64. package/templates/features/template/tools/builder/core/merge-templates.js.hbs +13 -26
  65. package/templates/features/testinNutin/{test → testin-nutin}/core/index.js.hbs +1 -1
  66. package/templates/features/testinNutin/testin-nutin/core/src/globals/assertion-lib.js.hbs +136 -0
  67. package/templates/features/testinNutin/testin-nutin/core/src/globals/jsdom-setup.js.hbs +101 -0
  68. package/templates/features/testinNutin/{test → testin-nutin}/core/src/globals/register-test-globals.js.hbs +15 -1
  69. package/templates/features/testinNutin/testin-nutin/core/src/globals/spyon.js.hbs +59 -0
  70. package/templates/features/testinNutin/{test → testin-nutin}/core/src/utils/print.js.hbs +3 -1
  71. package/templates/features/testinNutin/{test → testin-nutin}/core/src/utils/test-discovery.js.hbs +5 -1
  72. package/templates/features/testinNutin/{test → testin-nutin}/core/src/utils/test-queue.js.hbs +3 -1
  73. package/templates/features/testinNutin/{test → testin-nutin}/core/tests/assertions.test.js.hbs +26 -2
  74. package/templates/features/testinNutin/testin-nutin/runner.js.hbs +35 -0
  75. package/templates/features/testinNutin/{test → testin-nutin}/watch-tests.js.hbs +1 -1
  76. package/templates/features/testinNutin/testin-nutin.config.js.hbs +14 -0
  77. package/templates/base/Dockerfile.hbs +0 -13
  78. package/templates/base/tools/builder/core/sass.config.js.hbs +0 -17
  79. package/templates/base/tools/builder/docs.md.hbs +0 -9
  80. package/templates/features/testinNutin/test/core/src/globals/assertion-lib.js.hbs +0 -118
  81. package/templates/features/testinNutin/test/core/src/globals/spyon.js.hbs +0 -22
  82. package/templates/features/testinNutin/test/core/src/jsdom-setup.js.hbs +0 -12
  83. package/templates/features/testinNutin/test/docs.md.hbs +0 -39
  84. package/templates/features/testinNutin/test/runner.js.hbs +0 -36
  85. /package/templates/features/testinNutin/{test → testin-nutin}/core/src/utils/queue.js.hbs +0 -0
  86. /package/templates/features/testinNutin/{test → testin-nutin}/core/tests/globals-each-all.test.js.hbs +0 -0
  87. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/create-mock-method.js.hbs +0 -0
  88. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/mock-event-bus.js.hbs +0 -0
  89. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/mock-http-client.js.hbs +0 -0
  90. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/mock-i18n.js.hbs +0 -0
  91. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/mock-router.js.hbs +0 -0
  92. /package/templates/features/testinNutin/{test → testin-nutin}/mocks/mock-store.js.hbs +0 -0
package/CHANGELOG.md CHANGED
@@ -1,19 +1,74 @@
1
1
  # Changelog
2
2
 
3
- ## V1.0.1
3
+ ## V1.2.1
4
4
 
5
- - Fixed typo issue when using i18n feature
5
+ - Builder
6
6
 
7
- ## V1.0.2
7
+ - Added config file `builder.config.js` file (esbuild, verbose)
8
8
 
9
- - Partially fixed `npm run dev` script when using internal templates. *Page still needs to be reload manually from time to time.*
9
+ - I18N
10
+
11
+ - Added JSON config file for centralized languages (`config/languages.json`)
12
+
13
+ - testin-nutin
14
+
15
+ - Added config file `test.config.js` (origins array, verbose boolean)
16
+ - Added assertions + automated 'not' counterparts
17
+ - Improved spyOn
18
+ - Improved JSDOM setup & global registration
19
+
20
+ - Improved deployment tools Dockerfile (nginx conf + gzip)
21
+
22
+ - Fixed typo and added comments in `nginx.conf`.
23
+ - Extracted gzip config from Dockerfile (removed `sed` command)
24
+ - Moved Dockerfile and deployment config files (`nginx.conf`, `gzip.conf`) into their own folder `tools/deployment`.
25
+ - Added `docker:build` and `docker:run` scripts in package.json.
26
+
27
+ See [DEPLOYMENT.md file](../../docs/DEPLOYMENT_HELPERS.md) for details.
28
+
29
+ - Moved dev tools (`serve.js`, `dev-serve.js`, `watcher.js`) into their own `tools/dev` folder.
30
+
31
+ - Added explicit chokidar devDependency (sass & live-server transitive).
32
+
33
+ ## V1.2.0
34
+
35
+ - Fixed `npm run dev` command. Added middleware to reload nested routes.
36
+
37
+ - Improved `data-optional` tag:
38
+ - Can now specify which attribute to check with `data-optional="attrName"` (`src`, `href`, ...)
39
+ - Now works for `img`, `input`, etc
40
+
41
+ - Event Bus :
42
+ - Tracks both event name + callback.
43
+ - cleanupEventListeners now works correctly.
44
+ - New property: `once`. `once` subscriptions automatically remove themselves after first call.
45
+
46
+ - HTTP client :
47
+ - Optional request / response interceptors.
48
+ - Full timeout / abort controller support preserved.
49
+ - onDestroy now clears interceptors to prevent memory leaks.
50
+
51
+ - Improved builder
52
+
53
+ - Implemented `esbuild` & `html-minifier-terser`.
54
+ - Added flags `--bundle` (for production-ready build. *`npm run build --bundle` is equivalent to `npm run build:prod`)* and `--log` (verbose output). **Doesn't work with yarn or bun**.
55
+ - Commands: `npm run build`, `npm run build:prod`, `npm run serve:only`, `npm run serve`, `npm run dev`.
56
+
57
+ *Note: `--prod` or `--production` will set NODE_ENV to production, and have the same effect as `--bundle`.* `const isProd = process.env.npm_config_bundle || process.env.NODE_ENV === 'production';`
58
+
59
+ - Improved deployment tools Dockerfile (nginx conf + gzip)
60
+
61
+ See [DEPLOYMENT.md file](../../docs/DEPLOYMENT_HELPERS.md) for details.
62
+
63
+ - stylin-nutin (generator)
64
+ - When generating a component, prompts (boolean) to generate a `_component-name.scss` file in `styles/components` (forwarded by `stymes/components/_index.scss`).
10
65
 
11
66
  ## V1.1.0
12
67
 
13
68
  - Added index access in CatalogConfig. Use with `config.index`.
14
69
  ```typescript
15
70
  interface CatalogItemBase {
16
- idx: number;
71
+ index: number;
17
72
  }
18
73
  type CatalogItemObject<T extends object> = T & CatalogItemBase;
19
74
  interface CatalogItemPrimitive extends CatalogItemBase {
@@ -25,4 +80,12 @@ type CatalogItemConfig<T = any> =
25
80
  T extends object ? CatalogItemObject<T> : CatalogItemPrimitive;
26
81
  ```
27
82
 
28
- **Notes:** *Primitive data arrays (string, number, etc) needs to be accessed with `config.value`.*
83
+ **Notes:** *Primitive data arrays (string, number, etc) needs to be accessed with `config.value`.*
84
+
85
+ ## V1.0.2
86
+
87
+ - Partially fixed `npm run dev` script when using internal templates. *Page still needs to be reload manually from time to time.*
88
+
89
+ ## V1.0.1
90
+
91
+ - Fixed typo issue when using i18n feature
package/README.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # [nutin](https://www.nutin.org)
2
2
 
3
- **A lightweight, highly tweakable frontend toolkit, crafted for building lean, dynamic single-page applications without the complexity of full-scale frameworks.**
3
+ **Build SPAs by understanding SPAs. A minimal frontend toolkit crafted for learning and lean applications.**
4
4
  Includes essential features out of the box, with zero runtime dependencies.
5
- *TypeScript/Javascript,SASS,HTML*
5
+ *TypeScript / Javascript, SASS, HTML*
6
+
7
+ - Required : Node >=18 **If using testin-nutin: Node >=20.19.0 (JSDOM requirement : `{ node: '^20.19.0 || ^22.12.0 || >=24.0.0' }`)**
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ # install package globally
13
+ npm install -g @nutin/cli
14
+ ```
15
+
16
+ ## New App
17
+
18
+ ```bash
19
+ # create a new app
20
+ create-nutin-app # or
21
+ nutin-new
22
+ ```
23
+
24
+ - Flags
25
+
26
+ ```bash
27
+ # argument: project-name
28
+
29
+ -d --defaults
30
+ -pm --package-manager <manager> # npm (Default), yarn, pnpm, bun
31
+
32
+ --no-template # Use inline templates
33
+ --no-stylin-nutin # Do not use built-in SCSS utility
34
+ --testin-nutin # Use testin-nutin toolkit
35
+ --no-i18n # Do not use i18n & json-based content
36
+ --transition # Use animated view transitions. Note: May interfere with CSS `position: fixed`, `z-index`...
37
+
38
+ # Defaults
39
+ --template # (Default) Use external templates
40
+ --stylin-nutin # (Default) Use built-in SCSS utility classes & mixins
41
+ --i18n # (Default) Use i18n & json-based content
42
+ --no-testin-nutin # (Default) Do not use testin-nutin toolkit
43
+ --no-transition # (Default) Do not use animated view transitions
44
+
45
+ # Help
46
+ -h --help
47
+ ```
48
+
49
+ ## [First app tutorial](https://www.nutin.org/tutorial)
50
+
51
+ - Visit the [website](https://www.nutin.org)
52
+ - [Project repository](https://github.com/LoisKOUNINEF/nutin)
package/lib/index.mjs CHANGED
@@ -2,24 +2,24 @@ import { program } from 'commander';
2
2
  import { print } from './src/print.mjs';
3
3
  import { promptUser } from './src/prompts.mjs';
4
4
  import { createProject } from './src/file-generator.mjs';
5
- import { displaySuccessMessage } from './src/utils.mjs';
5
+ import { displaySuccessMessage, packageVersion } from './src/utils.mjs';
6
6
 
7
7
  export async function createApp() {
8
8
  program
9
- .version('1.0.0')
9
+ .version(packageVersion)
10
10
  .argument('[projectName]', 'Name of the project')
11
11
  .option('-d, --defaults', 'Use default options')
12
- .option('-pm, --package-manager <manager>', 'Specify package manager (npm, yarn, pnpm)')
13
- .option('--template', 'Use external templates')
14
- .option('--no-template', '(Default) Do not use external templates')
12
+ .option('-pm, --package-manager <manager>', 'Specify package manager (npm, yarn, pnpm, bun)')
13
+ .option('--template', '(Default) Use external templates')
14
+ .option('--no-template', 'Do not use external templates')
15
15
  .option('--stylin-nutin', '(Default) Use built-in SCSS utility classes & mixins')
16
16
  .option('--no-stylin-nutin', 'Do not use built-in SCSS utility')
17
- .option('--i18n', 'Use i18n & json-based content')
18
- .option('--no-i18n', '(Default) Do not use i18n & json-based content')
19
- .option('--transition', 'Use animated view transitions\nNote: May interfere with CSS `position: fixed`, `z-index`...')
20
- .option('--no-transition', '(Default) Do not use animated view transitions')
17
+ .option('--i18n', '(Default) Use i18n & json-based content')
18
+ .option('--no-i18n', 'Do not use i18n & json-based content')
21
19
  .option('--testin-nutin', 'Use testin-nutin toolkit')
22
20
  .option('--no-testin-nutin', '(Default) Do not use testin-nutin toolkit')
21
+ .option('--transition', 'Use animated view transitions\nNote: May interfere with CSS `position: fixed`, `z-index`...')
22
+ .option('--no-transition', '(Default) Do not use animated view transitions')
23
23
  .addHelpText('afterAll', '\nChaining options :\nExample: -d -pm npm --i18n --testinNutin')
24
24
  .action(async (projectName, cliOptions) => {
25
25
  print.blue('🚀 Welcome to nutin !');
@@ -4,7 +4,8 @@ import * as fsExtra from 'fs-extra';
4
4
  import { TemplateCompiler } from './template-compiler.mjs';
5
5
  import { print } from './print.mjs';
6
6
  import { initializeGit } from './git-manager.mjs';
7
- import { installDependencies, generatePackageJson, generateTsconfigJson } from './package-manager.mjs';
7
+ import { installDependencies, generatePackageJson, generateTsconfigJson, getCiCommand } from './package-manager.mjs';
8
+ import { packageVersion } from './utils.mjs';
8
9
 
9
10
  const fs = fsExtra.default;
10
11
  const __filename = fileURLToPath(import.meta.url);
@@ -48,14 +49,15 @@ export class ProjectGenerator {
48
49
  const context = this.buildContext(answers);
49
50
  const templateDir = this.getTemplateDirectory(answers);
50
51
 
51
- print.section('\n📝 Processing templates...');
52
+ print.section('📝 Processing templates...');
52
53
  await this.processTemplateDirectory(templateDir, projectPath, context);
53
54
 
54
55
  await this.processFeatureTemplates(projectPath, context);
55
56
  }
56
57
 
57
58
  buildContext(answers) {
58
- const version = '1.1.0';
59
+ const version = packageVersion;
60
+ const ciCommand = getCiCommand(answers.packageManager);
59
61
 
60
62
  return {
61
63
  projectName: answers.projectName,
@@ -71,6 +73,7 @@ export class ProjectGenerator {
71
73
 
72
74
  year: new Date().getFullYear(),
73
75
  packageManager: answers.packageManager || 'npm',
76
+ ciCommand: ciCommand,
74
77
  version: version
75
78
  };
76
79
  }
@@ -111,7 +114,7 @@ export class ProjectGenerator {
111
114
  if (BINARY_EXTENSIONS.has(fileExt)) {
112
115
  const outputPath = path.join(outputDir, fileName);
113
116
  await fs.copy(templatePath, outputPath);
114
- print.info(`📄 Copied: ${fileName}`);
117
+ // print.info(`📄 Copied: ${fileName}`);
115
118
  } else if (fileName.endsWith('.hbs')) {
116
119
 
117
120
  const outputFileName = fileName.replace('.hbs', '');
@@ -120,7 +123,7 @@ export class ProjectGenerator {
120
123
  try {
121
124
  const compiledContent = await this.compiler.compileFile(templatePath, context);
122
125
  await fs.writeFile(outputPath, compiledContent);
123
- print.info(`📝 Generated: ${outputFileName}`);
126
+ // print.info(`📝 Generated: ${outputFileName}`);
124
127
  } catch (error) {
125
128
  print.boldError(`❌ Failed to process template: ${fileName}`);
126
129
  throw error;
@@ -128,7 +131,7 @@ export class ProjectGenerator {
128
131
  } else {
129
132
  const outputPath = path.join(outputDir, fileName);
130
133
  await fs.copy(templatePath, outputPath);
131
- print.info(`📄 Copied: ${fileName}`);
134
+ // print.info(`📄 Copied: ${fileName}`);
132
135
  }
133
136
  }
134
137
 
@@ -146,7 +149,7 @@ export class ProjectGenerator {
146
149
  const featureTemplateDir = path.join(featuresDir, feature);
147
150
 
148
151
  if (await fs.pathExists(featureTemplateDir)) {
149
- print.info(`\n🔧 Adding ${feature} feature...`);
152
+ print.info(`🔧 Adding ${feature} feature...`);
150
153
  await this.processTemplateDirectory(featureTemplateDir, projectPath, context);
151
154
  }
152
155
  }
@@ -156,6 +159,18 @@ export class ProjectGenerator {
156
159
  async generateJsonFiles(projectPath, answers) {
157
160
  await generatePackageJson(projectPath, answers);
158
161
  await generateTsconfigJson(projectPath, answers);
162
+ if (answers.i18n) this.generateConfigFiles(projectPath);
163
+ }
164
+
165
+ async generateConfigFiles(projectPath) {
166
+ const configPath = path.join(projectPath, 'config');
167
+ await fs.ensureDir(configPath);
168
+ const languages = {
169
+ "languages": ["en"],
170
+ "defaultLanguage": "en"
171
+ };
172
+
173
+ await fs.writeJSON(path.join(configPath, 'languages.json'), languages, { spaces: 2 });
159
174
  }
160
175
 
161
176
  async runPostSetupTasks(projectPath, answers) {
@@ -168,10 +183,10 @@ export class ProjectGenerator {
168
183
  }
169
184
 
170
185
  async runSetupScripts(projectPath, answers) {
171
- print.section('\n⚙️ Running setup scripts...');
186
+ print.section('⚙️ Running setup scripts...');
172
187
 
173
188
  try {
174
- const setupScriptsTemplate = path.join(__dirname, '../../templates/scripts');
189
+ const setupScriptsTemplate = path.join(__dirname, '..', '..', 'templates', 'scripts');
175
190
 
176
191
  if (await fs.pathExists(setupScriptsTemplate)) {
177
192
  const scriptsDir = path.join(projectPath, 'scripts');
@@ -12,84 +12,102 @@ export async function installDependencies(projectPath, packageManager) {
12
12
  await promiseExec(installCommand, { cwd: projectPath });
13
13
  }
14
14
 
15
- export function getInstallCommand(packageManager) {
15
+ export function getCiCommand(packageManager) {
16
+ switch (packageManager) {
17
+ case 'yarn':
18
+ return 'yarn install --frozen-lockfile';
19
+ case 'pnpm':
20
+ return 'pnpm install --frozen-lockfile';
21
+ case 'bun':
22
+ return 'bun install --frozen-lockfile'
23
+ default:
24
+ return 'npm ci';
25
+ }
26
+ }
27
+
28
+ function getInstallCommand(packageManager) {
16
29
  switch (packageManager) {
17
30
  case 'yarn':
18
31
  return 'yarn install';
19
32
  case 'pnpm':
20
33
  return 'pnpm install';
34
+ case 'bun':
35
+ return 'bun install'
21
36
  default:
22
37
  return 'npm install';
23
38
  }
24
39
  }
25
40
 
26
- export async function generatePackageJson(projectPath, answers) {
27
- const { testinNutin, projectName, template } = answers;
28
-
29
- const baseDevDeps = {
30
- "concurrently": "^9.1.2",
31
- "live-server": "^1.2.2",
32
- "sass": "^1.89.0",
33
- "typescript": "^5.8.3"
34
- };
35
-
36
- const devDependencies = testinNutin
37
- ? { ...baseDevDeps, "jsdom": "^26.1.0" }
38
- : baseDevDeps;
41
+ function getScripts(answers) {
42
+ const { testinNutin, packageManager, projectName } = answers;
39
43
 
40
44
  const baseScripts = {
41
- "patch": "npm version patch -m 'CI/CD: Bump version to %s'",
42
- "minor": "npm version minor -m 'CI/CD: Bump version to %s'",
43
- "major": "npm version major -m 'CI/CD: Bump version to %s'",
44
- "build:ts": "tsc --project tsconfig.json",
45
- "build-static": "node tools/builder/builder.js",
46
- "serve": "npm run build && live-server dist/src --port=9090 --entry-file=index.html",
47
- "generate": "node tools/generator/generator.js"
48
- }
45
+ "patch": `${packageManager} version patch -m 'CI/CD: Bump version to %s'`,
46
+ "minor": `${packageManager} version minor -m 'CI/CD: Bump version to %s'`,
47
+ "major": `${packageManager} version major -m 'CI/CD: Bump version to %s'`,
48
+ "build": "node tools/builder/builder.js",
49
+ "build:prod": "NODE_ENV=production node tools/builder/builder.js",
50
+ "serve:only": "node tools/dev/serve.js",
51
+ "serve": `${packageManager} run build && ${packageManager} run serve:only`,
52
+ "dev": "node tools/dev/dev-serve.js",
53
+ "generate": "node tools/generator/generator.js",
54
+ "docker:build": `docker build -t ${projectName} -f tools/deployment/Dockerfile .`,
55
+ "docker:run": `docker run -p 9090:9090 ${projectName}:latest`
56
+ };
57
+
58
+ const testinNutinScripts = {
59
+ "test": "node testin-nutin/runner.js",
60
+ "test:rebuild": `${packageManager} run build && ${packageManager} run test`,
61
+ "test:watch": `${packageManager} run build && node testin-nutin/watch-tests.js`
62
+ }
49
63
 
50
- let scripts = testinNutin
64
+ return testinNutin
51
65
  ? {
52
66
  ...baseScripts,
53
- "test": "node test/runner.js",
54
- "test--rebuild": "npm run build && npm run test",
55
- "test:watch": "npm run build && node test/watch-tests.js",
56
- "serve": "npm run build && npm run serve:only",
57
- "serve:only": "live-server dist/src --port=9090 --entry-file=index.html --open",
58
- "dev": "concurrently \"node tools/watcher.js\" \"npm run build && npm run serve:only > /dev/null 2>&1\""
67
+ ...testinNutinScripts
59
68
  }
60
69
  : baseScripts;
70
+ }
61
71
 
62
- scripts = template
63
- ? {
64
- ...scripts,
65
- "build:clear": "rm -rf dist/src/* dist-build",
66
- "build:finalize": "mkdir -p dist && mv dist-build/src dist/ && rm -rf dist-build",
67
- "build": "npm run build:clear && npm run build:ts && npm run build-static && npm run build:finalize"
68
- }
69
- : {
70
- ...scripts,
71
- "build:clear": "rm -rf dist",
72
- "build": "npm run build:clear && npm run build:ts && npm run build-static"
73
- };
72
+ export async function generatePackageJson(projectPath, answers) {
73
+ const { testinNutin, projectName, packageManager } = answers;
74
+
75
+ const devDependencies = {
76
+ "chokidar": "^4.0.3",
77
+ "esbuild": "^0.25.12",
78
+ "html-minifier-terser": "^7.2.0",
79
+ "live-server": "^1.2.2",
80
+ "sass": "^1.89.0",
81
+ "typescript": "^5.8.3",
82
+ ...(testinNutin && {
83
+ "jsdom": "^26.1.0",
84
+ })
85
+ };
86
+
87
+ const scripts = getScripts(answers);
74
88
 
75
89
  const packageJson = {
76
90
  "name": projectName,
77
91
  "version": "0.1.0",
78
- "main": "index.js",
79
92
  "type": "module",
80
- "imports": testinNutin ? {
81
- "#root/*.js": "./*.js"
82
- } : {},
93
+ ...(testinNutin && {
94
+ "imports": {
95
+ "#root/*.js": "./*.js"
96
+ }
97
+ }),
83
98
  scripts,
84
- devDependencies
99
+ devDependencies,
100
+ ...(testinNutin && {
101
+ "engines": {
102
+ "node": ">=20.19.0"
103
+ }
104
+ })
85
105
  };
86
106
 
87
107
  await fs.writeJSON(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 });
88
108
  }
89
109
 
90
110
  export async function generateTsconfigJson(projectPath, answers) {
91
- const { template } = answers;
92
-
93
111
  const tsconfig = {
94
112
  "compilerOptions": {
95
113
  "baseUrl": "./",
@@ -97,13 +115,16 @@ export async function generateTsconfigJson(projectPath, answers) {
97
115
  "target": "ESNext",
98
116
  "module": "NodeNext",
99
117
  "moduleResolution": "NodeNext",
100
- "rootDir": ".",
101
- "outDir": template ? "dist-build" : 'dist',
118
+ "rootDir": "src",
119
+ "outDir": "dist-build/src",
102
120
  "strict": true,
121
+ "skipLibCheck": true,
122
+ "forceConsistentCasingInFileNames": true,
123
+ "noUncheckedIndexedAccess": true,
103
124
  "esModuleInterop": true,
104
125
  "allowSyntheticDefaultImports": true,
105
126
  "lib": ["es2022", "DOM"],
106
- "types": [],
127
+ "removeComments": true,
107
128
  "resolveJsonModule": true,
108
129
  "typeRoots": ["src/types", "node_modules/@types"]
109
130
  },
@@ -22,7 +22,7 @@ export async function promptUser(initialName, cliOptions = {}) {
22
22
  type: 'list',
23
23
  name: 'packageManager',
24
24
  message: 'Package manager:',
25
- choices: ['npm', 'yarn', 'pnpm'],
25
+ choices: ['npm', 'yarn', 'pnpm', 'bun'],
26
26
  default: 'npm'
27
27
  }
28
28
  ]);
@@ -34,10 +34,10 @@ export async function promptUser(initialName, cliOptions = {}) {
34
34
  projectName,
35
35
  packageManager,
36
36
  stylinNutin: cliOptions.stylinNutin || true,
37
- template: cliOptions.template || false,
38
- i18n: cliOptions.i18n || false,
39
- transition: cliOptions.transitions || false,
40
- testinNutin: cliOptions.testinNutin || false
37
+ template: cliOptions.template || true,
38
+ i18n: cliOptions.i18n || true,
39
+ testinNutin: cliOptions.testinNutin || false,
40
+ transition: cliOptions.transitions || false
41
41
  };
42
42
  }
43
43
 
@@ -47,7 +47,7 @@ export async function promptUser(initialName, cliOptions = {}) {
47
47
  questions.push({
48
48
  type: 'confirm',
49
49
  name: 'stylinNutin',
50
- message: 'Use built-in SCSS utility classes?',
50
+ message: 'Use built-in SCSS utility classes ?',
51
51
  default: true
52
52
  });
53
53
  }
@@ -56,8 +56,8 @@ export async function promptUser(initialName, cliOptions = {}) {
56
56
  questions.push({
57
57
  type: 'confirm',
58
58
  name: 'template',
59
- message: 'Use external templates?',
60
- default: false
59
+ message: 'Use external templates ?',
60
+ default: true
61
61
  });
62
62
  }
63
63
 
@@ -65,8 +65,8 @@ export async function promptUser(initialName, cliOptions = {}) {
65
65
  questions.push({
66
66
  type: 'confirm',
67
67
  name: 'i18n',
68
- message: 'Use i18n & json-based content?',
69
- default: false
68
+ message: 'Use i18n with json-based content ?',
69
+ default: true
70
70
  });
71
71
  }
72
72
 
package/lib/src/utils.mjs CHANGED
@@ -5,11 +5,14 @@ import { print } from './print.mjs';
5
5
  export const promiseExec = promisify(exec);
6
6
 
7
7
  export function displaySuccessMessage(answers) {
8
- const { projectName, installDeps, packageManager } = answers;
8
+ const { projectName } = answers;
9
9
 
10
10
  print.boldSuccess('\n🎉 Your project is ready!');
11
11
  print.info('\nNext steps:');
12
12
  print.info(` cd ${projectName} && npm run serve`);
13
+ print.boldInfo(`\nDocumentation on https://www.nutin.org`);
13
14
 
14
15
  print.success('\nHappy coding! 🚀\n');
15
16
  }
17
+
18
+ export const packageVersion = '1.2.1';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nutin/cli",
3
- "version": "1.1.0",
4
- "description": "A lightweight, highly tweakable frontend toolkit, crafted for building lean, dynamic single-page applications without the complexity of full-scale frameworks.",
3
+ "version": "1.2.1",
4
+ "description": "Build SPAs by understanding SPAs. A minimal frontend toolkit crafted for learning and lean applications.",
5
5
  "preferGlobal": true,
6
6
  "main": "lib/index.mjs",
7
7
  "bin": {
@@ -19,6 +19,7 @@
19
19
  "nutin",
20
20
  "Frontend",
21
21
  "SPA",
22
+ "Learning",
22
23
  "Minimalist",
23
24
  "Lighweight",
24
25
  "Customizable"
@@ -32,7 +33,7 @@
32
33
  "inquirer": "^9.0.0"
33
34
  },
34
35
  "engines": {
35
- "node": ">=18.0.0"
36
+ "node": ">=18"
36
37
  },
37
38
  "repository": {
38
39
  "type": "git",
@@ -1,5 +1,6 @@
1
1
  node_modules
2
2
  dist
3
+ dist-build
3
4
  .github
4
5
  .gitignore
5
6
  .git
@@ -7,6 +8,15 @@ dist
7
8
  *.md
8
9
  .env
9
10
  *.txt
10
- {{#if i18n}}
11
- *.test
11
+ {{#if testinNutin}}
12
+ *.test.js
13
+ testin-nutin
12
14
  {{/if}}
15
+ *.log
16
+
17
+ npm-debug.log
18
+ .nyc_output
19
+ coverage
20
+ .DS_Store
21
+ .cache
22
+ .parcel-cache
@@ -1 +1,24 @@
1
1
  # {{projectName}} - Built with nutin
2
+
3
+ ## Start
4
+
5
+ - `{{packageManager}} run serve` (rebuild), `{{packageManager}} run serve:only` (no rebuild), `{{packageManager}} run dev` (watch).
6
+
7
+ ## Build
8
+
9
+ - `{{packageManager}} run build` (dev) or `{{packageManager}} run build:prod` (production)
10
+
11
+ Accepts `--bundle` (= build:prod) and `--log` (verbose output) flags
12
+
13
+ ## Generate Component, View, Service
14
+
15
+ - `{{packageManager}} run generate ELEMENT ELEMENT_NAME`
16
+
17
+ Supports nested paths.
18
+
19
+ {{#if testinNutin}}
20
+ ## Test
21
+
22
+ - `{{packageManager}} run test:rebuild`, `{{packageManager}} run test`, `{{packageManager}} run test:watch`.
23
+
24
+ {{/if}}
@@ -0,0 +1,28 @@
1
+ export default {
2
+ esbuild: {
3
+ bundle: true,
4
+ minify: true,
5
+ sourcemap: false,
6
+ platform: 'browser',
7
+ format: 'esm',
8
+ target: ['es2015'],
9
+ legalComments: 'none',
10
+ loader: {
11
+ '.json': 'json',
12
+ },
13
+ define: {
14
+ 'process.env.NODE_ENV': '"production"',
15
+ },
16
+ },
17
+ sass: {
18
+ paths: [
19
+ 'base',
20
+ 'core',
21
+ {{#if stylinNutin}}
22
+ 'components',
23
+ 'views',
24
+ {{/if}}
25
+ ], // in styles/
26
+ },
27
+ verbose: false,
28
+ }