@nutin/cli 1.3.1 → 2.0.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/CHANGELOG.md +89 -9
- package/README.md +20 -35
- package/bin/add-feature.mjs +9 -0
- package/bin/cli.mjs +8 -0
- package/bin/create-app.mjs +5 -4
- package/bin/update-app.mjs +9 -0
- package/lib/index.mjs +76 -25
- package/lib/src/add-feature/feature-adder.mjs +83 -0
- package/lib/src/add-feature/feature-context-builder.mjs +25 -0
- package/lib/src/add-feature/nutin-config-updater.mjs +29 -0
- package/lib/src/add-feature/package-json-updater.mjs +49 -0
- package/lib/src/common/feature-registry.mjs +11 -0
- package/lib/src/common/file-generator.mjs +159 -0
- package/lib/src/common/meta-bootstrap-prompt.mjs +33 -0
- package/lib/src/common/package-data.mjs +10 -0
- package/lib/src/common/package-json-helper.mjs +103 -0
- package/lib/src/common/project-meta.mjs +54 -0
- package/lib/src/create-app/context-builder.mjs +21 -0
- package/lib/src/{git-manager.mjs → create-app/git-manager.mjs} +2 -2
- package/lib/src/create-app/json-manager.mjs +73 -0
- package/lib/src/{prompts.mjs → create-app/new-app-prompt.mjs} +6 -6
- package/lib/src/{project-generator.mjs → create-app/project-generator.mjs} +10 -8
- package/lib/src/create-app/success-message.mjs +14 -0
- package/lib/src/update-app/conflict-report-writer.mjs +31 -0
- package/lib/src/update-app/fetch-old-templates.mjs +61 -0
- package/lib/src/update-app/project-updater.mjs +136 -0
- package/lib/src/update-app/template-differ.mjs +124 -0
- package/lib/src/update-app/update-context-builder.mjs +25 -0
- package/lib/src/update-app/update-summary-printer.mjs +22 -0
- package/lib/src/update-app/version-compare.mjs +12 -0
- package/lib/src/utils/print.mjs +36 -0
- package/lib/src/utils/promise-exec-alias.mjs +4 -0
- package/package.json +17 -12
- package/templates/base/.gitignore.hbs +6 -1
- package/templates/base/AGENTS.md.hbs +169 -0
- package/templates/base/GETTING_STARTED.md.hbs +227 -0
- package/templates/base/README.md.hbs +8 -17
- package/templates/base/config/languages.json.hbs +6 -0
- package/templates/base/config/seo.json.hbs +12 -0
- package/templates/base/nutin.config.js.hbs +51 -0
- package/templates/base/src/app/components/index.ts.hbs +1 -2
- package/templates/base/src/app/globals.d.ts.hbs +3 -19
- package/templates/base/src/{libs/guards → app}/guards.ts.hbs +1 -5
- package/templates/base/src/app/main.ts.hbs +7 -26
- package/templates/base/src/app/services/index.ts.hbs +1 -1
- package/templates/base/src/app/views/home/home.view.html.hbs +7 -0
- package/templates/base/src/app/views/home/home.view.ts.hbs +1 -56
- package/templates/base/src/app/views/index.ts.hbs +1 -0
- package/templates/base/src/app/views/not-found/not-found.view.html.hbs +8 -0
- package/templates/base/src/app/views/not-found/not-found.view.ts.hbs +4 -37
- package/templates/base/src/core/base-classes/base-component/base-component.test.js.hbs +158 -0
- package/templates/base/src/core/base-classes/base-component/base-component.ts.hbs +68 -35
- package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.test.js.hbs +124 -0
- package/templates/base/src/core/base-classes/base-component/helpers/catalog.helper.ts.hbs +9 -8
- package/templates/base/src/core/base-classes/base-component/helpers/children.helper.test.js.hbs +74 -0
- package/templates/base/src/core/base-classes/base-component/helpers/children.helper.ts.hbs +1 -1
- package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.test.js.hbs +145 -0
- package/templates/base/src/core/base-classes/base-component/helpers/dom.helper.ts.hbs +7 -1
- package/templates/base/src/core/base-classes/base-component/helpers/event.helper.test.js.hbs +88 -0
- package/templates/base/src/core/base-classes/base-component/helpers/event.helper.ts.hbs +2 -2
- package/templates/base/src/core/base-classes/base-component/helpers/i18n.helper.test.js.hbs +62 -0
- package/templates/base/src/core/base-classes/base-component/helpers/pipe.helper.test.js.hbs +82 -0
- package/templates/base/src/core/base-classes/base-component/helpers/security.helper.test.js.hbs +142 -0
- package/templates/base/src/core/base-classes/base-component/helpers/security.helper.ts.hbs +67 -22
- package/templates/base/src/core/base-classes/base-component/helpers/token.helper.test.js.hbs +183 -0
- package/templates/base/src/core/base-classes/component/component.test.js.hbs +85 -0
- package/templates/base/src/core/base-classes/component/component.ts.hbs +24 -33
- package/templates/base/src/core/base-classes/component/helpers/config.helper.test.js.hbs +58 -0
- package/templates/base/src/core/base-classes/component/helpers/data-binding.helper.test.js.hbs +75 -0
- package/templates/base/src/core/base-classes/service/service.test.js.hbs +150 -0
- package/templates/base/src/core/base-classes/service/service.ts.hbs +26 -20
- package/templates/base/src/core/base-classes/view/view.test.js.hbs +74 -0
- package/templates/base/src/core/base-classes/view/view.ts.hbs +17 -41
- package/templates/base/src/core/config.ts.hbs +7 -0
- package/templates/base/src/core/index.ts.hbs +0 -3
- package/templates/base/src/core/internals.d.ts.hbs +27 -0
- package/templates/base/src/core/nutin-config.d.ts.hbs +4 -0
- package/templates/base/src/core/services/event-bus/event-bus.test.js.hbs +67 -3
- package/templates/base/src/core/services/event-bus/event-bus.ts.hbs +9 -4
- package/templates/base/src/core/services/event-bus/index.ts.hbs +3 -0
- package/templates/base/src/core/services/event-bus/lifecycle.facade.test.js.hbs +123 -0
- package/templates/base/src/core/services/event-bus/lifecycle.facade.ts.hbs +61 -0
- package/templates/base/src/core/services/event-bus/navigation.facade.test.js.hbs +46 -0
- package/templates/base/src/core/services/event-bus/navigation.facade.ts.hbs +25 -0
- package/templates/base/src/core/services/globals/globals.test.js.hbs +149 -0
- package/templates/base/src/core/services/globals/globals.ts.hbs +95 -0
- package/templates/base/src/core/services/http-client/helpers/http-builder.helper.test.js.hbs +25 -0
- package/templates/base/src/core/services/http-client/helpers/http-manager.helper.test.js.hbs +20 -0
- package/templates/base/src/core/services/http-client/http-client.test.js.hbs +43 -0
- package/templates/base/src/core/services/i18n/i18n.test.js.hbs +270 -0
- package/templates/{features/i18n → base}/src/core/services/i18n/i18n.ts.hbs +22 -4
- package/templates/base/src/core/services/index.ts.hbs +5 -6
- package/templates/base/src/core/services/pipe-registry/pipe-registry.test.js.hbs +60 -1
- package/templates/base/src/core/services/pipe-registry/pipe-registry.ts.hbs +1 -1
- package/templates/base/src/core/services/pipe-registry/pipes.test.js.hbs +128 -0
- package/templates/base/src/{libs/pipes → core/services/pipe-registry}/pipes.ts.hbs +8 -5
- package/templates/base/src/core/services/router/helpers/navigation-manager.helper.test.js.hbs +149 -6
- package/templates/base/src/core/services/router/helpers/navigation-manager.helper.ts.hbs +40 -29
- package/templates/base/src/core/services/router/helpers/route-guard-manager.helper.test.js.hbs +27 -0
- package/templates/base/src/core/services/router/helpers/view-render-manager.helper.test.js.hbs +83 -17
- package/templates/base/src/core/services/router/helpers/view-render-manager.helper.ts.hbs +14 -38
- package/templates/base/src/core/services/router/router.test.js.hbs +226 -2
- package/templates/base/src/core/services/router/router.ts.hbs +40 -8
- package/templates/base/src/index.html.hbs +2 -6
- package/templates/base/src/styles/_styles.scss.hbs +102 -43
- package/templates/base/src/styles/base/_variables.scss.hbs +1 -86
- package/templates/base/src/styles/main.scss.hbs +1 -18
- package/templates/base/src/styles/tailwind.css.hbs +2 -0
- package/templates/base/tools/builder/builder.config.js.hbs +40 -0
- package/templates/base/tools/builder/builder.js.hbs +24 -26
- package/templates/base/tools/builder/core/app/binary-extensions.test.js.hbs +16 -0
- package/templates/base/tools/builder/core/app/compile-ts.js.hbs +16 -0
- package/templates/base/tools/builder/core/{copy-static.js.hbs → app/copy-static.js.hbs} +27 -34
- package/templates/base/tools/builder/core/app/validate-routes.js.hbs +77 -0
- package/templates/base/tools/builder/core/finalize-build.js.hbs +16 -7
- package/templates/base/tools/builder/core/{add-tags.js.hbs → html-index/add-tags.js.hbs} +2 -2
- package/templates/base/tools/builder/core/html-index/add-tags.test.js.hbs +56 -0
- package/templates/base/tools/builder/core/{validate-html.js.hbs → html-index/validate-html.js.hbs} +5 -11
- package/templates/base/tools/builder/core/html-templates/merge-templates.js.hbs +152 -0
- package/templates/base/tools/builder/core/html-templates/minify-html.js.hbs +15 -0
- package/templates/base/tools/builder/core/html-templates/process-html-templates.js.hbs +8 -0
- package/templates/{features/i18n/tools/builder/core → base/tools/builder/core/i18n}/build-i18n.js.hbs +6 -17
- package/templates/base/tools/builder/core/prod-bundle/compress-files.js.hbs +37 -0
- package/templates/base/tools/builder/core/prod-bundle/esbuild.js.hbs +30 -0
- package/templates/base/tools/builder/core/{hash-files.js.hbs → prod-bundle/hash-files.js.hbs} +14 -11
- package/templates/base/tools/builder/core/seo/generate-robots-txt.js.hbs +51 -0
- package/templates/base/tools/builder/core/seo/generate-seo-files.js.hbs +16 -0
- package/templates/base/tools/builder/core/seo/generate-seo-html.js.hbs +128 -0
- package/templates/base/tools/builder/core/seo/generate-sitemap-xml.js.hbs +43 -0
- package/templates/base/tools/builder/core/seo/html-substitutions.js.hbs +99 -0
- package/templates/base/tools/builder/core/seo/i18n-resolution.js.hbs +66 -0
- package/templates/base/tools/builder/core/seo/route-output.js.hbs +64 -0
- package/templates/base/tools/builder/core/seo/ssr/ssr-bundle.js.hbs +54 -0
- package/templates/base/tools/builder/core/seo/ssr/ssr-polyfills.js.hbs +132 -0
- package/templates/base/tools/builder/core/seo/ssr/ssr-render.js.hbs +95 -0
- package/templates/base/tools/builder/core/styles/sass.js.hbs +40 -0
- package/templates/base/tools/builder/core/styles/tailwind.js.hbs +84 -0
- package/templates/base/tools/dev/dev-serve.js.hbs +26 -18
- package/templates/base/tools/dev/serve.js.hbs +11 -1
- package/templates/base/tools/dev/watcher.js.hbs +14 -6
- package/templates/base/tools/generator/generator.js.hbs +64 -47
- package/templates/base/tools/generator/handle-file.js.hbs +17 -44
- package/templates/base/tools/generator/handle-file.test.js.hbs +72 -0
- package/templates/base/tools/generator/templates/{component.template.js.hbs → component/component.template.js.hbs} +3 -2
- package/templates/base/tools/generator/templates/component/component.template.test.js.hbs +23 -0
- package/templates/base/tools/generator/templates/html/html.template.js.hbs +2 -0
- package/templates/base/tools/generator/templates/html/html.template.test.js.hbs +7 -0
- package/templates/base/tools/generator/templates/index.js.hbs +7 -12
- package/templates/base/tools/generator/templates/locale/locale.template.js.hbs +4 -0
- package/templates/base/tools/generator/templates/locale/locale.template.test.js.hbs +7 -0
- package/templates/base/tools/generator/templates/scss/scss.template.js.hbs +1 -0
- package/templates/base/tools/generator/templates/scss/scss.template.test.js.hbs +7 -0
- package/templates/base/tools/generator/templates/service/service.template.js.hbs +17 -0
- package/templates/base/tools/generator/templates/service/service.template.test.js.hbs +22 -0
- package/templates/base/tools/generator/templates/test/test.template.js.hbs +10 -0
- package/templates/base/tools/generator/templates/test/test.template.test.js.hbs +27 -0
- package/templates/base/tools/generator/templates/{view.template.js.hbs → view/view.template.js.hbs} +3 -2
- package/templates/base/tools/generator/templates/view/view.template.test.js.hbs +24 -0
- package/templates/base/tools/testin-nutin/core/coverage/collect-coverage.js.hbs +39 -0
- package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.js.hbs +115 -0
- package/templates/base/tools/testin-nutin/core/coverage/compute-coverage.test.js.hbs +74 -0
- package/templates/base/tools/testin-nutin/core/coverage/write-summary-report.js.hbs +54 -0
- package/templates/base/tools/testin-nutin/core/coverage/write-uncovered-report.js.hbs +44 -0
- package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/assertion-lib.js.hbs +62 -24
- package/templates/base/tools/testin-nutin/core/globals/clock.js.hbs +206 -0
- package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/jsdom-setup.js.hbs +19 -6
- package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/register-test-globals.js.hbs +13 -4
- package/templates/base/tools/testin-nutin/core/globals/silence-console.js.hbs +23 -0
- package/templates/{features/testinNutin/testin-nutin/core/src → base/tools/testin-nutin/core}/globals/spyon.js.hbs +2 -0
- package/templates/base/tools/testin-nutin/core/index.js.hbs +9 -0
- package/templates/base/tools/testin-nutin/core/printer.js.hbs +85 -0
- package/templates/base/tools/testin-nutin/core/queue/queue.test.js.hbs +46 -0
- package/templates/base/tools/testin-nutin/core/queue/test-discovery.test.js.hbs +46 -0
- package/templates/base/tools/testin-nutin/core/queue/test-queue.js.hbs +154 -0
- package/templates/{features/testinNutin → base/tools}/testin-nutin/core/tests/assertions.test.js.hbs +27 -0
- package/templates/base/tools/testin-nutin/core/tests/clock.test.js.hbs +118 -0
- package/templates/base/tools/testin-nutin/core/tests/globals-each-all.test.js.hbs +28 -0
- package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/create-mock-method.js.hbs +2 -1
- package/templates/base/tools/testin-nutin/mocks/create-mock-method.test.js.hbs +64 -0
- package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-event-bus.js.hbs +3 -2
- package/templates/base/tools/testin-nutin/mocks/mock-event-bus.test.js.hbs +66 -0
- package/templates/base/tools/testin-nutin/mocks/mock-http-client.test.js.hbs +26 -0
- package/templates/base/tools/testin-nutin/mocks/mock-i18n.test.js.hbs +61 -0
- package/templates/base/tools/testin-nutin/mocks/mock-router.test.js.hbs +29 -0
- package/templates/base/tools/testin-nutin/runner.js.hbs +100 -0
- package/templates/base/tools/testin-nutin/watch-tests.js.hbs +37 -0
- package/templates/base/tools/utils/error-exit.js.hbs +8 -0
- package/templates/base/tools/utils/format.js.hbs +10 -10
- package/templates/base/tools/utils/format.test.js.hbs +45 -0
- package/templates/base/tools/utils/get-files-recursive.js.hbs +6 -1
- package/templates/base/tools/utils/get-files-recursive.test.js.hbs +49 -0
- package/templates/base/tools/utils/get-rel-to-core.test.js.hbs +18 -0
- package/templates/base/tools/utils/index.js.hbs +1 -3
- package/templates/base/tools/utils/languages.js.hbs +15 -0
- package/templates/base/tools/utils/languages.test.js.hbs +16 -0
- package/templates/base/tools/utils/print.js.hbs +19 -13
- package/templates/base/tools/utils/print.test.js.hbs +60 -0
- package/templates/base/tools/utils/prompt-boolean.js.hbs +7 -0
- package/templates/base/tools/utils/prompt-boolean.test.js.hbs +54 -0
- package/templates/base/tools/utils/run-command.js.hbs +4 -2
- package/templates/base/tools/utils/run-command.test.js.hbs +19 -0
- package/templates/base/tools/utils/run-script.js.hbs +14 -3
- package/templates/base/tools/utils/run-script.test.js.hbs +40 -0
- package/templates/features/{deployHelper → docker}/.dockerignore.hbs +4 -4
- package/templates/features/docker/tools/docker/Dockerfile.template.hbs +51 -0
- package/templates/features/{deployHelper/tools/deployment/nginx.conf.hbs → docker/tools/docker/nginx.conf.template} +4 -2
- package/templates/features/docker/tools/docker/scripts/docker-build.js.hbs +20 -0
- package/templates/features/docker/tools/docker/scripts/docker-ports.js.hbs +48 -0
- package/templates/features/docker/tools/docker/scripts/docker-ports.test.js.hbs +52 -0
- package/templates/features/docker/tools/docker/scripts/docker-run.js.hbs +28 -0
- package/templates/features/docker/tools/docker/scripts/render-docker-template.js.hbs +23 -0
- package/templates/features/docker/tools/docker/scripts/render-docker-template.test.js.hbs +60 -0
- package/templates/features/docker/tools/docker/scripts/validate-docker.js.hbs +30 -0
- package/lib/src/context-builder.mjs +0 -40
- package/lib/src/file-generator.mjs +0 -109
- package/lib/src/json-generator.mjs +0 -31
- package/lib/src/package-manager.mjs +0 -139
- package/lib/src/print.mjs +0 -32
- package/lib/src/utils.mjs +0 -18
- package/lib/src/version.mjs +0 -1
- package/templates/base/builder.config.js.hbs +0 -36
- package/templates/base/src/app/components/common/anchor/anchor.component.ts.hbs +0 -32
- package/templates/base/src/app/components/common/button/button.component.ts.hbs +0 -40
- package/templates/base/src/app/dom.test.js.hbs +0 -13
- package/templates/base/src/app/services/example/example.service.ts.hbs +0 -18
- package/templates/base/src/app/views/home/home.view.test.js.hbs +0 -26
- package/templates/base/src/core/services/store/store.test.js.hbs +0 -8
- package/templates/base/src/core/services/store/store.ts.hbs +0 -39
- package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.test.js.hbs +0 -0
- package/templates/base/src/core/utils/anchor-manager/anchor-manager.utils.ts.hbs +0 -113
- package/templates/base/src/core/utils/button-manager/button-manager.utils.test.js.hbs +0 -249
- package/templates/base/src/core/utils/button-manager/button-manager.utils.ts.hbs +0 -131
- package/templates/base/src/core/utils/helpers/attributes.helper.ts.hbs +0 -50
- package/templates/base/src/core/utils/index.ts.hbs +0 -2
- package/templates/base/src/libs/index.ts.hbs +0 -4
- package/templates/base/src/libs/popover/helpers/focus-trap.helper.ts.hbs +0 -197
- package/templates/base/src/libs/popover/helpers/popover-dom.helper.ts.hbs +0 -75
- package/templates/base/src/libs/popover/popover.ts.hbs +0 -138
- package/templates/base/src/libs/snackbar/snackbar.ts.hbs +0 -75
- package/templates/base/src/styles/base/_functions.scss.hbs +0 -9
- package/templates/base/src/styles/core/_anchors.scss.hbs +0 -10
- package/templates/base/src/styles/core/_index.scss.hbs +0 -6
- package/templates/base/src/styles/core/_popover.scss.hbs +0 -96
- package/templates/base/src/styles/core/_snackbar.scss.hbs +0 -50
- package/templates/base/tools/builder/core/esbuild.js.hbs +0 -25
- package/templates/base/tools/builder/core/minify-html.js.hbs +0 -60
- package/templates/base/tools/builder/core/sass.js.hbs +0 -22
- package/templates/base/tools/builder/core/tsc.js.hbs +0 -12
- package/templates/base/tools/generator/templates/service.template.js.hbs +0 -17
- package/templates/base/tools/utils/export-flags.js.hbs +0 -6
- package/templates/features/deployHelper/tools/builder/core/compress-files.js.hbs +0 -56
- package/templates/features/deployHelper/tools/deployment/Dockerfile.hbs +0 -30
- package/templates/features/i18n/src/app/views/home/locales/en.json.hbs +0 -9
- package/templates/features/i18n/src/app/views/not-found/locales/en.json +0 -8
- package/templates/features/i18n/src/app/views/not-found/locales/fr.json +0 -8
- package/templates/features/i18n/src/core/config.ts.hbs +0 -3
- package/templates/features/i18n/src/core/services/i18n/i18n.test.js.hbs +0 -125
- package/templates/features/i18n/tools/generator/templates/json.template.js.hbs +0 -8
- package/templates/features/i18n/tools/utils/languages.js.hbs +0 -7
- package/templates/features/stylinNutin/src/styles/_custom-classes.scss.hbs +0 -9
- package/templates/features/stylinNutin/src/styles/base/_mixins.scss.hbs +0 -372
- package/templates/features/stylinNutin/src/styles/components/_index.scss.hbs +0 -3
- package/templates/features/stylinNutin/src/styles/core/_utilities.scss.hbs +0 -254
- package/templates/features/stylinNutin/src/styles/views/_index.scss.hbs +0 -0
- package/templates/features/stylinNutin/tools/generator/templates/scss.template.js.hbs +0 -4
- package/templates/features/template/src/app/views/home/home.view.html.hbs +0 -56
- package/templates/features/template/src/app/views/not-found/not-found.view.html.hbs +0 -19
- package/templates/features/template/tools/builder/core/merge-templates.js.hbs +0 -49
- package/templates/features/template/tools/generator/templates/html.template.js.hbs +0 -2
- package/templates/features/testinNutin/testin-nutin/core/index.js.hbs +0 -5
- package/templates/features/testinNutin/testin-nutin/core/src/utils/print.js.hbs +0 -64
- package/templates/features/testinNutin/testin-nutin/core/src/utils/test-queue.js.hbs +0 -64
- package/templates/features/testinNutin/testin-nutin/core/tests/globals-each-all.test.js.hbs +0 -28
- package/templates/features/testinNutin/testin-nutin/mocks/mock-store.js.hbs +0 -38
- package/templates/features/testinNutin/testin-nutin/runner.js.hbs +0 -36
- package/templates/features/testinNutin/testin-nutin/watch-tests.js.hbs +0 -21
- package/templates/features/testinNutin/testin-nutin.config.js.hbs +0 -14
- /package/lib/src/{template-compiler.mjs → common/template-compiler.mjs} +0 -0
- /package/templates/{features/i18n → base}/src/core/base-classes/base-component/helpers/i18n.helper.ts.hbs +0 -0
- /package/templates/{features/i18n → base}/src/core/services/i18n/languages.ts.hbs +0 -0
- /package/templates/base/tools/builder/{variables → core/app}/binary-extensions.js.hbs +0 -0
- /package/templates/base/tools/builder/core/{paths.js.hbs → app/paths.js.hbs} +0 -0
- /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/queue.js.hbs +0 -0
- /package/templates/{features/testinNutin/testin-nutin/core/src/utils → base/tools/testin-nutin/core/queue}/test-discovery.js.hbs +0 -0
- /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-http-client.js.hbs +0 -0
- /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-i18n.js.hbs +0 -0
- /package/templates/{features/testinNutin → base/tools}/testin-nutin/mocks/mock-router.js.hbs +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,86 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## 2.0.0
|
|
4
|
+
|
|
5
|
+
Version 2.0.0 focuses on simplicity and clear APIs over feature accumulation: fewer abstractions, clearer responsibilities, and a more focused API.
|
|
6
|
+
|
|
7
|
+
### Breaking Changes
|
|
8
|
+
|
|
9
|
+
- Renamed `BaseComponent`'s `childConfigs()` to `registerChildren()` and `catalogConfig` to `createCatalogComponents()`.
|
|
10
|
+
- Raised the required Node.js version from `>=18` to `>=22`.
|
|
11
|
+
- Removed all libraries except `Pipes`, as they did not fit Nutin's philosophy.
|
|
12
|
+
- Removed `Store`. Its responsibilities were unclear and largely duplicated what services already provide.
|
|
13
|
+
- Removed the `force` parameter from `listenToRenderEvents()`. It is no longer needed.
|
|
14
|
+
|
|
15
|
+
### Architecture & API
|
|
16
|
+
|
|
17
|
+
- Clarified and separated the responsibilities of the base classes:
|
|
18
|
+
- **`BaseComponent`**: render lifecycle, hydration, DOM lifecycle, DOM and EventBus subscriptions, teardown, render guard, and composition orchestration.
|
|
19
|
+
- **`Component`**: props (`className`, `style`, `data-bindings`), configuration/defaults/normalization, and template generation through `templateFn`.
|
|
20
|
+
- **`View`**: route parameters, navigation hooks (`onEnter()` / `onExit()`), and view identity (`viewName`).
|
|
21
|
+
|
|
22
|
+
- Components and Views now inherit `listen()` and `listenToRenderEvents()` methods with automatic unsubscription.
|
|
23
|
+
- Added explicit lifecycle hooks:
|
|
24
|
+
- **Component:** `onBeforeRender()`, `onAfterRender()`, `onBeforeDestroy()`, `onAfterDestroy()`
|
|
25
|
+
- **View:** `onEnter()`, `onExit()`
|
|
26
|
+
|
|
27
|
+
- Simplified the EventBus API:
|
|
28
|
+
- Added `AppEventMap` for app-level events. Nutin's internal events are no longer declared in `globals.d.ts`.
|
|
29
|
+
- Event payload types are now objects.
|
|
30
|
+
- EventBus now exposes domain facades for `Navigation` and `Lifecycle` events.
|
|
31
|
+
- Event subscription functions (`on*`) now return a closure for unsubscription.
|
|
32
|
+
- `AppEventBus` can still be used directly when needed (`once()`, etc.), but subscriptions must then be unsubscribed manually through the `onBeforeDestroy()` hook.
|
|
33
|
+
```ts
|
|
34
|
+
// emit
|
|
35
|
+
Navigation.navigateTo('path');
|
|
36
|
+
// closure
|
|
37
|
+
const unsub = Navigation.onNavigate(this.doStuff);
|
|
38
|
+
// onDestroy
|
|
39
|
+
unsub()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Services
|
|
43
|
+
|
|
44
|
+
- Services now expose a single `getInstance()` method.
|
|
45
|
+
- Arguments can be passed to `getInstance()`, but are only used during the first instantiation.
|
|
46
|
+
|
|
47
|
+
### Configuration & Build
|
|
48
|
+
|
|
49
|
+
- Added `nutin.config.js` as the central configuration file for Nutin options, builder, generator, and testing.
|
|
50
|
+
- Added optional Tailwind CSS v4 support as a utility layer alongside SASS.
|
|
51
|
+
- Added globally scoped stylesheets co-located with feature files. **Use unique class names.** Nutin's naming convention encourages prefixes such as `home__header`.
|
|
52
|
+
- HTML templates can now be either inline or external `.html` files. Defining both, or neither, fails the build.
|
|
53
|
+
- Added configurable Docker ports through `nutin.config.js`.
|
|
54
|
+
- Dockerfile now builds a Brotli-enabled image.
|
|
55
|
+
|
|
56
|
+
### SEO & i18n
|
|
57
|
+
|
|
58
|
+
- Added optional generation of static SEO files from `config/seo.json`.
|
|
59
|
+
- Production builds generate static HTML for each route using the actual components.
|
|
60
|
+
- Only `title`, `description`, and `ogImage` remain hand-authored SEO content.
|
|
61
|
+
- Generates `robots.txt` and `sitemap.xml`.
|
|
62
|
+
- Supports per-route `disallow` and `disallowBots`.
|
|
63
|
+
|
|
64
|
+
- i18n now uses the URL, aligning with common practices and allowing static SEO HTML to be generated for each language.
|
|
65
|
+
|
|
66
|
+
### CLI & Developer Experience
|
|
67
|
+
|
|
68
|
+
- Added `nutin-update`, which updates Nutin to the latest patch or minor version by diffing the project against the new templates and merging compatible changes. Unresolved conflicts are reported.
|
|
69
|
+
- Added `nutin-add docker`.
|
|
70
|
+
- Added `GETTING_STARTED.md`, providing the architectural context and conventions needed to start working with a Nutin project without immediately consulting the full documentation.
|
|
71
|
+
- Added `AGENTS.md`, providing LLMs with the minimal context required to work effectively in a Nutin project.
|
|
72
|
+
|
|
73
|
+
### TestinNutin
|
|
74
|
+
|
|
75
|
+
- Added code coverage summaries for branches, functions, and lines.
|
|
76
|
+
- Added `it.todo`.
|
|
77
|
+
- Added clock mocking for `setTimeout` and `setInterval`.
|
|
78
|
+
|
|
79
|
+
### Bug Fixes
|
|
80
|
+
|
|
81
|
+
- Numerous bug fixes and stability improvements.
|
|
82
|
+
|
|
83
|
+
## 1.3.1
|
|
4
84
|
|
|
5
85
|
- Minor features:
|
|
6
86
|
- New BaseComponent protected method.
|
|
@@ -34,7 +114,7 @@
|
|
|
34
114
|
CI/CD: Minimal + deployment helpers
|
|
35
115
|
- Remaining flags: `--i18n`, `--deploy-helper`, `--testin-nutin`, `--transition`
|
|
36
116
|
|
|
37
|
-
##
|
|
117
|
+
## 1.3.0
|
|
38
118
|
|
|
39
119
|
Version 1.3.0 marks a stability milestone with various improvements and refinements, making this the recommended version for new projects.
|
|
40
120
|
|
|
@@ -69,11 +149,11 @@ Version 1.3.0 marks a stability milestone with various improvements and refineme
|
|
|
69
149
|
- TestinNutin
|
|
70
150
|
- Now applies `setupJsdom()` beforeAll (was beforeEach) and `teardownJsdom()` afterAll (was afterEach) in `test-queue.js` (improved efficiency / speed)
|
|
71
151
|
|
|
72
|
-
##
|
|
152
|
+
## 1.2.3
|
|
73
153
|
|
|
74
154
|
- `nginx.conf` : fixed multi-line CSP map warning (single line map)
|
|
75
155
|
|
|
76
|
-
##
|
|
156
|
+
## 1.2.2
|
|
77
157
|
|
|
78
158
|
- Fixed Nginx security headers in child location blocks.
|
|
79
159
|
|
|
@@ -81,7 +161,7 @@ Version 1.3.0 marks a stability milestone with various improvements and refineme
|
|
|
81
161
|
|
|
82
162
|
- Removed ghost files
|
|
83
163
|
|
|
84
|
-
##
|
|
164
|
+
## 1.2.1
|
|
85
165
|
|
|
86
166
|
- Builder
|
|
87
167
|
|
|
@@ -109,7 +189,7 @@ Version 1.3.0 marks a stability milestone with various improvements and refineme
|
|
|
109
189
|
|
|
110
190
|
- Added explicit chokidar devDependency (sass & live-server transitive).
|
|
111
191
|
|
|
112
|
-
##
|
|
192
|
+
## 1.2.0
|
|
113
193
|
|
|
114
194
|
- Fixed `npm run dev` command. Added middleware to reload nested routes.
|
|
115
195
|
|
|
@@ -140,7 +220,7 @@ Version 1.3.0 marks a stability milestone with various improvements and refineme
|
|
|
140
220
|
- stylin-nutin (generator)
|
|
141
221
|
- When generating a component, prompts (boolean) to generate a `_component-name.scss` file in `styles/components` (forwarded by `styles/components/_index.scss`).
|
|
142
222
|
|
|
143
|
-
##
|
|
223
|
+
## 1.1.0
|
|
144
224
|
|
|
145
225
|
- Added index access in CatalogConfig. Use with `config.index`.
|
|
146
226
|
```typescript
|
|
@@ -159,10 +239,10 @@ type CatalogItemConfig<T = any> =
|
|
|
159
239
|
|
|
160
240
|
**Notes:** *Primitive data arrays (string, number, etc) needs to be accessed with `config.value`.*
|
|
161
241
|
|
|
162
|
-
##
|
|
242
|
+
## 1.0.2
|
|
163
243
|
|
|
164
244
|
- Partially fixed `npm run dev` script when using internal templates. *Page still needs to be reload manually from time to time.*
|
|
165
245
|
|
|
166
|
-
##
|
|
246
|
+
## 1.0.1
|
|
167
247
|
|
|
168
248
|
- Fixed typo issue when using i18n feature
|
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
# [
|
|
1
|
+
# [Nutin](https://www.nutin.org)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
Includes essential features out of the box.
|
|
5
|
-
*Pure TypeScript, SASS, and DOM-driven components — zero runtime dependencies.*
|
|
3
|
+
`The structure of a framework. The freedom of vanilla.`
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Nutin provides the structure and tooling you'd expect from a framework, while keeping the underlying web platform visible and giving you code ownership.
|
|
6
|
+
|
|
7
|
+
**Your app owns Nutin — not the other way around.** The source code lives alongside your application, so you can read it, modify it, and make it yours. Nutin's update system is designed to preserve those changes.
|
|
8
|
+
|
|
9
|
+
Nutin is deliberately pragmatic, lightweight, and dependency-free on runtime.
|
|
9
10
|
|
|
10
11
|
## Install
|
|
11
12
|
|
|
@@ -18,44 +19,28 @@ npm install -g @nutin/cli
|
|
|
18
19
|
|
|
19
20
|
```bash
|
|
20
21
|
# create a new app
|
|
21
|
-
|
|
22
|
-
nutin-new
|
|
22
|
+
nutin-new # or create-nutin-app
|
|
23
23
|
|
|
24
24
|
# without global installation
|
|
25
25
|
npx @nutin/cli
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
## Update Nutin
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-h --help
|
|
35
|
-
|
|
36
|
-
# Defaults settings - see below
|
|
37
|
-
-d --defaults
|
|
38
|
-
|
|
39
|
-
# Package manager
|
|
40
|
-
-pm --package-manager <manager> # npm (Default), yarn, pnpm, bun
|
|
31
|
+
# update Nutin while preserving your changes
|
|
32
|
+
nutin-update
|
|
33
|
+
```
|
|
41
34
|
|
|
42
|
-
|
|
43
|
-
--preset <minimal|standard|full|cicd>
|
|
44
|
-
# minimal: external templates
|
|
45
|
-
# standard: minimal + i18n & built-in SCSS classes
|
|
46
|
-
# full: standard + deployment helpers & built-in testing toolkit
|
|
47
|
-
# cicd: minimal + deployment helpers
|
|
35
|
+
## Add Docker
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
--testin-nutin # Use testin-nutin toolkit
|
|
53
|
-
--transition # Use animated view transitions. Note: May interfere with CSS `position: fixed`, `z-index`...
|
|
37
|
+
```bash
|
|
38
|
+
# ready-to-use Dockerfile for Nutin apps
|
|
39
|
+
nutin-add docker
|
|
54
40
|
```
|
|
55
41
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
## 📄 Docs
|
|
42
|
+
## Useful links
|
|
59
43
|
|
|
60
|
-
-
|
|
61
|
-
-
|
|
44
|
+
- [Nutin website](https://www.nutin.org)
|
|
45
|
+
- [First app tutorial](https://www.nutin.org/tutorial)
|
|
46
|
+
- [Repository documentation](https://github.com/LoisKOUNINEF/nutin/tree/main/docs)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { addFeatureCommand } from '../lib/index.mjs';
|
|
5
|
+
|
|
6
|
+
addFeatureCommand(new Command()).parseAsync(process.argv).catch((err) => {
|
|
7
|
+
console.error(err instanceof Error ? err.stack : err);
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
});
|
package/bin/cli.mjs
ADDED
package/bin/create-app.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { createAppCommand } from '../lib/index.mjs';
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
console.error(
|
|
7
|
-
process.
|
|
6
|
+
createAppCommand(new Command()).parseAsync(process.argv).catch((err) => {
|
|
7
|
+
console.error(err instanceof Error ? err.stack : err);
|
|
8
|
+
process.exitCode = 1;
|
|
8
9
|
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { updateAppCommand } from '../lib/index.mjs';
|
|
5
|
+
|
|
6
|
+
updateAppCommand(new Command()).parseAsync(process.argv).catch((err) => {
|
|
7
|
+
console.error(err instanceof Error ? err.stack : err);
|
|
8
|
+
process.exitCode = 1;
|
|
9
|
+
});
|
package/lib/index.mjs
CHANGED
|
@@ -1,33 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { print, chalk } from './src/print.mjs';
|
|
3
|
-
import {
|
|
4
|
-
import { createProject } from './src/project-generator.mjs';
|
|
5
|
-
import { displaySuccessMessage } from './src/
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { print, chalk } from './src/utils/print.mjs';
|
|
3
|
+
import { newAppPrompt } from './src/create-app/new-app-prompt.mjs';
|
|
4
|
+
import { createProject } from './src/create-app/project-generator.mjs';
|
|
5
|
+
import { displaySuccessMessage } from './src/create-app/success-message.mjs';
|
|
6
|
+
import { PACKAGE_VERSION } from './src/common/package-data.mjs';
|
|
7
|
+
import { FEATURES, findFeatureByCli } from './src/common/feature-registry.mjs';
|
|
8
|
+
import { addFeatureToProject } from './src/add-feature/feature-adder.mjs';
|
|
9
|
+
import { updateProject } from './src/update-app/project-updater.mjs';
|
|
10
|
+
|
|
11
|
+
export function createAppCommand(command) {
|
|
12
|
+
return command
|
|
13
|
+
.version(PACKAGE_VERSION)
|
|
11
14
|
.configureOutput({
|
|
12
|
-
helpWidth: 100
|
|
15
|
+
helpWidth: 100
|
|
13
16
|
})
|
|
14
17
|
.argument('[projectName]', 'Name of the project')
|
|
15
18
|
.option('-pm, --package-manager <manager>', 'Specify package manager (npm, yarn, pnpm, bun)')
|
|
16
|
-
.option('--preset <preset>',
|
|
17
|
-
`${chalk.yellow('Project preset configuration:')}
|
|
18
|
-
${chalk.cyan('• minimal')}${chalk.boldGray(' - external templates')}
|
|
19
|
-
${chalk.cyan('• standard')}${chalk.boldGray(' - minimal + i18n & built-in SCSS utilities')}
|
|
20
|
-
${chalk.cyan('• full')}${chalk.boldGray(' - standard + deployment helpers & built-in testing toolkit')}
|
|
21
|
-
${chalk.cyan('• cicd')}${chalk.boldGray(' - minimal + deployment helpers')}`
|
|
22
|
-
)
|
|
23
|
-
.option('--i18n', 'Use i18n & json-based content')
|
|
24
|
-
.option('--deploy-helper', 'Use Docker & deployment helpers')
|
|
25
|
-
.option('--testin-nutin', 'Use built-in testing toolkit')
|
|
26
|
-
.option('--transition', 'Use animated view transitions\nNote: may interfere with CSS `position: fixed`, `z-index`…')
|
|
27
19
|
.action(async (projectName, cliOptions) => {
|
|
28
|
-
print.
|
|
20
|
+
print.boldSuccess('\n🚀 Welcome to your new nutin app!\n');
|
|
29
21
|
try {
|
|
30
|
-
const preferences = await
|
|
22
|
+
const preferences = await newAppPrompt(projectName, cliOptions);
|
|
31
23
|
await createProject(preferences);
|
|
32
24
|
displaySuccessMessage(preferences);
|
|
33
25
|
} catch (error) {
|
|
@@ -35,7 +27,66 @@ export async function createApp() {
|
|
|
35
27
|
process.exit(1);
|
|
36
28
|
}
|
|
37
29
|
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function addFeatureCommand(command) {
|
|
33
|
+
const featureChoices = [...FEATURES.map((feature) => feature.cli), 'all'];
|
|
34
|
+
|
|
35
|
+
return command
|
|
36
|
+
.version(PACKAGE_VERSION)
|
|
37
|
+
.configureOutput({
|
|
38
|
+
helpWidth: 100
|
|
39
|
+
})
|
|
40
|
+
.argument('<feature>', `Feature to add to the current project: ${featureChoices.join(', ')}`)
|
|
41
|
+
.action(async (featureArg) => {
|
|
42
|
+
if (!featureChoices.includes(featureArg)) {
|
|
43
|
+
print.boldError(`❌ Unknown feature "${featureArg}". Choose one of: ${featureChoices.join(', ')}`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
if (featureArg === 'all') {
|
|
49
|
+
for (const feature of FEATURES) {
|
|
50
|
+
await addFeatureToProject(feature.key);
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
const feature = findFeatureByCli(featureArg);
|
|
54
|
+
await addFeatureToProject(feature.key);
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
print.boldError(`❌ Error adding feature: ${error.stack}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
38
62
|
|
|
39
|
-
|
|
63
|
+
export function updateAppCommand(command) {
|
|
64
|
+
return command
|
|
65
|
+
.version(PACKAGE_VERSION)
|
|
66
|
+
.configureOutput({
|
|
67
|
+
helpWidth: 100
|
|
68
|
+
})
|
|
69
|
+
.option('-y, --yes', 'Skip the confirmation prompt and apply safe updates immediately')
|
|
70
|
+
.option('--from <path>', 'Use a local templates/ directory as the old baseline instead of fetching from npm')
|
|
71
|
+
.action(async (cliOptions) => {
|
|
72
|
+
print.boldSuccess('🚀 nutin — update');
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
await updateProject(process.cwd(), cliOptions);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
print.boldError(`❌ Error updating project: ${error.stack}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
40
81
|
}
|
|
41
82
|
|
|
83
|
+
export function buildCli() {
|
|
84
|
+
const program = new Command();
|
|
85
|
+
program.name('nutin').version(PACKAGE_VERSION);
|
|
86
|
+
|
|
87
|
+
createAppCommand(program.command('new', { isDefault: true }).description('Create a new nutin app'));
|
|
88
|
+
addFeatureCommand(program.command('add').description('Add a feature to the current project'));
|
|
89
|
+
updateAppCommand(program.command('update').description('Update nutin while preserving your changes'));
|
|
90
|
+
|
|
91
|
+
return program;
|
|
92
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
import * as fsExtra from 'fs-extra';
|
|
4
|
+
import { print } from '../utils/print.mjs';
|
|
5
|
+
import { FileGenerator } from '../common/file-generator.mjs';
|
|
6
|
+
import { FEATURES } from '../common/feature-registry.mjs';
|
|
7
|
+
import { PACKAGE_VERSION } from '../common/package-data.mjs';
|
|
8
|
+
import { installDependencies } from '../common/package-json-helper.mjs';
|
|
9
|
+
import { readProjectMeta, updateProjectMeta } from '../common/project-meta.mjs';
|
|
10
|
+
import { FeatureContextBuilder } from './feature-context-builder.mjs';
|
|
11
|
+
import { updatePackageJson } from './package-json-updater.mjs';
|
|
12
|
+
import { updateNutinConfig } from './nutin-config-updater.mjs';
|
|
13
|
+
|
|
14
|
+
const fs = fsExtra.default;
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
|
|
18
|
+
export class FeatureAdder {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.fileGenerator = new FileGenerator();
|
|
21
|
+
this.builder = new FeatureContextBuilder();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async addFeatureToProject(featureKey) {
|
|
25
|
+
const feature = FEATURES.find((candidate) => candidate.key === featureKey);
|
|
26
|
+
if (!feature) {
|
|
27
|
+
throw new Error(`Unknown feature: ${featureKey}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const projectPath = process.cwd();
|
|
31
|
+
await this.validateProject(projectPath, feature);
|
|
32
|
+
|
|
33
|
+
const meta = await readProjectMeta(projectPath);
|
|
34
|
+
if (meta?.features?.[feature.key]) {
|
|
35
|
+
print.gray(`${feature.key} is already enabled in this project — skipping.`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
print.boldInfo(`\nAdding ${feature.key} to ${projectPath}...`);
|
|
40
|
+
|
|
41
|
+
const context = await this.builder.buildContext(projectPath, feature);
|
|
42
|
+
|
|
43
|
+
await this.applyFeatureTemplate(projectPath, feature, context);
|
|
44
|
+
await this.runPostAddTasks(projectPath, feature, context);
|
|
45
|
+
|
|
46
|
+
print.boldInfo(`${feature.key} added.`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async validateProject(projectPath, feature) {
|
|
50
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
51
|
+
if (!(await fs.pathExists(packageJsonPath))) {
|
|
52
|
+
throw new Error(`No package.json found in ${projectPath} — run this from a nutin project's root.`);
|
|
53
|
+
}
|
|
54
|
+
if (!(await fs.pathExists(path.join(projectPath, 'nutin.config.js')))) {
|
|
55
|
+
throw new Error(`No nutin.config.js file found in ${projectPath} — is this a nutin project?`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async applyFeatureTemplate(projectPath, feature, context) {
|
|
60
|
+
const featureTemplateDir = path.join(__dirname, '..', '..', '..', 'templates', 'features', feature.key);
|
|
61
|
+
|
|
62
|
+
await this.fileGenerator.processTemplateDirectory(featureTemplateDir, projectPath, context, { skipExisting: true });
|
|
63
|
+
|
|
64
|
+
await updatePackageJson(projectPath, feature);
|
|
65
|
+
await updateNutinConfig(projectPath, feature);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async runPostAddTasks(projectPath, feature, context) {
|
|
69
|
+
await updateProjectMeta(projectPath, {
|
|
70
|
+
version: PACKAGE_VERSION,
|
|
71
|
+
packageManager: context.packageManager,
|
|
72
|
+
features: { [feature.key]: true },
|
|
73
|
+
});
|
|
74
|
+
if (feature.key === 'docker') return;
|
|
75
|
+
await installDependencies(projectPath, context.packageManager);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const featureAdder = new FeatureAdder();
|
|
80
|
+
|
|
81
|
+
export async function addFeatureToProject(featureKey) {
|
|
82
|
+
return featureAdder.addFeatureToProject(featureKey);
|
|
83
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import * as fsExtra from 'fs-extra';
|
|
3
|
+
import { getCiCommand, detectPackageManager } from '../common/package-json-helper.mjs';
|
|
4
|
+
import { PACKAGE_VERSION } from '../common/package-data.mjs';
|
|
5
|
+
import { readProjectMeta } from '../common/project-meta.mjs';
|
|
6
|
+
import { bootstrapProjectMeta } from '../common/meta-bootstrap-prompt.mjs';
|
|
7
|
+
|
|
8
|
+
const fs = fsExtra.default;
|
|
9
|
+
|
|
10
|
+
export class FeatureContextBuilder {
|
|
11
|
+
async buildContext(projectPath, feature) {
|
|
12
|
+
const packageJson = await fs.readJSON(path.join(projectPath, 'package.json'));
|
|
13
|
+
const packageManager = await detectPackageManager(projectPath);
|
|
14
|
+
const meta = (await readProjectMeta(projectPath)) ?? (await bootstrapProjectMeta(projectPath));
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
projectName: packageJson.name,
|
|
18
|
+
packageManager,
|
|
19
|
+
ciCommand: getCiCommand(packageManager),
|
|
20
|
+
version: PACKAGE_VERSION,
|
|
21
|
+
...(meta.features ?? {}),
|
|
22
|
+
[feature.key]: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import * as fsExtra from 'fs-extra';
|
|
3
|
+
import { print } from '../utils/print.mjs';
|
|
4
|
+
|
|
5
|
+
const fs = fsExtra.default;
|
|
6
|
+
|
|
7
|
+
const GENERATE_SEO_LINE_RE = /^([ \t]*generateSEOFiles:[^\n]*\n)/m;
|
|
8
|
+
const DOCKER_PORTS_LINE = '\n// Nutin features\n dockerPorts: [9090], // Ports the Docker container exposes/listens on — edit as needed\n';
|
|
9
|
+
|
|
10
|
+
export async function updateNutinConfig(projectPath, feature) {
|
|
11
|
+
if (feature.key !== 'docker') return;
|
|
12
|
+
|
|
13
|
+
const configPath = path.join(projectPath, 'nutin.config.js');
|
|
14
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
15
|
+
|
|
16
|
+
if (/dockerPorts\s*:/.test(content)) {
|
|
17
|
+
print.info('Kept existing "dockerPorts" value in nutin.config.js');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!GENERATE_SEO_LINE_RE.test(content)) {
|
|
22
|
+
print.warn('Could not find a "generateSEOFiles:" line in nutin.config.js — add "dockerPorts: [9090]" to it manually before building.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const updated = content.replace(GENERATE_SEO_LINE_RE, `$1${DOCKER_PORTS_LINE}`);
|
|
27
|
+
await fs.writeFile(configPath, updated);
|
|
28
|
+
print.warn('Added "dockerPorts" to nutin.config.js — edit it if you need different port(s).');
|
|
29
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import * as fsExtra from 'fs-extra';
|
|
3
|
+
import { print } from '../utils/print.mjs';
|
|
4
|
+
import { getDockerScripts } from '../common/package-json-helper.mjs';
|
|
5
|
+
|
|
6
|
+
const fs = fsExtra.default;
|
|
7
|
+
|
|
8
|
+
function mergeAdditive(target, additions) {
|
|
9
|
+
const merged = { ...target };
|
|
10
|
+
const added = [];
|
|
11
|
+
const skipped = [];
|
|
12
|
+
|
|
13
|
+
for (const [key, value] of Object.entries(additions)) {
|
|
14
|
+
if (Object.prototype.hasOwnProperty.call(merged, key)) {
|
|
15
|
+
skipped.push(key);
|
|
16
|
+
} else {
|
|
17
|
+
merged[key] = value;
|
|
18
|
+
added.push(key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { merged, added, skipped };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function updatePackageJson(projectPath, feature) {
|
|
26
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
27
|
+
const packageJson = await fs.readJSON(packageJsonPath);
|
|
28
|
+
|
|
29
|
+
const isDocker = feature.key === 'docker';
|
|
30
|
+
|
|
31
|
+
let scripts = {};
|
|
32
|
+
|
|
33
|
+
if (isDocker) {
|
|
34
|
+
scripts = getDockerScripts();
|
|
35
|
+
} else {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const scriptsResult = mergeAdditive(packageJson.scripts ?? {}, scripts);
|
|
40
|
+
packageJson.scripts = scriptsResult.merged;
|
|
41
|
+
|
|
42
|
+
await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
|
|
43
|
+
|
|
44
|
+
const skipped = scriptsResult.skipped;
|
|
45
|
+
if (skipped.length > 0) {
|
|
46
|
+
print.info(`Kept existing package.json values for: ${skipped.join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
print.info('Updated package.json');
|
|
49
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Single source of truth for the optional, additive features under templates/features
|
|
2
|
+
export const FEATURES = [
|
|
3
|
+
{
|
|
4
|
+
key: 'docker',
|
|
5
|
+
cli: 'docker',
|
|
6
|
+
},
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export function findFeatureByCli(cliName) {
|
|
10
|
+
return FEATURES.find((feature) => feature.cli === cliName);
|
|
11
|
+
}
|