From 0fb9e84990f4c63a7271204fb715321a2aee8c3f Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 19:20:03 -0500 Subject: [PATCH 01/16] adding license file and removing image from published --- .npmignore | 1 + LICENSE | 8 ++++++++ README.md | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 LICENSE diff --git a/.npmignore b/.npmignore index 3874581..a7c754d 100644 --- a/.npmignore +++ b/.npmignore @@ -7,6 +7,7 @@ testables/ .npmignore .travis.yml +chest-temp.png mocha.opts tsconfig.json tslint.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9fc972a --- /dev/null +++ b/LICENSE @@ -0,0 +1,8 @@ +# License +© 2017 NativeCode Development + +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/README.md b/README.md index afd9d74..78b31e9 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ # @beard/chest

- +

# WTF From 065a4237d2b58859483cf793f61765ed496fbb0c Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 19:27:38 -0500 Subject: [PATCH 02/16] fixing test --- package.json | 2 +- src/Chest.spec.ts | 8 ++++---- src/Core/Actions/Packages.ts | 6 +++--- src/Core/Actions/Typings.ts | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 019af49..63a868a 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-3", + "version": "2.0.0-alpha-4", "dependencies": { "chalk": "^2.3.0" }, diff --git a/src/Chest.spec.ts b/src/Chest.spec.ts index 150ad6f..d9545c8 100644 --- a/src/Chest.spec.ts +++ b/src/Chest.spec.ts @@ -45,14 +45,14 @@ describe('when using RootProject to load a project', () => { Chest.project(directory).then(project => Chest.projects(project).should.eventually.throw()) }) - it('should run scripts for single project', () => { + it('should run scripts for single project', (done) => { const directory = Files.join(process.cwd(), 'testables', 'single') - Chest.run(directory, ...Object.keys(Registry.all())) + Chest.run(directory, ...Object.keys(Registry.all())).then(() => done()) }) - it('should run scripts for workspace project', () => { + it('should run scripts for workspace project', (done) => { const directory = Files.join(process.cwd(), 'testables', 'workspaces') - Chest.run(directory, ...Object.keys(Registry.all())) + Chest.run(directory, ...Object.keys(Registry.all())).then(() => done()) }) }) diff --git a/src/Core/Actions/Packages.ts b/src/Core/Actions/Packages.ts index 3e47a53..84173ce 100644 --- a/src/Core/Actions/Packages.ts +++ b/src/Core/Actions/Packages.ts @@ -24,8 +24,8 @@ class Script extends UpdateScript { } public async workspace(project: Project): Promise { - const source = await project.package - const target = await project.owner.package + const source = await project.owner.package + const target = await project.package target.author = source.author target.bugs = source.bugs @@ -37,7 +37,7 @@ class Script extends UpdateScript { const filename = path.join(project.path, 'package.json') if (this.testing) { - this.log.task('updated package info', filename, target) + this.log.task('updated package info', filename, JSON.stringify(target, null, 2)) } else { await Files.save(filename, target) this.log.task('updated package info', filename) diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index 0b566fb..ddaeb8d 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -36,7 +36,7 @@ class Script extends UpdateScript { tsconfig.compilerOptions.types = typings.map(typing => typing.npmname).sort() if (this.testing) { - this.log.task('updated types', tsconfigfile, tsconfig) + this.log.task('updated types', tsconfigfile, JSON.stringify(tsconfig, null, 2)) } else { await Files.save(tsconfigfile, tsconfig) this.log.task('updated types', tsconfigfile) From 28ab1f92a2d4a45aeafe906f2e0acb292fa32db8 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 21:06:13 -0500 Subject: [PATCH 03/16] adding tests --- .gitignore | 1 + .npmignore | 1 + package.json | 2 +- src/Chest.spec.ts | 12 ++++++---- src/Chest.ts | 7 ++++-- src/Core/Files.spec.ts | 27 +++++++++++++++++++++ src/Core/Files.ts | 13 ++++++++++ src/Core/Project.ts | 2 ++ src/Core/Registry.spec.ts | 50 +++++++++++++++++++++++++++++++++++++++ src/Core/Registry.ts | 9 +++++++ 10 files changed, 116 insertions(+), 8 deletions(-) create mode 100644 src/Core/Files.spec.ts create mode 100644 src/Core/Registry.spec.ts diff --git a/.gitignore b/.gitignore index 7ff4843..5631318 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .nyc_output/ +artifacts/ lib/ node_modules/ diff --git a/.npmignore b/.npmignore index a7c754d..1335f3d 100644 --- a/.npmignore +++ b/.npmignore @@ -1,4 +1,5 @@ .nyc_output/ +artifacts/ node_modules/ src/ testables/ diff --git a/package.json b/package.json index 63a868a..caf6ac5 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "scripts": { "build": "tsc --project tsconfig.json", "lint": "tslint src/**/*.ts", - "prebuild": "rimraf lib", + "prebuild": "rimraf lib && rimraf artifacts", "postbuild": "bin-shebang && yarn run lint", "test": "cross-env NODE_ENV=test nyc mocha --opts mocha.opts", "pretest": "yarn run build", diff --git a/src/Chest.spec.ts b/src/Chest.spec.ts index d9545c8..0583953 100644 --- a/src/Chest.spec.ts +++ b/src/Chest.spec.ts @@ -4,7 +4,7 @@ import * as chai from 'chai' import * as chaiAsPromised from 'chai-as-promised' import { Chest } from './Chest' -import { Files, Registry } from './Core' +import { Files, Project, Registry } from './Core' const expect = chai.expect @@ -35,9 +35,9 @@ describe('when using RootProject to load a project', () => { expect(projects[0].owner).to.not.equal(undefined) }) - it('should throw error when single project does not exist', async () => { + it('should return static InvalidProject when single project does not exist', async () => { const directory = Files.join(process.cwd(), 'testables', 'nonexistant') - Chest.project(directory).then(project => Chest.projects(project).should.eventually.throw()) + Chest.project(directory).then(project => Chest.projects(project).should.eventually.equal(Project.InvalidProject)) }) it('should throw error when workspace project has no child projects', async () => { @@ -47,12 +47,14 @@ describe('when using RootProject to load a project', () => { it('should run scripts for single project', (done) => { const directory = Files.join(process.cwd(), 'testables', 'single') - Chest.run(directory, ...Object.keys(Registry.all())).then(() => done()) + const args = Object.keys(Registry.all()) + Chest.run(directory, ...args).then(() => done()) }) it('should run scripts for workspace project', (done) => { const directory = Files.join(process.cwd(), 'testables', 'workspaces') - Chest.run(directory, ...Object.keys(Registry.all())).then(() => done()) + const args = Object.keys(Registry.all()) + Chest.run(directory, ...args).then(() => done()) }) }) diff --git a/src/Chest.ts b/src/Chest.ts index cece83b..bb8de3d 100644 --- a/src/Chest.ts +++ b/src/Chest.ts @@ -1,8 +1,10 @@ import * as path from 'path' -import { Files, NPM, Project, Registry, UpdaterType } from './Core' +import { Files, Log, Logger, NPM, Project, Registry, UpdaterType } from './Core' export class Chest { + private static readonly Log: Log = Logger('chest') + public static async run(root: string, ...args: string[]): Promise { const project = await Chest.project(root) const projects = await Chest.projects(project) @@ -23,7 +25,8 @@ export class Chest { const npmfile = path.join(root, 'package.json') if (await Files.exists(npmfile) === false) { - throw new Error(`failed to find ${npmfile} in ${root}`) + Chest.Log.error(new Error(`failed to find ${npmfile} in ${root}`)) + return Project.InvalidProject } const npm = await Files.json(npmfile) diff --git a/src/Core/Files.spec.ts b/src/Core/Files.spec.ts new file mode 100644 index 0000000..e652c53 --- /dev/null +++ b/src/Core/Files.spec.ts @@ -0,0 +1,27 @@ +import 'mocha' + +import * as chai from 'chai' +import * as chaiAsPromise from 'chai-as-promised' + +import { Files } from './Files' + +const expect = chai.expect + +describe('', () => { + + before(async () => { + const artifacts = Files.join(process.cwd(), 'artifacts') + await Files.mkdir(artifacts) + }) + + beforeEach(() => { + chai.should() + chai.use(chaiAsPromise) + }) + + it('should write file', () => { + const filename = Files.join(process.cwd(), 'artifacts', 'test.json') + Files.writefile(filename, {}).should.eventually.not.throw() + }) + +}) diff --git a/src/Core/Files.ts b/src/Core/Files.ts index cce268c..dcc43d3 100644 --- a/src/Core/Files.ts +++ b/src/Core/Files.ts @@ -55,6 +55,18 @@ class InternalFiles { return stats.filter(stat => stat.file).map(stat => stat.filename) } + public mkdir(filepath: string): Promise { + return new Promise(async (resolve, reject) => { + fs.mkdir(filepath, (error: NodeJS.ErrnoException) => { + if (error) { + reject(error) + } else { + resolve() + } + }) + }) + } + public async save(filepath: string, data: T): Promise { await this.writefile(filepath, JSON.stringify(data, null, 2)) } @@ -116,6 +128,7 @@ export interface Files { readfile(filepath: string): Promise listdirs(filepath: string): Promise listfiles(filepath: string): Promise + mkdir(filepath: string): Promise save(filepath: string, data: T): Promise statfile(filepath: string): Promise statfiles(filepath: string): Promise diff --git a/src/Core/Project.ts b/src/Core/Project.ts index 32b0137..5d0a521 100644 --- a/src/Core/Project.ts +++ b/src/Core/Project.ts @@ -2,6 +2,8 @@ import { Files } from './Files' import { NPM } from './Interfaces' export class Project { + public static InvalidProject: Project = new Project('invalid', 'invalid') + private readonly _name: string private readonly _owner: Project private readonly _path: string diff --git a/src/Core/Registry.spec.ts b/src/Core/Registry.spec.ts new file mode 100644 index 0000000..b6bd4ad --- /dev/null +++ b/src/Core/Registry.spec.ts @@ -0,0 +1,50 @@ +import 'mocha' + +import * as chai from 'chai' +import * as chaiAsPromised from 'chai-as-promised' + +import { Files } from './Files' +import { UpdaterType } from './Interfaces' +import { Registry } from './Registry' +import { UpdateScript } from './UpdateScript' + +const expect = chai.expect +const ScriptName = Files.extensionless(__filename) +const RootScriptName = `${ScriptName}-root` +const ProjectsScriptName = `${ScriptName}-projects` + +class DoesNothingGoesNowhereRoot extends UpdateScript { + constructor() { + super(RootScriptName, UpdaterType.Root) + } +} + +class DoesNothingGoesNowhereProjects extends UpdateScript { + constructor() { + super(ProjectsScriptName, UpdaterType.Projects) + } +} + +describe('', () => { + + beforeEach(() => { + chai.should() + chai.use(chaiAsPromised) + }) + + it('should return registered script names', () => { + expect(Registry.names().length).to.be.gt(0) + }) + + it('should register new script object', () => { + expect(Registry.contains(RootScriptName)).to.equal(false) + Registry.add(RootScriptName, new DoesNothingGoesNowhereRoot()) + expect(Registry.contains(RootScriptName)).to.equal(true) + expect(Registry.get(RootScriptName).name).to.equal(RootScriptName) + }) + + it('should throw error when calling "get" and script does not exist', () => { + expect(() => Registry.get('invalid')).to.throw(Error) + }) + +}) diff --git a/src/Core/Registry.ts b/src/Core/Registry.ts index a4606c6..cf4fcf3 100644 --- a/src/Core/Registry.ts +++ b/src/Core/Registry.ts @@ -11,6 +11,10 @@ export class Registry { return Object.assign({}, this.registrations) } + public static contains(name: string): boolean { + return this.registrations[name.toLowerCase()] !== undefined + } + public static execute(root: string, ...args: string[]): Promise { return Promise.all( args.map(arg => arg.toLowerCase()) @@ -20,10 +24,15 @@ export class Registry { public static get(name: string): Updater { const key = name.toLowerCase() + if (this.registrations[key]) { return this.registrations[key] } throw new Error(`no registered updaters named ${name}`) } + + public static names(): string[] { + return Object.keys(this.registrations) + } } From 51b1f6ace44cee5e9999dacc31a6c85fb48f7816 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 22:37:16 -0500 Subject: [PATCH 04/16] fixing async tests --- src/Chest.spec.ts | 21 ++++++++++++--------- src/Chest.ts | 14 +++++++++----- src/Core/Actions/Typings.ts | 6 +++++- src/Core/Files.spec.ts | 4 ++-- src/Core/Registry.spec.ts | 14 +++----------- src/Core/UpdateScript.ts | 3 +++ testables/workspaces-invalid/package.json | 1 + 7 files changed, 35 insertions(+), 28 deletions(-) diff --git a/src/Chest.spec.ts b/src/Chest.spec.ts index 0583953..9444af7 100644 --- a/src/Chest.spec.ts +++ b/src/Chest.spec.ts @@ -35,26 +35,29 @@ describe('when using RootProject to load a project', () => { expect(projects[0].owner).to.not.equal(undefined) }) - it('should return static InvalidProject when single project does not exist', async () => { + it('should return static InvalidProject when single project does not exist', () => { const directory = Files.join(process.cwd(), 'testables', 'nonexistant') - Chest.project(directory).then(project => Chest.projects(project).should.eventually.equal(Project.InvalidProject)) + + return Chest.project(directory).then(project => expect(project).to.equal(Project.InvalidProject)) }) - it('should throw error when workspace project has no child projects', async () => { + it('should throw error when workspace project has no child projects', () => { const directory = Files.join(process.cwd(), 'testables', 'workspaces-invalid') - Chest.project(directory).then(project => Chest.projects(project).should.eventually.throw()) + return Chest.project(directory).then(async project => { + const projects = await Chest.projects(project) + expect(projects).to.deep.equal([Project.InvalidProject]) + }) }) - it('should run scripts for single project', (done) => { + it('should run scripts for single project', () => { const directory = Files.join(process.cwd(), 'testables', 'single') const args = Object.keys(Registry.all()) - Chest.run(directory, ...args).then(() => done()) + return Chest.run(directory, ...args) }) - it('should run scripts for workspace project', (done) => { + it('should run scripts for workspace project', () => { const directory = Files.join(process.cwd(), 'testables', 'workspaces') const args = Object.keys(Registry.all()) - Chest.run(directory, ...args).then(() => done()) + return Chest.run(directory, ...args) }) - }) diff --git a/src/Chest.ts b/src/Chest.ts index bb8de3d..9ab572e 100644 --- a/src/Chest.ts +++ b/src/Chest.ts @@ -25,7 +25,7 @@ export class Chest { const npmfile = path.join(root, 'package.json') if (await Files.exists(npmfile) === false) { - Chest.Log.error(new Error(`failed to find ${npmfile} in ${root}`)) + Chest.Log.error(new Error(`failed to find ${npmfile} in [${root}]`)) return Project.InvalidProject } @@ -36,6 +36,7 @@ export class Chest { public static async projects(owner: Project): Promise { const project = await Chest.project(owner.path) const npm = await project.package + this.Log.debug('project', project.name) if (npm.private && npm.workspace) { return npm.workspace.map(workspaceRoot => Chest.workspaces(project, workspaceRoot)) @@ -49,15 +50,18 @@ export class Chest { workspaceRoot = Files.join(owner.path, workspaceRoot.substring(0, workspaceRoot.indexOf('/*'))) if (await Files.exists(workspaceRoot) === false) { - throw new Error(`failed to find workspace ${workspaceRoot} in ${owner.name}`) + Chest.Log.error(new Error(`[workspace] failed to find ${workspaceRoot} in [${owner.name}]`)) + return [Project.InvalidProject] } const projects = await Files.listdirs(workspaceRoot) - return Promise.all(projects.map(async project => { - const npmfile = path.join(project, 'package.json') + return Promise.all(projects.map(async projectPath => { + const npmfile = path.join(projectPath, 'package.json') const npm = await Files.json(npmfile) - return new Project(npm.name, project, owner) + const project = new Project(npm.name, projectPath, owner) + this.Log.debug('project.workspace', owner.name, '->', project.name) + return project })) } } diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index ddaeb8d..cd29ea3 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -30,7 +30,11 @@ class Script extends UpdateScript { const packagedirs = await Files.listdirs(packagedir) const tsconfig = await Files.json(tsconfigfile) - const dependencies = await Promise.all(packagedirs.map(async packagedir => await this.map(packagedir))) + const dependencies = await Promise.all(packagedirs.map(packagedir => { + this.log.debug('dependency', packagedir) + return this.map(packagedir) + })) + const typings = dependencies.reduce((previous, current) => previous.concat(current.filter(c => !!c.typings)), []) tsconfig.compilerOptions.types = typings.map(typing => typing.npmname).sort() diff --git a/src/Core/Files.spec.ts b/src/Core/Files.spec.ts index e652c53..259227c 100644 --- a/src/Core/Files.spec.ts +++ b/src/Core/Files.spec.ts @@ -7,7 +7,7 @@ import { Files } from './Files' const expect = chai.expect -describe('', () => { +describe('when working with files', () => { before(async () => { const artifacts = Files.join(process.cwd(), 'artifacts') @@ -21,7 +21,7 @@ describe('', () => { it('should write file', () => { const filename = Files.join(process.cwd(), 'artifacts', 'test.json') - Files.writefile(filename, {}).should.eventually.not.throw() + return Files.writefile(filename, {}) }) }) diff --git a/src/Core/Registry.spec.ts b/src/Core/Registry.spec.ts index b6bd4ad..ff4cc79 100644 --- a/src/Core/Registry.spec.ts +++ b/src/Core/Registry.spec.ts @@ -1,14 +1,12 @@ import 'mocha' -import * as chai from 'chai' -import * as chaiAsPromised from 'chai-as-promised' +import { expect } from 'chai' import { Files } from './Files' import { UpdaterType } from './Interfaces' import { Registry } from './Registry' import { UpdateScript } from './UpdateScript' -const expect = chai.expect const ScriptName = Files.extensionless(__filename) const RootScriptName = `${ScriptName}-root` const ProjectsScriptName = `${ScriptName}-projects` @@ -25,12 +23,7 @@ class DoesNothingGoesNowhereProjects extends UpdateScript { } } -describe('', () => { - - beforeEach(() => { - chai.should() - chai.use(chaiAsPromised) - }) +describe('when using the script registry', () => { it('should return registered script names', () => { expect(Registry.names().length).to.be.gt(0) @@ -44,7 +37,6 @@ describe('', () => { }) it('should throw error when calling "get" and script does not exist', () => { - expect(() => Registry.get('invalid')).to.throw(Error) + expect(() => Registry.get('invalid')).to.throw() }) - }) diff --git a/src/Core/UpdateScript.ts b/src/Core/UpdateScript.ts index 46d8150..d5b53cf 100644 --- a/src/Core/UpdateScript.ts +++ b/src/Core/UpdateScript.ts @@ -48,11 +48,14 @@ export abstract class UpdateScript implements Updater { protected run(project: Project, command: string, ...args: string[]): Promise { return new Promise((resolve, reject) => { this.log.debug('run', project.name, command, ...args) + const child = cp.exec(`${command} ${args.join(' ')}`, { cwd: project.path }, error => { if (error) this.log.error(error) }) + child.stderr.on('data', data => this.args(project, process.stderr, data).map(lines => lines).forEach(args => this.log.error(...args))) child.stdout.on('data', data => this.args(project, process.stdout, data).map(lines => lines).forEach(args => this.log.task(...args))) + child.addListener('exit', (code: number, signal: string) => { if (code === 0) { resolve() diff --git a/testables/workspaces-invalid/package.json b/testables/workspaces-invalid/package.json index 9d1a800..097624d 100644 --- a/testables/workspaces-invalid/package.json +++ b/testables/workspaces-invalid/package.json @@ -7,6 +7,7 @@ "@types/chalk": "*" }, "name": "project-single", + "private": true, "version": "1.0.0", "workspace": [ "packages/*" From 6fb1e3ce07ea0683e5924c61956ae3329fdab774 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 22:47:52 -0500 Subject: [PATCH 05/16] fixing output and adding tsconfig --- src/Core/Actions/Typings.ts | 9 +++++---- testables/single/tsconfig.json | 3 +++ testables/workspaces-invalid/tsconfig.json | 3 +++ .../workspaces/packages/simple-package/tsconfig.json | 3 +++ .../workspaces/projects/simple-project/tsconfig.json | 3 +++ testables/workspaces/tsconfig.json | 3 +++ 6 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 testables/single/tsconfig.json create mode 100644 testables/workspaces-invalid/tsconfig.json create mode 100644 testables/workspaces/packages/simple-package/tsconfig.json create mode 100644 testables/workspaces/projects/simple-project/tsconfig.json create mode 100644 testables/workspaces/tsconfig.json diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index cd29ea3..f9cb509 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -25,14 +25,15 @@ class Script extends UpdateScript { public async exec(rootpath: string): Promise { const tsconfigfile = path.join(rootpath, 'tsconfig.json') const packagedir = path.join(rootpath, 'node_modules') + this.log.debug('exec', this.name, rootpath, packagedir) if (await Files.exists(tsconfigfile) && await Files.exists(packagedir)) { const packagedirs = await Files.listdirs(packagedir) const tsconfig = await Files.json(tsconfigfile) const dependencies = await Promise.all(packagedirs.map(packagedir => { - this.log.debug('dependency', packagedir) - return this.map(packagedir) + this.log.debug('dependencies', packagedir) + return this.dependencies(packagedir) })) const typings = dependencies.reduce((previous, current) => previous.concat(current.filter(c => !!c.typings)), []) @@ -48,13 +49,13 @@ class Script extends UpdateScript { } } - private async map(packagedir: string): Promise { + private async dependencies(packagedir: string): Promise { const dirname = path.basename(packagedir) if (dirname[0] === '@') { const scopedirs = await Files.listdirs(packagedir) - return await Promise.all(scopedirs + return Promise.all(scopedirs .map(scope => [scope, path.join(scope, 'package.json')]) .map(async ([scope, scopepath]): Promise => { const npm = await Files.json(path.join(scope, 'package.json')) diff --git a/testables/single/tsconfig.json b/testables/single/tsconfig.json new file mode 100644 index 0000000..875cb60 --- /dev/null +++ b/testables/single/tsconfig.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": {} +} diff --git a/testables/workspaces-invalid/tsconfig.json b/testables/workspaces-invalid/tsconfig.json new file mode 100644 index 0000000..875cb60 --- /dev/null +++ b/testables/workspaces-invalid/tsconfig.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": {} +} diff --git a/testables/workspaces/packages/simple-package/tsconfig.json b/testables/workspaces/packages/simple-package/tsconfig.json new file mode 100644 index 0000000..875cb60 --- /dev/null +++ b/testables/workspaces/packages/simple-package/tsconfig.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": {} +} diff --git a/testables/workspaces/projects/simple-project/tsconfig.json b/testables/workspaces/projects/simple-project/tsconfig.json new file mode 100644 index 0000000..875cb60 --- /dev/null +++ b/testables/workspaces/projects/simple-project/tsconfig.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": {} +} diff --git a/testables/workspaces/tsconfig.json b/testables/workspaces/tsconfig.json new file mode 100644 index 0000000..875cb60 --- /dev/null +++ b/testables/workspaces/tsconfig.json @@ -0,0 +1,3 @@ +{ + "compilerOptions": {} +} From b0df3f508d6dbd96bae88acf588de028a24cb168 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 22:52:17 -0500 Subject: [PATCH 06/16] 2.0.0-alpha-5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index caf6ac5..2c70cc1 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-4", + "version": "2.0.0-alpha-5", "dependencies": { "chalk": "^2.3.0" }, From 47b9e81ca91db14fd960564a2a4cb068c4428438 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 22:59:27 -0500 Subject: [PATCH 07/16] fixing test --- src/Chest.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Chest.spec.ts b/src/Chest.spec.ts index d9381da..9444af7 100644 --- a/src/Chest.spec.ts +++ b/src/Chest.spec.ts @@ -49,13 +49,13 @@ describe('when using RootProject to load a project', () => { }) }) - it('should run scripts for single project', (done) => { + it('should run scripts for single project', () => { const directory = Files.join(process.cwd(), 'testables', 'single') const args = Object.keys(Registry.all()) return Chest.run(directory, ...args) }) - it('should run scripts for workspace project', (done) => { + it('should run scripts for workspace project', () => { const directory = Files.join(process.cwd(), 'testables', 'workspaces') const args = Object.keys(Registry.all()) return Chest.run(directory, ...args) From 9b4907b646486cf0a4742a476f4fdde570189dd7 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Wed, 15 Nov 2017 23:16:44 -0500 Subject: [PATCH 08/16] adding templates --- .npmignore | 1 + docs/contributing.md | 1 + docs/issue_template.md | 3 +++ docs/pull_request_template.md | 3 +++ 4 files changed, 8 insertions(+) create mode 100644 docs/contributing.md create mode 100644 docs/issue_template.md create mode 100644 docs/pull_request_template.md diff --git a/.npmignore b/.npmignore index 1335f3d..2e7c7c0 100644 --- a/.npmignore +++ b/.npmignore @@ -1,5 +1,6 @@ .nyc_output/ artifacts/ +docs/ node_modules/ src/ testables/ diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..49f69dc --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1 @@ +# How to contribute diff --git a/docs/issue_template.md b/docs/issue_template.md new file mode 100644 index 0000000..f4e0438 --- /dev/null +++ b/docs/issue_template.md @@ -0,0 +1,3 @@ +# ISSUE + +# FIX SUGGESTION diff --git a/docs/pull_request_template.md b/docs/pull_request_template.md new file mode 100644 index 0000000..08481ab --- /dev/null +++ b/docs/pull_request_template.md @@ -0,0 +1,3 @@ +# What issue does this fix/feature? + +# What tests cover the fix/feature? From b7317ed5e0d38cfa9b826f15e0a8984fe51e561b Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 00:22:48 -0500 Subject: [PATCH 09/16] closed #1 refactored Project class to do most of the heavy lifting --- src/Chest.spec.ts | 36 +------------- src/Chest.ts | 49 +----------------- src/Core/Actions/Packages.ts | 36 +++++++------- src/Core/Actions/Typings.ts | 72 ++++++--------------------- src/Core/Files.ts | 5 ++ src/Core/Logger.ts | 20 +++++--- src/Core/Project.spec.ts | 38 ++++++++++++++ src/Core/Project.ts | 96 ++++++++++++++++++++++++++++++++++-- 8 files changed, 184 insertions(+), 168 deletions(-) create mode 100644 src/Core/Project.spec.ts diff --git a/src/Chest.spec.ts b/src/Chest.spec.ts index 9444af7..d3835d7 100644 --- a/src/Chest.spec.ts +++ b/src/Chest.spec.ts @@ -8,47 +8,13 @@ import { Files, Project, Registry } from './Core' const expect = chai.expect -describe('when using RootProject to load a project', () => { +describe('when loading projects', () => { beforeEach(() => { chai.should() chai.use(chaiAsPromised) }) - it('should load single npm project', async () => { - const directory = Files.join(process.cwd(), 'testables', 'single') - const project = await Chest.project(directory) - const projects = await Chest.projects(project) - expect(projects.length).to.equal(1) - expect(projects[0].name).to.equal('project-single') - expect(projects[0].path).to.equal(directory) - }) - - it('should load yarn workspace project', async () => { - const directory = Files.join(process.cwd(), 'testables', 'workspaces') - const project = await Chest.project(directory) - const projects = await Chest.projects(project) - expect(projects.length).to.equal(2) - expect(projects[0].name).to.equal('simple-package') - expect(projects[1].name).to.equal('simple-project') - expect(projects[0].owner).to.not.equal(undefined) - expect(projects[0].owner).to.not.equal(undefined) - }) - - it('should return static InvalidProject when single project does not exist', () => { - const directory = Files.join(process.cwd(), 'testables', 'nonexistant') - - return Chest.project(directory).then(project => expect(project).to.equal(Project.InvalidProject)) - }) - - it('should throw error when workspace project has no child projects', () => { - const directory = Files.join(process.cwd(), 'testables', 'workspaces-invalid') - return Chest.project(directory).then(async project => { - const projects = await Chest.projects(project) - expect(projects).to.deep.equal([Project.InvalidProject]) - }) - }) - it('should run scripts for single project', () => { const directory = Files.join(process.cwd(), 'testables', 'single') const args = Object.keys(Registry.all()) diff --git a/src/Chest.ts b/src/Chest.ts index 9ab572e..4ee432a 100644 --- a/src/Chest.ts +++ b/src/Chest.ts @@ -6,8 +6,7 @@ export class Chest { private static readonly Log: Log = Logger('chest') public static async run(root: string, ...args: string[]): Promise { - const project = await Chest.project(root) - const projects = await Chest.projects(project) + const project = await Project.load(root) const updaters = Registry.all() Object.keys(updaters).forEach(async name => { @@ -16,52 +15,8 @@ export class Chest { if (updater.type === UpdaterType.Root) { await updater.exec(root) } else { - await Promise.all(projects.map(child => updater.workspace(child))) + await Promise.all(project.children.map(child => updater.workspace(child))) } }) } - - public static async project(root: string): Promise { - const npmfile = path.join(root, 'package.json') - - if (await Files.exists(npmfile) === false) { - Chest.Log.error(new Error(`failed to find ${npmfile} in [${root}]`)) - return Project.InvalidProject - } - - const npm = await Files.json(npmfile) - return new Project(npm.name, root) - } - - public static async projects(owner: Project): Promise { - const project = await Chest.project(owner.path) - const npm = await project.package - this.Log.debug('project', project.name) - - if (npm.private && npm.workspace) { - return npm.workspace.map(workspaceRoot => Chest.workspaces(project, workspaceRoot)) - .reduce(async (previous, current) => (await previous).concat(await current), Promise.resolve([])) - } - - return [project] - } - - private static async workspaces(owner: Project, workspaceRoot: string): Promise { - workspaceRoot = Files.join(owner.path, workspaceRoot.substring(0, workspaceRoot.indexOf('/*'))) - - if (await Files.exists(workspaceRoot) === false) { - Chest.Log.error(new Error(`[workspace] failed to find ${workspaceRoot} in [${owner.name}]`)) - return [Project.InvalidProject] - } - - const projects = await Files.listdirs(workspaceRoot) - - return Promise.all(projects.map(async projectPath => { - const npmfile = path.join(projectPath, 'package.json') - const npm = await Files.json(npmfile) - const project = new Project(npm.name, projectPath, owner) - this.Log.debug('project.workspace', owner.name, '->', project.name) - return project - })) - } } diff --git a/src/Core/Actions/Packages.ts b/src/Core/Actions/Packages.ts index 84173ce..eb997f7 100644 --- a/src/Core/Actions/Packages.ts +++ b/src/Core/Actions/Packages.ts @@ -24,23 +24,25 @@ class Script extends UpdateScript { } public async workspace(project: Project): Promise { - const source = await project.owner.package - const target = await project.package - - target.author = source.author - target.bugs = source.bugs - target.description = source.description - target.homepage = source.homepage - target.license = source.license - target.repository = source.repository - - const filename = path.join(project.path, 'package.json') - - if (this.testing) { - this.log.task('updated package info', filename, JSON.stringify(target, null, 2)) - } else { - await Files.save(filename, target) - this.log.task('updated package info', filename) + if (project.owner) { + const source = await project.owner.package + const target = await project.package + + target.author = source.author + target.bugs = source.bugs + target.description = source.description + target.homepage = source.homepage + target.license = source.license + target.repository = source.repository + + const filename = path.join(project.path, 'package.json') + + if (this.testing) { + this.log.task('workspace', filename, JSON.stringify(target, null, 2)) + } else { + await Files.save(filename, target) + this.log.task('workspace', filename) + } } } } diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index f9cb509..94a43b5 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -1,4 +1,5 @@ import * as path from 'path' +import { CompilerOptions } from 'typescript' import { Files, Logger, NPM, Project, Registry, Updater, UpdateScript, UpdaterType } from '../index' const ScriptName = Files.extensionless(__filename) @@ -13,6 +14,10 @@ interface Dependency { typings?: string } +interface TsConfig { + compilerOptions: CompilerOptions +} + /* * Updates the "types" property of "tsconfig.json" files by * looking for types from @types. @@ -23,67 +28,20 @@ class Script extends UpdateScript { } public async exec(rootpath: string): Promise { - const tsconfigfile = path.join(rootpath, 'tsconfig.json') - const packagedir = path.join(rootpath, 'node_modules') - this.log.debug('exec', this.name, rootpath, packagedir) - - if (await Files.exists(tsconfigfile) && await Files.exists(packagedir)) { - const packagedirs = await Files.listdirs(packagedir) - const tsconfig = await Files.json(tsconfigfile) - - const dependencies = await Promise.all(packagedirs.map(packagedir => { - this.log.debug('dependencies', packagedir) - return this.dependencies(packagedir) - })) - - const typings = dependencies.reduce((previous, current) => previous.concat(current.filter(c => !!c.typings)), []) - - tsconfig.compilerOptions.types = typings.map(typing => typing.npmname).sort() - - if (this.testing) { - this.log.task('updated types', tsconfigfile, JSON.stringify(tsconfig, null, 2)) - } else { - await Files.save(tsconfigfile, tsconfig) - this.log.task('updated types', tsconfigfile) - } - } - } - - private async dependencies(packagedir: string): Promise { - const dirname = path.basename(packagedir) - - if (dirname[0] === '@') { - const scopedirs = await Files.listdirs(packagedir) - - return Promise.all(scopedirs - .map(scope => [scope, path.join(scope, 'package.json')]) - .map(async ([scope, scopepath]): Promise => { - const npm = await Files.json(path.join(scope, 'package.json')) + this.log.task('exec', rootpath) + const project = await Project.load(rootpath) - return { - filename: 'package.json', - filepath: scope, - npmname: npm.name, - scope: dirname, - typings: npm.types || npm.typings || npm.typeScriptVersion ? 'index.d.ts' : undefined, - } - })) + if (project === Project.InvalidProject) { + this.log.error(`failed to load any projects at ${rootpath}`) + return } - const packagefile = path.join(packagedir, 'package.json') - - if (await Files.exists(packagefile)) { - const npm = await Files.json(packagefile) - - return [{ - filename: 'package.json', - filepath: packagedir, - npmname: npm.name, - typings: npm.types || npm.typings || npm.typeScriptVersion ? 'index.d.ts' : undefined, - }] - } + const tsconfig = await project.json('tsconfig.json') + tsconfig.compilerOptions.types = await this.gatherTypeDefinitions(project) + } - return [] + private gatherTypeDefinitions(project: Project): Promise { + return Promise.resolve([]) } } diff --git a/src/Core/Files.ts b/src/Core/Files.ts index dcc43d3..6201dca 100644 --- a/src/Core/Files.ts +++ b/src/Core/Files.ts @@ -8,6 +8,10 @@ export interface Stat { } class InternalFiles { + public basename(filepath: string): string { + return path.basename(filepath) + } + public exists(filepath: string): Promise { return new Promise((resolve, reject) => { fs.exists(filepath, (exists: boolean) => resolve(exists)) @@ -121,6 +125,7 @@ class InternalFiles { } export interface Files { + basename(filepath: string): string exists(filepath: string): Promise extensionless(filename: string): string join(...args: string[]): string diff --git a/src/Core/Logger.ts b/src/Core/Logger.ts index 50d9f0f..69e1026 100644 --- a/src/Core/Logger.ts +++ b/src/Core/Logger.ts @@ -13,26 +13,30 @@ export function Logger(name: string, category?: string): Log { const cat = category ? `:${category}` : '' const bold = (name: string) => chalk.default.bold(`[${name}${cat}]`) + const log = (...args: any[]) => { + if (['production', 'test', 'testing'].every(env => env !== process.env.NODE_ENV)) { + console.log(...args) + } + } + return { debug: (...args: any[]): void => { - if (process.env.NODE_ENV !== 'production') { - console.log(chalk.default.yellow.inverse(bold(name), ...args)) - } + log(chalk.default.yellow.inverse(bold(name), ...args)) }, error: (...args: any[]): void => { - console.log(chalk.default.red.inverse(bold(name), ...args)) + log(chalk.default.red.inverse(bold(name), ...args)) }, info: (...args: any[]): void => { - console.log(chalk.default.grey.italic(bold(name), ...args)) + log(chalk.default.grey.italic(bold(name), ...args)) }, start: (...args: any[]): void => { - console.log(chalk.default.grey.dim(bold(name), ...args)) + log(chalk.default.grey.dim(bold(name), ...args)) }, done: (...args: any[]): void => { - console.log(chalk.default.grey.dim(bold(name), ...args)) + log(chalk.default.grey.dim(bold(name), ...args)) }, task: (...args: any[]): void => { - console.log(chalk.default.blue(bold(name), ...args)) + log(chalk.default.blue(bold(name), ...args)) } } } diff --git a/src/Core/Project.spec.ts b/src/Core/Project.spec.ts new file mode 100644 index 0000000..4354e93 --- /dev/null +++ b/src/Core/Project.spec.ts @@ -0,0 +1,38 @@ +import 'mocha' + +import * as chai from 'chai' +import * as chaiAsPromised from 'chai-as-promised' + +import { Files } from './Files' +import { Project } from './Project' +import { Registry } from './Registry' + +const expect = chai.expect + +describe('when loading projects', () => { + + beforeEach(() => { + chai.should() + chai.use(chaiAsPromised) + }) + + it('should load single npm project', async () => { + const directory = Files.join(process.cwd(), 'testables', 'single') + const project = await Project.load(directory) + expect(project.children.length).to.equal(0) + expect(project.name).to.equal('project-single') + expect(project.path).to.equal(directory) + }) + + it('should load yarn workspace project', async () => { + const directory = Files.join(process.cwd(), 'testables', 'workspaces') + const project = await Project.load(directory) + expect(project.children.length).to.equal(2) + + expect(project.children[0].name).to.equal('simple-package') + expect(project.children[0].owner).to.not.equal(undefined) + + expect(project.children[1].name).to.equal('simple-project') + expect(project.children[1].owner).to.not.equal(undefined) + }) +}) diff --git a/src/Core/Project.ts b/src/Core/Project.ts index 5d0a521..c4ac6a8 100644 --- a/src/Core/Project.ts +++ b/src/Core/Project.ts @@ -1,24 +1,40 @@ import { Files } from './Files' import { NPM } from './Interfaces' +import { Log, Logger } from './Logger' + +interface LernaConfig { + packages?: string[] + useWorkspaces?: boolean + version: string +} export class Project { public static InvalidProject: Project = new Project('invalid', 'invalid') + private readonly _children: Project[] private readonly _name: string - private readonly _owner: Project + private readonly _owner: Project | undefined private readonly _path: string + private readonly log: Log - constructor(name: string, path: string, owner?: Project) { + private constructor(name: string, path: string, owner?: Project) { + this._children = [] this._name = name - this._owner = owner || this + this._owner = owner this._path = path + + this.log = Logger(`project:${this.name}`) + } + + public get children(): Project[] { + return this._children } public get name(): string { return this._name } - public get owner(): Project { + public get owner(): Project | undefined { return this._owner } @@ -29,4 +45,76 @@ export class Project { public get path(): string { return this._path } + + public static async load(rootpath: string): Promise { + const npmfile = Files.join(rootpath, 'package.json') + + if (await Files.exists(npmfile) === false) { + return Project.InvalidProject + } + + const npm = await Files.json(npmfile) + const project = new Project(npm.name, rootpath) + + if (npm.private && npm.workspace) { + const result = await project.loadChildProjects(npm) + return result + } + + return project + } + + public json(filename: string): Promise { + return Files.json(Files.join(this.path, filename)) + } + + private async loadChildProjects(npm: NPM): Promise { + const lernafile = Files.join(this.path, 'lerna.json') + if (await Files.exists(lernafile)) { + this.log.debug('lerna-packages', this.path) + return this.loadLernaPackages(lernafile, this) + } + this.log.debug('yarn-workspaces', this.path) + return this.loadYarnWorkspaces(this) + } + + private async loadLernaPackages(filepath: string, project: Project): Promise { + const lerna = await Files.json(filepath) + if (lerna.packages && lerna.useWorkspaces) { + lerna.packages.forEach(async workspace => { + const workspaceName = workspace.substring(0, workspace.indexOf('/*')) + const workspacePath = Files.join(project.path, workspaceName) + const children = await this.loadProjects(workspacePath) + children.forEach(child => this.children.push(child)) + this.log.debug('lerna-package', workspaceName) + }) + } + return this + } + + private async loadYarnWorkspaces(project: Project): Promise { + const npm = await this.package + if (npm.workspace) { + return Promise.all(npm.workspace.map(async workspace => { + const workspaceName = workspace.substring(0, workspace.indexOf('/*')) + const workspacePath = Files.join(project.path, workspaceName) + const children = await this.loadProjects(workspacePath) + children.forEach(child => this.children.push(child)) + this.log.debug('yarn-workspace', workspaceName) + })).then(() => this) + } + return this + } + + private async loadProjects(workspacePath: string): Promise { + const projects = await Files.listdirs(workspacePath) + return Promise.all(projects.map(async projectPath => { + const projectName = Files.basename(projectPath) + const npmfile = Files.join(projectPath, 'package.json') + const npm = await Files.json(npmfile) + const child = new Project(npm.name, projectPath, this) + this.log.debug('added-project', npm.name) + return child + })) + } } From 01ec10fb19332409a945604b8a793ecd4240f895 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 00:29:51 -0500 Subject: [PATCH 10/16] fixing non-deterministic test --- src/Core/Project.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Core/Project.spec.ts b/src/Core/Project.spec.ts index 4354e93..33cf2d6 100644 --- a/src/Core/Project.spec.ts +++ b/src/Core/Project.spec.ts @@ -28,11 +28,7 @@ describe('when loading projects', () => { const directory = Files.join(process.cwd(), 'testables', 'workspaces') const project = await Project.load(directory) expect(project.children.length).to.equal(2) - - expect(project.children[0].name).to.equal('simple-package') expect(project.children[0].owner).to.not.equal(undefined) - - expect(project.children[1].name).to.equal('simple-project') expect(project.children[1].owner).to.not.equal(undefined) }) }) From 20666facf32594bd6320d26093ab40383f14872b Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 01:02:22 -0500 Subject: [PATCH 11/16] adding more tests --- src/Core/Files.spec.ts | 23 +++++++++++++++++++++++ src/Core/Project.spec.ts | 1 + 2 files changed, 24 insertions(+) diff --git a/src/Core/Files.spec.ts b/src/Core/Files.spec.ts index 259227c..9d17dff 100644 --- a/src/Core/Files.spec.ts +++ b/src/Core/Files.spec.ts @@ -19,6 +19,29 @@ describe('when working with files', () => { chai.use(chaiAsPromise) }) + it('should list directories', async () => { + const directories = await Files.listdirs(Files.join(process.cwd(), 'testables')) + expect(directories.length).to.equal(3) + expect(directories).to.contain(Files.join(process.cwd(), 'testables/single')) + expect(directories).to.contain(Files.join(process.cwd(), 'testables/workspaces')) + expect(directories).to.contain(Files.join(process.cwd(), 'testables/workspaces-invalid')) + }) + + it('should throw error when listing directories', (done) => { + Files.listdirs(Files.join(process.cwd(), 'nonexistant')).catch(() => done()) + }) + + it('should list files', async () => { + const filepaths = await Files.listfiles(Files.join(process.cwd(), 'testables/single')) + expect(filepaths.length).to.equal(2) + expect(filepaths).to.contain(Files.join(process.cwd(), 'testables/single/package.json')) + expect(filepaths).to.contain(Files.join(process.cwd(), 'testables/single/tsconfig.json')) + }) + + it('should throw error when listing files', (done) => { + Files.listfiles(Files.join(process.cwd(), 'nonexistant')).catch(() => done()) + }) + it('should write file', () => { const filename = Files.join(process.cwd(), 'artifacts', 'test.json') return Files.writefile(filename, {}) diff --git a/src/Core/Project.spec.ts b/src/Core/Project.spec.ts index 33cf2d6..c12f9ca 100644 --- a/src/Core/Project.spec.ts +++ b/src/Core/Project.spec.ts @@ -31,4 +31,5 @@ describe('when loading projects', () => { expect(project.children[0].owner).to.not.equal(undefined) expect(project.children[1].owner).to.not.equal(undefined) }) + }) From 0a1a0b1f18f37e90ae968297e137014f168730e6 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 11:16:09 -0500 Subject: [PATCH 12/16] typings refactor --- src/Core/Actions/Typings.ts | 33 +++++++++++++++++++++++++++++++-- src/Core/Project.ts | 4 ++++ src/Core/UpdateScript.ts | 13 +++++++++++-- 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index 94a43b5..124a43e 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -38,10 +38,39 @@ class Script extends UpdateScript { const tsconfig = await project.json('tsconfig.json') tsconfig.compilerOptions.types = await this.gatherTypeDefinitions(project) + + if (this.testing) { + this.log.task('tsconfig', JSON.stringify(tsconfig, null, 2)) + } else { + await project.save('tsconfig.json', tsconfig) + this.log.task('tsconfig') + } } - private gatherTypeDefinitions(project: Project): Promise { - return Promise.resolve([]) + private async gatherTypeDefinitions(project: Project): Promise { + const npm = await project.package + let dependencies: string[] = [] + + if (npm.dependencies) { + dependencies = dependencies.concat(Object.keys(npm.dependencies)) + } + + if (npm.devDependencies) { + dependencies = dependencies.concat(Object.keys(npm.devDependencies)) + } + + const modulesPath = Files.join(project.path, 'node_modules') + + return Promise.all(dependencies.map(async dependency => { + const dependencyPath = Files.join(modulesPath, dependency) + if (await Files.exists(dependencyPath)) { + const npm = await Files.json(dependencyPath) + if (npm.types || npm.typings) { + return dependency + } + } + return '' + })).then(values => values.filter(value => value)) } } diff --git a/src/Core/Project.ts b/src/Core/Project.ts index c4ac6a8..4e6a316 100644 --- a/src/Core/Project.ts +++ b/src/Core/Project.ts @@ -68,6 +68,10 @@ export class Project { return Files.json(Files.join(this.path, filename)) } + public save(filename: string, data: T): Promise { + return Files.save(Files.join(this.path, filename), data) + } + private async loadChildProjects(npm: NPM): Promise { const lernafile = Files.join(this.path, 'lerna.json') if (await Files.exists(lernafile)) { diff --git a/src/Core/UpdateScript.ts b/src/Core/UpdateScript.ts index d5b53cf..693798b 100644 --- a/src/Core/UpdateScript.ts +++ b/src/Core/UpdateScript.ts @@ -53,8 +53,17 @@ export abstract class UpdateScript implements Updater { if (error) this.log.error(error) }) - child.stderr.on('data', data => this.args(project, process.stderr, data).map(lines => lines).forEach(args => this.log.error(...args))) - child.stdout.on('data', data => this.args(project, process.stdout, data).map(lines => lines).forEach(args => this.log.task(...args))) + child.stderr.on('data', data => + this.args(project, process.stderr, data) + .map(lines => lines) + .forEach(args => this.log.error(...args)) + ) + + child.stdout.on('data', data => + this.args(project, process.stdout, data) + .map(lines => lines) + .forEach(args => this.log.task(...args)) + ) child.addListener('exit', (code: number, signal: string) => { if (code === 0) { From b3a3bb3cffa2452cd8d4e17e5dd26f3deb13886c Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 11:20:32 -0500 Subject: [PATCH 13/16] bumping version for publish --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2c70cc1..5804ab0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-5", + "version": "2.0.0-alpha-6", "dependencies": { "chalk": "^2.3.0" }, From abfcb05fbbbde3b0087f40bf7e943308a2f27261 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 11:36:33 -0500 Subject: [PATCH 14/16] adding error handling to typings --- package.json | 2 +- src/Core/Actions/Typings.ts | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 5804ab0..fcdd9d4 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-6", + "version": "2.0.0-alpha-7", "dependencies": { "chalk": "^2.3.0" }, diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index 124a43e..4dbb275 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -28,22 +28,26 @@ class Script extends UpdateScript { } public async exec(rootpath: string): Promise { - this.log.task('exec', rootpath) - const project = await Project.load(rootpath) + try { + this.log.task('exec', rootpath) + const project = await Project.load(rootpath) - if (project === Project.InvalidProject) { - this.log.error(`failed to load any projects at ${rootpath}`) - return - } + if (project === Project.InvalidProject) { + this.log.error(`failed to load any projects at ${rootpath}`) + return + } - const tsconfig = await project.json('tsconfig.json') - tsconfig.compilerOptions.types = await this.gatherTypeDefinitions(project) + const tsconfig = await project.json('tsconfig.json') + tsconfig.compilerOptions.types = await this.gatherTypeDefinitions(project) - if (this.testing) { - this.log.task('tsconfig', JSON.stringify(tsconfig, null, 2)) - } else { - await project.save('tsconfig.json', tsconfig) - this.log.task('tsconfig') + if (this.testing) { + this.log.task('tsconfig', JSON.stringify(tsconfig, null, 2)) + } else { + await project.save('tsconfig.json', tsconfig) + this.log.task('tsconfig') + } + } catch (error) { + this.log.error(error) } } From 121c7d2131a5ebf024f39f1dbb2e72c637206dc5 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 11:46:01 -0500 Subject: [PATCH 15/16] fixing dependency checks for typings --- package.json | 2 +- src/Core/Actions/Typings.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fcdd9d4..e87b246 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-7", + "version": "2.0.0-alpha-8", "dependencies": { "chalk": "^2.3.0" }, diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index 4dbb275..5bab593 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -66,7 +66,7 @@ class Script extends UpdateScript { const modulesPath = Files.join(project.path, 'node_modules') return Promise.all(dependencies.map(async dependency => { - const dependencyPath = Files.join(modulesPath, dependency) + const dependencyPath = Files.join(modulesPath, dependency, 'package.json') if (await Files.exists(dependencyPath)) { const npm = await Files.json(dependencyPath) if (npm.types || npm.typings) { From c7e665d9160d13f727e9fc9c4a6598d21278ae96 Mon Sep 17 00:00:00 2001 From: Mike Pham Date: Fri, 17 Nov 2017 12:14:02 -0500 Subject: [PATCH 16/16] fixing typings to loop through children --- package.json | 2 +- src/Core/Actions/Typings.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e87b246..d3fc92b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "license": "MIT", "main": "./lib/CLI.js", "typings": "./lib/index.d.ts", - "version": "2.0.0-alpha-8", + "version": "2.0.0-alpha-9", "dependencies": { "chalk": "^2.3.0" }, diff --git a/src/Core/Actions/Typings.ts b/src/Core/Actions/Typings.ts index 5bab593..db07445 100644 --- a/src/Core/Actions/Typings.ts +++ b/src/Core/Actions/Typings.ts @@ -38,7 +38,14 @@ class Script extends UpdateScript { } const tsconfig = await project.json('tsconfig.json') - tsconfig.compilerOptions.types = await this.gatherTypeDefinitions(project) + const declarations: string[] = [] + + await Promise.all(project.children.map(async child => { + const dependencies = await this.gatherTypeDefinitions(project) + dependencies.forEach(dependency => declarations.push(dependency)) + })) + + tsconfig.compilerOptions.types = declarations.sort() if (this.testing) { this.log.task('tsconfig', JSON.stringify(tsconfig, null, 2))