@leo-h/create-nodejs-app 1.0.2 → 1.0.3
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/README.md +19 -0
- package/dist/index.js +1 -1
- package/dist/package.json.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/utils/capitalize-first-word.js +1 -0
- package/dist/src/validations/framework.validation.js +1 -1
- package/dist/src/validations/project-name-validation.js +1 -1
- package/package.json +1 -2
- package/dist/src/utils/to-pascal-case.js +0 -1
package/README.md
CHANGED
@@ -27,8 +27,27 @@ With PNPM:
|
|
27
27
|
pnpm create @leo-h/nodejs-app
|
28
28
|
```
|
29
29
|
|
30
|
+
## CLI
|
31
|
+
|
32
|
+
You can create the project non-interactively through the CLI. Arguments or options not provided will still be asked if it is mandatory information for creation.
|
33
|
+
|
34
|
+
```bash
|
35
|
+
Usage: @leo-h/create-nodejs-app [options] [project-directory]
|
36
|
+
|
37
|
+
Arguments:
|
38
|
+
project-directory Name of the project or relative path of the project considering where the script was called.
|
39
|
+
|
40
|
+
Options:
|
41
|
+
-pm, --package-manager <package-manager> Package manager that will be used in the project.
|
42
|
+
-t, --template <template-name> Template that will be used in the project.
|
43
|
+
-f, --framework <framework-name> Framework that will be used in the project.
|
44
|
+
-h, --help display help for command
|
45
|
+
```
|
46
|
+
|
30
47
|
## Features
|
31
48
|
|
32
49
|
- **Fast**: All templates use [tsx](https://tsx.is/) to run Node.js with TypeScript and [unbuild](https://github.com/unjs/unbuild) to build the application. Both tools use [esbuild](https://esbuild.github.io/), an extremely fast packager also used by tools like [Vite](https://vitejs.dev/).
|
33
50
|
|
34
51
|
- **Lint and code format**: All templates use [eslint](https://eslint.org/) to identify problems in the code and [prettier](https://prettier.io/) to ensure consistent code formatting. Both are integrated with [husky](https://typicode.github.io/husky/) and [lint-staged](https://github.com/lint-staged/lint-staged) to automatically run them before every commit you make with git.
|
52
|
+
|
53
|
+
- **Tests**: To encourage the use of tests, all templates already have a pre-configured unit testing setup with [Vitest](https://vitest.dev/). The API templates also come with end-to-end usage example tests, including all utility tools like [Supertest](https://github.com/ladjs/supertest#readme) and [Faker.js](https://fakerjs.dev/).
|
package/dist/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
#!/usr/bin/env node
|
2
|
-
const index=require("./src/config/index.js"),commander=require("commander"),path=require("path"),picocolors=require("picocolors"),C=require("prompts"),_package=require("./package.json.js"),copyTemplate_compose=require("./src/compose-app/copy-template.compose.js"),replaceContentInFile_compose=require("./src/compose-app/replace-content-in-file.compose.js"),logs=require("./src/utils/logs.js"),onCancel=require("./src/utils/on-cancel.js"),framework_validation=require("./src/validations/framework.validation.js"),packageManager_validation=require("./src/validations/package-manager.validation.js"),projectNameValidation=require("./src/validations/project-name-validation.js"),template_validation=require("./src/validations/template.validation.js"),g=new commander.Command().name(_package.default.name).description(_package.default.description);g.argument("[project-directory]","Name of the project or relative path of the project considering where the script was called.").option("--package-manager <package-manager>","Package manager that will be used in the project.").option("-t, --template <template-name>","Template that will be used in the project.").option("-f, --framework <framework-name>","Framework that will be used in the project.").action(async(i,o)=>{const r={projectDirectory:{value:i,validation:projectNameValidation.ProjectNameValidation.create({path:i})},packageManager:{value:o.packageManager,validation:packageManager_validation.PackageManagerValidation.create({packageManager:o.packageManager})},template:{value:o.template,validation:template_validation.TemplateValidation.create({template:o.template})},framework:{value:o.framework,validation:framework_validation.FrameworkValidation.create({framework:o.framework})}},l=Object.keys(r);for(const a of l){const t=r[a];t.value&&await t.validation.fromCli()}const{projectDirectory:e,packageManager:s,template:p,framework:n}=r,m=await C([{type:e.value?null:"text",name:"projectDirectory",message:"What is your project name?",validate:async a=>await e.validation.fromPrompt({path:a})},{type:s.value?null:"select",name:"packageManager",message:"What is your favorite package manager?",choices:packageManager_validation.packageManagers,initial:2},{type:!p.value&&!n.value?"select":null,name:"template",message:"Select your template:",choices:template_validation.templates},{type:(a,t)=>!n.value&&(p.value==="api"||t.template==="api")?"select":null,name:"framework",message:"What is your favorite framework?",choices:framework_validation.frameworks}],{onCancel:onCancel.onCancelPrompt});for(const a of l){const t=m[a];t&&(r[a].value=t)}n.value&&(r.template.value="api");const c=path.basename(e.value);e.value=path.resolve(index.GENERATED_APP_TARGET_ROOT_PATH,e.value),await copyTemplate_compose.copyTemplateCompose(e.value,n.value??"clean");const u=path.resolve(e.value,"package.json"),v=path.resolve(e.value,".env.example"),d=path.resolve(e.value,".husky/pre-commit");await Promise.all([replaceContentInFile_compose.replaceContentInFileCompose(u,[["app-name",c]]),replaceContentInFile_compose.replaceContentInFileCompose(v,[["app-name",c]]),replaceContentInFile_compose.replaceContentInFileCompose(d,[["pnpm",s.value]])]),logs.successLog(`Success in creating new app ${picocolors.cyan(c)}!`,`> ${e.value}`)});(async()=>await g.parseAsync(process.argv))();
|
2
|
+
const index=require("./src/config/index.js"),commander=require("commander"),path=require("path"),picocolors=require("picocolors"),C=require("prompts"),_package=require("./package.json.js"),copyTemplate_compose=require("./src/compose-app/copy-template.compose.js"),replaceContentInFile_compose=require("./src/compose-app/replace-content-in-file.compose.js"),logs=require("./src/utils/logs.js"),onCancel=require("./src/utils/on-cancel.js"),framework_validation=require("./src/validations/framework.validation.js"),packageManager_validation=require("./src/validations/package-manager.validation.js"),projectNameValidation=require("./src/validations/project-name-validation.js"),template_validation=require("./src/validations/template.validation.js"),g=new commander.Command().name(_package.default.name).description(_package.default.description);g.argument("[project-directory]","Name of the project or relative path of the project considering where the script was called.").option("-pm, --package-manager <package-manager>","Package manager that will be used in the project.").option("-t, --template <template-name>","Template that will be used in the project.").option("-f, --framework <framework-name>","Framework that will be used in the project.").action(async(i,o)=>{const r={projectDirectory:{value:i,validation:projectNameValidation.ProjectNameValidation.create({path:i})},packageManager:{value:o.packageManager,validation:packageManager_validation.PackageManagerValidation.create({packageManager:o.packageManager})},template:{value:o.template,validation:template_validation.TemplateValidation.create({template:o.template})},framework:{value:o.framework,validation:framework_validation.FrameworkValidation.create({framework:o.framework})}},l=Object.keys(r);for(const a of l){const t=r[a];t.value&&await t.validation.fromCli()}const{projectDirectory:e,packageManager:s,template:p,framework:n}=r,m=await C([{type:e.value?null:"text",name:"projectDirectory",message:"What is your project name?",validate:async a=>await e.validation.fromPrompt({path:a})},{type:s.value?null:"select",name:"packageManager",message:"What is your favorite package manager?",choices:packageManager_validation.packageManagers,initial:2},{type:!p.value&&!n.value?"select":null,name:"template",message:"Select your template:",choices:template_validation.templates},{type:(a,t)=>!n.value&&(p.value==="api"||t.template==="api")?"select":null,name:"framework",message:"What is your favorite framework?",choices:framework_validation.frameworks}],{onCancel:onCancel.onCancelPrompt});for(const a of l){const t=m[a];t&&(r[a].value=t)}n.value&&(r.template.value="api");const c=path.basename(e.value);e.value=path.resolve(index.GENERATED_APP_TARGET_ROOT_PATH,e.value),await copyTemplate_compose.copyTemplateCompose(e.value,n.value??"clean");const u=path.resolve(e.value,"package.json"),v=path.resolve(e.value,".env.example"),d=path.resolve(e.value,".husky/pre-commit");await Promise.all([replaceContentInFile_compose.replaceContentInFileCompose(u,[["app-name",c]]),replaceContentInFile_compose.replaceContentInFileCompose(v,[["app-name",c]]),replaceContentInFile_compose.replaceContentInFileCompose(d,[["pnpm",s.value]])]),logs.successLog(`Success in creating new app ${picocolors.cyan(c)}!`,`> ${e.value}`)});(async()=>await g.parseAsync(process.argv))();
|
package/dist/package.json.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Object.defineProperty(exports,"__esModule",{value:!0});const name="@leo-h/create-nodejs-app",version="1.0.
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0});const name="@leo-h/create-nodejs-app",version="1.0.3",packageManager="pnpm@9.1.1",author="Leonardo Henrique <leonardo0507.business@gmail.com>",description="Create a modern Node.js app with TypeScript using one command.",license="MIT",keywords=["node","node.js","typescript"],bin={"create-nodejs-app":"./dist/index.js"},files=["./dist","./templates"],repository={type:"git",url:"https://github.com/Leo-Henrique/create-nodejs-app"},scripts={prepare:"husky",start:"node ./dist/index.js","start:dev":"tsx ./src/index.ts","start:dev:watch":"tsx watch ./src/index.ts",typecheck:"tsc --noEmit",lint:"eslint . --ext .ts --max-warnings 0 --cache","lint:fix":"pnpm lint --fix",format:"prettier . --write --cache","test:unit":"vitest run","test:unit:watch":"vitest","test:e2e":"vitest run --config ./vitest.config.e2e.mts","test:e2e:watch":"vitest --config ./vitest.config.e2e.mts","test:coverage":"vitest run --coverage.enabled=true --coverage.all=false",template:"tsx ./scripts/template-cli.ts",prebuild:"rimraf ./dist",build:"unbuild",prepublishOnly:"pnpm build"},dependencies={commander:"12.1.0",picocolors:"1.0.1",prompts:"2.4.2","validate-npm-package-name":"5.0.1",zod:"3.23.8"},devDependencies={"@faker-js/faker":"8.4.1","@types/node":"20.12.12","@types/prompts":"2.4.9","@types/validate-npm-package-name":"4.0.2","@typescript-eslint/eslint-plugin":"7.10.0","@typescript-eslint/parser":"7.10.0","conventional-changelog-conventionalcommits":"8.0.0",eslint:"8.57.0","eslint-config-prettier":"9.1.0","eslint-plugin-vitest":"0.4.0",husky:"9.0.11","lint-staged":"15.2.2","npm-run-all":"4.1.5",prettier:"3.2.5",rimraf:"5.0.7",tsx:"4.10.5",typescript:"5.4.5",unbuild:"2.0.0","vite-tsconfig-paths":"4.3.2",vitest:"1.6.0"},f={name,version,packageManager,author,description,license,keywords,bin,files,repository,scripts,dependencies,devDependencies};exports.author=author;exports.bin=bin;exports.default=f;exports.dependencies=dependencies;exports.description=description;exports.devDependencies=devDependencies;exports.files=files;exports.keywords=keywords;exports.license=license;exports.name=name;exports.packageManager=packageManager;exports.repository=repository;exports.scripts=scripts;exports.version=version;
|
package/dist/src/config/index.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
const
|
1
|
+
const fs=require("fs"),path=require("path");process.env.NODE_ENV||(process.argv[1].endsWith(".js")?process.env.NODE_ENV="production":process.env.NODE_ENV="development");const n=(e=__dirname)=>fs.readdirSync(e,{encoding:"utf-8"}).includes("package.json")?e:n(path.resolve(e,"..")),o=n(),GENERATED_APP_TARGET_ROOT_PATH=process.env.NODE_ENV==="production"?process.cwd():path.resolve(o,"generated-apps");process.env.NODE_ENV!=="production"&&!fs.existsSync(GENERATED_APP_TARGET_ROOT_PATH)&&fs.mkdirSync(GENERATED_APP_TARGET_ROOT_PATH);const TEMPLATES_PATH=path.resolve(o,"templates");path.resolve(TEMPLATES_PATH,"clean");exports.GENERATED_APP_TARGET_ROOT_PATH=GENERATED_APP_TARGET_ROOT_PATH;exports.TEMPLATES_PATH=TEMPLATES_PATH;
|
@@ -0,0 +1 @@
|
|
1
|
+
function capitalizeFirstWord(i){return i[0].toUpperCase()+i.slice(1)}exports.capitalizeFirstWord=capitalizeFirstWord;
|
@@ -1 +1 @@
|
|
1
|
-
const validation=require("../core/validation.js"),getValidOptionsFromPrompt=require("../utils/get-valid-options-from-prompt.js"),frameworks=[{title:"Fastify",value:"fastify"},{title:"Nest",value:"nest"},{title:"tRPC",value:"trpc",disabled:!0}],validFrameworks=getValidOptionsFromPrompt.getValidOptionsFromSelect(frameworks);class FrameworkValidation extends validation.Validation{static create(
|
1
|
+
const validation=require("../core/validation.js"),getValidOptionsFromPrompt=require("../utils/get-valid-options-from-prompt.js"),frameworks=[{title:"Fastify",value:"fastify"},{title:"Nest",value:"nest",disabled:!0},{title:"tRPC",value:"trpc",disabled:!0}],validFrameworks=getValidOptionsFromPrompt.getValidOptionsFromSelect(frameworks);class FrameworkValidation extends validation.Validation{static create(e){return new this().createValidation(e)}async validate(){let{framework:e}=this.params;return e=e.toLowerCase(),validFrameworks.includes(e)?{isValid:!0}:{isValid:!1,issue:`Invalid framework, consider the options: ${validFrameworks.map(t=>`"${t}"`).join(", ")}.`}}}exports.FrameworkValidation=FrameworkValidation;exports.frameworks=frameworks;exports.validFrameworks=validFrameworks;
|
@@ -1 +1 @@
|
|
1
|
-
const index=require("../config/index.js"),validation=require("../core/validation.js"),
|
1
|
+
const index=require("../config/index.js"),validation=require("../core/validation.js"),capitalizeFirstWord=require("../utils/capitalize-first-word.js"),fs=require("fs"),promises=require("fs/promises"),path=require("path"),c=require("validate-npm-package-name");class ProjectNameValidation extends validation.Validation{static create(e){return new this().createValidation(e)}async validate(){const{path:e}=this.params,i=path.basename(e),a=path.resolve(index.GENERATED_APP_TARGET_ROOT_PATH,e);if(fs.existsSync(a)&&(await promises.readdir(a)).includes(i))return{isValid:!1,issue:`Folder with name "${i}" already exists in project directory.`};const s=c(i);return s.validForNewPackages?{isValid:!0}:{isValid:!1,issue:capitalizeFirstWord.capitalizeFirstWord(s.errors[0])}}}exports.ProjectNameValidation=ProjectNameValidation;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@leo-h/create-nodejs-app",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.3",
|
4
4
|
"packageManager": "pnpm@9.1.1",
|
5
5
|
"author": "Leonardo Henrique <leonardo0507.business@gmail.com>",
|
6
6
|
"description": "Create a modern Node.js app with TypeScript using one command.",
|
@@ -41,7 +41,6 @@
|
|
41
41
|
"prepublishOnly": "pnpm build"
|
42
42
|
},
|
43
43
|
"dependencies": {
|
44
|
-
"app-root-path": "3.1.0",
|
45
44
|
"commander": "12.1.0",
|
46
45
|
"picocolors": "1.0.1",
|
47
46
|
"prompts": "2.4.2",
|
@@ -1 +0,0 @@
|
|
1
|
-
function toPascalCase(a){return a[0].toUpperCase()+a.slice(1)}exports.toPascalCase=toPascalCase;
|