diff --git a/.eslintrc.js b/.eslintrc.js index 7f7b234..2b98dee 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,21 +1,12 @@ module.exports = { - "env": { - "es6": true, - "node": true + env: { + es6: true, + node: true }, - "extends": "eslint:recommended", - "rules": { - "indent": [ - "error", - 2 - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ] + extends: "eslint:recommended", + rules: { + indent: ["error", 2], + quotes: [false], + semi: ["error", "always"] } -}; \ No newline at end of file +}; diff --git a/generators/app/index.js b/generators/app/index.js index 7e9a4f1..7e06d66 100644 --- a/generators/app/index.js +++ b/generators/app/index.js @@ -1,10 +1,12 @@ -'use strict'; -const Generator = require('yeoman-generator'); -const chalk = require('chalk'); -const yosay = require('yosay'); -const path = require('path'); -const _ = require('lodash'); -const shelljs = require('shelljs'); +"use strict"; +const Generator = require("yeoman-generator"); +const chalk = require("chalk"); +const yosay = require("yosay"); +const path = require("path"); +const _ = require("lodash"); +const shelljs = require("shelljs"); + +const BUILD_PATH = "build"; module.exports = Generator.extend({ initializing: function() { @@ -13,31 +15,31 @@ module.exports = Generator.extend({ // Have Yeoman greet the user. this.log( yosay( - 'Welcome to the minimal ' + chalk.red('Node TypeScript') + ' generator!' + "Welcome to the minimal " + chalk.red("Node TypeScript") + " generator!" ) ); this.log( chalk.cyan( - 'I simply get down to business of generating, no questions asked!' + "I simply get down to business of generating, no questions asked!" ) + - '\n' + + "\n" + chalk.yellow( - 'Libraries you ask? I use npm as task runner and jest for testing.' + "Libraries you ask? I use npm as task runner and jest for testing." ) + - '\n' + + "\n" + chalk.gray( - 'Can you change these? Of course, it\'s your code. I get out of the way after scaffolding.' + "Can you change these? Of course, it's your code. I get out of the way after scaffolding." ) ); this.composeWith( - require.resolve('../classlib'), - Object.assign({ arguments: ['Greeter'] }, this.options) + require.resolve("../classlib"), + Object.assign({ arguments: ["Greeter"] }, this.options) ); if (this.options.gulp) { - throw new Error('Gulp option is no longer supported.'); + throw new Error("Gulp option is no longer supported."); } done(); @@ -46,92 +48,122 @@ module.exports = Generator.extend({ writing: { vsCodeFiles: function() { this.fs.copy( - this.templatePath('_vscode/tasks.json'), - this.destinationPath('.vscode/tasks.json') + this.templatePath("_vscode/tasks.json"), + this.destinationPath(".vscode/tasks.json") ); this.fs.copy( - this.templatePath('_vscode/settings.json'), - this.destinationPath('.vscode/settings.json') + this.templatePath("_vscode/settings.json"), + this.destinationPath(".vscode/settings.json") ); if (!(this.options.mocha || this.options.ava)) { // copy launch.json only for default jest configuration this.fs.copy( - this.templatePath('_vscode/launch.json'), - this.destinationPath('.vscode/launch.json') + this.templatePath("_vscode/launch.json"), + this.destinationPath(".vscode/launch.json"), + { buildpath: BUILD_PATH } ); } }, rootFiles: function() { - const today = new Date(); - if (this.options.mocha) { // copy mocha files this.fs.copyTpl( - this.templatePath('_package_mocha.json'), - this.destinationPath('package.json'), - { appname: _.kebabCase(path.basename(process.cwd())) } + this.templatePath("_package_mocha.json"), + this.destinationPath("package.json"), + { + appname: _.kebabCase(path.basename(process.cwd())), + buildpath: BUILD_PATH + } ); this.fs.copy( - this.templatePath('travis_mocha.yml'), - this.destinationPath('.travis.yml') + this.templatePath("travis_mocha.yml"), + this.destinationPath(".travis.yml") ); } else if (this.options.ava) { // copy ava files this.fs.copyTpl( - this.templatePath('_package_ava.json'), - this.destinationPath('package.json'), - { appname: _.kebabCase(path.basename(process.cwd())) } + this.templatePath("_package_ava.json"), + this.destinationPath("package.json"), + { + appname: _.kebabCase(path.basename(process.cwd())), + buildpath: BUILD_PATH + } ); this.fs.copy( - this.templatePath('travis_ava.yml'), - this.destinationPath('.travis.yml') + this.templatePath("travis_ava.yml"), + this.destinationPath(".travis.yml") ); - this.fs.copy( - this.templatePath('_tsconfig.test.json'), - this.destinationPath('tsconfig.test.json') + this.fs.copyTpl( + this.templatePath("_tsconfig.test.json"), + this.destinationPath("tsconfig.test.json"), + { + buildpath: BUILD_PATH + } ); } else { // copy files for default jest configuration this.fs.copyTpl( - this.templatePath('_package.json'), - this.destinationPath('package.json'), - { appname: _.kebabCase(path.basename(process.cwd())) } + this.templatePath("_package.json"), + this.destinationPath("package.json"), + { + appname: _.kebabCase(path.basename(process.cwd())), + buildpath: BUILD_PATH + } ); this.fs.copy( - this.templatePath('travis.yml'), - this.destinationPath('.travis.yml') + this.templatePath("travis.yml"), + this.destinationPath(".travis.yml") ); } // copy files common for all configurations this.fs.copy( - this.templatePath('README.md'), - this.destinationPath('README.md') + this.templatePath("README.md"), + this.destinationPath("README.md"), + { buildpath: BUILD_PATH } + ); + this.fs.copyTpl( + this.templatePath("_tsconfig.json"), + this.destinationPath("tsconfig.json"), + { buildpath: BUILD_PATH } ); this.fs.copy( - this.templatePath('_tsconfig.json'), - this.destinationPath('tsconfig.json') + this.templatePath("_tslint.json"), + this.destinationPath("tslint.json") ); this.fs.copy( - this.templatePath('_tslint.json'), - this.destinationPath('tslint.json') + this.templatePath("editorconfig"), + this.destinationPath(".editorconfig") ); this.fs.copy( - this.templatePath('editorconfig'), - this.destinationPath('.editorconfig') + this.templatePath("dockerignore"), + this.destinationPath(".dockerignore"), + { buildpath: BUILD_PATH } ); this.fs.copy( - this.templatePath('gitignore'), - this.destinationPath('.gitignore') + this.templatePath("gitignore"), + this.destinationPath(".gitignore"), + { buildpath: BUILD_PATH } ); this.fs.copy( - this.templatePath('npmignore'), - this.destinationPath('.npmignore') + this.templatePath("npmignore"), + this.destinationPath(".npmignore"), + { buildpath: BUILD_PATH } + ); + this.fs.copyTpl( + this.templatePath("docker-compose.yml"), + this.destinationPath("docker-compose.yml"), + { appname: _.kebabCase(path.basename(process.cwd())) } + ); + this.fs.copyTpl( + this.templatePath("docker-compose.builder.yml"), + this.destinationPath("docker-compose.builder.yml"), + { appname: _.kebabCase(path.basename(process.cwd())) } ); this.fs.copyTpl( - this.templatePath('LICENSE'), - this.destinationPath('LICENSE'), - { year: today.getFullYear().toPrecision(4) } + this.templatePath("Makefile"), + this.destinationPath("Makefile"), + { appname: _.kebabCase(path.basename(process.cwd())) } ); } }, @@ -139,11 +171,11 @@ module.exports = Generator.extend({ install: { npmInstall: function() { const generator = this; - if (shelljs.which('yarn')) { + if (shelljs.which("yarn")) { generator.yarnInstall(); } else { generator.npmInstall(null, { - skipInstall: this.options['skip-install'] + skipInstall: this.options["skip-install"] }); } } diff --git a/generators/app/templates/LICENSE b/generators/app/templates/LICENSE deleted file mode 100644 index c1c9034..0000000 --- a/generators/app/templates/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) <%= year %> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/generators/app/templates/Makefile b/generators/app/templates/Makefile new file mode 100644 index 0000000..88975a9 --- /dev/null +++ b/generators/app/templates/Makefile @@ -0,0 +1,8 @@ +setup: + docker volume create <%= appname %>-nodemodules + +install: + docker-compose -f docker-compose.builder.yml run --rm install + +build-watch: + docker-compose up diff --git a/generators/app/templates/README.md b/generators/app/templates/README.md index 49c1028..7300c92 100644 --- a/generators/app/templates/README.md +++ b/generators/app/templates/README.md @@ -4,7 +4,7 @@ # Using this module in other modules -Here is a quick example of how this module can be used in other modules. The [TypeScript Module Resolution Logic](https://www.typescriptlang.org/docs/handbook/module-resolution.html) makes it quite easy. The file `src/index.ts` is a [barrel](https://basarat.gitbooks.io/typescript/content/docs/tips/barrel.html) that re-exports selected exports from other files. The _package.json_ file contains `main` attribute that points to the generated `lib/index.js` file and `typings` attribute that points to the generated `lib/index.d.ts` file. +Here is a quick example of how this module can be used in other modules. The [TypeScript Module Resolution Logic](https://www.typescriptlang.org/docs/handbook/module-resolution.html) makes it quite easy. The file `src/index.ts` is a [barrel](https://basarat.gitbooks.io/typescript/content/docs/tips/barrel.html) that re-exports selected exports from other files. The _package.json_ file contains `main` attribute that points to the generated `<%= buildpath %>/index.js` file and `typings` attribute that points to the generated `<%= buildpath %>/index.d.ts` file. > If you are planning to have code in multiple files (which is quite natural for a NodeJS module) that users can import, make sure you update `src/index.ts` file appropriately. diff --git a/generators/app/templates/_package.json b/generators/app/templates/_package.json index 41cd879..47434dd 100644 --- a/generators/app/templates/_package.json +++ b/generators/app/templates/_package.json @@ -2,7 +2,7 @@ "name": "<%= appname %>", "version": "0.0.0", "description": "<%= appname %>", - "license": "MIT", + "license": "UNLICENSED", "repository": "", "author": { "name": "", @@ -13,32 +13,34 @@ "" ], "files": [ - "lib" + "<%= buildpath %>" ], - "main": "lib/index", - "types": "lib/index", + "main": "<%= buildpath %>/index", + "types": "<%= buildpath %>/index", "scripts": { - "clean": "rimraf lib && rimraf coverage", + "clean": "rimraf <%= buildpath %> && rimraf coverage", "format": "prettier --write \"{src,__tests__}/**/*.ts\" --single-quote --trailing-comma es5", "lint": "tslint --force --format verbose \"src/**/*.ts\"", "prepublishOnly": "npm run build", + "start": "node ./<%= buildpath %>/index.js", "prebuild": "npm run clean && npm run format && npm run lint && echo Using TypeScript && tsc --version", "build": "tsc --pretty", + "build:watch": "nodemon --legacy-watch src/index.ts", "test": "jest", - "coverage": "jest --coverage", - "watch": "npm run build -- --watch", - "watch:test": "jest --watch" + "test:watch": "jest --watch", + "coverage": "jest --coverage" }, "dependencies": {}, "devDependencies": { - "@types/jest": "^23.3.3", - "@types/node": "^10.11.4", + "@types/jest": "^24.0.13", + "@types/node": "^10.14.7", "coveralls": "^3.0.2", - "jest": "^23.6.0", + "jest": "^24.8.0", + "nodemon": "^1.19.0", "prettier": "^1.14.3", "rimraf": "^2.6.2", - "ts-jest": "^23.10.3", - "ts-node": "^7.0.1", + "ts-jest": "^24.0.2", + "ts-node": "^8.1.0", "tslint": "^5.11.0", "tslint-config-prettier": "^1.15.0", "typescript": "^3.1.1" diff --git a/generators/app/templates/_package_ava.json b/generators/app/templates/_package_ava.json index 3cbb640..836f657 100644 --- a/generators/app/templates/_package_ava.json +++ b/generators/app/templates/_package_ava.json @@ -9,15 +9,15 @@ "" ], "files": [ - "lib" + "<%= buildpath %>" ], - "main": "lib/index", - "types": "lib/index", + "main": "<%= buildpath %>/index", + "types": "<%= buildpath %>/index", "scripts": { - "clean": "rimraf lib && rimraf coverage && rimraf .nyc_output && rimraf lib_test", + "clean": "rimraf <%= buildpath %> && rimraf coverage && rimraf .nyc_output && rimraf lib_test", "format": "prettier --write \"{src,test}/**/*.ts\"", "lint": "tslint --force --format verbose \"src/**/*.ts\"", - "prepublishOnly": "npm run build", + "prepublishOnly": "npm run <%= buildpath %>", "prebuild": "npm run clean && npm run format && npm run lint && echo Using TypeScript && tsc --version", "build": "tsc --pretty && tsc -p tsconfig.test.json --pretty", "test": "npm run clean && tsc -p tsconfig.test.json --pretty && nyc --exclude \"**/*-spec.js\" ava \"**/*-spec.js\" --verbose", diff --git a/generators/app/templates/_package_mocha.json b/generators/app/templates/_package_mocha.json index eb69483..51049d0 100644 --- a/generators/app/templates/_package_mocha.json +++ b/generators/app/templates/_package_mocha.json @@ -9,12 +9,12 @@ "" ], "files": [ - "lib" + "<%= buildpath %>" ], - "main": "lib/index", - "types": "lib/index", + "main": "<%= buildpath %>/index", + "types": "<%= buildpath %>/index", "scripts": { - "clean": "rimraf lib", + "clean": "rimraf <%= buildpath %>", "format": "prettier --write \"{src,test}/**/*.ts\"", "lint": "tslint --force --format verbose \"src/**/*.ts\"", "prepublishOnly": "npm run build", @@ -48,7 +48,7 @@ "src/**/*.ts" ], "exclude": [ - "lib" + "<%= buildpath %>" ], "extension": [ ".ts" diff --git a/generators/app/templates/_tsconfig.json b/generators/app/templates/_tsconfig.json index 3e55a34..02686ca 100644 --- a/generators/app/templates/_tsconfig.json +++ b/generators/app/templates/_tsconfig.json @@ -3,11 +3,9 @@ "declaration": true, "module": "commonjs", "moduleResolution": "node", - "lib": [ - "esnext" - ], + "lib": ["esnext"], "target": "es2015", - "outDir": "./lib", + "outDir": "./<%= buildpath %>", "removeComments": true, "inlineSourceMap": true, "inlineSources": true, @@ -20,11 +18,6 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true }, - "include": [ - "src/**/*" - ], - "exclude": [ - "node_modules", - "**/*-spec.ts" - ] + "include": ["src/**/*"], + "exclude": ["node_modules", "<%= buildpath %>"] } diff --git a/generators/app/templates/_tslint.json b/generators/app/templates/_tslint.json index 09b2fba..4632b84 100644 --- a/generators/app/templates/_tslint.json +++ b/generators/app/templates/_tslint.json @@ -1,6 +1,9 @@ { - "extends": [ - "tslint:latest", - "tslint-config-prettier" - ] + "extends": ["tslint:latest", "tslint-config-prettier"], + "rules": { + "no-implicit-dependencies": [true, "dev"] + }, + "linterOptions": { + "exclude": ["node_modules/**/*"] + } } diff --git a/generators/app/templates/_vscode/launch.json b/generators/app/templates/_vscode/launch.json index b5c82bb..2f3537a 100644 --- a/generators/app/templates/_vscode/launch.json +++ b/generators/app/templates/_vscode/launch.json @@ -8,13 +8,13 @@ "type": "node", "request": "launch", "name": "Debug file", - "program": "${workspaceRoot}/lib/${fileBasenameNoExtension}.js", + "program": "${workspaceRoot}/<%= buildpath %>/${fileBasenameNoExtension}.js", "cwd": "${workspaceRoot}", "sourceMaps": true, "smartStep": true, - "preLaunchTask": "build", + "preLaunchTask": "<%= buildpath %>", "outFiles": [ - "${workspaceRoot}/lib/*.js" + "${workspaceRoot}/<%= buildpath %>/*.js" ] }, { diff --git a/generators/app/templates/docker-compose.builder.yml b/generators/app/templates/docker-compose.builder.yml new file mode 100644 index 0000000..bb28496 --- /dev/null +++ b/generators/app/templates/docker-compose.builder.yml @@ -0,0 +1,29 @@ +version: "2" + +services: + + base: + image: node:10 + volumes: + - <%= appname %>-nodemodules:/usr/work/node_modules + - .:/usr/work/ + working_dir: /usr/work/ + + install: + extends: + service: base + command: npm i + + build: + extends: + service: base + command: npm run build + + start: + extends: + service: base + command: npm run start + +volumes: + <%= appname %>-nodemodules: + external: true diff --git a/generators/app/templates/docker-compose.yml b/generators/app/templates/docker-compose.yml new file mode 100644 index 0000000..dc82bc0 --- /dev/null +++ b/generators/app/templates/docker-compose.yml @@ -0,0 +1,18 @@ +version: "3.7" + +volumes: + <%= appname %>-nodemodules: + external: true + +services: + + dev: + image: node:10 + container_name: dev-<%= appname %> + volumes: + - <%= appname %>-nodemodules:/usr/work/node_modules + - .:/usr/work + environment: + - NODE_ENV=development + working_dir: /usr/work + command: npm run build:watch diff --git a/generators/app/templates/dockerignore b/generators/app/templates/dockerignore new file mode 100644 index 0000000..d0616e0 --- /dev/null +++ b/generators/app/templates/dockerignore @@ -0,0 +1,9 @@ +coverage/ +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.nyc_output +.vscode/ +<%= buildpath %> +<%= buildpath %>_test diff --git a/generators/app/templates/gitignore b/generators/app/templates/gitignore index 1ac051d..ecb3915 100644 --- a/generators/app/templates/gitignore +++ b/generators/app/templates/gitignore @@ -4,5 +4,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* .nyc_output -lib -lib_test +<%= buildpath %> +<%= buildpath %>_test diff --git a/generators/app/templates/nodemon.json b/generators/app/templates/nodemon.json new file mode 100644 index 0000000..abec6b0 --- /dev/null +++ b/generators/app/templates/nodemon.json @@ -0,0 +1,14 @@ +{ + "watch": [ + "src" + ], + "ext": "ts", + "ignore": [ + "*.test.ts", + "*.spec.ts" + ], + "delay": "3", + "execMap": { + "ts": "ts-node" + } +} diff --git a/generators/app/templates/npmignore b/generators/app/templates/npmignore index c80deb3..3c9d86b 100644 --- a/generators/app/templates/npmignore +++ b/generators/app/templates/npmignore @@ -6,11 +6,11 @@ npm-debug.log* yarn-debug.log* yarn-error.log* .nyc_output -lib -lib_test +<%= buildpath %> +<%= buildpath %>_test # npmignore src/ __tests__/ -.vscode/ \ No newline at end of file +.vscode/ diff --git a/package.json b/package.json index 9eec6a7..66e05cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "generator-node-typescript", - "version": "4.4.1", + "version": "4.5.1", "description": "A minimal Yeoman Generator for creating NodeJS modules using TypeScript", "license": "MIT", "main": "app/index.js", diff --git a/test/test-app.js b/test/test-app.js index 3ac0674..dd51edb 100644 --- a/test/test-app.js +++ b/test/test-app.js @@ -5,8 +5,8 @@ const path = require('path'); const assert = require('yeoman-assert'); const helpers = require('yeoman-test'); -describe('node-typescript:app with mocha', function() { - before(function(done) { +describe('node-typescript:app with mocha', function () { + before(function (done) { helpers .run(path.join(__dirname, '../generators/app')) .withOptions({ @@ -16,7 +16,7 @@ describe('node-typescript:app with mocha', function() { .on('end', done); }); - it('creates project files', function() { + it('creates project files', function () { assert.file([ '.vscode/tasks.json', '.vscode/settings.json', @@ -31,14 +31,16 @@ describe('node-typescript:app with mocha', function() { '.editorconfig', '.gitignore', '.npmignore', - 'LICENSE', - 'README.md' + 'README.md', + 'docker-compose.yml', + 'docker-compose.builder.yml', + 'Makefile' ]); }); }); -describe('node-typescript:app with ava', function() { - before(function(done) { +describe('node-typescript:app with ava', function () { + before(function (done) { helpers .run(path.join(__dirname, '../generators/app')) .withOptions({ @@ -48,7 +50,7 @@ describe('node-typescript:app with ava', function() { .on('end', done); }); - it('creates project files', function() { + it('creates project files', function () { assert.file([ '.vscode/tasks.json', '.vscode/settings.json', @@ -64,14 +66,16 @@ describe('node-typescript:app with ava', function() { '.editorconfig', '.gitignore', '.npmignore', - 'LICENSE', - 'README.md' + 'README.md', + 'docker-compose.yml', + 'docker-compose.builder.yml', + 'Makefile' ]); }); }); -describe('node-typescript:app with jest - default configuration', function() { - before(function(done) { +describe('node-typescript:app with jest - default configuration', function () { + before(function (done) { helpers .run(path.join(__dirname, '../generators/app')) .withOptions({ @@ -80,7 +84,7 @@ describe('node-typescript:app with jest - default configuration', function() { .on('end', done); }); - it('creates project files', function() { + it('creates project files', function () { assert.file([ '.vscode/tasks.json', '.vscode/settings.json', @@ -96,8 +100,10 @@ describe('node-typescript:app with jest - default configuration', function() { '.editorconfig', '.gitignore', '.npmignore', - 'LICENSE', - 'README.md' + 'README.md', + 'docker-compose.yml', + 'docker-compose.builder.yml', + 'Makefile' ]); }); });