diff --git a/.gitignore b/.gitignore index ad46b30..9649623 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,5 @@ typings/ # next.js build output .next + +dist/ diff --git a/bin/watch-module.js b/bin/watch-module.js index 49542ff..edda235 100755 --- a/bin/watch-module.js +++ b/bin/watch-module.js @@ -1,3 +1,3 @@ #!/usr/bin/env node -require('../src/index.js'); +require('../dist/index.js'); diff --git a/package.json b/package.json index e4c9b8e..36a62b0 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,10 @@ "bin": { "watch-module": "bin/watch-module.js" }, + "scripts": { + "build": "tsc --build tsconfig.json", + "prepublishOnly": "tsc --build tsconfig.json" + }, "repository": "https://github.com/mapado/watch-module", "license": "MIT", "dependencies": { @@ -14,5 +18,12 @@ "fs-extra": "^8.1.0", "has-yarn": "^2.1.0", "minimist": "^1.2.0" + }, + "devDependencies": { + "@types/debounce": "^1.2.0", + "@types/fs-extra": "^8.0.0", + "@types/minimist": "^1.2.0", + "@types/node": "^12.7.2", + "typescript": "^3.5.3" } } diff --git a/src/index.js b/src/index.ts similarity index 64% rename from src/index.js rename to src/index.ts index c8d3dd2..c3bda65 100644 --- a/src/index.js +++ b/src/index.ts @@ -1,17 +1,17 @@ -const { exec } = require('child_process'); -const fs = require('fs-extra'); -const debounce = require('debounce'); -const chokidar = require('chokidar'); -const minimist = require('minimist'); -const chalk = require('chalk'); -const process = require('process'); -const hasYarn = require('has-yarn'); - -const theme = { - success: '#a9dc76', - moduleName: '#ab9df2', - date: '#808080', - debug: '#ffd866', +import { exec } from 'child_process'; +import fs from 'fs-extra'; +import nodeProcess from 'process'; +import debounce from 'debounce'; +import chokidar from 'chokidar'; +import minimist from 'minimist'; +import chalk from 'chalk'; +import hasYarn from 'has-yarn'; + +enum Theme { + success = '#a9dc76', + moduleName = '#ab9df2', + date = '#808080', + debug = '#ffd866', // colors are taken from https://www.monokai.pro/ // magenta: '#ff6188', @@ -23,27 +23,27 @@ const theme = { }; /* ================== logging ================== */ -const cwd = process.cwd(); -const argv = minimist(process.argv.slice(2)); +const cwd = nodeProcess.cwd(); +const argv = minimist(nodeProcess.argv.slice(2)).filter((a: string|undefined) => a); -const logDate = () => chalk.hex(theme.date)(`[${new Date().toISOString()}]`); +const logDate = () => chalk.hex(Theme.date)(`[${new Date().toISOString()}]`); -const debug = (...args) => { +const debug = (...args: string[]) => { if (argv.v || argv.verbose) { - console.debug(logDate(), chalk.hex(theme.debug)('DEBUG'), ...args); + console.debug(logDate(), chalk.hex(Theme.debug)('DEBUG'), ...args); } } -const log = (...args) => { +const log = (...args: string[]) => { console.log(logDate(), ...args); } -const logModuleName = chalk.hex(theme.moduleName); +const logModuleName = chalk.hex(Theme.moduleName); debug('arguments: ', argv); -const moduleNameByPath = {}; -function getModuleNameForPath(path) { +const moduleNameByPath: {[key:string]: string} = {}; +function getModuleNameForPath(path: string): string { if (!moduleNameByPath[path]) { moduleNameByPath[path] = require(`${cwd}/${path}/package.json`).name; } @@ -51,7 +51,7 @@ function getModuleNameForPath(path) { return moduleNameByPath[path]; } -function getModuleCommandForPath(path) { +function getModuleCommandForPath(path: string): string { const packageJson = require(`${cwd}/${path}/package.json`); if (packageJson['watch-module'] && packageJson['watch-module']['command']) { return packageJson['watch-module']['command']; @@ -64,13 +64,13 @@ function getModuleCommandForPath(path) { } /* ================== build ================== */ -const changedModules = new Set(); -function buildAll() { +const changedModules: Set = new Set(); +function buildAll(): void { changedModules.forEach(buildPath); changedModules.clear(); } -function buildPath(path) { +function buildPath(path: string): void { const moduleName = getModuleNameForPath(path); log(logModuleName(moduleName), `Change detected`); @@ -95,7 +95,7 @@ function buildPath(path) { return fs.ensureDir(modulePath) .then(() => fs.copy(path, modulePath, { - filter: (src, dest) => { + filter: (src: string, dest: string) => { const srcAppendSlash = `${src}/`; return ( @@ -106,10 +106,7 @@ function buildPath(path) { }) ) .then(() => { - log( - logModuleName(moduleName), - chalk.hex(theme.success)('build done') - ); + log(logModuleName(moduleName), chalk.hex(Theme.success)('build done')); }) .catch(console.error); } @@ -119,13 +116,13 @@ function buildPath(path) { /* ================== debounce & events ================== */ const debouncedOnChangeAll = debounce(buildAll, 200); -function onChange(modulePath) { +function onChange(modulePath: string): void { changedModules.add(modulePath); debouncedOnChangeAll(); } /* ================== main ================== */ -function main() { +function main(): void { const modulePaths = argv._; if (modulePaths.length === 0) { @@ -133,13 +130,13 @@ function main() { return; } - const srcPaths = modulePaths.map(path => `${path}/src`); + const srcPaths = modulePaths.map((path: string) => `${path}/src`); // One-liner for current directory, ignores .dotfiles chokidar .watch(srcPaths, { ignored: /(^|[\/\\])\.[^\.\/]/ }) - .on('all', (event, path) => { - const modulePath = modulePaths.find(tmpPath => path.startsWith(`${tmpPath}/`)); + .on('all', (event: any, path: string) => { + const modulePath = modulePaths.find((tmpPath: string) => path.startsWith(`${tmpPath}/`)); onChange(modulePath); }); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1fa828b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "sourceMap": true, + "strict": true, + "moduleResolution": "node", + "module": "commonjs", + "esModuleInterop": true, + "target": "es5", + "allowJs": true + + }, + "include": [ + "./src/" + ] +} diff --git a/yarn.lock b/yarn.lock index 3fa8651..adadde8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,28 @@ # yarn lockfile v1 +"@types/debounce@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/debounce/-/debounce-1.2.0.tgz#9ee99259f41018c640b3929e1bb32c3dcecdb192" + integrity sha512-bWG5wapaWgbss9E238T0R6bfo5Fh3OkeoSt245CM7JJwVwpw6MEBCbIxLq5z8KzsE3uJhzcIuQkyiZmzV3M/Dw== + +"@types/fs-extra@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.0.tgz#d3e2c313ca29f95059f198dd60d1f774642d4b25" + integrity sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q== + dependencies: + "@types/node" "*" + +"@types/minimist@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" + integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= + +"@types/node@*", "@types/node@^12.7.2": + version "12.7.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" + integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg== + ansi-styles@^3.2.1: version "3.2.1" resolved "http://npm.mapado.net:4873/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -191,6 +213,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +typescript@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"