diff --git a/.gitignore b/.gitignore index 556d043..6c59b09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.log node_modules -lib -es6 +/dist dev coverage diff --git a/package-lock.json b/package-lock.json index 54bfa98..3052e3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "io-ts-types", - "version": "0.5.7", + "version": "0.5.8", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -588,9 +588,9 @@ "dev": true }, "@types/node": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.4.tgz", - "integrity": "sha1-mqvBNZed7TgzJXSfUIiUxmKUjIs=", + "version": "14.0.27", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz", + "integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g==", "dev": true }, "@types/stack-utils": { @@ -2004,9 +2004,9 @@ } }, "fp-ts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.0.0.tgz", - "integrity": "sha512-oz8L+EZiztqGVLhgdL+63b4hpfdJkEKH/4vRoS/AuUwYqmn7vHAzWMu1jtoYfB0pPxo5UioWVT2XOuftyivUSQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-2.8.1.tgz", + "integrity": "sha512-HuA/6roEliHoBgEOLCKmGRcM90e2trW/ITZZ9d9P/ra7PreqQagC3Jg6OzqWkai13KUbG90b8QO9rHPBGK/ckw==", "dev": true }, "fragment-cache": { @@ -2882,7 +2882,7 @@ } }, "import-path-rewrite": { - "version": "github:gcanti/import-path-rewrite#0086599732ccc761a33255a702a07266895d0572", + "version": "github:gcanti/import-path-rewrite#39b4178f9ff80aed3fa18a702584e0d0f0d6d8bc", "from": "github:gcanti/import-path-rewrite", "dev": true, "requires": { diff --git a/package.json b/package.json index d2dea5d..4238a2c 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,6 @@ "name": "io-ts-types", "version": "0.5.8", "description": "A collection of codecs and combinators for use with io-ts", - "files": [ - "lib", - "es6" - ], "main": "lib/index.js", "module": "es6/index.js", "typings": "lib/index.d.ts", @@ -16,13 +12,17 @@ "fix-prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,test}/**/*.ts\"", "jest": "jest --ci", "test": "npm run build && npm run lint && npm run dtslint && npm run prettier && npm run jest && npm run docs", - "clean": "rm -rf lib/* es6/*", - "build": "npm run clean && tsc && tsc -p ./tsconfig.es6.json", - "prepublish": "npm run build", + "clean": "rm -rf ./dist", + "prebuild": "npm run clean", + "build": "tsc -p ./tsconfig.build.json && tsc -p ./tsconfig.build-es6.json && npm run import-path-rewrite && ts-node scripts/build", + "postbuild": "prettier --loglevel=silent --write \"./dist/**/*.ts\"", + "prepublishOnly": "ts-node scripts/pre-publish", "dtslint": "dtslint dtslint", "mocha": "mocha -r ts-node/register test/*.ts", "docs": "docs-ts", - "postbuild": "import-path-rewrite" + "prerelease": "npm run build", + "release": "ts-node scripts/release", + "import-path-rewrite": "import-path-rewrite" }, "repository": { "type": "git", @@ -42,11 +42,10 @@ }, "devDependencies": { "@types/jest": "^24.0.15", - "@types/node": "7.0.4", + "@types/node": "^14.0.27", "docs-ts": "^0.3.4", "dtslint": "github:gcanti/dtslint", - "fp-ts": "^2.0.0", - "import-path-rewrite": "github:gcanti/import-path-rewrite", + "fp-ts": "^2.8.0", "io-ts": "^2.0.0", "jest": "^24.8.0", "mocha": "^5.2.0", @@ -57,7 +56,8 @@ "ts-node": "3.2.1", "tslint": "^5.12.1", "tslint-config-standard": "^8.0.1", - "typescript": "^3.9.3" + "typescript": "^3.9.3", + "import-path-rewrite": "github:gcanti/import-path-rewrite" }, "tags": [ "io-ts", diff --git a/scripts/FileSystem.ts b/scripts/FileSystem.ts new file mode 100644 index 0000000..9e2c2c4 --- /dev/null +++ b/scripts/FileSystem.ts @@ -0,0 +1,29 @@ +import * as TE from 'fp-ts/TaskEither' +import { flow } from 'fp-ts/function' +import * as fs from 'fs' +import G from 'glob' + +export interface FileSystem { + readonly readFile: (path: string) => TE.TaskEither + readonly writeFile: (path: string, content: string) => TE.TaskEither + readonly copyFile: (from: string, to: string) => TE.TaskEither + readonly glob: (pattern: string) => TE.TaskEither> + readonly mkdir: (path: string) => TE.TaskEither +} + +const readFile = TE.taskify(fs.readFile) +const writeFile = TE.taskify(fs.writeFile) +const copyFile = TE.taskify(fs.copyFile) +const glob = TE.taskify>(G) +const mkdirTE = TE.taskify(fs.mkdir) + +export const fileSystem: FileSystem = { + readFile: (path) => readFile(path, 'utf8'), + writeFile, + copyFile, + glob, + mkdir: flow( + mkdirTE, + TE.map(() => undefined) + ) +} diff --git a/scripts/build.ts b/scripts/build.ts new file mode 100644 index 0000000..ba6ec6f --- /dev/null +++ b/scripts/build.ts @@ -0,0 +1,88 @@ +import * as path from 'path' +import * as E from 'fp-ts/Either' +import { pipe } from 'fp-ts/function' +import * as RTE from 'fp-ts/ReaderTaskEither' +import * as A from 'fp-ts/ReadonlyArray' +import * as TE from 'fp-ts/TaskEither' +import { FileSystem, fileSystem } from './FileSystem' +import { run } from './run' + +interface Build extends RTE.ReaderTaskEither {} + +const OUTPUT_FOLDER = 'dist' +const PKG = 'package.json' + +export const copyPackageJson: Build = (C) => + pipe( + C.readFile(PKG), + TE.chain((s) => TE.fromEither(E.parseJSON(s, E.toError))), + TE.map((v) => { + const clone = Object.assign({}, v as any) + + delete clone.scripts + delete clone.files + delete clone.devDependencies + + return clone + }), + TE.chain((json) => C.writeFile(path.join(OUTPUT_FOLDER, PKG), JSON.stringify(json, null, 2))) + ) + +export const FILES: ReadonlyArray = ['CHANGELOG.md', 'LICENSE', 'README.md'] + +export const copyFiles: Build> = (C) => + pipe( + FILES, + A.traverse(TE.taskEither)((from) => C.copyFile(from, path.resolve(OUTPUT_FOLDER, from))) + ) + +const traverse = A.traverse(TE.taskEither) + +export const makeModules: Build = (C) => + pipe( + C.glob(`${OUTPUT_FOLDER}/lib/*.js`), + TE.map(getModules), + TE.chain(traverse(makeSingleModule(C))), + TE.map(() => undefined) + ) + +function getModules(paths: ReadonlyArray): ReadonlyArray { + return paths.map((filePath) => path.basename(filePath, '.js')).filter((x) => x !== 'index') +} + +function makeSingleModule(C: FileSystem): (module: string) => TE.TaskEither { + return (m) => + pipe( + C.mkdir(path.join(OUTPUT_FOLDER, m)), + TE.chain(() => makePkgJson(m)), + TE.chain((data) => C.writeFile(path.join(OUTPUT_FOLDER, m, 'package.json'), data)) + ) +} + +function makePkgJson(module: string): TE.TaskEither { + return pipe( + JSON.stringify( + { + main: `../lib/${module}.js`, + module: `../es6/${module}.js`, + typings: `../lib/${module}.d.ts`, + sideEffects: false + }, + null, + 2 + ), + TE.right + ) +} + +const main: Build = pipe( + copyPackageJson, + RTE.chain(() => copyFiles), + RTE.chain(() => makeModules) +) + +run( + main({ + ...fileSystem + }) +) diff --git a/scripts/pre-publish.ts b/scripts/pre-publish.ts new file mode 100644 index 0000000..c326efd --- /dev/null +++ b/scripts/pre-publish.ts @@ -0,0 +1,7 @@ +import { left } from 'fp-ts/TaskEither' +import { run } from './run' + +const main = left(new Error('"npm publish" can not be run from root, run "npm run release" instead')) + +run(main) + diff --git a/scripts/release.ts b/scripts/release.ts new file mode 100644 index 0000000..750f3ed --- /dev/null +++ b/scripts/release.ts @@ -0,0 +1,23 @@ +import { run } from './run' +import * as child_process from 'child_process' +import { left, right } from 'fp-ts/Either' +import * as TE from 'fp-ts/TaskEither' + +const DIST = 'dist' + +const exec = (cmd: string, args?: child_process.ExecOptions): TE.TaskEither => () => + new Promise((resolve) => { + child_process.exec(cmd, args, (err) => { + if (err !== null) { + return resolve(left(err)) + } + + return resolve(right(undefined)) + }) + }) + +export const main = exec('npm publish', { + cwd: DIST +}) + +run(main) diff --git a/scripts/run.ts b/scripts/run.ts new file mode 100644 index 0000000..7629fe1 --- /dev/null +++ b/scripts/run.ts @@ -0,0 +1,21 @@ +import { fold } from 'fp-ts/Either' +import { TaskEither } from 'fp-ts/TaskEither' + +export function run(eff: TaskEither): void { + eff() + .then( + fold( + (e) => { + throw e + }, + (_) => { + process.exitCode = 0 + } + ) + ) + .catch((e) => { + console.error(e) // tslint:disable-line no-console + + process.exitCode = 1 + }) +} diff --git a/tsconfig.build-es6.json b/tsconfig.build-es6.json new file mode 100644 index 0000000..6b5e341 --- /dev/null +++ b/tsconfig.build-es6.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "outDir": "./dist/es6", + "module": "es6" + } +} diff --git a/tsconfig.es6.json b/tsconfig.build.json similarity index 55% rename from tsconfig.es6.json rename to tsconfig.build.json index fa53d00..9d833c2 100644 --- a/tsconfig.es6.json +++ b/tsconfig.build.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "./es6", - "module": "es6" - } + "noEmit": false + }, + "include": ["./src"] } diff --git a/tsconfig.json b/tsconfig.json index 293eb10..9c43f0d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,8 @@ { "compilerOptions": { - "outDir": "./lib", + "outDir": "./dist/lib", + "noEmit": true, + "esModuleInterop": true, "sourceMap": false, "declaration": true, "module": "commonjs",