├── .editorconfig
├── .gitignore
├── .npmrc
├── LICENSE
├── README.md
├── e2e
├── ngm-multi
│ ├── .gitignore
│ └── src
│ │ ├── mod-1
│ │ ├── alert.component.html
│ │ ├── alert.component.ts
│ │ ├── alert.module.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── scss
│ │ │ └── _variables.scss
│ │ └── tsconfig.json
│ │ └── mod-2
│ │ ├── alert.component.html
│ │ ├── alert.component.ts
│ │ ├── alert.module.ts
│ │ ├── index.ts
│ │ ├── package.json
│ │ ├── scss
│ │ └── _variables.scss
│ │ └── tsconfig.json
└── ngm-single
│ ├── .gitignore
│ └── src
│ ├── alert.component.html
│ ├── alert.component.ts
│ ├── alert.module.ts
│ ├── index.ts
│ ├── package.json
│ ├── scss
│ └── _variables.scss
│ └── tsconfig.json
├── package-lock.json
├── package.json
├── src
├── @types
│ ├── cpy
│ │ ├── index.d.ts
│ │ └── package.json
│ └── listr
│ │ ├── index.d.ts
│ │ └── package.json
├── README.md
├── bin
│ └── ngm-cli.ts
├── commands
│ ├── build.command.ts
│ ├── dist-tag.command.ts
│ ├── index.ts
│ ├── init.ts
│ ├── link.command.ts
│ ├── publish.command.ts
│ ├── test.ts
│ └── version.command.ts
├── helpers
│ └── inline-resources.ts
├── lib
│ └── ngm.ts
├── models
│ ├── rollup.globals.ts
│ └── webpack-umd.config.ts
├── package.json
├── tasks
│ ├── build.task.ts
│ ├── bundle-es2015.ts
│ ├── bundle-umd.task.ts
│ ├── clean-dist.task.ts
│ ├── index.ts
│ ├── npm
│ │ ├── build-pkg-json.task.ts
│ │ ├── index.ts
│ │ ├── npm-dist-tag.task.ts
│ │ ├── npm-install.task.ts
│ │ ├── npm-link.task.ts
│ │ ├── npm-publish.task.ts
│ │ └── npm-version.task.ts
│ └── prepublish-git-check.task.ts
├── test
│ └── e2e.ts
├── tsconfig.json
├── types.ts
└── utils
│ ├── constants.ts
│ ├── index.ts
│ ├── merge-package-json.ts
│ ├── submodules-resolution.ts
│ └── tasks-watch.ts
└── todo.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn.lock
6 |
7 | # Runtime data
8 | pids
9 | *.pid
10 | *.seed
11 |
12 | # Directory for instrumented libs generated by jscoverage/JSCover
13 | lib-cov
14 |
15 | # Coverage directory used by tools like istanbul
16 | coverage
17 |
18 | # nyc test coverage
19 | .nyc_output
20 |
21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
22 | .grunt
23 |
24 | # node-waf configuration
25 | .lock-wscript
26 |
27 | # Compiled binary addons (http://nodejs.org/api/addons.html)
28 | build/Release
29 |
30 | # Dependency directories
31 | node_modules
32 | jspm_packages
33 |
34 | # Optional npm cache directory
35 | .npm
36 |
37 | # Optional REPL history
38 | .node_repl_history
39 |
40 | # IDEs and editors
41 | /.idea
42 | /.vscode
43 | .project
44 | .classpath
45 | *.launch
46 | .settings/
47 |
48 | dist
49 |
50 | **/*.js
51 | **/*.js.map
52 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | save-exact = true
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Valor Software
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # npm-submodules
2 | Simple way to manage typescipt | angular2 submodules from one repository
3 |
4 | This is a base lib
5 |
6 | If you want to try this out, please check [tsm-cli](https://www.npmjs.com/package/tsm-cli) and [ngm-cli](https://www.npmjs.com/package/ngm-cli) tools at npm
7 |
8 | ## Developers
9 | How to try this monster locally?
10 |
11 | 1. Git clone source repo
12 | 2. In order to run this you need to build and link src folder
13 | with tsm-cli from npm, it is in dev dependencies already so just do:
14 | ```bash
15 | $ npm run build
16 | ```
17 | on linux `npm link` requires sudo
18 | ```bash
19 | $ (sudo) ./node_module/.bin/tsm link -p src
20 | ```
21 | now you have can use 2 tsm versions in parallel
22 | - local tsm - is from npm
23 | - global tsm - is your dev version
24 |
25 | Have fun! ;)
--------------------------------------------------------------------------------
/e2e/ngm-multi/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /temp
3 | /.tmp
4 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/alert.component.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/alert.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'alert',
5 | templateUrl: './alert.component.html'
6 | })
7 | export class AlertComponent implements OnInit {
8 | @Input() public type:string = 'warning';
9 | @Input() public dismissible:boolean;
10 | @Input() public dismissOnTimeout:number;
11 |
12 | @Output() public close:EventEmitter = new EventEmitter(false);
13 |
14 | public closed:boolean;
15 | protected classes:Array = [];
16 |
17 | public ngOnInit():any {
18 | this.classes[0] = `alert-${this.type}`;
19 | if (this.dismissible) {
20 | this.classes[1] = 'alert-dismissible';
21 | } else {
22 | this.classes.length = 1;
23 | }
24 |
25 | if (this.dismissOnTimeout) {
26 | setTimeout(() => this.onClose(), this.dismissOnTimeout);
27 | }
28 | }
29 |
30 | // todo: mouse event + touch + pointer
31 | public onClose():void {
32 | this.closed = true;
33 | this.close.emit(this);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/alert.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 |
4 | import { AlertComponent } from './alert.component';
5 |
6 | @NgModule({
7 | imports: [CommonModule],
8 | declarations: [AlertComponent],
9 | exports: [AlertComponent]
10 | })
11 | export class AlertModule {
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/index.ts:
--------------------------------------------------------------------------------
1 | export { AlertComponent } from './alert.component';
2 | export { AlertModule } from './alert.module';
3 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-module",
3 | "version": "0.0.1"
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | //-Brand Colors----------------
2 | $color-primary-light: #90A4AE;
3 | $color-primary: #182642;
4 | $color-primary-dark: #1c202a;
5 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-1/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../../dist/mod-1",
4 | "module": "commonjs",
5 | "target": "es5",
6 | "moduleResolution": "node",
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "sourceMap": true,
10 | "noEmitHelpers": false,
11 | "declaration": true,
12 | "skipLibCheck": true,
13 | "stripInternal": true,
14 | "noImplicitAny": false,
15 | "noEmitOnError": false,
16 | "lib": ["dom", "es6"]
17 | },
18 | "exclude": [
19 | "node_modules"
20 | ],
21 | "angularCompilerOptions": {
22 | "genDir": "../../temp/mod-1/factories",
23 | "strictMetadataEmit": true,
24 | "skipTemplateCodegen": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/alert.component.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/alert.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'alert',
5 | templateUrl: './alert.component.html'
6 | })
7 | export class AlertComponent implements OnInit {
8 | @Input() public type:string = 'warning';
9 | @Input() public dismissible:boolean;
10 | @Input() public dismissOnTimeout:number;
11 |
12 | @Output() public close:EventEmitter = new EventEmitter(false);
13 |
14 | public closed:boolean;
15 | protected classes:Array = [];
16 |
17 | public ngOnInit():any {
18 | this.classes[0] = `alert-${this.type}`;
19 | if (this.dismissible) {
20 | this.classes[1] = 'alert-dismissible';
21 | } else {
22 | this.classes.length = 1;
23 | }
24 |
25 | if (this.dismissOnTimeout) {
26 | setTimeout(() => this.onClose(), this.dismissOnTimeout);
27 | }
28 | }
29 |
30 | // todo: mouse event + touch + pointer
31 | public onClose():void {
32 | this.closed = true;
33 | this.close.emit(this);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/alert.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 |
4 | import { AlertComponent } from './alert.component';
5 |
6 | @NgModule({
7 | imports: [CommonModule],
8 | declarations: [AlertComponent],
9 | exports: [AlertComponent]
10 | })
11 | export class AlertModule {
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/index.ts:
--------------------------------------------------------------------------------
1 | export { AlertComponent } from './alert.component';
2 | export { AlertModule } from './alert.module';
3 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-module2",
3 | "version": "0.0.1"
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | //-Brand Colors----------------
2 | $color-primary-light: #90A4AE;
3 | $color-primary: #182642;
4 | $color-primary-dark: #1c202a;
5 |
--------------------------------------------------------------------------------
/e2e/ngm-multi/src/mod-2/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../../dist/mod-2",
4 | "module": "commonjs",
5 | "target": "es5",
6 | "moduleResolution": "node",
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "sourceMap": true,
10 | "noEmitHelpers": false,
11 | "declaration": true,
12 | "skipLibCheck": true,
13 | "stripInternal": true,
14 | "noImplicitAny": false,
15 | "noEmitOnError": false,
16 | "lib": ["dom", "es6"]
17 | },
18 | "exclude": [
19 | "node_modules"
20 | ],
21 | "angularCompilerOptions": {
22 | "genDir": "../../temp/mod-2/factories",
23 | "strictMetadataEmit": true,
24 | "skipTemplateCodegen": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/e2e/ngm-single/.gitignore:
--------------------------------------------------------------------------------
1 | /dist
2 | /temp
3 | /.tmp
4 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/alert.component.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/alert.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'alert',
5 | templateUrl: './alert.component.html'
6 | })
7 | export class AlertComponent implements OnInit {
8 | @Input() public type:string = 'warning';
9 | @Input() public dismissible:boolean;
10 | @Input() public dismissOnTimeout:number;
11 |
12 | @Output() public close:EventEmitter = new EventEmitter(false);
13 |
14 | public closed:boolean;
15 | protected classes:Array = [];
16 |
17 | public ngOnInit():any {
18 | this.classes[0] = `alert-${this.type}`;
19 | if (this.dismissible) {
20 | this.classes[1] = 'alert-dismissible';
21 | } else {
22 | this.classes.length = 1;
23 | }
24 |
25 | if (this.dismissOnTimeout) {
26 | setTimeout(() => this.onClose(), this.dismissOnTimeout);
27 | }
28 | }
29 |
30 | // todo: mouse event + touch + pointer
31 | public onClose():void {
32 | this.closed = true;
33 | this.close.emit(this);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/alert.module.ts:
--------------------------------------------------------------------------------
1 | import { CommonModule } from '@angular/common';
2 | import { NgModule } from '@angular/core';
3 |
4 | import { AlertComponent } from './alert.component';
5 |
6 | @NgModule({
7 | imports: [CommonModule],
8 | declarations: [AlertComponent],
9 | exports: [AlertComponent]
10 | })
11 | export class AlertModule {
12 | }
13 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/index.ts:
--------------------------------------------------------------------------------
1 | export { AlertComponent } from './alert.component';
2 | export { AlertModule } from './alert.module';
3 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ng2-module",
3 | "version": "0.0.1"
4 | }
5 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/scss/_variables.scss:
--------------------------------------------------------------------------------
1 | //-Brand Colors----------------
2 | $color-primary-light: #90A4AE;
3 | $color-primary: #182642;
4 | $color-primary-dark: #1c202a;
5 |
--------------------------------------------------------------------------------
/e2e/ngm-single/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../dist",
4 | "module": "commonjs",
5 | "target": "es5",
6 | "moduleResolution": "node",
7 | "emitDecoratorMetadata": true,
8 | "experimentalDecorators": true,
9 | "sourceMap": true,
10 | "noEmitHelpers": false,
11 | "declaration": true,
12 | "skipLibCheck": true,
13 | "stripInternal": true,
14 | "noImplicitAny": false,
15 | "noEmitOnError": false,
16 | "lib": ["dom", "es6"]
17 | },
18 | "exclude": [
19 | "node_modules"
20 | ],
21 | "angularCompilerOptions": {
22 | "genDir": "../temp/factories",
23 | "strictMetadataEmit": true,
24 | "skipTemplateCodegen": true
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "base-npm-submodules",
3 | "version": "1.0.4",
4 | "private": true,
5 | "description": "Simple way to manage angular submodules in one repository",
6 | "bin": {
7 | "ngm": "bin/ngm-cli.js"
8 | },
9 | "scripts": {
10 | "build": "tsc -p src/tsconfig.json",
11 | "test": "echo 'all good, move on ;)'",
12 | "e2e-tsm": "node dist/test/e2e.js",
13 | "e2e": "echo 'dont touch it'",
14 | "ebuild-multi": "ngm build -p e2e/ngm-multi",
15 | "ebuild-single": "ngm build -p e2e/ngm-single"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+ssh://git@github.com/valor-software/npm-submodules.git"
20 | },
21 | "keywords": [
22 | "npm",
23 | "node",
24 | "typescript",
25 | "angular",
26 | "angular2",
27 | "angularcli"
28 | ],
29 | "author": "Dmitriy Shekhovtsov (https://twitter.com/valorkin)",
30 | "license": "MIT",
31 | "bugs": {
32 | "url": "https://github.com/valor-software/npm-submodules/issues"
33 | },
34 | "homepage": "https://github.com/valor-software/npm-submodules#readme",
35 | "peerDependencies": {
36 | "ts-loader": ">=4.3.0",
37 | "node-sass": ">=4.0.0",
38 | "node-sass-tilde-importer": ">=1.0.0",
39 | "webpack": ">=4.0.0",
40 | "typescript": ">=2.7.2"
41 | },
42 | "dependencies": {
43 | "chalk": "2.4.1",
44 | "cpy": "7.0.0",
45 | "del": "3.0.0",
46 | "execa": "0.10.0",
47 | "inquirer": "5.2.0",
48 | "listr": "0.14.1",
49 | "lodash": "4.17.10",
50 | "meow": "5.0.0",
51 | "node-sass": "^4.5.3",
52 | "node-sass-tilde-importer": "1.0.2",
53 | "read-pkg": "3.0.0",
54 | "rollup": "0.58.2",
55 | "rollup-plugin-commonjs": "9.1.3",
56 | "rollup-plugin-node-resolve": "3.3.0",
57 | "semver": "5.5.0",
58 | "split": "1.0.1",
59 | "stream-to-observable": "0.2.0",
60 | "ts-loader": "4.3.0",
61 | "tsconfig": "7.0.0",
62 | "typescript": "~2.7.2",
63 | "update-notifier": "2.5.0",
64 | "webpack": "4.6.0",
65 | "write-pkg": "3.1.0"
66 | },
67 | "devDependencies": {
68 | "@angular/animations": "6.0.1",
69 | "@angular/common": "6.0.1",
70 | "@angular/compiler": "6.0.1",
71 | "@angular/compiler-cli": "6.0.1",
72 | "@angular/core": "6.0.1",
73 | "@angular/forms": "6.0.1",
74 | "@angular/http": "6.0.1",
75 | "@angular/platform-browser": "6.0.1",
76 | "@angular/platform-browser-dynamic": "6.0.1",
77 | "@angular/platform-server": "6.0.1",
78 | "@angular/router": "6.0.1",
79 | "@angular/tsc-wrapped": "4.4.6",
80 | "@types/chokidar": "1.7.5",
81 | "@types/node": "10.0.8",
82 | "@types/webpack": "4.1.6",
83 | "reflect-metadata": "0.1.12",
84 | "rxjs": "6.1.0",
85 | "zone.js": "0.8.26"
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/@types/cpy/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'cpy' {
2 | declare interface CpyOptions {
3 | cwd?:string;
4 | parents?:boolean;
5 | rename?:string;
6 | }
7 | declare function cpy(files:string[], destination: string,
8 | options?:CpyOptions, );
9 | export = cpy;
10 | }
--------------------------------------------------------------------------------
/src/@types/cpy/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "listr",
3 | "typings": "index.d.ts",
4 | "main": "index.js"
5 | }
6 |
--------------------------------------------------------------------------------
/src/@types/listr/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'listr' {
2 | declare interface ListrTask {
3 | title: string;
4 | task: Function;
5 | skip?: Function;
6 | }
7 | declare interface ListrOptions {
8 | concurrent?: boolean;
9 | renderer?:string|Object;
10 | showSubtasks?:boolean;
11 | }
12 | declare class Listr {
13 | constructor(tasks:ListrTask[], opts?:ListrOptions);
14 | run(context?:Object):Promise;
15 | add(task:ListrTask):Listr;
16 | get task():ListrTask|ListrTask[];
17 | render():any;
18 | }
19 | export = Listr;
20 | }
--------------------------------------------------------------------------------
/src/@types/listr/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "listr",
3 | "typings": "index.d.ts"
4 | }
5 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | Sample projects structure
2 | ```
3 | +-- dist // target folder
4 | +-- src
5 | | +-- package.json // module package.json
6 | angular-cli.json
7 | package.json // root package.json
8 | ```
9 | 1. Safety: add `"private":true` to your root `package.json`
10 |
11 | 2. Module package.json (see sample project structure above) should contain dependencies and peerDepencies of module, sample:
12 |
13 | ```json
14 | {
15 | "name": "ng2-bootstrap",
16 | "dependencies": {
17 | "moment": "*"
18 | },
19 | "peerDependencies": {
20 | "@angular/common": "*",
21 | "@angular/compiler": "*",
22 | "@angular/core": "*",
23 | "@angular/forms": "*"
24 | }
25 | }
26 | ```
27 |
28 | 3. Module configuration: by default `ngm` reads `angular-cli.json` in projects root
29 | ```json
30 | {
31 | "module":[{
32 | "name": "ng2-bootstrap",
33 | "root": "src",
34 | "outDir": "dist",
35 | "main":"index.ts",
36 | "tsconfig": "tsconfig.json"
37 | }]
38 | }
39 | ```
40 |
41 | 4. Running: just add `ngm` script to your root package.json (see sample project structure above)
42 |
43 | ```json
44 | "scripts": {
45 | "build": "ngm"
46 | }
47 | ```
48 |
49 | 5. Ready steady go:
50 | ```sh
51 | npm run build
52 | ```
53 |
54 | 6. Now you can go to `dist` folder and do `npm publish` (will be added as a command later)
55 |
--------------------------------------------------------------------------------
/src/bin/ngm-cli.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | // todo: add support for config file
3 | // todo: add help per command (sample: tsm help build)
4 | // todd: add test and e2e command (cut of from publish tasks)
5 | // todo: move help to separate file
6 | // todo: use Observables
7 | // todo: add rollup bundle
8 | // todo: disable bundling in watch mode
9 | // todo: add info about --main? read it from package.json?
10 | // todo: validation package.json
11 |
12 | const meow = require('meow');
13 | const updateNotifier = require('update-notifier');
14 |
15 | // init - updates root pkg scripts with required commands, adds tsm-readme.md
16 |
17 | const cli = meow(`
18 | Usage
19 | $ ngm [options]
20 |
21 | Commands:
22 | ----------------------------------------------------------------
23 | build - build typescript projects
24 | Usage:
25 | $ tsm build -p src
26 | Mandatory options:
27 | -p DIRECTORY, Compile the project in the given directory
28 | --project DIRECTORY
29 | Optional options (default: false):
30 | --no-local Use version numbers from local submodules when building package.json,
31 | usually needed only for publish command
32 | -w, --watch Watch input files
33 | --verbose Enable verbose mode
34 | --clean Cleaning dist folders
35 | It removes folder, so you will need to rerun commands like 'link', etc...
36 | --skip-bundles Works only in --watch mode, allows to skip umd bundling
37 |
38 | ----------------------------------------------------------------
39 | link - runs 'npm link' in each submodule dist folder
40 | Usage:
41 | $ tsm link -p src
42 | Hint:
43 | 'npm link' doesn't track adding new files, please rerun this command if file was added/removed
44 | Mandatory options:
45 | -p DIRECTORY, Compile the project in the given directory
46 | --project DIRECTORY
47 | Optional options:
48 | --no-deep By default local submodules will be linked to each other
49 | --here Links submodules to root package
50 |
51 | ----------------------------------------------------------------
52 | publish - runs 'npm publish' in each dist submodule folders, how it works:
53 |
54 | 1. Runs git checks (you should be on master branch, without changes in working tree, and up to date with remote history
55 | --any-branch - disables on 'master' check
56 | --skip-git-check - to skip all git checks
57 |
58 | 2. Performs clean install of dependecies
59 | --yarn - to install dependencies with 'yarn'
60 | --skip-cleanup - to not delete 'node_modules' before installing
61 |
62 | 3. Running tests (npm test) from root folder
63 |
64 | 4. Running e2e test (npm run e2e), all submodules will be built in local mode and linked (npm link)
65 |
66 | 5. Publishing, with separate clean build
67 | --skip-publish - skip publishing and clean build, in case you want to double check something
68 | --tag - same as 'npm publish --tag next', use in case you want new release without changing 'latest' npm tag
69 | --access - same as 'npm publish --access p*'
70 | Steps 1-4 can be skipped with --yolo flag
71 |
72 | ----------------------------------------------------------------
73 | version - runs 'npm version ' in each submodule and than in root folder
74 | Usage:
75 | $ tsm version prerelease -p src
76 | Mandatory options:
77 | -m MESSAGE, Commit message when creating a version commit
78 | --message MESSAGE
79 | --no-git-tag-version Do not create a version commit and tag (applied only to root folder)
80 | Optional options:
81 | --skip-push Skip pushing of version commit and tags
82 | ----------------------------------------------------------------
83 |
84 | `, {
85 | flags: {
86 | message: {
87 | type: 'string',
88 | alias: 'm'
89 | },
90 | project: {
91 | type: 'string',
92 | alias: 'p',
93 | default: 'src'
94 | },
95 | config: {
96 | type: 'string',
97 | alias: 'c'
98 | },
99 | watch: {
100 | type: 'boolean',
101 | alias: 'w',
102 | default: false
103 | },
104 | version: {
105 | type: 'boolean',
106 | alias: 'c',
107 | default: false
108 | },
109 | local: {
110 | type: 'boolean',
111 | default: false
112 | },
113 | verbose: {
114 | type: 'boolean',
115 | default: true
116 | }
117 | }
118 | });
119 |
120 | updateNotifier({pkg: cli.pkg}).notify();
121 |
122 | if (cli.flags.version) {
123 | console.log(`${cli.pkg.name} ${cli.pkg.version}`);
124 | process.exit();
125 | }
126 |
127 | // show help and exit by default
128 | if (cli.input.length === 0) {
129 | cli.showHelp(0);
130 | }
131 |
132 | // project flag is mandatory for now
133 | // if (!cli.flags.project) {
134 | // console.error('Please provide path to your projects source folder, `-p DIR` ');
135 | // process.exit(1);
136 | // }
137 |
138 | import { main } from '../lib/ngm';
139 |
140 | Promise
141 | .resolve()
142 | .then(() => {
143 | // default verbose to true
144 | cli.flags.verbose = cli.flags.verbose !== false;
145 | return main(cli.input[0], cli);
146 | })
147 | .catch(err => {
148 | console.error(`\n`, err && err.stderr || '');
149 | console.error(`\n`, err);
150 | process.exit(1);
151 | });
152 |
--------------------------------------------------------------------------------
/src/commands/build.command.ts:
--------------------------------------------------------------------------------
1 | // todo: add load from config file, TBD
2 |
3 | import path = require('path');
4 |
5 | const Listr = require('listr');
6 | const cpy = require('cpy');
7 | const del = require('del');
8 | const fs = require('fs');
9 |
10 | import { findSubmodules, tasksWatch } from '../utils';
11 | import { build, bundleUmd, buildPkgs, bundleEs2015 } from '../tasks';
12 | import { inlineResources } from '../helpers/inline-resources';
13 |
14 |
15 | export function buildCommand({project, verbose, clean, local, main, watch, skipBundles, buildEs2015}) {
16 | // 1. clean dist folders
17 | // 2.1 merge pkg json
18 | // todo: 2.2 validate pkg (main, module, types fields)
19 | // 2.3 write pkg
20 | // 3. compile ts
21 | return findSubmodules(project, {local})
22 | .then(opts => new Listr([
23 | /**
24 | * 1. Clean /dist folders
25 | * delete only dist content, but not folders itself
26 | * no not break npm link
27 | */
28 | {
29 | title: 'Clean dist folders',
30 | task: () => new Listr(
31 | opts.map(opt => ({
32 | title: `Cleaning ${opt.dist}`,
33 | task: () => del(path.join(opt.dist, '**/*'))
34 | }))
35 | ),
36 | skip: () => !clean
37 | },
38 | {
39 | title: 'Copy *.md and license files',
40 | task: () => Promise.all(opts.map(opt =>
41 | cpy(['*.md', 'LICENSE'], opt.dist)
42 | .then(() =>
43 | cpy([
44 | path.join(opt.src, '*.md'),
45 | path.join(opt.src, 'LICENSE')
46 | ],
47 | opt.dist))
48 | ))
49 | },
50 | {
51 | title: 'Build package.json files',
52 | task: () => buildPkgs(opts, {local})
53 | },
54 | {
55 | title: 'Copy source files to temporary folder',
56 | task: () => new Listr(
57 | opts.map(opt => ({
58 | title: `Copying ${opt.pkg.name} source files to ${opt.src}`,
59 | task: () => cpy(
60 | ['**/*.*', '!node_modules'],
61 | // opt.tmp,
62 | path.resolve(opt.tmp),
63 | {
64 | cwd: opt.project,
65 | parents: true,
66 | overwrite: true,
67 | nodir: true
68 | }
69 | )
70 | }))
71 | )
72 | },
73 | /**
74 | * 3. Inline template (.html) and style (.css) files into the component .ts files.
75 | * We do this on the /.tmp folder to avoid editing the original /src files
76 | */
77 | {
78 | title: 'Inline template and style files into the components',
79 | task: () => new Listr(
80 | opts.map(opt => ({
81 | title: `Inlining ${opt.pkg.name} templates and styles`,
82 | task: () => inlineResources(opt.tmp)
83 | }))
84 | )
85 | },
86 | {
87 | title: 'Build projects',
88 | task: () => new Listr(
89 | opts.map(opt => ({
90 | title: `Building ${opt.pkg.name} (${opt.src})`,
91 | task: () => watch ?
92 | build(opt.tmp) :
93 | build(opt.tmp).catch(error => {
94 | console.log(error.toString());
95 | process.exit(1);
96 | })
97 | }))
98 | )
99 | },
100 | {
101 | title: 'Copy assets to dist folder',
102 | skip: () => false,
103 | task: () => new Listr(
104 | opts.map(opt => ({
105 | title: `Copying ${opt.pkg.name} assets to ${opt.src}`,
106 | task: () => cpy(
107 | ['**/*', '!node_modules', '!**/*.{ts, html}', '!package.json', '!tsconfig.json'],
108 | path.relative(opt.project, opt.dist),
109 | {
110 | cwd: opt.project,
111 | parents: true,
112 | overwrite: true,
113 | nodir: true
114 | }
115 | )
116 | }))
117 | )
118 | },
119 | {
120 | title: 'Bundling umd version',
121 | task: () => new Listr(
122 | opts.map(opt => ({
123 | title: `Bundling ${opt.pkg.name}`,
124 | task: () => {
125 | if (Array.isArray(main) && main.length) {
126 | return Promise.all(main.map((entryPoint, i) => bundleUmd({
127 | main: entryPoint,
128 | src: opt.tmp,
129 | dist: opt.dist,
130 | name: i === 0 ? opt.pkg.name : entryPoint.replace('.ts', ''),
131 | tsconfig: opt.tsconfig.path,
132 | minify: false
133 | })))
134 | }
135 |
136 | return bundleUmd({
137 | main,
138 | src: opt.tmp,
139 | dist: opt.dist,
140 | name: opt.pkg.name,
141 | tsconfig: opt.tsconfig.path,
142 | minify: false
143 | })
144 | },
145 | skip: () => watch || skipBundles
146 | }))
147 | ),
148 | skip: () => watch || skipBundles
149 | },
150 | {
151 | title: 'Bundling minified umd version',
152 | task: () => new Listr(
153 | opts.map(opt => ({
154 | title: `Bundling ${opt.pkg.name}`,
155 | task: () => {
156 | if (Array.isArray(main) && main.length) {
157 | return Promise.all(main.map((entryPoint, i) => bundleUmd({
158 | main: entryPoint,
159 | src: opt.tmp,
160 | dist: opt.dist,
161 | name: i === 0 ? opt.pkg.name : entryPoint.replace('.ts', ''),
162 | tsconfig: opt.tsconfig.path,
163 | minify: true
164 | })))
165 | }
166 |
167 | return bundleUmd({
168 | main,
169 | src: opt.tmp,
170 | dist: opt.dist,
171 | name: opt.pkg.name,
172 | tsconfig: opt.tsconfig.path,
173 | minify: true
174 | })
175 | },
176 | skip: () => watch || skipBundles
177 | }))
178 | ),
179 | skip: () => watch || skipBundles
180 | },
181 | {
182 | title: 'Bundling es2015 version',
183 | task: () => new Listr(
184 | opts.map(opt => ({
185 | title: `Bundling ${opt.pkg.name}`,
186 | task: () => {
187 | const tsconfig = JSON.parse(fs.readFileSync(path.resolve(opt.tmp, 'tsconfig.json'), 'utf8'));
188 | tsconfig.compilerOptions.target = 'es2015';
189 | tsconfig.compilerOptions.module = 'es2015';
190 | tsconfig.compilerOptions.outDir = 'dist-es2015';
191 | fs.writeFileSync(path.resolve(opt.tmp, 'tsconfig.json'), JSON.stringify(tsconfig), 'utf8');
192 |
193 | if (Array.isArray(main) && main.length) {
194 | return Promise.all(main.map((entryPoint, i) => bundleEs2015({
195 | input: entryPoint,
196 | dist: opt.dist,
197 | name: i === 0 ? opt.pkg.name : entryPoint.replace('.ts', ''),
198 | tmp: opt.tmp
199 | })))
200 | }
201 |
202 | return bundleEs2015({
203 | input: main,
204 | dist: opt.dist,
205 | name: opt.pkg.name,
206 | tmp: opt.tmp
207 | });
208 | },
209 | skip: () => !buildEs2015 || watch || skipBundles
210 | }))
211 | ),
212 | skip: () => !buildEs2015 || watch || skipBundles
213 | },
214 | {
215 | title: 'Clean .tmp folders',
216 | task: () => new Listr(
217 | opts.map(opt => ({
218 | title: `Cleaning ${opt.tmp}`,
219 | task: () => del(path.join(opt.tmp, '**/*'), {force: true})
220 | }))
221 | )
222 | }
223 | ], {renderer: verbose ? 'verbose' : 'default'}));
224 | }
225 |
226 | export function buildTsRun(cli) {
227 | const config = cli.flags.config ? JSON.parse(fs.readFileSync(path.resolve(cli.flags.config), 'utf8')) : {};
228 | let {src, main, modules, watch, verbose, clean, local, skipBundles, buildEs2015} = config;
229 | const project = cli.flags.project || src;
230 | main = cli.flags.main || main || 'index.ts';
231 | verbose = cli.flags.verbose || verbose;
232 | watch = cli.flags.watch || watch;
233 | clean = cli.flags.clean || clean;
234 | skipBundles = cli.flags.skipBundles || skipBundles;
235 | buildEs2015 = cli.flags.buildEs2015 || buildEs2015;
236 | const modulePaths = modules ? modules.map(module => module.src) : [];
237 |
238 | if (!project && !modulePaths) {
239 | console.error('Please provide path to your projects source folder, `-p DIR` or specify `src` or `modules` in config');
240 | process.exit(1);
241 | }
242 |
243 | if (modulePaths.length) {
244 | const commands = modules.map((module: any) => {
245 | return {
246 | title: `Build ${module.src}`,
247 | task: () => buildCommand({project: module.src, verbose, clean, local, main: module.entryPoints, watch, skipBundles, buildEs2015})
248 | }
249 | });
250 |
251 | const taskQueue = new Listr(commands, {renderer: verbose ? 'verbose' : 'default'});
252 | return tasksWatch({project: modulePaths, taskQueue, watch, paths: modulePaths});
253 | }
254 |
255 | return buildCommand({project, verbose, clean, local, main, watch, skipBundles, buildEs2015})
256 | .then(taskQueue => tasksWatch({project, taskQueue, watch, paths: null}));
257 | }
258 |
--------------------------------------------------------------------------------
/src/commands/dist-tag.command.ts:
--------------------------------------------------------------------------------
1 | const execa = require('execa');
2 | import Listr = require('listr');
3 | import { npmDistTag } from '../tasks';
4 | import { findSubmodules } from '../utils/index';
5 |
6 | export function npmDistTagRun(cli) {
7 | const {project, verbose, yarn} = cli.flags;
8 | const cmd = cli.input[1];
9 | const tag = cli.input[2];
10 |
11 | return findSubmodules(project)
12 | .then((opts: TsmOptions[]) => {
13 | const tasks = new Listr([
14 | {
15 | title: 'Version all submodules',
16 | task: () => new Listr(
17 | opts.map(opt => ({
18 | title: `npm dist-tag ${cmd} ${opt.pkg.name}@${opt.pkg.version}`,
19 | task: () => npmDistTag({
20 | yarn, cmd, tag,
21 | module: opt.pkg.name,
22 | version: opt.pkg.version
23 | })
24 | }))
25 | )
26 | }
27 | ], {renderer: verbose ? 'verbose' : 'default'});
28 |
29 | return tasks.run();
30 | });
31 | }
32 |
--------------------------------------------------------------------------------
/src/commands/index.ts:
--------------------------------------------------------------------------------
1 | export {buildCommand, buildTsRun} from './build.command';
2 | export { npmDistTagRun } from './dist-tag.command';
3 | export { npmLinkCommand, run as npmLinkRun } from './link.command';
4 | export { run as npmPublishRun } from './publish.command';
5 | // test
6 | export { run as npmVersionRun } from './version.command';
7 |
--------------------------------------------------------------------------------
/src/commands/init.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by valorkin on 11/23/16.
3 | */
4 |
--------------------------------------------------------------------------------
/src/commands/link.command.ts:
--------------------------------------------------------------------------------
1 | const Listr = require('listr');
2 | import { findSubmodules } from '../utils';
3 | import { npmLink } from '../tasks';
4 |
5 | // todo: 'npm-link` doesn't track adding new files,
6 | // so watch mode should be added
7 |
8 | export function npmLinkCommand({project, local, deep, verbose, yarn, here}) {
9 | const noDeepLinking = deep === false;
10 | // 1. clean dist folders
11 | // 2.1 merge pkg json
12 | // 2.2 validate pkg (main, module, types)
13 | // 2.3 write pkg
14 | // 3. compile ts
15 | return findSubmodules(project, {local})
16 | .then((opts: TsmOptions[]) => new Listr([
17 | {
18 | title: 'Link all submodules',
19 | task: () => {
20 | const linkingTasks = new Listr(
21 | opts.map(opt => ({
22 | title: `npm link ${opt.pkg.name} (from: ${opt.dist})`,
23 | task: () => npmLink({yarn, cwd: opt.dist})
24 | }))
25 | );
26 |
27 | if (noDeepLinking) {
28 | return linkingTasks;
29 | }
30 |
31 | opts.filter(opt => opt.cross.length > 0)
32 | .forEach(opt => opt.cross
33 | .forEach(crossName => linkingTasks.add(
34 | {
35 | title: `npm link ${crossName} to ${opt.pkg.name} (${opt.src})`,
36 | task: () => npmLink({yarn, cwd: opt.dist, module: crossName})
37 | }
38 | )));
39 | return linkingTasks;
40 | }
41 | },
42 | {
43 | title: 'Link submodules to local project',
44 | task: () => new Listr(
45 | opts.map(opt => ({
46 | title: `npm link ${opt.pkg.name}`,
47 | task: () => npmLink({yarn, module: opt.pkg.name, cwd: '.'})
48 | }))
49 | ),
50 | skip: () => here !== true
51 |
52 | }
53 | ], {renderer: verbose ? 'verbose' : 'default'}));
54 | }
55 |
56 | export function run(cli) {
57 | const {project, verbose, local, deep, yarn, here} = cli.flags;
58 | return npmLinkCommand({project, verbose, local, deep, yarn, here})
59 | .then(tasks => tasks.run());
60 | }
61 |
--------------------------------------------------------------------------------
/src/commands/publish.command.ts:
--------------------------------------------------------------------------------
1 | // import { TsmOptions } from '../types';
2 | import { findSubmodules } from '../utils';
3 | import { npmPublish, prepublishGitCheck, npmLink, npmInstall } from '../tasks';
4 | import { npmLinkCommand } from './link.command';
5 | /**
6 | * Heavily inspired by https://github.com/sindresorhus/np
7 | * */
8 | const execa = require('execa');
9 | import Listr = require('listr');
10 |
11 | export function run(cli, {buildCommand}) {
12 | const {
13 | project, verbose, tag, access, anyBranch,
14 | skipCleanup, skipGitCheck, yarn, yolo, skipPublish
15 | } = cli.flags;
16 |
17 | return findSubmodules(project)
18 | .then((opts: TsmOptions[]) => {
19 | const tasks = new Listr([
20 | {
21 | title: 'Git checks',
22 | task: () => prepublishGitCheck({anyBranch}),
23 | skip: () => skipGitCheck || yolo
24 | },
25 | // test command
26 | {
27 | title: 'Installing dependencies',
28 | task: () => new Listr(npmInstall({skipCleanup, yarn})),
29 | skip: () => yolo
30 | },
31 | {
32 | title: 'Running unit tests tests',
33 | task: () => execa('npm', ['test']),
34 | skip: () => yolo
35 | },
36 | // e2e command
37 | {
38 | title: 'Build submodules for e2e',
39 | task: () => buildCommand({project, verbose, clean: true, local: true}),
40 | skip: () => yolo
41 | },
42 | {
43 | title: 'Link submodules',
44 | task: () => npmLinkCommand({project, local: true, deep: true, verbose, yarn, here: true}),
45 | skip: () => yolo
46 | },
47 | // publish
48 | // set numeric package version before publish
49 | {
50 | title: 'Build submodules for publish',
51 | task: () => buildCommand({project, verbose, clean: true, local: false})
52 | },
53 | {
54 | title: 'Publish all submodules',
55 | task: () => new Listr(opts.map(opt => ({
56 | title: `npm publish (${opt.pkg.name}) (from: ${opt.dist})`,
57 | task: () => npmPublish({yarn, cwd: opt.dist, tag, access})
58 | }))
59 | ),
60 | skip: () => skipPublish
61 | },
62 | {
63 | title: 'Pushing tags',
64 | task: () => execa('git', ['push', '--follow-tags']),
65 | skip: () => true
66 | }
67 | ], {renderer: verbose ? 'verbose' : 'default'});
68 |
69 | return tasks.run();
70 | });
71 | }
72 |
--------------------------------------------------------------------------------
/src/commands/test.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by valorkin on 20/11/2016.
3 | */
4 |
--------------------------------------------------------------------------------
/src/commands/version.command.ts:
--------------------------------------------------------------------------------
1 | // import { TsmOptions } from '../types';
2 | const execa = require('execa');
3 | const path = require('path');
4 | import Listr = require('listr');
5 | import { findSubmodules } from '../utils/submodules-resolution';
6 | import { npmVersion } from '../tasks/npm/npm-version.task';
7 |
8 | export function run(cli) {
9 | const {project, verbose, message, gitTagVersion, yarn, skipPush} = cli.flags;
10 | const noGitTagVersion = gitTagVersion === false;
11 | const version = cli.input[1];
12 |
13 | if (!version) {
14 | return Promise.reject('Error: please provide version like (patch, major, prerelase, 1.2.3, etc.');
15 | }
16 |
17 | return findSubmodules(project)
18 | .then((opts: TsmOptions[]) => {
19 | // 1. version all sub modules
20 | // 2. version root package
21 | const tasks = new Listr([
22 | {
23 | title: 'Version all submodules',
24 | task: () => new Listr(
25 | opts.map(opt => ({
26 | title: `npm version (${opt.pkg.name}: ${opt.src})`,
27 | task: () => npmVersion({yarn, src: opt.src, version, noGitTagVersion: true})
28 | }))
29 | )
30 | },
31 | {
32 | title: 'git add -A',
33 | task: () => execa.shell('git add -A'),
34 | skip: () => noGitTagVersion
35 | },
36 | {
37 | title: 'Version root package',
38 | task: () => npmVersion({yarn, src: '.', version, message, noGitTagVersion: true})
39 | },
40 | {
41 | title: 'Create version commit',
42 | task: () => {
43 | const pkg = require(path.resolve('package.json'));
44 | return execa.stdout('git', ['commit', '-am', message || `v${pkg.version}`]);
45 | },
46 | skip: () => noGitTagVersion
47 | },
48 | {
49 | title: 'Add tag version',
50 | task: () => {
51 | const pkg = require(path.resolve('package.json'));
52 | return execa.stdout('git', ['tag', `v${pkg.version}`]);
53 | },
54 | skip: () => noGitTagVersion
55 | },
56 | {
57 | title: 'Push to origin with tags',
58 | task: () => {
59 | const currentBranch = execa.shellSync(`git branch | sed -n '/\* /s///p'`).stdout;
60 | return execa.stdout('git', ['push', 'origin', currentBranch, '--tags'])
61 | },
62 | skip: () => skipPush
63 | }
64 | ], {renderer: verbose ? 'verbose' : 'default'});
65 |
66 | return tasks.run();
67 | });
68 | }
69 |
--------------------------------------------------------------------------------
/src/helpers/inline-resources.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // https://github.com/filipesilva/angular-quickstart-lib/blob/master/inline-resources.js
3 | 'use strict';
4 |
5 | const fs = require('fs');
6 | const path = require('path');
7 | const glob = require('glob');
8 | const sass = require('node-sass');
9 | const tildeImporter = require('node-sass-tilde-importer');
10 |
11 | /**
12 | * Simple Promiseify function that takes a Node API and return a version that supports promises.
13 | * We use promises instead of synchronized functions to make the process less I/O bound and
14 | * faster. It also simplifies the code.
15 | */
16 | function promiseify(fn): Function {
17 | return function () {
18 | const args = [].slice.call(arguments, 0);
19 | return new Promise((resolve, reject) => {
20 | fn.apply(this, args.concat([function (err, value) {
21 | if (err) {
22 | reject(err);
23 | } else {
24 | resolve(value);
25 | }
26 | }]));
27 | });
28 | };
29 | }
30 |
31 | const readFile = promiseify(fs.readFile);
32 | const writeFile = promiseify(fs.writeFile);
33 |
34 | /**
35 | * Inline resources in a tsc/ngc compilation.
36 | * @param projectPath {string} Path to the project.
37 | */
38 | export function inlineResources(projectPath) {
39 |
40 | // Match only TypeScript files in projectPath.
41 | const files = glob.sync('**/*.ts', {cwd: projectPath});
42 |
43 | // For each file, inline the templates and styles under it and write the new file.
44 | return Promise.all(files.map(filePath => {
45 | const fullFilePath = path.join(projectPath, filePath);
46 | return readFile(fullFilePath, 'utf-8')
47 | .then(content => inlineResourcesFromString(content, url => {
48 | // Resolve the template url.
49 | return path.join(path.dirname(fullFilePath), url);
50 | }))
51 | .then(content => writeFile(fullFilePath, content))
52 | .catch(err => {
53 | console.error('An error occured: ', err);
54 | });
55 | }));
56 | }
57 |
58 | /**
59 | * Inline resources from a string content.
60 | * @param content {string} The source file's content.
61 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
62 | * @returns {string} The content with resources inlined.
63 | */
64 | export function inlineResourcesFromString(content, urlResolver) {
65 | // Curry through the inlining functions.
66 | return [
67 | inlineTemplate,
68 | inlineStyle,
69 | removeModuleId
70 | ].reduce((content, fn) => fn(content, urlResolver), content);
71 | }
72 |
73 | /**
74 | * Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
75 | * replace with `template: ...` (with the content of the file included).
76 | * @param content {string} The source file's content.
77 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
78 | * @return {string} The content with all templates inlined.
79 | */
80 | function inlineTemplate(content, urlResolver) {
81 | return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function (m, templateUrl) {
82 | const templateFile = urlResolver(templateUrl);
83 | const templateContent = fs.readFileSync(templateFile, 'utf-8');
84 | const shortenedTemplate = templateContent
85 | .replace(/([\n\r]\s*)+/gm, ' ')
86 | .replace(/"/g, '\\"');
87 | return `template: "${shortenedTemplate}"`;
88 | });
89 | }
90 |
91 |
92 | /**
93 | * Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
94 | * replace with `styles: [...]` (with the content of the file included).
95 | * @param urlResolver {Function} A resolver that takes a URL and return a path.
96 | * @param content {string} The source file's content.
97 | * @return {string} The content with all styles inlined.
98 | */
99 | function inlineStyle(content, urlResolver) {
100 | return content.replace(/styleUrls\s*:\s*(\[[\s\S]*?\])/gm, function (m, styleUrls) {
101 | const urls = eval(styleUrls);
102 | return 'styles: ['
103 | + urls.map(styleUrl => {
104 | const styleFile = urlResolver(styleUrl);
105 | const originContent = fs.readFileSync(styleFile, 'utf-8');
106 | const styleContent = styleFile.endsWith('.scss') ? buildSass(originContent, styleFile) : originContent;
107 | const shortenedStyle = styleContent
108 | .replace(/([\n\r]\s*)+/gm, ' ')
109 | .replace(/\\/g, '\\\\')
110 | .replace(/"/g, '\\"');
111 | return `"${shortenedStyle}"`;
112 | })
113 | .join(',\n')
114 | + ']';
115 | });
116 | }
117 |
118 | /**
119 | * build sass content to css
120 | * @param content {string} the css content
121 | * @param sourceFile {string} the scss file sourceFile
122 | * @return {string} the generated css, empty string if error occured
123 | */
124 | function buildSass(content, sourceFile) {
125 | try {
126 | const result = sass.renderSync({
127 | data: content,
128 | file: sourceFile,
129 | importer: tildeImporter
130 | });
131 | return result.css.toString()
132 | } catch (e) {
133 | console.error('\x1b[41m');
134 | console.error('at ' + sourceFile + ':' + e.line + ":" + e.column);
135 | console.error(e.formatted);
136 | console.error('\x1b[0m');
137 | return "";
138 | }
139 | }
140 |
141 | /**
142 | * Remove every mention of `moduleId: module.id`.
143 | * @param content {string} The source file's content.
144 | * @returns {string} The content with all moduleId: mentions removed.
145 | */
146 | function removeModuleId(content) {
147 | return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
148 | }
149 |
--------------------------------------------------------------------------------
/src/lib/ngm.ts:
--------------------------------------------------------------------------------
1 | import { buildTsRun, buildCommand, npmLinkRun, npmVersionRun, npmPublishRun, npmDistTagRun } from '../commands';
2 |
3 | // command - string, cli.inputs[0]
4 | // cli - meow object
5 | export function main(command, cli) {
6 | // todo: can I generate this?
7 | return run(command, cli);
8 | }
9 |
10 | function run(command, cli) {
11 | switch (command) {
12 | case 'build': return buildTsRun(cli);
13 | case 'link': return npmLinkRun(cli);
14 | case 'version': return npmVersionRun(cli);
15 | case 'dist-tag': return npmDistTagRun(cli);
16 | case 'publish': return npmPublishRun(cli, {buildCommand});
17 | default: throw new Error(`You are using unknown command '${command}',
18 | please refer to help for a list of available commands`)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/models/rollup.globals.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | // Angular dependencies
3 | '@angular/animations': 'ng.animations',
4 | '@angular/core': 'ng.core',
5 | '@angular/common': 'ng.common',
6 | '@angular/common/http': 'ng.common.http',
7 | '@angular/forms': 'ng.forms',
8 | '@angular/http': 'ng.http',
9 | '@angular/router': 'ng.router',
10 | '@angular/platform-browser': 'ng.platformBrowser',
11 | '@angular/platform-browser-dynamic': 'ng.platformBrowserDynamic',
12 | '@angular/platform-browser/animations': 'ng.platformBrowser.animations',
13 | // RxJS dependencies
14 | 'rxjs/AnonymousSubject': 'Rx',
15 | 'rxjs/AsyncSubject': 'Rx',
16 | 'rxjs/BehaviorSubject': 'Rx',
17 | 'rxjs/Notifiction': 'Rx',
18 | 'rxjs/ObservableInput': 'Rx',
19 | 'rxjs/Observable': 'Rx',
20 | 'rxjs/Observer': 'Rx',
21 | 'rxjs/ReplaySubject': 'Rx',
22 | 'rxjs/Scheduler': 'Rx',
23 | 'rxjs/Subject': 'Rx',
24 | 'rxjs/SubjectSubscriber': 'Rx',
25 | 'rxjs/SubscribableOrPromise': 'Rx',
26 | 'rxjs/Subscriber': 'Rx',
27 | 'rxjs/Subscription': 'Rx',
28 | 'rxjs/TeardownLogic': 'Rx',
29 | 'rxjs/add/observable/bindCallback': 'Rx.Observable',
30 | 'rxjs/add/observable/bindNodeCallback': 'Rx.Observable',
31 | 'rxjs/add/observable/combineLatest': 'Rx.Observable',
32 | 'rxjs/add/observable/concat': 'Rx.Observable',
33 | 'rxjs/add/observable/create': 'Rx.Observable',
34 | 'rxjs/add/observable/defer': 'Rx.Observable',
35 | 'rxjs/add/observable/empty': 'Rx.Observable',
36 | 'rxjs/add/observable/forkJoin': 'Rx.Observable',
37 | 'rxjs/add/observable/from': 'Rx.Observable',
38 | 'rxjs/add/observable/fromEvent': 'Rx.Observable',
39 | 'rxjs/add/observable/fromEventPattern': 'Rx.Observable',
40 | 'rxjs/add/observable/fromPromise': 'Rx.Observable',
41 | 'rxjs/add/observable/interval': 'Rx.Observable',
42 | 'rxjs/add/observable/merge': 'Rx.Observable',
43 | 'rxjs/add/observable/never': 'Rx.Observable',
44 | 'rxjs/add/observable/of': 'Rx.Observable',
45 | 'rxjs/add/observable/range': 'Rx.Observable',
46 | 'rxjs/add/observable/throw': 'Rx.Observable',
47 | 'rxjs/add/observable/timer': 'Rx.Observable',
48 | 'rxjs/add/observable/webSocket': 'Rx.Observable',
49 | 'rxjs/add/observable/zip': 'Rx.Observable',
50 | 'rxjs/add/observable': 'Rx.Observable',
51 | 'rxjs/add/operator/audit': 'Rx.Observable.prototype',
52 | 'rxjs/add/operator/auditTime': 'Rx.Observable.prototype',
53 | 'rxjs/add/operator/buffer': 'Rx.Observable.prototype',
54 | 'rxjs/add/operator/bufferCount': 'Rx.Observable.prototype',
55 | 'rxjs/add/operator/bufferTime': 'Rx.Observable.prototype',
56 | 'rxjs/add/operator/bufferToggle': 'Rx.Observable.prototype',
57 | 'rxjs/add/operator/bufferWhen': 'Rx.Observable.prototype',
58 | 'rxjs/add/operator/catch': 'Rx.Observable.prototype',
59 | 'rxjs/add/operator/combineAll': 'Rx.Observable.prototype',
60 | 'rxjs/add/operator/combineLatest': 'Rx.Observable.prototype',
61 | 'rxjs/add/operator/concat': 'Rx.Observable.prototype',
62 | 'rxjs/add/operator/concatAll': 'Rx.Observable.prototype',
63 | 'rxjs/add/operator/concatMap': 'Rx.Observable.prototype',
64 | 'rxjs/add/operator/concatMapTo': 'Rx.Observable.prototype',
65 | 'rxjs/add/operator/count': 'Rx.Observable.prototype',
66 | 'rxjs/add/operator/debounce': 'Rx.Observable.prototype',
67 | 'rxjs/add/operator/debounceTime': 'Rx.Observable.prototype',
68 | 'rxjs/add/operator/defaultIfEmpty': 'Rx.Observable.prototype',
69 | 'rxjs/add/operator/delay': 'Rx.Observable.prototype',
70 | 'rxjs/add/operator/delayWhen': 'Rx.Observable.prototype',
71 | 'rxjs/add/operator/dematerialize': 'Rx.Observable.prototype',
72 | 'rxjs/add/operator/distinct': 'Rx.Observable.prototype',
73 | 'rxjs/add/operator/distinctUntilChanged': 'Rx.Observable.prototype',
74 | 'rxjs/add/operator/distinctUntilKeyChanged': 'Rx.Observable.prototype',
75 | 'rxjs/add/operator/do': 'Rx.Observable.prototype',
76 | 'rxjs/add/operator/elementAt': 'Rx.Observable.prototype',
77 | 'rxjs/add/operator/every': 'Rx.Observable.prototype',
78 | 'rxjs/add/operator/exhaust': 'Rx.Observable.prototype',
79 | 'rxjs/add/operator/exhaustMap': 'Rx.Observable.prototype',
80 | 'rxjs/add/operator/expand': 'Rx.Observable.prototype',
81 | 'rxjs/add/operator/filter': 'Rx.Observable.prototype',
82 | 'rxjs/add/operator/finally': 'Rx.Observable.prototype',
83 | 'rxjs/add/operator/find': 'Rx.Observable.prototype',
84 | 'rxjs/add/operator/findIndex': 'Rx.Observable.prototype',
85 | 'rxjs/add/operator/first': 'Rx.Observable.prototype',
86 | 'rxjs/add/operator/forEach': 'Rx.Observable.prototype',
87 | 'rxjs/add/operator/groupBy': 'Rx.Observable.prototype',
88 | 'rxjs/add/operator/ignoreElements': 'Rx.Observable.prototype',
89 | 'rxjs/add/operator/isEmpty': 'Rx.Observable.prototype',
90 | 'rxjs/add/operator/last': 'Rx.Observable.prototype',
91 | 'rxjs/add/operator/let': 'Rx.Observable.prototype',
92 | 'rxjs/add/operator/letProto': 'Rx.Observable.prototype',
93 | 'rxjs/add/operator/lift': 'Rx.Observable.prototype',
94 | 'rxjs/add/operator/map': 'Rx.Observable.prototype',
95 | 'rxjs/add/operator/mapTo': 'Rx.Observable.prototype',
96 | 'rxjs/add/operator/materialize': 'Rx.Observable.prototype',
97 | 'rxjs/add/operator/max': 'Rx.Observable.prototype',
98 | 'rxjs/add/operator/merge': 'Rx.Observable.prototype',
99 | 'rxjs/add/operator/mergeAll': 'Rx.Observable.prototype',
100 | 'rxjs/add/operator/mergeMap': 'Rx.Observable.prototype',
101 | 'rxjs/add/operator/mergeMapTo': 'Rx.Observable.prototype',
102 | 'rxjs/add/operator/mergeScan': 'Rx.Observable.prototype',
103 | 'rxjs/add/operator/min': 'Rx.Observable.prototype',
104 | 'rxjs/add/operator/multicast': 'Rx.Observable.prototype',
105 | 'rxjs/add/operator/observeOn': 'Rx.Observable.prototype',
106 | 'rxjs/add/operator/pairwise': 'Rx.Observable.prototype',
107 | 'rxjs/add/operator/partition': 'Rx.Observable.prototype',
108 | 'rxjs/add/operator/pluck': 'Rx.Observable.prototype',
109 | 'rxjs/add/operator/publish': 'Rx.Observable.prototype',
110 | 'rxjs/add/operator/publishBehavior':'Rx.Observable.prototype',
111 | 'rxjs/add/operator/publishLast': 'Rx.Observable.prototype',
112 | 'rxjs/add/operator/publishReplay': 'Rx.Observable.prototype',
113 | 'rxjs/add/operator/race': 'Rx.Observable.prototype',
114 | 'rxjs/add/operator/reduce': 'Rx.Observable.prototype',
115 | 'rxjs/add/operator/repeat': 'Rx.Observable.prototype',
116 | 'rxjs/add/operator/repeatWhen': 'Rx.Observable.prototype',
117 | 'rxjs/add/operator/retry': 'Rx.Observable.prototype',
118 | 'rxjs/add/operator/retryWhen': 'Rx.Observable.prototype',
119 | 'rxjs/add/operator/sample': 'Rx.Observable.prototype',
120 | 'rxjs/add/operator/sampleTime': 'Rx.Observable.prototype',
121 | 'rxjs/add/operator/scan': 'Rx.Observable.prototype',
122 | 'rxjs/add/operator/sequenceEqual': 'Rx.Observable.prototype',
123 | 'rxjs/add/operator/share': 'Rx.Observable.prototype',
124 | 'rxjs/add/operator/single': 'Rx.Observable.prototype',
125 | 'rxjs/add/operator/skip': 'Rx.Observable.prototype',
126 | 'rxjs/add/operator/skipUntil': 'Rx.Observable.prototype',
127 | 'rxjs/add/operator/skipWhile': 'Rx.Observable.prototype',
128 | 'rxjs/add/operator/startWith': 'Rx.Observable.prototype',
129 | 'rxjs/add/operator/subscribeOn': 'Rx.Observable.prototype',
130 | 'rxjs/add/operator/switch': 'Rx.Observable.prototype',
131 | 'rxjs/add/operator/switchMap': 'Rx.Observable.prototype',
132 | 'rxjs/add/operator/switchMapTo': 'Rx.Observable.prototype',
133 | 'rxjs/add/operator/take': 'Rx.Observable.prototype',
134 | 'rxjs/add/operator/takeLast': 'Rx.Observable.prototype',
135 | 'rxjs/add/operator/takeUntil': 'Rx.Observable.prototype',
136 | 'rxjs/add/operator/takeWhile': 'Rx.Observable.prototype',
137 | 'rxjs/add/operator/throttle': 'Rx.Observable.prototype',
138 | 'rxjs/add/operator/throttleTime': 'Rx.Observable.prototype',
139 | 'rxjs/add/operator/timeInterval': 'Rx.Observable.prototype',
140 | 'rxjs/add/operator/timeout': 'Rx.Observable.prototype',
141 | 'rxjs/add/operator/timeoutWith': 'Rx.Observable.prototype',
142 | 'rxjs/add/operator/timestamp': 'Rx.Observable.prototype',
143 | 'rxjs/add/operator/toArray': 'Rx.Observable.prototype',
144 | 'rxjs/add/operator/toPromise': 'Rx.Observable.prototype',
145 | 'rxjs/add/operator/window': 'Rx.Observable.prototype',
146 | 'rxjs/add/operator/windowCount': 'Rx.Observable.prototype',
147 | 'rxjs/add/operator/windowToggle': 'Rx.Observable.prototype',
148 | 'rxjs/add/operator/windowWhen': 'Rx.Observable.prototype',
149 | 'rxjs/add/operator/withLatestFrom': 'Rx.Observable.prototype',
150 | 'rxjs/add/operator/zipAll': 'Rx.Observable.prototype',
151 | 'rxjs/add/operator/zipProto': 'Rx.Observable.prototype',
152 | 'rxjs/add/operator': 'Rx.Observable.prototype',
153 | 'rxjs/observable/bindCallback': 'Rx.Observable',
154 | 'rxjs/observable/bindNodeCallback': 'Rx.Observable',
155 | 'rxjs/observable/combineLatest': 'Rx.Observable',
156 | 'rxjs/observable/concat': 'Rx.Observable',
157 | 'rxjs/observable/defer': 'Rx.Observable',
158 | 'rxjs/observable/empty': 'Rx.Observable',
159 | 'rxjs/observable/forkJoin': 'Rx.Observable',
160 | 'rxjs/observable/from': 'Rx.Observable',
161 | 'rxjs/observable/fromEvent': 'Rx.Observable',
162 | 'rxjs/observable/fromEventPattern': 'Rx.Observable',
163 | 'rxjs/observable/fromPromise': 'Rx.Observable',
164 | 'rxjs/observable/if': 'Rx.Observable',
165 | 'rxjs/observable/interval': 'Rx.Observable',
166 | 'rxjs/observable/merge': 'Rx.Observable',
167 | 'rxjs/observable/never': 'Rx.Observable',
168 | 'rxjs/observable/of': 'Rx.Observable',
169 | 'rxjs/observable/pairs': 'Rx.Observable',
170 | 'rxjs/observable/range': 'Rx.Observable',
171 | 'rxjs/observable/throw': 'Rx.Observable',
172 | 'rxjs/observable/timer': 'Rx.Observable',
173 | 'rxjs/observable/using': 'Rx.Observable',
174 | 'rxjs/observable/zip': 'Rx.Observable',
175 | 'rxjs/observable': 'Rx.Observable',
176 | 'rxjs/operator/audit': 'Rx.Observable.prototype',
177 | 'rxjs/operator/auditTime': 'Rx.Observable.prototype',
178 | 'rxjs/operator/buffer': 'Rx.Observable.prototype',
179 | 'rxjs/operator/bufferCount': 'Rx.Observable.prototype',
180 | 'rxjs/operator/bufferTime': 'Rx.Observable.prototype',
181 | 'rxjs/operator/bufferToggle': 'Rx.Observable.prototype',
182 | 'rxjs/operator/bufferWhen': 'Rx.Observable.prototype',
183 | 'rxjs/operator/catch': 'Rx.Observable.prototype',
184 | 'rxjs/operator/combineAll': 'Rx.Observable.prototype',
185 | 'rxjs/operator/combineLatest': 'Rx.Observable.prototype',
186 | 'rxjs/operator/concat': 'Rx.Observable.prototype',
187 | 'rxjs/operator/concatAll': 'Rx.Observable.prototype',
188 | 'rxjs/operator/concatMap': 'Rx.Observable.prototype',
189 | 'rxjs/operator/concatMapTo': 'Rx.Observable.prototype',
190 | 'rxjs/operator/count': 'Rx.Observable.prototype',
191 | 'rxjs/operator/debounce': 'Rx.Observable.prototype',
192 | 'rxjs/operator/debounceTime': 'Rx.Observable.prototype',
193 | 'rxjs/operator/defaultIfEmpty': 'Rx.Observable.prototype',
194 | 'rxjs/operator/delay': 'Rx.Observable.prototype',
195 | 'rxjs/operator/delayWhen': 'Rx.Observable.prototype',
196 | 'rxjs/operator/dematerialize': 'Rx.Observable.prototype',
197 | 'rxjs/operator/distinct': 'Rx.Observable.prototype',
198 | 'rxjs/operator/distinctUntilChanged': 'Rx.Observable.prototype',
199 | 'rxjs/operator/distinctUntilKeyChanged': 'Rx.Observable.prototype',
200 | 'rxjs/operator/do': 'Rx.Observable.prototype',
201 | 'rxjs/operator/elementAt': 'Rx.Observable.prototype',
202 | 'rxjs/operator/every': 'Rx.Observable.prototype',
203 | 'rxjs/operator/exhaust': 'Rx.Observable.prototype',
204 | 'rxjs/operator/exhaustMap': 'Rx.Observable.prototype',
205 | 'rxjs/operator/expand': 'Rx.Observable.prototype',
206 | 'rxjs/operator/filter': 'Rx.Observable.prototype',
207 | 'rxjs/operator/finally': 'Rx.Observable.prototype',
208 | 'rxjs/operator/find': 'Rx.Observable.prototype',
209 | 'rxjs/operator/findIndex': 'Rx.Observable.prototype',
210 | 'rxjs/operator/first': 'Rx.Observable.prototype',
211 | 'rxjs/operator/forEach': 'Rx.Observable.prototype',
212 | 'rxjs/operator/groupBy': 'Rx.Observable.prototype',
213 | 'rxjs/operator/ignoreElements': 'Rx.Observable.prototype',
214 | 'rxjs/operator/isEmpty': 'Rx.Observable.prototype',
215 | 'rxjs/operator/last': 'Rx.Observable.prototype',
216 | 'rxjs/operator/let': 'Rx.Observable.prototype',
217 | 'rxjs/operator/letProto': 'Rx.Observable.prototype',
218 | 'rxjs/operator/lift': 'Rx.Observable.prototype',
219 | 'rxjs/operator/map': 'Rx.Observable.prototype',
220 | 'rxjs/operator/mapTo': 'Rx.Observable.prototype',
221 | 'rxjs/operator/materialize': 'Rx.Observable.prototype',
222 | 'rxjs/operator/max': 'Rx.Observable.prototype',
223 | 'rxjs/operator/merge': 'Rx.Observable.prototype',
224 | 'rxjs/operator/mergeAll': 'Rx.Observable.prototype',
225 | 'rxjs/operator/mergeMap': 'Rx.Observable.prototype',
226 | 'rxjs/operator/mergeMapTo': 'Rx.Observable.prototype',
227 | 'rxjs/operator/mergeScan': 'Rx.Observable.prototype',
228 | 'rxjs/operator/min': 'Rx.Observable.prototype',
229 | 'rxjs/operator/multicast': 'Rx.Observable.prototype',
230 | 'rxjs/operator/observeOn': 'Rx.Observable.prototype',
231 | 'rxjs/operator/pairwise': 'Rx.Observable.prototype',
232 | 'rxjs/operator/partition': 'Rx.Observable.prototype',
233 | 'rxjs/operator/pluck': 'Rx.Observable.prototype',
234 | 'rxjs/operator/publish': 'Rx.Observable.prototype',
235 | 'rxjs/operator/publishBehavior':'Rx.Observable.prototype',
236 | 'rxjs/operator/publishLast': 'Rx.Observable.prototype',
237 | 'rxjs/operator/publishReplay': 'Rx.Observable.prototype',
238 | 'rxjs/operator/race': 'Rx.Observable.prototype',
239 | 'rxjs/operator/reduce': 'Rx.Observable.prototype',
240 | 'rxjs/operator/repeat': 'Rx.Observable.prototype',
241 | 'rxjs/operator/repeatWhen': 'Rx.Observable.prototype',
242 | 'rxjs/operator/retry': 'Rx.Observable.prototype',
243 | 'rxjs/operator/retryWhen': 'Rx.Observable.prototype',
244 | 'rxjs/operator/sample': 'Rx.Observable.prototype',
245 | 'rxjs/operator/sampleTime': 'Rx.Observable.prototype',
246 | 'rxjs/operator/scan': 'Rx.Observable.prototype',
247 | 'rxjs/operator/sequenceEqual': 'Rx.Observable.prototype',
248 | 'rxjs/operator/share': 'Rx.Observable.prototype',
249 | 'rxjs/operator/single': 'Rx.Observable.prototype',
250 | 'rxjs/operator/skip': 'Rx.Observable.prototype',
251 | 'rxjs/operator/skipUntil': 'Rx.Observable.prototype',
252 | 'rxjs/operator/skipWhile': 'Rx.Observable.prototype',
253 | 'rxjs/operator/startWith': 'Rx.Observable.prototype',
254 | 'rxjs/operator/subscribeOn': 'Rx.Observable.prototype',
255 | 'rxjs/operator/switch': 'Rx.Observable.prototype',
256 | 'rxjs/operator/switchMap': 'Rx.Observable.prototype',
257 | 'rxjs/operator/switchMapTo': 'Rx.Observable.prototype',
258 | 'rxjs/operator/take': 'Rx.Observable.prototype',
259 | 'rxjs/operator/takeLast': 'Rx.Observable.prototype',
260 | 'rxjs/operator/takeUntil': 'Rx.Observable.prototype',
261 | 'rxjs/operator/takeWhile': 'Rx.Observable.prototype',
262 | 'rxjs/operator/throttle': 'Rx.Observable.prototype',
263 | 'rxjs/operator/throttleTime': 'Rx.Observable.prototype',
264 | 'rxjs/operator/timeInterval': 'Rx.Observable.prototype',
265 | 'rxjs/operator/timeout': 'Rx.Observable.prototype',
266 | 'rxjs/operator/timeoutWith': 'Rx.Observable.prototype',
267 | 'rxjs/operator/timestamp': 'Rx.Observable.prototype',
268 | 'rxjs/operator/toArray': 'Rx.Observable.prototype',
269 | 'rxjs/operator/toPromise': 'Rx.Observable.prototype',
270 | 'rxjs/operator/window': 'Rx.Observable.prototype',
271 | 'rxjs/operator/windowCount': 'Rx.Observable.prototype',
272 | 'rxjs/operator/windowToggle': 'Rx.Observable.prototype',
273 | 'rxjs/operator/windowWhen': 'Rx.Observable.prototype',
274 | 'rxjs/operator/withLatestFrom': 'Rx.Observable.prototype',
275 | 'rxjs/operator/zipAll': 'Rx.Observable.prototype',
276 | 'rxjs/operator/zipProto': 'Rx.Observable.prototype',
277 | 'rxjs/operator': 'Rx.Observable.prototype',
278 | 'rxjs/operators/audit': 'Rx.Observable.prototype',
279 | 'rxjs/operators/auditTime': 'Rx.Observable.prototype',
280 | 'rxjs/operators/buffer': 'Rx.Observable.prototype',
281 | 'rxjs/operators/bufferCount': 'Rx.Observable.prototype',
282 | 'rxjs/operators/bufferTime': 'Rx.Observable.prototype',
283 | 'rxjs/operators/bufferToggle': 'Rx.Observable.prototype',
284 | 'rxjs/operators/bufferWhen': 'Rx.Observable.prototype',
285 | 'rxjs/operators/catch': 'Rx.Observable.prototype',
286 | 'rxjs/operators/combineAll': 'Rx.Observable.prototype',
287 | 'rxjs/operators/combineLatest': 'Rx.Observable.prototype',
288 | 'rxjs/operators/concat': 'Rx.Observable.prototype',
289 | 'rxjs/operators/concatAll': 'Rx.Observable.prototype',
290 | 'rxjs/operators/concatMap': 'Rx.Observable.prototype',
291 | 'rxjs/operators/concatMapTo': 'Rx.Observable.prototype',
292 | 'rxjs/operators/count': 'Rx.Observable.prototype',
293 | 'rxjs/operators/debounce': 'Rx.Observable.prototype',
294 | 'rxjs/operators/debounceTime': 'Rx.Observable.prototype',
295 | 'rxjs/operators/defaultIfEmpty': 'Rx.Observable.prototype',
296 | 'rxjs/operators/delay': 'Rx.Observable.prototype',
297 | 'rxjs/operators/delayWhen': 'Rx.Observable.prototype',
298 | 'rxjs/operators/dematerialize': 'Rx.Observable.prototype',
299 | 'rxjs/operators/distinct': 'Rx.Observable.prototype',
300 | 'rxjs/operators/distinctUntilChanged': 'Rx.Observable.prototype',
301 | 'rxjs/operators/distinctUntilKeyChanged': 'Rx.Observable.prototype',
302 | 'rxjs/operators/do': 'Rx.Observable.prototype',
303 | 'rxjs/operators/elementAt': 'Rx.Observable.prototype',
304 | 'rxjs/operators/every': 'Rx.Observable.prototype',
305 | 'rxjs/operators/exhaust': 'Rx.Observable.prototype',
306 | 'rxjs/operators/exhaustMap': 'Rx.Observable.prototype',
307 | 'rxjs/operators/expand': 'Rx.Observable.prototype',
308 | 'rxjs/operators/filter': 'Rx.Observable.prototype',
309 | 'rxjs/operators/finally': 'Rx.Observable.prototype',
310 | 'rxjs/operators/find': 'Rx.Observable.prototype',
311 | 'rxjs/operators/findIndex': 'Rx.Observable.prototype',
312 | 'rxjs/operators/first': 'Rx.Observable.prototype',
313 | 'rxjs/operators/forEach': 'Rx.Observable.prototype',
314 | 'rxjs/operators/groupBy': 'Rx.Observable.prototype',
315 | 'rxjs/operators/ignoreElements': 'Rx.Observable.prototype',
316 | 'rxjs/operators/isEmpty': 'Rx.Observable.prototype',
317 | 'rxjs/operators/last': 'Rx.Observable.prototype',
318 | 'rxjs/operators/let': 'Rx.Observable.prototype',
319 | 'rxjs/operators/letProto': 'Rx.Observable.prototype',
320 | 'rxjs/operators/lift': 'Rx.Observable.prototype',
321 | 'rxjs/operators/map': 'Rx.Observable.prototype',
322 | 'rxjs/operators/mapTo': 'Rx.Observable.prototype',
323 | 'rxjs/operators/materialize': 'Rx.Observable.prototype',
324 | 'rxjs/operators/max': 'Rx.Observable.prototype',
325 | 'rxjs/operators/merge': 'Rx.Observable.prototype',
326 | 'rxjs/operators/mergeAll': 'Rx.Observable.prototype',
327 | 'rxjs/operators/mergeMap': 'Rx.Observable.prototype',
328 | 'rxjs/operators/mergeMapTo': 'Rx.Observable.prototype',
329 | 'rxjs/operators/mergeScan': 'Rx.Observable.prototype',
330 | 'rxjs/operators/min': 'Rx.Observable.prototype',
331 | 'rxjs/operators/multicast': 'Rx.Observable.prototype',
332 | 'rxjs/operators/observeOn': 'Rx.Observable.prototype',
333 | 'rxjs/operators/pairwise': 'Rx.Observable.prototype',
334 | 'rxjs/operators/partition': 'Rx.Observable.prototype',
335 | 'rxjs/operators/pluck': 'Rx.Observable.prototype',
336 | 'rxjs/operators/publish': 'Rx.Observable.prototype',
337 | 'rxjs/operators/publishBehavior':'Rx.Observable.prototype',
338 | 'rxjs/operators/publishLast': 'Rx.Observable.prototype',
339 | 'rxjs/operators/publishReplay': 'Rx.Observable.prototype',
340 | 'rxjs/operators/race': 'Rx.Observable.prototype',
341 | 'rxjs/operators/reduce': 'Rx.Observable.prototype',
342 | 'rxjs/operators/repeat': 'Rx.Observable.prototype',
343 | 'rxjs/operators/repeatWhen': 'Rx.Observable.prototype',
344 | 'rxjs/operators/retry': 'Rx.Observable.prototype',
345 | 'rxjs/operators/retryWhen': 'Rx.Observable.prototype',
346 | 'rxjs/operators/sample': 'Rx.Observable.prototype',
347 | 'rxjs/operators/sampleTime': 'Rx.Observable.prototype',
348 | 'rxjs/operators/scan': 'Rx.Observable.prototype',
349 | 'rxjs/operators/sequenceEqual': 'Rx.Observable.prototype',
350 | 'rxjs/operators/share': 'Rx.Observable.prototype',
351 | 'rxjs/operators/single': 'Rx.Observable.prototype',
352 | 'rxjs/operators/skip': 'Rx.Observable.prototype',
353 | 'rxjs/operators/skipUntil': 'Rx.Observable.prototype',
354 | 'rxjs/operators/skipWhile': 'Rx.Observable.prototype',
355 | 'rxjs/operators/startWith': 'Rx.Observable.prototype',
356 | 'rxjs/operators/subscribeOn': 'Rx.Observable.prototype',
357 | 'rxjs/operators/switch': 'Rx.Observable.prototype',
358 | 'rxjs/operators/switchMap': 'Rx.Observable.prototype',
359 | 'rxjs/operators/switchMapTo': 'Rx.Observable.prototype',
360 | 'rxjs/operators/take': 'Rx.Observable.prototype',
361 | 'rxjs/operators/takeLast': 'Rx.Observable.prototype',
362 | 'rxjs/operators/takeUntil': 'Rx.Observable.prototype',
363 | 'rxjs/operators/takeWhile': 'Rx.Observable.prototype',
364 | 'rxjs/operators/throttle': 'Rx.Observable.prototype',
365 | 'rxjs/operators/throttleTime': 'Rx.Observable.prototype',
366 | 'rxjs/operators/timeInterval': 'Rx.Observable.prototype',
367 | 'rxjs/operators/timeout': 'Rx.Observable.prototype',
368 | 'rxjs/operators/timeoutWith': 'Rx.Observable.prototype',
369 | 'rxjs/operators/timestamp': 'Rx.Observable.prototype',
370 | 'rxjs/operators/toArray': 'Rx.Observable.prototype',
371 | 'rxjs/operators/toPromise': 'Rx.Observable.prototype',
372 | 'rxjs/operators/window': 'Rx.Observable.prototype',
373 | 'rxjs/operators/windowCount': 'Rx.Observable.prototype',
374 | 'rxjs/operators/windowToggle': 'Rx.Observable.prototype',
375 | 'rxjs/operators/windowWhen': 'Rx.Observable.prototype',
376 | 'rxjs/operators/withLatestFrom': 'Rx.Observable.prototype',
377 | 'rxjs/operators/zipAll': 'Rx.Observable.prototype',
378 | 'rxjs/operators/zipProto': 'Rx.Observable.prototype',
379 | 'rxjs/operators': 'Rx.Observable.prototype',
380 | 'rxjs/symbol/iterator': 'Rx.Symbol',
381 | 'rxjs/symbol/observable': 'Rx.Symbol',
382 | 'rxjs/symbol/rxSubscriber': 'Rx.Symbol',
383 | 'rxjs/symbol': 'Rx.Symbol',
384 | 'rxjs/scheduler/Action': 'Rx.Scheduler',
385 | 'rxjs/scheduler/animationFrame': 'Rx.Scheduler',
386 | 'rxjs/scheduler/AnimationFrameAction': 'Rx.Scheduler',
387 | 'rxjs/scheduler/asap': 'Rx.Scheduler',
388 | 'rxjs/scheduler/AsapAction': 'Rx.Scheduler',
389 | 'rxjs/scheduler/async': 'Rx.Scheduler',
390 | 'rxjs/scheduler/AsyncAction': 'Rx.Scheduler',
391 | 'rxjs/scheduler/AsyncScheduler': 'Rx.Scheduler',
392 | 'rxjs/scheduler/queue': 'Rx.Scheduler',
393 | 'rxjs/scheduler/QueueAction': 'Rx.Scheduler',
394 | 'rxjs/scheduler/QueueScheduler': 'Rx.Scheduler',
395 | 'rxjs/scheduler/VirtualTimeScheduler': 'Rx.Scheduler',
396 | 'rxjs/scheduler': 'Rx.Scheduler'
397 | };
398 |
--------------------------------------------------------------------------------
/src/models/webpack-umd.config.ts:
--------------------------------------------------------------------------------
1 | import webpack = require('webpack');
2 | // const TsConfigPathsPlugin = require('awesome-typescript-loader').TsConfigPathsPlugin;
3 |
4 | export function getWebpackConfig(config) {
5 | return {
6 | mode: 'production',
7 | devtool: 'source-map',
8 |
9 | resolve: {
10 | extensions: ['.ts', '.js']
11 | },
12 |
13 | entry: config.entry,
14 |
15 | output: {
16 | path: config.output,
17 | publicPath: '/',
18 | filename: `${config.name}.js`,
19 | libraryTarget: 'umd',
20 | library: config.name
21 | },
22 |
23 | // require those dependencies but don't bundle them
24 | externals: [/^\@angular\//, /^rxjs\//],
25 |
26 | module: {
27 | rules: [
28 | {
29 | test: /\.ts$/,
30 | loader: `ts-loader`,
31 | exclude: [/\.e2e\.ts$/],
32 | options: {
33 | transpileOnly: true,
34 | configFile: config.tsconfig,
35 | compilerOptions: {
36 | declaration: false,
37 | emitDecoratorMetadata: false
38 | },
39 | }
40 | },
41 | // in main, load css as raw text
42 | {
43 | // exclude: styles,
44 | test: /\.css$/,
45 | loaders: ['raw-loader', 'postcss-loader']
46 | }, {
47 | // exclude: styles,
48 | test: /\.styl$/,
49 | loaders: ['raw-loader', 'postcss-loader', 'stylus-loader']
50 | },
51 | {
52 | // exclude: styles,
53 | test: /\.less$/,
54 | loaders: ['raw-loader', 'postcss-loader', 'less-loader']
55 | }, {
56 | // exclude: styles,
57 | test: /\.scss$|\.sass$/,
58 | loaders: ['raw-loader', 'postcss-loader', 'sass-loader']
59 | }
60 | ]
61 | },
62 |
63 | plugins: [
64 | // new TsConfigPathsPlugin(),
65 | // fix the warning in ./~/@angular/core/src/linker/system_js_ng_module_factory_loader.js
66 | new webpack.ContextReplacementPlugin(
67 | /angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
68 | config.root
69 | )
70 | ],
71 |
72 | optimization: {
73 | minimize: false
74 | },
75 | // Hide webpack output because its noisy.
76 | // noInfo: true,
77 | // Also prevent chunk and module display output, cleaner look. Only emit errors.
78 | stats: 'errors-only',
79 | devServer: {
80 | stats: 'errors-only'
81 | },
82 | };
83 | };
84 |
--------------------------------------------------------------------------------
/src/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngm-cli",
3 | "bin": {
4 | "ngm": "bin/ngm-cli.js"
5 | },
6 | "peerDependencies": {
7 | "@angular/compiler-cli": "*",
8 | "awesome-typescript-loader": "*",
9 | "webpack": "*",
10 | "typescript": "*"
11 | },
12 | "dependencies": {
13 | "node-sass": "*",
14 | "node-sass-tilde-importer": "*",
15 | "chalk": "*",
16 | "cpy": "*",
17 | "del": "*",
18 | "execa": "*",
19 | "inquirer": "*",
20 | "listr": "*",
21 | "lodash": "*",
22 | "meow": "*",
23 | "read-pkg": "*",
24 | "rollup": "*",
25 | "rollup-plugin-commonjs": "*",
26 | "rollup-plugin-node-resolve": "*",
27 | "semver": "*",
28 | "split": "*",
29 | "stream-to-observable": "*",
30 | "tsconfig": "*",
31 | "update-notifier": "*",
32 | "write-pkg": "*"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/tasks/build.task.ts:
--------------------------------------------------------------------------------
1 | const execa = require('execa');
2 |
3 | export function build(project:string) {
4 | return execa('ngc', ['-p', project], {preferLocal: true});
5 | }
6 |
--------------------------------------------------------------------------------
/src/tasks/bundle-es2015.ts:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const execa = require('execa');
3 | const rollup = require('rollup');
4 | const resolve = require('rollup-plugin-node-resolve');
5 | const commonjs = require('rollup-plugin-commonjs');
6 |
7 | import { inlineResources } from '../helpers/inline-resources';
8 | import ROLLUP_GLOBALS from '../models/rollup.globals';
9 |
10 | const bundlesDir = 'bundles';
11 |
12 |
13 | export async function bundleEs2015(config) {
14 | await inlineResources(config.tmp);
15 | await execa('ngc', ['-p', config.tmp], { preferLocal: true });
16 | return rollup.rollup({
17 | input: path.resolve(config.tmp, 'dist-es2015', config.input.replace('.ts', '')),
18 | external: Object.keys(ROLLUP_GLOBALS),
19 | plugins: [
20 | resolve({
21 | module: true,
22 | main: true
23 | }),
24 | commonjs({
25 | include: 'node_modules/**',
26 | })
27 | ],
28 | onwarn: warning => {
29 | const skip_codes = [
30 | 'THIS_IS_UNDEFINED',
31 | 'MISSING_GLOBAL_NAME'
32 | ];
33 | if (skip_codes.indexOf(warning.code) != -1) return;
34 | console.error(warning);
35 | }
36 | }).then(bundle => bundle.write({
37 | file: path.resolve(config.dist, bundlesDir, config.name + '.es2015.js'),
38 | name: config.name,
39 | format: 'es',
40 | sourcemap: true
41 | }));
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/src/tasks/bundle-umd.task.ts:
--------------------------------------------------------------------------------
1 | import path = require('path');
2 | import { ROOT } from '../utils';
3 | import { getWebpackConfig } from '../models/webpack-umd.config';
4 | const webpack = require('webpack');
5 |
6 | // todo: move to constants and make it configurable
7 | const bundlesDir = 'bundles';
8 |
9 | // Configure build and output;
10 | let lastHash = null;
11 | const webpackOutputOptions = {
12 | colors: true,
13 | chunks: true,
14 | modules: false,
15 | reasons: false,
16 | chunkModules: false
17 | };
18 |
19 | // export function bundleUmd(dir, moduleConf, minify) {
20 | export function bundleUmd({src, dist, name, main, tsconfig, minify}) {
21 | const config = getWebpackConfig({
22 | name: !minify ? `${name}.umd` : `${name}.umd.min`,
23 | root: path.resolve(ROOT, src),
24 | entry: path.resolve(ROOT, src, main),
25 | output: path.resolve(dist, bundlesDir),
26 | tsconfig: tsconfig
27 | });
28 |
29 | if (minify) {
30 | config.optimization.minimize = true;
31 | }
32 |
33 | const webpackCompiler = webpack(config);
34 |
35 | return new Promise((resolve, reject) => {
36 | webpackCompiler.run((err, stats) => {
37 | if (err) {
38 | if (stats) {
39 | process.stdout.write(stats.toString(webpackOutputOptions) + '\n');
40 | }
41 | return reject(err);
42 | }
43 |
44 | if (stats.hasErrors()) {
45 | process.stdout.write(stats.toString(webpackOutputOptions) + '\n');
46 | }
47 |
48 | return stats.hasErrors() ? reject() : resolve();
49 | });
50 | });
51 | }
52 |
--------------------------------------------------------------------------------
/src/tasks/clean-dist.task.ts:
--------------------------------------------------------------------------------
1 | // import { TsmOptions } from '../types';
2 |
3 | export function cleanDist(opts: TsmOptions[]){
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/src/tasks/index.ts:
--------------------------------------------------------------------------------
1 | export { build } from './build.task';
2 | export { bundleUmd } from './bundle-umd.task';
3 | export { bundleEs2015 } from './bundle-es2015';
4 | export * from './npm';
5 | export { cleanDist } from './clean-dist.task';
6 | export { prepublishGitCheck } from './prepublish-git-check.task';
7 |
--------------------------------------------------------------------------------
/src/tasks/npm/build-pkg-json.task.ts:
--------------------------------------------------------------------------------
1 | import path = require('path');
2 | import { ROOT } from '../../utils/constants';
3 | import { mergePackageJson} from '../../utils/merge-package-json';
4 | // import { TsmOptions } from '../../types';
5 | // todo: replace
6 | const readPkg = require('read-pkg');
7 | const writePkg = require('write-pkg');
8 |
9 | /**
10 | * Smart merge of package.json files like Object.assign({}, src, dist)
11 | * @param opts
12 | * @param localDependencies
13 | * @param options
14 | */
15 | export function buildPkgJson(opts:TsmOptions, localDependencies, options: {local: boolean}) {
16 | // read base package.json
17 | const base = readPkg.sync(ROOT);
18 | // read package.json in module root folder
19 | const module = readPkg.sync(opts.src);
20 | // merge packages
21 | localDependenciesVersionFallback(base, localDependencies);
22 | const pkg = mergePackageJson({base, module, localDependencies});
23 | pkg.version = pkg.version || base.version;
24 | // write packages
25 | // todo: for some reason, read pkg ignores readme.md and says that readme not found, and this is not true
26 | delete pkg.readme;
27 | return writePkg(opts.dist, pkg);
28 | }
29 |
30 | /**
31 | *
32 | * @param tsmOptions
33 | * @param options
34 | */
35 | export function buildPkgs(tsmOptions:TsmOptions[], options: {local: boolean}) {
36 | // 0. read base package.json
37 | // 1. read all sub module packages
38 | // 2. include sub module versions in modules hash
39 | // if options.local === true, resolve local dependencies as file paths: "module-a": "../module-a"
40 | // in general you need non relative dependencies only before publishing
41 | const localDependencies = tsmOptions.reduce((memo, val)=>{
42 | memo[val.pkg.name] = !options.local ? val.pkg.version : path.resolve(val.dist);
43 | return memo;
44 | }, {});
45 | // 3. merge packages
46 | return Promise.all(tsmOptions.map(optPkg => buildPkgJson(optPkg, localDependencies, options)));
47 | // 4. validate required fields in packages
48 | // todo:
49 | }
50 |
51 | function localDependenciesVersionFallback(base, localDependencies) {
52 | for (let pkgName in localDependencies) {
53 | localDependencies[pkgName] = localDependencies[pkgName] || base.version;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/tasks/npm/index.ts:
--------------------------------------------------------------------------------
1 | export { buildPkgJson, buildPkgs } from './build-pkg-json.task';
2 | // export {} from './npm-dist-tag'
3 | export { npmInstall } from './npm-install.task';
4 | export { npmLink } from './npm-link.task';
5 | export { npmPublish } from './npm-publish.task';
6 | export { npmVersion } from './npm-version.task';
7 | export { npmDistTag } from './npm-dist-tag.task';
--------------------------------------------------------------------------------
/src/tasks/npm/npm-dist-tag.task.ts:
--------------------------------------------------------------------------------
1 | // npm dist-tag add @ []
2 | // npm dist-tag rm
3 | // npm dist-tag ls []opt.dist
4 | import path = require('path');
5 | const execa = require('execa');
6 |
7 | export function npmDistTag({yarn, cmd, module, version, tag = ''}) {
8 | // const npm = yarn ? 'yarn' : 'npm';
9 | const pkg = cmd === 'add' ? `${module}@${version}` : module;
10 | return execa.shell(['npm', 'dist-tag', cmd, pkg, tag].join(' '))
11 | .then(res => {
12 | console.log(`Package ${module}`);
13 | console.log(res.stdout);
14 | });
15 | }
--------------------------------------------------------------------------------
/src/tasks/npm/npm-install.task.ts:
--------------------------------------------------------------------------------
1 | const del = require('del');
2 | const execa = require('execa');
3 | import Listr = require('listr');
4 | import ListrTask = require('listr');
5 |
6 | export function npmInstall({skipCleanup, yarn}) {
7 | return yarn ?
8 | // if yarn
9 | [{
10 | title: 'Clean install dependencies',
11 | task: () => execa('yarn', [skipCleanup ? '' : 'upgrade'])
12 | }]
13 | // else npm
14 | : [
15 | {
16 | title: 'Node modules cleanup',
17 | task: () => del('node_modules'),
18 | skip: () => skipCleanup
19 | },
20 | {
21 | // todo: maybe install only dev dependencies
22 | title: 'Installing dependencies',
23 | task: () => execa('npm', ['install']),
24 | skip: () => skipCleanup
25 | }
26 | ];
27 | }
28 |
--------------------------------------------------------------------------------
/src/tasks/npm/npm-link.task.ts:
--------------------------------------------------------------------------------
1 | import path = require('path');
2 | const execa = require('execa');
3 |
4 | export function npmLink({cwd, yarn, module = ''}) {
5 | // const npm = yarn ? 'yarn' : 'npm';
6 | return execa.shell(['npm', 'link', module].join(' '), {
7 | cwd: path.resolve(cwd)
8 | });
9 | }
--------------------------------------------------------------------------------
/src/tasks/npm/npm-publish.task.ts:
--------------------------------------------------------------------------------
1 | const execa = require('execa');
2 |
3 | export function npmPublish({cwd, yarn, tag = '', access = ''}) {
4 | // const args = [yarn ? 'yarn --new-version' : 'npm', 'publish', cwd];
5 | // todo: next time yarn, next time
6 | const args = ['npm', 'publish', cwd];
7 | if (tag) {
8 | args.push('--tag', tag);
9 | }
10 | if (access) {
11 | args.push('--access', access);
12 | }
13 | return execa.shell(args.join(' '), {preferLocal: true});
14 | }
15 |
--------------------------------------------------------------------------------
/src/tasks/npm/npm-version.task.ts:
--------------------------------------------------------------------------------
1 | import path = require('path');
2 | const execa = require('execa');
3 |
4 | export function npmVersion({yarn, src, version, noGitTagVersion, message = ''}) {
5 | // we just updated subpackages versions, so working dir is not clean
6 | // but we knew it and using --force flag
7 | // so it will produce error: npm WARN using --force I sure hope you know what you are doing.
8 | // and we can swallow it
9 | const args = [' ', '--force'];
10 | const command = yarn
11 | ? `yarn version --new-version ${version}`
12 | : `npm version ${version}`;
13 | if (message && !yarn) {
14 | args.push('-m', `"${message}"`);
15 | }
16 | if (noGitTagVersion) {
17 | args.push('--no-git-tag-version');
18 | }
19 | const cmd = command + args.join(' ');
20 | return new Promise(resolve => execa.shell(cmd, {cwd: path.resolve(src)})
21 | .then(resolve).catch(resolve));
22 | }
23 |
--------------------------------------------------------------------------------
/src/tasks/prepublish-git-check.task.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * This file was copied from https://github.com/sindresorhus/np/blob/858f3c6481ad63c31f98ce2597fe92e431adb91b/lib/git.js
3 | * @licence MIT
4 | * @copyright Sindre Sorhus (sindresorhus.com)
5 | * @author Sam Verschueren
6 | * @author Zeke Sikelianos
7 | */
8 |
9 | const execa = require('execa');
10 | const Listr = require('listr');
11 |
12 | export function prepublishGitCheck({anyBranch}) {
13 | const tasks = [
14 | {
15 | title: 'Check current branch',
16 | task: () => execa.stdout('git', ['symbolic-ref', '--short', 'HEAD']).then(branch => {
17 | if (branch !== 'master') {
18 | throw new Error('Not on `master` branch. Use --any-branch to publish anyway.');
19 | }
20 | }),
21 | skip: () => anyBranch
22 | },
23 | {
24 | title: 'Check local working tree',
25 | task: () => execa.stdout('git', ['status', '--porcelain']).then(status => {
26 | if (status !== '') {
27 | throw new Error('Unclean working tree. Commit or stash changes first.');
28 | }
29 | })
30 | },
31 | {
32 | title: 'Check remote history',
33 | task: () => execa.stdout('git', ['rev-list', '--count', '--left-only', '@{u}...HEAD']).then(result => {
34 | if (result !== '0') {
35 | throw new Error('Remote history differs. Please pull changes.');
36 | }
37 | })
38 | }
39 | ];
40 |
41 | return new Listr(tasks);
42 | }
--------------------------------------------------------------------------------
/src/test/e2e.ts:
--------------------------------------------------------------------------------
1 | import { bundleUmd } from '../tasks';
2 |
3 | // build -p e2e/ngm-single/src --main index.ts
4 |
5 | const main = 'index.ts';
6 | const opt = {
7 | src: 'e2e/ngm-single/src',
8 | dist: 'e2e/ngm-single/dist',
9 | pkg: {name: 'ng2-module'},
10 | tsconfig: {config: {}, path: 'e2e/ngm-single/src/tsconfig.json'}
11 | };
12 |
13 | bundleUmd({
14 | src: opt.src,
15 | dist: opt.dist,
16 | name: opt.pkg.name,
17 | tsconfig: opt.tsconfig.path,
18 | main,
19 | minify: false
20 | });
21 |
--------------------------------------------------------------------------------
/src/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "../dist",
4 | "module": "commonjs",
5 | "target": "es6",
6 | "declaration" :true,
7 | "inlineSourceMap": true,
8 | "moduleResolution": "node",
9 | "noEmitHelpers": false,
10 | "noImplicitAny": false,
11 | "skipLibCheck": true,
12 | "skipDefaultLibCheck": true,
13 | "stripInternal": true,
14 | "noEmitOnError": false,
15 | "removeComments": false,
16 | "lib": ["dom", "es6"],
17 | "typeRoots": ["../../node_modules/@types"],
18 | "types": ["node", "webpack"],
19 | "baseUrl": ""
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------
1 | // todo: export to some typings
2 | // todo: add documentation
3 | declare interface TsmOptions {
4 | src: string;
5 | dist: string;
6 | tmp: string;
7 | project: string;
8 | pkg: any;
9 | /**
10 | * Array of local cross dependencies
11 | * */
12 | cross?: string[];
13 | tsconfig: {path: string; config: any;}
14 | }
15 |
16 | declare interface BuildOptions {
17 | project: string;
18 | verbose: boolean;
19 | clean: boolean;
20 | local: boolean;
21 | }
22 |
--------------------------------------------------------------------------------
/src/utils/constants.ts:
--------------------------------------------------------------------------------
1 | export const ROOT = process.cwd();
2 | export const pkgFileName = 'package.json';
3 | export const tsconfigName = 'tsconfig.json';
4 | export const ngCliConfName = 'angular-cli.json';
5 | export const dependencyKeys = ['devDependencies', 'dependencies', 'peerDependencies'];
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | // todo: export Observable exec
2 | export * from './constants';
3 | export { mergePackageJson } from './merge-package-json';
4 | export { findSubmodules } from './submodules-resolution';
5 | export { tasksWatch } from './tasks-watch';
6 |
7 |
--------------------------------------------------------------------------------
/src/utils/merge-package-json.ts:
--------------------------------------------------------------------------------
1 | //todo: add setting of cross-dependencies versions
2 | //todo: add readme field
3 | const _ = require('lodash');
4 |
5 | const fieldsToCopy = 'main version description main module typings browser keywords author license repository'.split(' ');
6 | // read dependencies from main package.json
7 | // if dependencies duplicated they will be overwritten by each other
8 | import { dependencyKeys } from './constants'
9 |
10 | export function mergePackageJson(data) {
11 | const {base, module, localDependencies} = data;
12 | // read only needed fields from main package.json
13 | const filteredBasePkg = _.pick(base, fieldsToCopy);
14 | let dependenciesHash = _(base)
15 | .pick(dependencyKeys)
16 | .reduce((memo, v) => Object.assign(memo, v), {});
17 |
18 | dependenciesHash = Object.assign(dependenciesHash, localDependencies);
19 |
20 | // update sub module package.json dependencies versions
21 | const newModulePkg = Object.assign(filteredBasePkg, module);
22 | _.each(dependencyKeys, (section) => {
23 | newModulePkg[section] = _.mapValues(newModulePkg[section], (version, dependency) => dependenciesHash[dependency]);
24 | });
25 |
26 | return newModulePkg;
27 | }
28 |
--------------------------------------------------------------------------------
/src/utils/submodules-resolution.ts:
--------------------------------------------------------------------------------
1 | // import { TsmOptions } from '../types';
2 | import { pkgFileName, dependencyKeys, ROOT } from './constants';
3 |
4 | const fs = require('fs');
5 | const path = require('path');
6 | const tsconfig = require('tsconfig');
7 | const readPkg = require('read-pkg');
8 |
9 | // todo: order by cross dependencies
10 | // todo: add --use-local-dependencies alias --local
11 |
12 | // should in the same folder as dist
13 | const _tmp = '.tmp';
14 |
15 | /**
16 | * Will try to find package.json in src folder
17 | * if not found will search in 1st level of directories
18 | * Returns list of directories with package.json
19 | * project - string, relative path to folder
20 | */
21 | export function findSubmodules(project: string, options?: { local: boolean }) {
22 | return listDirs(project)
23 | .then(dirs => orderByCrossDeps(
24 | dirs
25 | .filter(dir => isModuleRoot(dir))
26 | .map(dir => ({dir, tsconfig: tsconfig.loadSync(dir)}))
27 | .map(opt => resolveOptions(project, opt)))
28 | );
29 | }
30 |
31 | function listDirs(project: string): Promise {
32 | return Promise.resolve(
33 | [project].concat(
34 | fs
35 | .readdirSync(path.resolve(project))
36 | .filter(file => fs.statSync(path.resolve(project, file))
37 | .isDirectory())
38 | .map(dir => path.join(project, dir))
39 | ));
40 | }
41 |
42 | function isModuleRoot(dir: string) {
43 | if (fs.existsSync(path.join(dir, pkgFileName))) {
44 | return !!tsconfig.resolveSync(dir);
45 | }
46 | return false;
47 | }
48 |
49 | function resolveOptions(project: string, opt): TsmOptions {
50 | const tsOutDir = opt.tsconfig.config.compilerOptions.outDir;
51 | const tsConfigDir = path.dirname(opt.tsconfig.path);
52 | const relTsOutDir = path.relative(ROOT, path.resolve(tsConfigDir, tsOutDir));
53 | const moduleDir = path.relative(project, opt.dir);
54 | // submodule root
55 | const src = opt.dir;
56 | // tsc out dir
57 | const dist = relTsOutDir.indexOf(moduleDir) == -1
58 | ? path.join(relTsOutDir, moduleDir)
59 | : relTsOutDir;
60 |
61 | // convert tsout ( '../dist' --> '../.tmp' )
62 | const _distParsed = path.parse(tsOutDir);
63 | let tmp = moduleDir && moduleDir === _distParsed.base
64 | // '../dist/module-1'
65 | ? path.join(src, path.format(Object.assign(path.parse(_distParsed.dir), {base: _tmp})), moduleDir)
66 | // '../dist'
67 | : path.resolve(src, path.format(Object.assign({}, _distParsed, { base: _tmp })));
68 | // tsconfig project
69 | return {
70 | src, dist, tmp,
71 | tsconfig: opt.tsconfig,
72 | project: path.relative(ROOT, tsConfigDir),
73 | pkg: readPkg.sync(src)
74 | };
75 | }
76 |
77 | // todo: split it in
78 | // 1. building cross dependencies
79 | // 2. sorting by cross dependencies count
80 | /**
81 | * */
82 | function orderByCrossDeps(options: TsmOptions[]): TsmOptions[] {
83 | const pkgName = options.map(opt => opt.pkg.name);
84 | return options
85 | .map(option => {
86 | option.cross = [];
87 | dependencyKeys.forEach(depKey => {
88 | if (!option.pkg[depKey]) {
89 | return;
90 | }
91 | pkgName.forEach(name => {
92 | if (name in option.pkg[depKey]) {
93 | option.cross.push(name);
94 | }
95 | });
96 | });
97 | return option;
98 | })
99 | .sort((a: TsmOptions, b: TsmOptions) => {
100 | if (a.cross.length === b.cross.length) {
101 | return 0;
102 | }
103 |
104 | return a.cross.length > b.cross.length ? 1 : -1;
105 | });
106 | }
107 |
--------------------------------------------------------------------------------
/src/utils/tasks-watch.ts:
--------------------------------------------------------------------------------
1 | import chokidar = require('chokidar');
2 | import path = require('path');
3 | // todo: use observables?
4 | export function tasksWatch({project, taskQueue, watch, paths}){
5 | let isRunning = false;
6 | let changedModule: number;
7 |
8 | runTasks();
9 |
10 | if (watch) {
11 | chokidar.watch(project, {ignored: /[\/\\]\./})
12 | .on('change', (event) => {
13 | changedModule = paths.indexOf(event.split(path.sep)[0]);
14 | console.log(`Changes detected: ${event}`);
15 | runTasks();
16 | });
17 | }
18 |
19 | return Promise.resolve();
20 |
21 | function runTasks() {
22 | if (isRunning) {
23 | return;
24 | }
25 |
26 | isRunning = true;
27 | taskQueue.tasks.forEach((task: any, i: number) => {
28 | task.skip = () => changedModule && i !== changedModule;
29 | });
30 | return taskQueue.run()
31 | .then(() => {
32 | console.log(`\n-------------------------------------\n`);
33 | isRunning = false;
34 | })
35 | .catch(err => {
36 | if (err) {
37 | console.error(err);
38 | }
39 | isRunning = false;
40 | });
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/todo.md:
--------------------------------------------------------------------------------
1 | - add npm unlink
2 |
3 | copy package to dist
4 | remove private: true
5 | rename to ngm-cli
6 |
--------------------------------------------------------------------------------