├── test
├── expected
│ ├── .gitattributes
│ ├── conflicts_dirname
│ │ └── foo-mx.d.ts
│ ├── commonjs
│ │ └── foo-mx.d.ts
│ ├── excludeExp
│ │ └── foo-mx.d.ts
│ ├── excludeFunc
│ │ └── foo-mx.d.ts
│ ├── includeExclude
│ │ └── foo-mx.d.ts
│ ├── out
│ │ └── fizz
│ │ │ └── buzz.d.ts
│ ├── remove
│ │ └── foo-mx.d.ts
│ ├── default
│ │ └── foo-mx.d.ts
│ ├── seprinnew
│ │ └── bar-mx.d.ts
│ ├── externals
│ │ └── foo-mx.d.ts
│ └── es6
│ │ └── foo-mx.d.ts
├── src
│ ├── commonjs
│ │ ├── sub
│ │ │ ├── index.ts
│ │ │ ├── sub.service.html
│ │ │ └── sub.service.ts
│ │ └── index.ts
│ ├── conflicts
│ │ └── dirname
│ │ │ ├── index.ts
│ │ │ ├── file1.ts
│ │ │ └── file1
│ │ │ └── file2.ts
│ ├── typings
│ │ └── external.d.ts
│ ├── es6
│ │ ├── sub.ts
│ │ ├── lib
│ │ │ ├── subC.ts
│ │ │ ├── subD.ts
│ │ │ └── subE.ts
│ │ └── index.ts
│ └── main
│ │ ├── lib
│ │ ├── exported-sub.ts
│ │ └── only-internal.ts
│ │ ├── Foo.ts
│ │ └── index.ts
├── seprinnew_cli-config.json
└── test.js
├── index.js
├── .gitattributes
├── .gitmodules
├── .travis.yml
├── .npmignore
├── debug.js
├── .gitignore
├── lib
├── tsconfig.json
├── dts-bundle.js
└── index.ts
├── LICENSE-MIT
├── package.json
├── Gruntfile.js
└── README.md
/test/expected/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ts eol=lf
2 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib/index');
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js text eol=lf
2 | *.ts text eol=lf
3 |
--------------------------------------------------------------------------------
/test/src/commonjs/sub/index.ts:
--------------------------------------------------------------------------------
1 | export * from './sub.service';
2 |
--------------------------------------------------------------------------------
/test/src/commonjs/sub/sub.service.html:
--------------------------------------------------------------------------------
1 |
{{getName()}}
2 |
--------------------------------------------------------------------------------
/test/src/conflicts/dirname/index.ts:
--------------------------------------------------------------------------------
1 | export * from './file1';
2 | export * from './file1/file2';
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "repo"]
2 | path = repo
3 | url = https://github.com/Bartvds/DefinitelyTyped.git
4 |
--------------------------------------------------------------------------------
/test/src/conflicts/dirname/file1.ts:
--------------------------------------------------------------------------------
1 | export class Foo1 {
2 | public property1: number;
3 | constructor() { }
4 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.11"
4 |
5 | before_install:
6 | - npm install -g grunt-cli
7 |
8 |
--------------------------------------------------------------------------------
/test/src/conflicts/dirname/file1/file2.ts:
--------------------------------------------------------------------------------
1 | export class Foo2 {
2 | public property2: string;
3 | constructor() { }
4 | }
--------------------------------------------------------------------------------
/test/seprinnew_cli-config.json:
--------------------------------------------------------------------------------
1 | {
2 | "prefix": "--",
3 | "indent": "\t",
4 | "newline": " //$\n",
5 | "separator": "#"
6 | }
--------------------------------------------------------------------------------
/test/src/commonjs/sub/sub.service.ts:
--------------------------------------------------------------------------------
1 | import './sub.service.html';
2 |
3 | export class SubService {
4 |
5 | constructor(public x: string){}
6 |
7 | hello(): string {
8 | return `Hello ${this.x}`;
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/test/src/typings/external.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'external1' {
2 | export class SomeType {
3 | foo(): void;
4 | }
5 | }
6 |
7 | declare module 'external2' {
8 | export class AnotherType {
9 | foo(): void;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/src/es6/sub.ts:
--------------------------------------------------------------------------------
1 | export interface A {
2 | name: string;
3 | }
4 |
5 | export class B {
6 | name: string;
7 | }
8 |
9 | export default function test(): A { return null; }
10 | export function foo(): A { return null; }
11 | export function bar(): A { return null; }
12 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /test
3 | /util
4 |
5 | /Gruntfile.js
6 | /debug.js
7 | /dtsm.json
8 |
9 | .npmignore
10 | .gitignore
11 | .gitmodules
12 |
13 | .travis.yml
14 | .jshintrc
15 | .editorconfig
16 |
17 | /tscommand*
18 | .tscache
19 | tmp/
20 |
21 | /*.tgz
22 | /*.txt
23 |
--------------------------------------------------------------------------------
/test/src/es6/lib/subC.ts:
--------------------------------------------------------------------------------
1 | export interface A {
2 | name: string;
3 | }
4 |
5 | export class B {
6 | name: string;
7 | }
8 |
9 | export default function test(): A { return null; }
10 | export function foo(): A { return null; }
11 | export function bar(): A { return null; }
12 |
--------------------------------------------------------------------------------
/test/src/es6/lib/subD.ts:
--------------------------------------------------------------------------------
1 | export interface A {
2 | name: string;
3 | }
4 |
5 | export class B {
6 | name: string;
7 | }
8 |
9 | export default function test(): A { return null; }
10 | export function foo(): A { return null; }
11 | export function bar(): A { return null; }
12 |
--------------------------------------------------------------------------------
/test/src/es6/lib/subE.ts:
--------------------------------------------------------------------------------
1 | export interface A {
2 | name: string;
3 | }
4 |
5 | export class B {
6 | name: string;
7 | }
8 |
9 | export default function test(): A { return null; }
10 | export function foo(): A { return null; }
11 | export function bar(): A { return null; }
12 |
--------------------------------------------------------------------------------
/debug.js:
--------------------------------------------------------------------------------
1 | var dts = require("./lib");
2 | var path = require("path");
3 | var actDir = "test/tmp/includeExclude";
4 |
5 | dts.bundle({
6 | name: 'foo-mx',
7 | main: path.join(actDir, 'index.d.ts'),
8 | externals: true,
9 | exclude: /exported\-sub/,
10 | newline: '\n'
11 | });
12 |
--------------------------------------------------------------------------------
/test/src/commonjs/index.ts:
--------------------------------------------------------------------------------
1 | import {SubService} from "./sub";
2 | export {SubService};
3 |
4 | export class mymod {
5 |
6 | public sub: SubService;
7 |
8 | constructor(){
9 | this.sub = new SubService("mymod");
10 | }
11 |
12 | getName(): string {
13 | return this.sub.hello();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/test/src/main/lib/exported-sub.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import Foo = require('../Foo');
4 | import mod2 = require('external2');
5 |
6 | export class ExternalContainer {
7 | public something: mod2.AnotherType;
8 | }
9 |
10 | export function bar(foo: Foo): string {
11 | return foo.foo + '-bar';
12 | }
13 |
14 | export function bazz(value: string, option?: boolean): string {
15 | return value + '-bazz';
16 | }
17 |
--------------------------------------------------------------------------------
/test/src/main/lib/only-internal.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import Foo = require('../Foo');
4 | import mod2 = require('external2');
5 |
6 | export class ExternalContainer {
7 | public something: mod2.AnotherType;
8 | }
9 |
10 | export function bar(foo: Foo): string {
11 | return foo.foo + '-bar';
12 | }
13 |
14 | export function bazz(value: string, option?: boolean): string {
15 | return value + '-bazz';
16 | }
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 |
3 | /.idea
4 | /.vagrant
5 |
6 | /node_modules
7 | /typings
8 |
9 | /lib/**/*.js
10 | !/lib/dts-bundle.js
11 |
12 | /test/tmp
13 | /test/build
14 | !/test/src/typings/*.d.ts
15 | /test/src/**/*.d.ts
16 | /test/src/**/*.js
17 | /test/src/**/*.js.map
18 |
19 | /tscommand*
20 | .tscache
21 |
22 | /*.tgz
23 | tmp/
24 | dump/
25 |
26 | .baseDir.ts
27 | .baseDir.d.ts
28 | .baseDir.js
29 | .baseDir.js.map
30 |
31 | _tmp.*
32 |
33 | npm-debug.log
34 |
--------------------------------------------------------------------------------
/test/expected/conflicts_dirname/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'foo-mx' {
3 | export * from 'foo-mx/file1';
4 | export * from 'foo-mx/file1/file2';
5 | }
6 |
7 | declare module 'foo-mx/file1' {
8 | export class Foo1 {
9 | property1: number;
10 | constructor();
11 | }
12 | }
13 |
14 | declare module 'foo-mx/file1/file2' {
15 | export class Foo2 {
16 | property2: string;
17 | constructor();
18 | }
19 | }
20 |
21 |
--------------------------------------------------------------------------------
/test/src/main/Foo.ts:
--------------------------------------------------------------------------------
1 | class Foo {
2 |
3 | foo: string;
4 | private counter: number = 0;
5 |
6 | constructor(private secret?: string) {
7 |
8 | }
9 |
10 | /**
11 | * Bars the foo.
12 | */
13 | barFoo(): void {
14 |
15 | }
16 | /**
17 | * Foos the bar.
18 | */
19 | private fooBar(): void {
20 |
21 | }
22 | /** Foos the baz. */
23 | fooBaz(): void {
24 |
25 | }
26 | }
27 |
28 | export = Foo;
29 |
--------------------------------------------------------------------------------
/test/src/es6/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./sub";
2 | import subA from "./sub";
3 | import * as subB from "./sub";
4 | import subC, {A} from "./lib/subC";
5 | import {bar} from "./lib/subD";
6 | import {foo as buzz} from "./lib/subE";
7 |
8 | export function indexA() {
9 | return subA();
10 | }
11 |
12 | export function indexB() {
13 | return new subB.B();
14 | }
15 |
16 | export function indexC() {
17 | return subC();
18 | }
19 |
20 | export function indexD() {
21 | return bar;
22 | }
23 |
24 | export function indexE() {
25 | return buzz;
26 | }
27 |
--------------------------------------------------------------------------------
/test/expected/commonjs/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'foo-mx' {
3 | import { SubService } from "foo-mx/sub";
4 | export { SubService };
5 | export class mymod {
6 | sub: SubService;
7 | constructor();
8 | getName(): string;
9 | }
10 | }
11 |
12 | declare module 'foo-mx/sub' {
13 | export * from 'foo-mx/sub/sub.service';
14 | }
15 |
16 | declare module 'foo-mx/sub/sub.service' {
17 | import './sub.service.html';
18 | export class SubService {
19 | x: string;
20 | constructor(x: string);
21 | hello(): string;
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/test/src/main/index.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | import int = require('./lib/only-internal');
4 | import exp = require('./lib/exported-sub');
5 | import mod1 = require('external1');
6 |
7 | export import Foo = require('./Foo');
8 | /*
9 | Licence foo module v1.2.3 - MIT
10 | */
11 | export function run(foo?: Foo): Foo {
12 | var foo = foo || new Foo();
13 | int.bazz(int.bar(foo));
14 | return foo;
15 | }
16 |
17 | // flep this
18 | export function flep(): exp.ExternalContainer {
19 | return new exp.ExternalContainer();
20 | }
21 |
22 | // bar that
23 | export function bar(): mod1.SomeType {
24 | return new mod1.SomeType();
25 | }
26 |
--------------------------------------------------------------------------------
/test/expected/excludeExp/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module:
2 | // ../../src/typings/external.d.ts
3 |
4 | declare module 'foo-mx' {
5 | import exp = require('foo-mx/lib/exported-sub');
6 | import mod1 = require('external1');
7 | export import Foo = require('foo-mx/Foo');
8 | export function run(foo?: Foo): Foo;
9 | export function flep(): exp.ExternalContainer;
10 | export function bar(): mod1.SomeType;
11 | }
12 |
13 | declare module 'foo-mx/Foo' {
14 | class Foo {
15 | foo: string;
16 | constructor(secret?: string);
17 | /**
18 | * Bars the foo.
19 | */
20 | barFoo(): void;
21 | /** Foos the baz. */
22 | fooBaz(): void;
23 | }
24 | export = Foo;
25 | }
26 |
--------------------------------------------------------------------------------
/test/expected/excludeFunc/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module:
2 | // ../../src/typings/external.d.ts
3 |
4 | declare module 'foo-mx' {
5 | import exp = require('foo-mx/lib/exported-sub');
6 | import mod1 = require('external1');
7 | export import Foo = require('foo-mx/Foo');
8 | export function run(foo?: Foo): Foo;
9 | export function flep(): exp.ExternalContainer;
10 | export function bar(): mod1.SomeType;
11 | }
12 |
13 | declare module 'foo-mx/Foo' {
14 | class Foo {
15 | foo: string;
16 | constructor(secret?: string);
17 | /**
18 | * Bars the foo.
19 | */
20 | barFoo(): void;
21 | /** Foos the baz. */
22 | fooBaz(): void;
23 | }
24 | export = Foo;
25 | }
26 |
--------------------------------------------------------------------------------
/lib/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.5.3",
3 | "compilerOptions": {
4 | "target": "es5",
5 | "module": "commonjs",
6 | "isolatedModules": false,
7 | "experimentalDecorators": true,
8 | "emitDecoratorMetadata": true,
9 | "declaration": false,
10 | "noImplicitAny": true,
11 | "removeComments": true,
12 | "noLib": false,
13 | "preserveConstEnums": false,
14 | "suppressImplicitAnyIndexErrors": false
15 | },
16 | "filesGlob": [
17 | "./**/*.ts",
18 | "../typings/**/*.ts",
19 | "./**/*.tsx",
20 | "!./node_modules/**/*"
21 | ],
22 | "files": [
23 | "./index.ts",
24 | "../typings/bundle.d.ts",
25 | "../typings/detect-indent/detect-indent.d.ts",
26 | "../typings/glob/glob.d.ts",
27 | "../typings/minimatch/minimatch.d.ts",
28 | "../typings/mkdirp/mkdirp.d.ts",
29 | "../typings/node/node.d.ts"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/test/expected/includeExclude/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'foo-mx' {
3 | import exp = require('foo-mx/lib/exported-sub');
4 | import mod1 = require('foo-mx/index//external1');
5 | export import Foo = require('foo-mx/Foo');
6 | export function run(foo?: Foo): Foo;
7 | export function flep(): exp.ExternalContainer;
8 | export function bar(): mod1.SomeType;
9 | }
10 |
11 | declare module 'foo-mx/index//external1' {
12 | export class SomeType {
13 | foo(): void;
14 | }
15 | }
16 |
17 | declare module 'foo-mx/index//external2' {
18 | export class AnotherType {
19 | foo(): void;
20 | }
21 | }
22 |
23 | declare module 'foo-mx/Foo' {
24 | class Foo {
25 | foo: string;
26 | constructor(secret?: string);
27 | /**
28 | * Bars the foo.
29 | */
30 | barFoo(): void;
31 | /** Foos the baz. */
32 | fooBaz(): void;
33 | }
34 | export = Foo;
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Bart van der Schoor
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/test/expected/out/fizz/buzz.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module:
2 | // ../../src/typings/external.d.ts
3 |
4 | declare module 'foo-mx' {
5 | import exp = require('foo-mx/lib/exported-sub');
6 | import mod1 = require('external1');
7 | export import Foo = require('foo-mx/Foo');
8 | export function run(foo?: Foo): Foo;
9 | export function flep(): exp.ExternalContainer;
10 | export function bar(): mod1.SomeType;
11 | }
12 |
13 | declare module 'foo-mx/lib/exported-sub' {
14 | import Foo = require('foo-mx/Foo');
15 | import mod2 = require('external2');
16 | export class ExternalContainer {
17 | something: mod2.AnotherType;
18 | }
19 | export function bar(foo: Foo): string;
20 | export function bazz(value: string, option?: boolean): string;
21 | }
22 |
23 | declare module 'foo-mx/Foo' {
24 | class Foo {
25 | foo: string;
26 | constructor(secret?: string);
27 | /**
28 | * Bars the foo.
29 | */
30 | barFoo(): void;
31 | /** Foos the baz. */
32 | fooBaz(): void;
33 | }
34 | export = Foo;
35 | }
36 |
--------------------------------------------------------------------------------
/test/expected/remove/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module:
2 | // ../../src/typings/external.d.ts
3 |
4 | declare module 'foo-mx' {
5 | import exp = require('foo-mx/lib/exported-sub');
6 | import mod1 = require('external1');
7 | export import Foo = require('foo-mx/Foo');
8 | export function run(foo?: Foo): Foo;
9 | export function flep(): exp.ExternalContainer;
10 | export function bar(): mod1.SomeType;
11 | }
12 |
13 | declare module 'foo-mx/lib/exported-sub' {
14 | import Foo = require('foo-mx/Foo');
15 | import mod2 = require('external2');
16 | export class ExternalContainer {
17 | something: mod2.AnotherType;
18 | }
19 | export function bar(foo: Foo): string;
20 | export function bazz(value: string, option?: boolean): string;
21 | }
22 |
23 | declare module 'foo-mx/Foo' {
24 | class Foo {
25 | foo: string;
26 | constructor(secret?: string);
27 | /**
28 | * Bars the foo.
29 | */
30 | barFoo(): void;
31 | /** Foos the baz. */
32 | fooBaz(): void;
33 | }
34 | export = Foo;
35 | }
36 |
--------------------------------------------------------------------------------
/test/expected/default/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module:
2 | // ../../src/typings/external.d.ts
3 |
4 | declare module 'foo-mx' {
5 | import exp = require('foo-mx/lib/exported-sub');
6 | import mod1 = require('external1');
7 | export import Foo = require('foo-mx/Foo');
8 | export function run(foo?: Foo): Foo;
9 | export function flep(): exp.ExternalContainer;
10 | export function bar(): mod1.SomeType;
11 | }
12 |
13 | declare module 'foo-mx/lib/exported-sub' {
14 | import Foo = require('foo-mx/Foo');
15 | import mod2 = require('external2');
16 | export class ExternalContainer {
17 | something: mod2.AnotherType;
18 | }
19 | export function bar(foo: Foo): string;
20 | export function bazz(value: string, option?: boolean): string;
21 | }
22 |
23 | declare module 'foo-mx/Foo' {
24 | class Foo {
25 | foo: string;
26 | constructor(secret?: string);
27 | /**
28 | * Bars the foo.
29 | */
30 | barFoo(): void;
31 | /** Foos the baz. */
32 | fooBaz(): void;
33 | }
34 | export = Foo;
35 | }
36 |
--------------------------------------------------------------------------------
/test/expected/seprinnew/bar-mx.d.ts:
--------------------------------------------------------------------------------
1 | // Dependencies for this module: //$
2 | // ../../src/typings/external.d.ts //$
3 | //$
4 | declare module 'bar-mx' { //$
5 | import exp = require('--bar-mx#lib#exported-sub'); //$
6 | import mod1 = require('external1'); //$
7 | export import Foo = require('--bar-mx#Foo'); //$
8 | export function run(foo?: Foo): Foo; //$
9 | export function flep(): exp.ExternalContainer; //$
10 | export function bar(): mod1.SomeType; //$
11 | } //$
12 | //$
13 | declare module '--bar-mx#lib#exported-sub' { //$
14 | import Foo = require('--bar-mx#Foo'); //$
15 | import mod2 = require('external2'); //$
16 | export class ExternalContainer { //$
17 | something: mod2.AnotherType; //$
18 | } //$
19 | export function bar(foo: Foo): string; //$
20 | export function bazz(value: string, option?: boolean): string; //$
21 | } //$
22 | //$
23 | declare module '--bar-mx#Foo' { //$
24 | class Foo { //$
25 | foo: string; //$
26 | constructor(secret?: string); //$
27 | /** //$
28 | * Bars the foo. //$
29 | */ //$
30 | barFoo(): void; //$
31 | /** Foos the baz. */ //$
32 | fooBaz(): void; //$
33 | } //$
34 | export = Foo; //$
35 | } //$
36 | //$
37 |
--------------------------------------------------------------------------------
/test/expected/externals/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'foo-mx' {
3 | import exp = require('foo-mx/lib/exported-sub');
4 | import mod1 = require('foo-mx/index//external1');
5 | export import Foo = require('foo-mx/Foo');
6 | export function run(foo?: Foo): Foo;
7 | export function flep(): exp.ExternalContainer;
8 | export function bar(): mod1.SomeType;
9 | }
10 |
11 | declare module 'foo-mx/index//external1' {
12 | export class SomeType {
13 | foo(): void;
14 | }
15 | }
16 |
17 | declare module 'foo-mx/index//external2' {
18 | export class AnotherType {
19 | foo(): void;
20 | }
21 | }
22 |
23 | declare module 'foo-mx/lib/exported-sub' {
24 | import Foo = require('foo-mx/Foo');
25 | import mod2 = require('foo-mx/index//external2');
26 | export class ExternalContainer {
27 | something: mod2.AnotherType;
28 | }
29 | export function bar(foo: Foo): string;
30 | export function bazz(value: string, option?: boolean): string;
31 | }
32 |
33 | declare module 'foo-mx/Foo' {
34 | class Foo {
35 | foo: string;
36 | constructor(secret?: string);
37 | /**
38 | * Bars the foo.
39 | */
40 | barFoo(): void;
41 | /** Foos the baz. */
42 | fooBaz(): void;
43 | }
44 | export = Foo;
45 | }
46 |
--------------------------------------------------------------------------------
/test/expected/es6/foo-mx.d.ts:
--------------------------------------------------------------------------------
1 |
2 | declare module 'foo-mx' {
3 | export * from "foo-mx/sub";
4 | import * as subB from "foo-mx/sub";
5 | import { A } from "foo-mx/lib/subC";
6 | import { bar } from "foo-mx/lib/subD";
7 | import { foo as buzz } from "foo-mx/lib/subE";
8 | export function indexA(): subB.A;
9 | export function indexB(): subB.B;
10 | export function indexC(): A;
11 | export function indexD(): typeof bar;
12 | export function indexE(): typeof buzz;
13 | }
14 |
15 | declare module 'foo-mx/sub' {
16 | export interface A {
17 | name: string;
18 | }
19 | export class B {
20 | name: string;
21 | }
22 | export default function test(): A;
23 | export function foo(): A;
24 | export function bar(): A;
25 | }
26 |
27 | declare module 'foo-mx/lib/subC' {
28 | export interface A {
29 | name: string;
30 | }
31 | export class B {
32 | name: string;
33 | }
34 | export default function test(): A;
35 | export function foo(): A;
36 | export function bar(): A;
37 | }
38 |
39 | declare module 'foo-mx/lib/subD' {
40 | export interface A {
41 | name: string;
42 | }
43 | export class B {
44 | name: string;
45 | }
46 | export default function test(): A;
47 | export function foo(): A;
48 | export function bar(): A;
49 | }
50 |
51 | declare module 'foo-mx/lib/subE' {
52 | export interface A {
53 | name: string;
54 | }
55 | export class B {
56 | name: string;
57 | }
58 | export default function test(): A;
59 | export function foo(): A;
60 | export function bar(): A;
61 | }
62 |
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dts-bundle",
3 | "version": "0.7.3",
4 | "description": "Export TypeScript .d.ts files as an external module definition",
5 | "keywords": [
6 | "typescript",
7 | "definition",
8 | "bundle",
9 | "export",
10 | "d.ts"
11 | ],
12 | "bin": {
13 | "dts-bundle": "./lib/dts-bundle.js"
14 | },
15 | "homepage": "https://github.com/grunt-ts/dts-bundle",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/grunt-ts/dts-bundle.git"
19 | },
20 | "author": {
21 | "name": "Bart van der Schoor",
22 | "url": "https://github.com/Bartvds"
23 | },
24 | "licenses": [
25 | {
26 | "type": "MIT",
27 | "url": "https://raw.github.com/grunt-ts/dts-bundle/master/LICENSE-MIT.txt"
28 | }
29 | ],
30 | "bugs": {
31 | "url": "https://github.com/grunt-ts/dts-bundle/issues"
32 | },
33 | "engines": {
34 | "node": ">= 0.10.0"
35 | },
36 | "scripts": {
37 | "test": "grunt test"
38 | },
39 | "main": "./index.js",
40 | "dependencies": {
41 | "@types/detect-indent": "0.1.30",
42 | "@types/glob": "5.0.30",
43 | "@types/mkdirp": "0.3.29",
44 | "@types/node": "8.0.0",
45 | "commander": "^2.9.0",
46 | "detect-indent": "^0.2.0",
47 | "glob": "^6.0.4",
48 | "mkdirp": "^0.5.0"
49 | },
50 | "devDependencies": {
51 | "chai": "^1.10.0",
52 | "chai-fs": "0.1.0",
53 | "grunt": "^0.4.5",
54 | "grunt-contrib-clean": "^0.5.0",
55 | "grunt-contrib-jshint": "^0.10.0",
56 | "grunt-dtsm": "1.0.0",
57 | "grunt-mocha-test": "^0.11.0",
58 | "grunt-ts": "^6.0.0-beta.16",
59 | "jshint-path-reporter": "^0.1.3",
60 | "mocha-unfunk-reporter": "^0.4.0",
61 | "ncp": "^0.5.1",
62 | "typescript": "^2.3.4"
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | 'use strict';
3 |
4 | grunt.loadNpmTasks('grunt-ts');
5 | grunt.loadNpmTasks('grunt-mocha-test');
6 | grunt.loadNpmTasks('grunt-contrib-clean');
7 |
8 | grunt.initConfig({
9 | pkg: grunt.file.readJSON('package.json'),
10 | clean: {
11 | cruft: {
12 | option: {
13 | dot: true
14 | },
15 | src: [
16 | 'tscommand-*.tmp.txt',
17 | 'test/**/.baseDir*'
18 | ]
19 | },
20 | tmp: [
21 | 'tmp/**/*',
22 | 'test/tmp/**/*'
23 | ],
24 | test: [
25 | 'test/build/**/*'
26 | ]
27 | },
28 | ts: {
29 | options: {
30 | fast: 'never',
31 | target: 'es5',
32 | module: 'commonjs',
33 | declaration: true,
34 | removeComments: false,
35 | sourceMap: false
36 | },
37 | main: {
38 | src: [
39 | './lib/index.ts',
40 | ],
41 | options: {
42 | "target": "es5",
43 | "module": "commonjs",
44 | "isolatedModules": false,
45 | "experimentalDecorators": true,
46 | "emitDecoratorMetadata": true,
47 | "declaration": false,
48 | "noImplicitAny": true,
49 | "removeComments": true,
50 | "noLib": false,
51 | "preserveConstEnums": false,
52 | "suppressImplicitAnyIndexErrors": false
53 | }
54 | },
55 | test: {
56 | src: ['test/src/main/index.ts'],
57 | outDir: 'test/build/sub/'
58 | },
59 | testEs6: {
60 | src: ['test/src/es6/index.ts'],
61 | outDir: 'test/build/es6/'
62 | },
63 | testCommonJs: {
64 | src: ['test/src/commonjs/index.ts'],
65 | outDir: 'test/build/commonjs'
66 | },
67 | testConflicts: {
68 | src: ['test/src/conflicts/dirname/index.ts'],
69 | outDir: 'test/build/conflicts/dirname'
70 | }
71 | },
72 | mochaTest: {
73 | options: {
74 | timeout: 5000,
75 | reporter: 'mocha-unfunk-reporter'
76 | },
77 | all: {
78 | src: 'test/test.js'
79 | }
80 | }
81 | });
82 |
83 | grunt.registerTask('prep', [
84 | 'clean:tmp',
85 | 'clean:test',
86 | 'clean:cruft'
87 | ]);
88 |
89 | grunt.registerTask('test', [
90 | 'prep',
91 | 'ts:test',
92 | 'ts:testEs6',
93 | 'ts:testCommonJs',
94 | 'ts:testConflicts',
95 | 'run'
96 | ]);
97 |
98 | grunt.registerTask('run', [
99 | 'clean:tmp',
100 | 'ts:main',
101 | 'mochaTest:all',
102 | 'sweep'
103 | ]);
104 |
105 | grunt.registerTask('prepublish', [
106 | 'build',
107 | 'ts:test',
108 | 'mochaTest:all',
109 | 'sweep'
110 | ]);
111 |
112 | grunt.registerTask('sweep', [
113 | 'clean:cruft'
114 | ]);
115 |
116 | grunt.registerTask('default', ['test']);
117 | };
118 |
--------------------------------------------------------------------------------
/lib/dts-bundle.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Remember remove \r chars at end of lines.
4 |
5 | var pkg = require('../package');
6 | var program = require('commander');
7 | var dts = require("./index");
8 | var path = require('path');
9 | var os = require('os');
10 |
11 | function mapOptions(argObj) {
12 | var result = argObj.configJson ? require(path.resolve(argObj.configJson)) : {};
13 |
14 | var optList = [
15 | "main",
16 | "name",
17 | "baseDir",
18 | "out",
19 | //"newline", // Manual
20 | //"indent", // not implemented
21 | "prefix",
22 | // "separator", not implemented
23 | "externals",
24 | //"exclude", // not implemented
25 | "removeSource",
26 | "verbose",
27 | "referenceExternals",
28 | "emitOnIncludedFileNotFound",
29 | "emitOnNoIncludedFileNotFound",
30 | "outputAsModuleFolder",
31 | "headerPath"
32 | ];
33 |
34 | optList.forEach(function (optName) {
35 | if (argObj.hasOwnProperty(optName))
36 | result[optName] = argObj[optName];
37 | }, this);
38 |
39 | if (argObj.hasOwnProperty("newline")) {
40 | switch (argObj.newline) {
41 | case "unix":
42 | result.newline = "\n";
43 | break;
44 | case "windows":
45 | result.newline = "\r\n";
46 | break;
47 | case "currentOsDefault":
48 | result.newline = os.EOL;
49 | break;
50 | }
51 | }
52 | return result;
53 | }
54 |
55 | function callBundle(options) {
56 | if (!options.name || !options.main) {
57 | console.log("'name' and 'main' parameters are required. --help for get option list.")
58 | process.exit(1);
59 | }
60 | return dts.bundle(options);
61 | }
62 |
63 | program
64 | .version(pkg.version)
65 | .option('--configJson ', "path to json config file. Load it first and override options with additional parameters")
66 | .option('--name ', 'name of module likein package.json *required')
67 | .option('--main ', 'path to entry-point (see documentation) *required')
68 | .option('--baseDir [value]', 'base directory to be used for discovering type declarations')
69 | .option('--out [value]', 'path of output file. Is relative from baseDir but you can use absolute paths. ')
70 | .option('--externals', 'include typings outside of the "baseDir" (i.e. like node.d.ts)')
71 | .option('--referenceExternals', 'reference external modules as tags *** Experimental, TEST NEEDED')
72 | //.option('--exclude ', 'filter to exclude typings, either a RegExp or a callback. match path relative to opts.baseDir')
73 | .option('--removeSource', 'delete all source typings (i.e. "/**/*.d.ts")')
74 | .option('--newline [style]', 'newline style to use in output file => unix|windows|currentOsDefault', /^(unix|windows|currentOsDefault)$/i)
75 | //.option('--indent', 'indentation to use in output file')
76 | .option('--prefix [value]', 'prefix for rewriting module names')
77 | // .option('--separator [value]', 'separator for rewriting module "path" names')
78 | .option('--verbose', 'enable verbose mode, prints detailed info about all references and includes/excludes')
79 | .option('--emitOnIncludedFileNotFound', 'emit although included files not found. See readme "Files not found" section. ')
80 | .option('--emitOnNoIncludedFileNotFound', 'emit although no included files not found. See readme "Files not found" section. ')
81 | .option('--outputAsModuleFolder', 'output as module folder format (no declare module) . See readme "Module folders" section.')
82 | .option('--headerPath [value]', 'path to file that contains the header')
83 | .parse(process.argv);
84 |
85 | console.log("%s version %s\n%s\n", pkg.name, pkg.version, pkg.description);
86 |
87 | var options = mapOptions(program);
88 |
89 | var result = callBundle(options);
90 |
91 | if (!result.emitted) {
92 | console.log("Result no emitted - use verbose to see details.");
93 | process.exit(1);
94 | }
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dts-bundle
2 |
3 | [](https://travis-ci.org/TypeStrong/dts-bundle) [](http://badge.fury.io/js/dts-bundle) [](https://david-dm.org/TypeStrong/dts-bundle) [](https://david-dm.org/TypeStrong/dts-bundle#info=devDependencies)
4 |
5 | > Export TypeScript .d.ts files as an external module definition
6 |
7 | This module is a naïve string-based approach at generating bundles from the .d.ts declaration files generated by a TypeScript compiler.
8 |
9 | The main use-case is generating definition for npm/bower modules written in TypeScript (commonjs/amd) so the TypeScript code should following the external-module pattern (using `import/export`'s and `--outDir`).
10 |
11 | :warning: Experimental; use with care.
12 |
13 | This module was born out of necessity and frustration. It is a little hacky but at least it seems to work..
14 |
15 | - Original code was extracted from an ad-hoc Grunt-task so for now it is fully synchronous with no error feedback.
16 | - It works by line-by-line string operations so please [report](https://github.com/grunt-ts/dts-bundle/issues) any edge-cases.
17 |
18 |
19 | ## Usage
20 |
21 | 1) Get it from npm:
22 |
23 | ````
24 | npm install dts-bundle
25 | ````
26 |
27 | 2) Compile your modules with the TypeScript compiler of your choice with the `--declaration` and `--outDir` flags (and probably `--module commonjs` too).
28 |
29 | Something like:
30 |
31 | ````shell
32 | tsc src/index.ts --declaration --module commonjs --target es5 --outDir build
33 | ````
34 |
35 | 3) Run `dts-bundle` (you can run it from cli, see "Command line" section.
36 |
37 | Let's assume the project is called `cool-project` and the main module is `build/index.js` with a `build/index.d.ts`:
38 |
39 | ````js
40 | var dts = require('dts-bundle');
41 |
42 | dts.bundle({
43 | name: 'cool-project',
44 | main: 'build/index.d.ts'
45 | });
46 | ````
47 |
48 | This will traverse all references and imports for the .d.ts files of your sub-modules and write `build/cool-project.d.ts` with the bundle of all 'local' imports.
49 |
50 | **Optional:**
51 |
52 | 4) Bonus points if you link the generated definition in your package.json's (or bower.json) `typescript` element:
53 |
54 | ````json
55 | {
56 | "name": "cool-project",
57 | "version": "0.1.3",
58 |
59 | "typescript": {
60 | "definition": "build/cool-project.d.ts"
61 | }
62 | }
63 | ````
64 |
65 | Using this makes the definition findable for tooling, for example the [TypeScript Definitions package manager](https://github.com/DefinitelyTyped/tsd) (from v0.6.x) can auto-link these into `tsd.d.ts` bundle file.
66 |
67 |
68 | ### Wrappers
69 |
70 | There is also a Grunt plugin [grunt-dts-bundle](https://www.github.com/grunt-ts/grunt-dts-bundle) that goes well with Grunt based compilers, like [grunt-ts](https://www.github.com/grunt-ts/grunt-ts) or [grunt-typescript](https://github.com/k-maru/grunt-typescript).
71 |
72 |
73 | ## Options
74 |
75 | Example of all options:
76 |
77 | ````js
78 | var opts = {
79 |
80 | // Required
81 |
82 | // name of module likein package.json
83 | // - used to declare module & import/require
84 | name: 'cool-project',
85 | // path to entry-point (generated .d.ts file for main module)
86 | // if you want to load all .d.ts files from a path recursively you can use "path/project/**/*.d.ts"
87 | // ^ *** Experimental, TEST NEEDED, see "All .d.ts files" section
88 | // - either relative or absolute
89 | main: 'build/index.d.ts',
90 |
91 | // Optional
92 |
93 | // base directory to be used for discovering type declarations (i.e. from this project itself)
94 | // - default: dirname of main
95 | baseDir: 'build',
96 | // path of output file. Is relative from baseDir but you can use absolute paths.
97 | // if starts with "~/" then is relative to current path. See https://github.com/TypeStrong/dts-bundle/issues/26
98 | // ^ *** Experimental, TEST NEEDED
99 | // - default: "/.d.ts"
100 | out: 'dist/cool-project.d.ts',
101 | // include typings outside of the 'baseDir' (i.e. like node.d.ts)
102 | // - default: false
103 | externals: false,
104 | // reference external modules as tags *** Experimental, TEST NEEDED
105 | // - default: false
106 | referenceExternals: false,
107 | // filter to exclude typings, either a RegExp or a callback. match path relative to opts.baseDir
108 | // - RegExp: a match excludes the file
109 | // - function: (file:String, external:Boolean) return true to exclude, false to allow
110 | // - always use forward-slashes (even on Windows)
111 | // - default: *pass*
112 | exclude: /^defs\/$/,
113 | // delete all source typings (i.e. "/**/*.d.ts")
114 | // - default: false
115 | removeSource: false,
116 | // newline to use in output file
117 | newline: os.EOL,
118 | // indentation to use in output file
119 | // - default 4 spaces
120 | indent: ' ',
121 | // prefix for rewriting module names
122 | // - default ''
123 | prefix: '__',
124 | // separator for rewriting module 'path' names
125 | // - default: forward slash (like sub-modules)
126 | separator: '/',
127 | // enable verbose mode, prints detailed info about all references and includes/excludes
128 | // - default: false
129 | verbose: false,
130 | // emit although included files not found. See "Files not found" section.
131 | // *** Experimental, TEST NEEDED
132 | // - default: false
133 | emitOnIncludedFileNotFound: false,
134 | // emit although no included files not found. See "Files not found" section.
135 | // *** Experimental, TEST NEEDED
136 | // - default: false
137 | emitOnNoIncludedFileNotFound: false,
138 | // output d.ts as designed for module folder. (no declare modules)
139 | outputAsModuleFolder: false,
140 | // path to file that contains the header
141 | // // insert a header in output file. i.e.: http://definitelytyped.org/guides/contributing.html#header
142 | // - default: null
143 | headerPath: "path/to/header/file",
144 | // text of the the header
145 | // doesn't work with headerPath
146 | // // insert a header in output file. i.e.: http://definitelytyped.org/guides/contributing.html#header
147 | // - default: ''
148 | headerTex: ""
149 | };
150 |
151 | // require module
152 | var dts = require('dts-bundle');
153 |
154 | // run it
155 | dts.bundle(opts);
156 | ````
157 |
158 | ### All `.d.ts` files
159 |
160 | Experimental - Test needed - https://github.com/TypeStrong/dts-bundle/issues/29
161 |
162 | You can bundle the definitions from for all files contained on a directory, and children directories.
163 | If you set `main` parameter to some path ended with `**/*.d.ts` then `dts-bundle` load all .d.ts files and generate a bundle.
164 | Internally `dts-bundle` builds a temporally file with export of the rest of the files. You can see it on verbose mode: i.e:
165 |
166 | ```` typescript
167 | // ## temporally main file ##
168 | export * from './Core/Bootstrap';
169 | export * from './Core/ChangeDetection';
170 | export * from './Core/ControllerDecorator';
171 | export * from './Core/LifeCycle\LifeCycleHooks';
172 | export * from './Decorators/Component';
173 | export * from './Decorators/Input';
174 | export * from './Decorators/Output';
175 | export * from './Directives/ngPropertyBinding';
176 | export * from './Events/EventEmitter';
177 | export * from './Expressions/ExpressionParser';
178 | export * from './Expressions/Ng1Lexer\Lexer';
179 | export * from './Ng2Emulation';
180 | export * from './Templates/HtmlParser\Parser';
181 | export * from './Templates/HtmlParser\ParserRule';
182 | export * from './Templates/HtmlParser\Rules\EventBindingRule';
183 | export * from './Templates/HtmlParser\Rules\TwoWayBindingRule';
184 | export * from './Utils/AngularHelpers';
185 | ````
186 |
187 | Then `dts-bundle` processes this file. When finish the temporally file is deleted.
188 |
189 | ### Module folders
190 | NPM introduced support for in-package typings,
191 | it is done by adding typings key into package.json file, which should refer to the
192 | typings file.
193 | when this is the case, the d.ts file is threated as module folder, and declare module
194 | is not allowed.
195 |
196 | * `outputAsModuleFolder`. When using this option output d.ts will be compatible with module folder. which means, no declare module are used,
197 | and all internal references are removed as they are merged into the output d.ts.
198 |
199 | ### Files not found.
200 |
201 | Experimental - Test needed -
202 |
203 | `dts-bundle` expects to find all references for all modules. Goes over all files referenced and tries to load each file to get the definitions,
204 | when he loads all files `dts-bundle` determines if include each one in the final bundle. If some file is not found dts-bundle doesn't emit the
205 | result file. You could want to emit the result file although some file are not found. The file not found can be an included or exclued file in
206 | the bundle then you have two options to control these cases:
207 |
208 | * `emitOnIncludedFileNotFound`. When there are files not found and these file should be included in the bundle,
209 | `dts-bundle` writes the output file if `emitOnIncludedFileNotFound` is true. This allow you to have external file
210 | definitions that you will load by other way in your final project.
211 | * `emitOnNoIncludedFileNotFound`. When there are files not found and these file shouldn't be included in the bundle,
212 | `dts-bundle` writes the output file if `emitOnNoIncludedFileNotFound` is true. This allow you don't to include external
213 | typings in your temporally output compile path.
214 |
215 | ## Return value
216 |
217 | Experimental - Test needed -
218 |
219 | `bundle` function return an object that implement this interface:
220 |
221 | ```` typescript
222 | export interface BundleResult {
223 | // a map with parse result per each process module.
224 | fileMap: { [moduleName: string]: Result; };
225 | // list of files not found that should be included in the bundle.
226 | includeFilesNotFound: string[];
227 | // list of files not found that shouldn`t be no included in the bundle.
228 | noIncludeFilesNotFound: string[];
229 | // true if dts-bunlde wrote the result, false otherwise.
230 | emitted?: boolean;
231 | // original options passed to the function.
232 | options: Options;
233 | }
234 | ````
235 |
236 | You can use the return value to determine if continue your gulp or grunt task or stop and emit an error.
237 |
238 | # Command line
239 |
240 | You can use `dts-bundle` from command line, its allow you use it from npm scripts [ see #13 ](https://github.com/TypeStrong/dts-bundle/issues/13).
241 | You have to install it using -g:
242 |
243 | ````
244 | npm install dts-bundle -g
245 | ````
246 |
247 | You can use the following options:
248 |
249 | ````
250 | Usage: dts-bundle [options]
251 |
252 | Options:
253 |
254 | -h, --help output usage information
255 | -V, --version output the version number
256 | --configJson path to json config file. Load it first and override options with additional parameters
257 | --name name of module likein package.json *required
258 | --main path to entry-point (see documentation) *required
259 | --baseDir [value] base directory to be used for discovering type declarations
260 | --out [value] path of output file. Is relative from baseDir but you can use absolute paths.
261 | --externals include typings outside of the "baseDir" (i.e. like node.d.ts)
262 | --referenceExternals reference external modules as tags
263 | --removeSource delete all source typings (i.e. "/**/*.d.ts")
264 | --newline [style] newline style to use in output file => unix|windows|currentOsDefault
265 | --prefix [value] prefix for rewriting module names
266 | --verbose enable verbose mode, prints detailed info about all references and includes/excludes
267 | --emitOnIncludedFileNotFound emit although included files not found. See readme "Files not found" section.
268 | --emitOnNoIncludedFileNotFound emit although no included files not found. See readme "Files not found" section.
269 | --outputAsModuleFolder output as module folder format (no declare module) . See readme "Module folders" section.
270 | --headerPath [value] path to file that contains the header
271 | --headerText [value] text of the header. Doesn't work with headerPath.
272 | ````
273 |
274 | For example:
275 | ````
276 | dts-bundle --name cool-project --main build/output/index.d.ts
277 | ````
278 | You can load config from a json file:
279 | ```` json
280 | // dts-bundle.json file
281 | {
282 | "name": "cool-project",
283 | "main": "tmp/out/index.d.ts"
284 | }
285 | ````
286 | Run this way:
287 | ````
288 | dts-bundle --configJson dts-bundle.json
289 | ````
290 | And can override properties:
291 | ````
292 | dts-bundle --configJson dts-bundle.json --name coolest
293 | ````
294 | Emitting `tmp/out/cooles.d.ts`.
295 |
296 |
297 | ## Todo
298 |
299 | - add feature to create a DefinitelyTyped header (using `definition-header` package)
300 | - add feature to auto-update package.json/bower.json with the definition link
301 | - find time to implement a parser based solution
302 | - run IO asyncronous
303 |
304 |
305 | # History
306 |
307 | * 0.4.x Several features.
308 | * CLI command
309 | * Support not found file (`emitOnIncludedFileNotFound` and `emitOnNoIncludedFileNotFound`)
310 | * Output relative to current path using "~/"
311 | * referenceExternals option
312 | * All files feature using `**/*.d.ts` on `main` option
313 | * Return a object with the result
314 | * Add Header using `headerPath`
315 | * 0.3.x - Support es6 module syntax & rewrite by TypeScript
316 | * 0.2.x - Fixed bugs & added many options (thanks @poelstra)
317 | * 0.1.x - First release
318 |
319 | ## Key People
320 |
321 | * [Javier Ros (tolemaC)](http://github.com/tolemac) : current lead
322 | * [Bart van der Schoor](https://github.com/Bartvds) : original creator
323 |
324 | ## Contributions
325 |
326 | They are very welcome. Beware this module is a quick hack-job so good luck!
327 |
328 | * Martin Poelstra (@poelstra): Exclude 'external' typings, optional debug output, improved configurability.
329 |
330 | ## License
331 |
332 | Licensed under the MIT license.
333 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs');
2 | var path = require('path');
3 | var glob = require('glob');
4 | var chai = require('chai');
5 | var mkdirp = require('mkdirp');
6 | var ncp = require('ncp');
7 |
8 | var execSync = require('child_process').execSync;
9 | var util = require("util");
10 |
11 | chai.use(require('chai-fs'));
12 | chai.config.includeStack = true;
13 |
14 | var assert = chai.assert;
15 |
16 | var dts = require('../index');
17 |
18 | var baseDir = __dirname;
19 | var buildDir = path.resolve(__dirname, 'build', 'sub');
20 | var expectDir = path.resolve(__dirname, 'expected');
21 | var tmpDir = path.resolve(__dirname, 'tmp');
22 |
23 | var bomOptExp = /^\uFEFF?/;
24 |
25 | function getFile(f) {
26 | return fs.readFileSync(f, 'utf8').replace(bomOptExp, '').replace(/\s*$/, '');
27 | }
28 |
29 | function fixPaths(arr) {
30 | return arr.map(function(p) {
31 | return p.replace('/', path.sep);
32 | }).sort();
33 | }
34 |
35 | function assertFiles(base, expHave, expNot) {
36 | var have = fixPaths(glob.sync('**/*.d.ts', {cwd: base}));
37 |
38 | assert.deepEqual(have, fixPaths(expHave), base);
39 | }
40 |
41 | function testit(name, assertion, run) {
42 | var call = function (done) {
43 | var testDir = path.join(tmpDir, name);
44 | var expDir = path.join(expectDir, name);
45 |
46 | mkdirp.sync(testDir);
47 |
48 | ncp.ncp(buildDir, testDir, function (err) {
49 | if (err) {
50 | done(err);
51 | return;
52 | }
53 | assertion(testDir, expDir);
54 | done();
55 | });
56 | };
57 |
58 | var label = 'bundle ' + name;
59 |
60 | if (run === 'skip') {
61 | it.skip(label, call);
62 | }
63 | else if (run === 'only') {
64 | it.only(label, call);
65 | }
66 | else {
67 | it(label, call);
68 | }
69 | }
70 |
71 | describe('dts bundle', function () {
72 |
73 | testit('default', function (actDir, expDir) {
74 | var result = dts.bundle({
75 | name: 'foo-mx',
76 | main: path.join(actDir, 'index.d.ts'),
77 | newline: '\n',
78 | verbose: true,
79 | headerPath: "none"
80 | });
81 | var name = 'foo-mx.d.ts';
82 | var actualFile = path.join(actDir, name);
83 | assert.isTrue(result.emitted, "not emit " + actualFile);
84 | var expectedFile = path.join(expDir, name);
85 | assertFiles(actDir, [
86 | name,
87 | 'index.d.ts',
88 | 'Foo.d.ts',
89 | 'lib/exported-sub.d.ts',
90 | 'lib/only-internal.d.ts'
91 | ]);
92 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
93 | });
94 |
95 | testit('default_cli', function (actDir, expDir) {
96 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
97 | execSync(util.format("node ./lib/dts-bundle.js --name foo-mx --main %s --newline unix --verbose --headerPath none", path.join(actDir, 'index.d.ts')));
98 | var name = 'foo-mx.d.ts';
99 | var actualFile = path.join(actDir, name);
100 | var expectedFile = path.join(expDir, name);
101 | assertFiles(actDir, [
102 | name,
103 | 'index.d.ts',
104 | 'Foo.d.ts',
105 | 'lib/exported-sub.d.ts',
106 | 'lib/only-internal.d.ts'
107 | ]);
108 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
109 | });
110 |
111 | testit('remove', function (actDir, expDir) {
112 | var result = dts.bundle({
113 | name: 'foo-mx',
114 | main: path.join(actDir, 'index.d.ts'),
115 | removeSource: true,
116 | newline: '\n',
117 | verbose: true,
118 | headerPath: "none"
119 | });
120 | var name = 'foo-mx.d.ts';
121 | var actualFile = path.join(actDir, name);
122 | assert.isTrue(result.emitted, "not emit " + actualFile);
123 | var expectedFile = path.join(expDir, name);
124 | assertFiles(actDir, [
125 | name
126 | ]);
127 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
128 | });
129 |
130 | testit('remove_cli', function (actDir, expDir) {
131 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
132 | execSync(util.format("node ./lib/dts-bundle --name foo-mx --main %s --removeSource --newline unix --verbose --headerPath none", path.join(actDir, 'index.d.ts')));
133 | var name = 'foo-mx.d.ts';
134 | var actualFile = path.join(actDir, name);
135 | var expectedFile = path.join(expDir, name);
136 | assertFiles(actDir, [
137 | name
138 | ]);
139 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
140 | });
141 |
142 | testit('out', function (actDir, expDir) {
143 | var result = dts.bundle({
144 | name: 'foo-mx',
145 | main: path.join(actDir, 'index.d.ts'),
146 | out: path.join(actDir, 'fizz', 'buzz.d.ts'),
147 | newline: '\n',
148 | verbose: true,
149 | headerPath: "none"
150 | });
151 | var name = path.join('fizz', 'buzz.d.ts');
152 | var actualFile = path.join(actDir, name);
153 | assert.isTrue(result.emitted, "not emit " + actualFile);
154 | var expectedFile = path.join(expDir, name);
155 | assertFiles(actDir, [
156 | name,
157 | 'index.d.ts',
158 | 'Foo.d.ts',
159 | 'lib/exported-sub.d.ts',
160 | 'lib/only-internal.d.ts'
161 | ]);
162 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
163 | });
164 |
165 | testit('out_cli', function (actDir, expDir) {
166 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
167 | execSync(util.format("node ./lib/dts-bundle --name foo-mx --main %s --out %s --newline unix --verbose --headerPath none",
168 | path.join(actDir, 'index.d.ts'),
169 | path.join(actDir, 'fizz', 'buzz.d.ts')));
170 | var name = path.join('fizz', 'buzz.d.ts');
171 | var actualFile = path.join(actDir, name);
172 | var expectedFile = path.join(expDir, name);
173 | assertFiles(actDir, [
174 | name,
175 | 'index.d.ts',
176 | 'Foo.d.ts',
177 | 'lib/exported-sub.d.ts',
178 | 'lib/only-internal.d.ts'
179 | ]);
180 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
181 | });
182 |
183 | testit('seprinnew', function (actDir, expDir) {
184 | var result = dts.bundle({
185 | name: 'bar-mx',
186 | main: path.join(actDir, 'index.d.ts'),
187 | removeSource: true,
188 | prefix: '--',
189 | separator: '#',
190 | indent: '\t',
191 | newline: ' //$\n',
192 | verbose: true,
193 | headerPath: "none"
194 | });
195 | var name = 'bar-mx.d.ts';
196 | var actualFile = path.join(actDir, name);
197 | assert.isTrue(result.emitted, "not emit " + actualFile);
198 | var expectedFile = path.join(expDir, name);
199 | assertFiles(actDir, [
200 | name
201 | ]);
202 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
203 | });
204 |
205 | testit('seprinnew_cli', function (actDir, expDir) {
206 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
207 | execSync(util.format("node ./lib/dts-bundle --configJson ./test/seprinnew_cli-config.json --name bar-mx --main %s --removeSource --verbose --headerPath none",
208 | path.join(actDir, 'index.d.ts'),
209 | path.join(actDir, 'fizz', 'buzz.d.ts')));
210 | var name = 'bar-mx.d.ts';
211 | var actualFile = path.join(actDir, name);
212 | var expectedFile = path.join(expDir, name);
213 | assertFiles(actDir, [
214 | name
215 | ]);
216 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
217 | });
218 |
219 | testit('externals', function (actDir, expDir) {
220 | var result = dts.bundle({
221 | name: 'foo-mx',
222 | main: path.join(actDir, 'index.d.ts'),
223 | externals: true,
224 | newline: '\n',
225 | verbose: true,
226 | headerPath: "none"
227 | });
228 | var name = 'foo-mx.d.ts';
229 | var actualFile = path.join(actDir, name);
230 | assert.isTrue(result.emitted, "not emit " + actualFile);
231 | var expectedFile = path.join(expDir, name);
232 | assertFiles(actDir, [
233 | name,
234 | 'index.d.ts',
235 | 'Foo.d.ts',
236 | 'lib/exported-sub.d.ts',
237 | 'lib/only-internal.d.ts'
238 | ]);
239 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
240 | });
241 |
242 | testit('externals_cli', function (actDir, expDir) {
243 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
244 | execSync(util.format("node ./lib/dts-bundle --name foo-mx --main %s --externals --newline unix --verbose --headerPath none",
245 | path.join(actDir, 'index.d.ts')));
246 | var name = 'foo-mx.d.ts';
247 | var actualFile = path.join(actDir, name);
248 | var expectedFile = path.join(expDir, name);
249 | assertFiles(actDir, [
250 | name,
251 | 'index.d.ts',
252 | 'Foo.d.ts',
253 | 'lib/exported-sub.d.ts',
254 | 'lib/only-internal.d.ts'
255 | ]);
256 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
257 | });
258 |
259 | testit('excludeExp', function (actDir, expDir) {
260 | var result = dts.bundle({
261 | name: 'foo-mx',
262 | main: path.join(actDir, 'index.d.ts'),
263 | exclude: /exported\-sub/,
264 | newline: '\n',
265 | verbose: true,
266 | headerPath: "none"
267 | });
268 | var name = 'foo-mx.d.ts';
269 | var actualFile = path.join(actDir, name);
270 | assert.isTrue(result.emitted, "not emit " + actualFile);
271 | var expectedFile = path.join(expDir, name);
272 | assertFiles(actDir, [
273 | name,
274 | 'index.d.ts',
275 | 'Foo.d.ts',
276 | 'lib/exported-sub.d.ts',
277 | 'lib/only-internal.d.ts'
278 | ]);
279 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
280 | });
281 |
282 | //testit('excludeExp_cli', function (actDir, expDir) { }); // No exclude options available from CLI.
283 |
284 | testit('excludeFunc', function (actDir, expDir) {
285 | var result = dts.bundle({
286 | name: 'foo-mx',
287 | main: path.join(actDir, 'index.d.ts'),
288 | exclude: function(file) {
289 | return /exported\-sub/.test(file);
290 | },
291 | newline: '\n',
292 | verbose: true,
293 | headerPath: "none"
294 | });
295 | var name = 'foo-mx.d.ts';
296 | var actualFile = path.join(actDir, name);
297 | assert.isTrue(result.emitted, "not emit " + actualFile);
298 | var expectedFile = path.join(expDir, name);
299 | assertFiles(actDir, [
300 | name,
301 | 'index.d.ts',
302 | 'Foo.d.ts',
303 | 'lib/exported-sub.d.ts',
304 | 'lib/only-internal.d.ts'
305 | ]);
306 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
307 | });
308 |
309 | //testit('excludeFunc_cli', function (actDir, expDir) { }); // No exclude options available from CLI.
310 |
311 | testit('includeExclude', function (actDir, expDir) {
312 | var result = dts.bundle({
313 | name: 'foo-mx',
314 | main: path.join(actDir, 'index.d.ts'),
315 | externals: true,
316 | exclude: /exported\-sub/,
317 | newline: '\n',
318 | verbose: true,
319 | headerPath: "none"
320 | });
321 | var name = 'foo-mx.d.ts';
322 | var actualFile = path.join(actDir, name);
323 | assert.isTrue(result.emitted, "not emit " + actualFile);
324 | var expectedFile = path.join(expDir, name);
325 | assertFiles(actDir, [
326 | name,
327 | 'index.d.ts',
328 | 'Foo.d.ts',
329 | 'lib/exported-sub.d.ts',
330 | 'lib/only-internal.d.ts'
331 | ]);
332 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
333 | });
334 |
335 | //testit('includeExclude_cli', function (actDir, expDir) { }); // No exclude options available from CLI.
336 |
337 | (function testit(name, assertion, run) {
338 | var buildDir = path.resolve(__dirname, 'build', 'conflicts', 'dirname');
339 | var call = function (done) {
340 | var testDir = path.join(tmpDir, name);
341 | var expDir = path.join(expectDir, name);
342 |
343 | mkdirp.sync(testDir);
344 |
345 | ncp.ncp(buildDir, testDir, function (err) {
346 | if (err) {
347 | done(err);
348 | return;
349 | }
350 | assertion(testDir, expDir);
351 | done();
352 | });
353 | };
354 |
355 | var label = 'bundle ' + name;
356 |
357 | if (run === 'skip') {
358 | it.skip(label, call);
359 | }
360 | else if (run === 'only') {
361 | it.only(label, call);
362 | }
363 | else {
364 | it(label, call);
365 | }
366 | })('conflicts_dirname', function (actDir, expDir) {
367 | var result = dts.bundle({
368 | name: 'foo-mx',
369 | main: path.join(actDir, 'index.d.ts'),
370 | newline: '\n',
371 | verbose: true,
372 | headerPath: "none"
373 | });
374 | var name = 'foo-mx.d.ts';
375 | var actualFile = path.join(actDir, name);
376 | assert.isTrue(result.emitted, "not emit " + actualFile);
377 | var expectedFile = path.join(expDir, name);
378 | assertFiles(actDir, [
379 | name,
380 | 'index.d.ts',
381 | 'file1.d.ts',
382 | 'file1/file2.d.ts',
383 | ]);
384 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
385 | });
386 |
387 | (function testit(name, assertion, run) {
388 | var buildDir = path.resolve(__dirname, 'build', 'es6');
389 | var call = function (done) {
390 | var testDir = path.join(tmpDir, name);
391 | var expDir = path.join(expectDir, name);
392 |
393 | mkdirp.sync(testDir);
394 |
395 | ncp.ncp(buildDir, testDir, function (err) {
396 | if (err) {
397 | done(err);
398 | return;
399 | }
400 | assertion(testDir, expDir);
401 | done();
402 | });
403 | };
404 |
405 | var label = 'bundle ' + name;
406 |
407 | if (run === 'skip') {
408 | it.skip(label, call);
409 | }
410 | else if (run === 'only') {
411 | it.only(label, call);
412 | }
413 | else {
414 | it(label, call);
415 | }
416 | })('es6', function (actDir, expDir) {
417 | var result = dts.bundle({
418 | name: 'foo-mx',
419 | main: path.join(actDir, '../es6', 'index.d.ts'),
420 | newline: '\n',
421 | verbose: true,
422 | headerPath: "none"
423 | });
424 | var name = 'foo-mx.d.ts';
425 | var actualFile = path.join(actDir, name);
426 | assert.isTrue(result.emitted, "not emit " + actualFile);
427 | var expectedFile = path.join(expDir, name);
428 | assertFiles(actDir, [
429 | name,
430 | 'index.d.ts',
431 | 'lib/subC.d.ts',
432 | 'lib/subD.d.ts',
433 | 'lib/subE.d.ts',
434 | 'sub.d.ts'
435 | ]);
436 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
437 | });
438 |
439 | (function testit(name, assertion, run) {
440 | var buildDir = path.resolve(__dirname, 'build', 'es6');
441 | var call = function (done) {
442 | var testDir = path.join(tmpDir, name);
443 | var expDir = path.join(expectDir, name);
444 |
445 | mkdirp.sync(testDir);
446 |
447 | ncp.ncp(buildDir, testDir, function (err) {
448 | if (err) {
449 | done(err);
450 | return;
451 | }
452 | assertion(testDir, expDir);
453 | done();
454 | });
455 | };
456 |
457 | var label = 'bundle ' + name;
458 |
459 | if (run === 'skip') {
460 | it.skip(label, call);
461 | }
462 | else if (run === 'only') {
463 | it.only(label, call);
464 | }
465 | else {
466 | it(label, call);
467 | }
468 | })('es6_cli', function (actDir, expDir) {
469 | expDir = expDir.substr(0, expDir.length - 4); // expDir is the same without "_cli" suffix
470 | execSync(util.format("node ./lib/dts-bundle --name foo-mx --main %s --newline unix --verbose --headerPath none",
471 | path.join(actDir, '../es6_cli', 'index.d.ts')));
472 | var name = 'foo-mx.d.ts';
473 | var actualFile = path.join(actDir, name);
474 | var expectedFile = path.join(expDir, name);
475 | assertFiles(actDir, [
476 | name,
477 | 'index.d.ts',
478 | 'lib/subC.d.ts',
479 | 'lib/subD.d.ts',
480 | 'lib/subE.d.ts',
481 | 'sub.d.ts'
482 | ]);
483 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
484 | });
485 |
486 | (function testit(name, assertion, run) {
487 | var buildDir = path.resolve(__dirname, 'build', 'commonjs');
488 | var call = function (done) {
489 | var testDir = path.join(tmpDir, name);
490 | var expDir = path.join(expectDir, name);
491 |
492 | mkdirp.sync(testDir);
493 |
494 | ncp.ncp(buildDir, testDir, function (err) {
495 | if (err) {
496 | done(err);
497 | return;
498 | }
499 | assertion(testDir, expDir);
500 | done();
501 | });
502 | };
503 |
504 | var label = 'bundle ' + name;
505 |
506 | if (run === 'skip') {
507 | it.skip(label, call);
508 | }
509 | else if (run === 'only') {
510 | it.only(label, call);
511 | }
512 | else {
513 | it(label, call);
514 | }
515 | })('commonjs', function (actDir, expDir) {
516 | var result = dts.bundle({
517 | name: 'foo-mx',
518 | main: path.join(actDir, '../commonjs', 'index.d.ts'),
519 | newline: '\n',
520 | verbose: true,
521 | headerPath: "none"
522 | });
523 | var name = 'foo-mx.d.ts';
524 | var actualFile = path.join(actDir, name);
525 | assert.isTrue(result.emitted, "not emit " + actualFile);
526 | var expectedFile = path.join(expDir, name);
527 | assertFiles(actDir, [
528 | name,
529 | 'index.d.ts',
530 | 'sub/index.d.ts',
531 | 'sub/sub.service.d.ts'
532 | ]);
533 | assert.strictEqual(getFile(actualFile), getFile(expectedFile));
534 | });
535 | });
536 |
--------------------------------------------------------------------------------
/lib/index.ts:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | import * as os from 'os';
4 | import * as fs from 'fs';
5 | import * as path from 'path';
6 | import * as util from 'util';
7 | import * as assert from 'assert';
8 | import * as glob from 'glob';
9 | import * as mkdirp from 'mkdirp';
10 | import * as detectIndent from 'detect-indent';
11 |
12 | let pkg = require('../package');
13 |
14 | const dtsExp = /\.d\.ts$/;
15 | const bomOptExp = /^\uFEFF?/;
16 |
17 | const externalExp = /^([ \t]*declare module )(['"])(.+?)(\2[ \t]*{?.*)$/;
18 | const importExp = /^([ \t]*(?:export )?(?:import .+? )= require\()(['"])(.+?)(\2\);.*)$/;
19 | const importEs6Exp = /^([ \t]*(?:export|import) ?(?:(?:\* (?:as [^ ,]+)?)|.*)?,? ?(?:[^ ,]+ ?,?)(?:\{(?:[^ ,]+ ?,?)*\})? ?from )(['"])([^ ,]+)(\2;.*)$/;
20 | const referenceTagExp = /^[ \t]*\/\/\/[ \t]*.*$/;
21 | const identifierExp = /^\w+(?:[\.-]\w+)*$/;
22 | const fileExp = /^([\./].*|.:.*)$/;
23 | const privateExp = /^[ \t]*(?:static )?private (?:static )?/;
24 | const publicExp = /^([ \t]*)(static |)(public |)(static |)(.*)/;
25 |
26 | export interface Options {
27 | main: string;
28 | name: string;
29 | baseDir?: string;
30 | out?: string;
31 | newline?: string;
32 | indent?: string;
33 | outputAsModuleFolder?: boolean;
34 | prefix?: string;
35 | separator?: string;
36 | externals?: boolean;
37 | exclude?: { (file: string): boolean; } | RegExp;
38 | removeSource?: boolean;
39 | verbose?: boolean;
40 | referenceExternals?: boolean;
41 | emitOnIncludedFileNotFound?: boolean;
42 | emitOnNoIncludedFileNotFound?: boolean;
43 | headerPath: string;
44 | headerText: string;
45 | }
46 |
47 | export interface ModLine {
48 | original: string;
49 | modified?: string;
50 | skip?: boolean;
51 | }
52 |
53 | export interface Result {
54 | file: string;
55 | name: string;
56 | indent: string;
57 | exp: string;
58 | refs: string[];
59 | externalImports: string[];
60 | relativeImports: string[];
61 | exports: string[];
62 | lines: ModLine[];
63 | importLineRef: ModLine[];
64 | relativeRef: ModLine[];
65 | fileExists: boolean;
66 | }
67 |
68 | export interface BundleResult {
69 | fileMap: { [name: string]: Result; };
70 | includeFilesNotFound: string[];
71 | noIncludeFilesNotFound: string[];
72 | emitted?: boolean;
73 | options: Options;
74 | }
75 |
76 | export function bundle(options: Options): BundleResult {
77 | assert(typeof options === 'object' && options, 'options must be an object');
78 |
79 | // if main ends with **/*.d.ts all .d.ts files will be loaded
80 | const allFiles = stringEndsWith(options.main, "**/*.d.ts");
81 |
82 | // option parsing & validation
83 | const main = allFiles ? "*.d.ts" : options.main;
84 | const exportName = options.name;
85 | const _baseDir = (() => {
86 | let baseDir = optValue(options.baseDir, path.dirname(options.main));
87 | if (allFiles) {
88 | baseDir = baseDir.substr(0, baseDir.length - 2);
89 | }
90 | return baseDir;
91 | })();
92 | const out = optValue(options.out, exportName + '.d.ts').replace(/\//g, path.sep);
93 |
94 | const newline = optValue(options.newline, os.EOL);
95 | const indent = optValue(options.indent, ' ');
96 | const outputAsModuleFolder = optValue(options.outputAsModuleFolder, false);
97 | const prefix = optValue(options.prefix, '');
98 | const separator = optValue(options.separator, '/');
99 |
100 | const externals = optValue(options.externals, false);
101 | const exclude = optValue(options.exclude, null);
102 | const removeSource = optValue(options.removeSource, false);
103 | const referenceExternals = optValue(options.referenceExternals, false);
104 | const emitOnIncludedFileNotFound = optValue(options.emitOnIncludedFileNotFound, false);
105 | const emitOnNoIncludedFileNotFound = optValue(options.emitOnNoIncludedFileNotFound, false);
106 | const _headerPath = optValue(options.headerPath, null);
107 | const headerText = optValue(options.headerText, '');
108 |
109 | // regular (non-jsdoc) comments are not actually supported by declaration compiler
110 | const comments = false;
111 |
112 | const verbose = optValue(options.verbose, false);
113 |
114 | assert.ok(main, 'option "main" must be defined');
115 | assert.ok(exportName, 'option "name" must be defined');
116 |
117 | assert(typeof newline === 'string', 'option "newline" must be a string');
118 | assert(typeof indent === 'string', 'option "indent" must be a string');
119 | assert(typeof prefix === 'string', 'option "prefix" must be a string');
120 | assert(separator.length > 0, 'option "separator" must have non-zero length');
121 |
122 | // turn relative paths into absolute paths
123 | const baseDir = path.resolve(_baseDir);
124 | let mainFile = allFiles ? path.resolve(baseDir, "**/*.d.ts") : path.resolve(main.replace(/\//g, path.sep));
125 | const outFile = calcOutFilePath(out, baseDir);
126 | let headerData = '// Generated by dts-bundle v' + pkg.version + newline;
127 | const headerPath = _headerPath && _headerPath !== "none" ? path.resolve(_headerPath.replace(/\//g, path.sep)) : _headerPath;
128 |
129 | trace('### settings object passed ###');
130 | traceObject(options);
131 |
132 | trace('### settings ###');
133 | trace('main: %s', main);
134 | trace('name: %s', exportName);
135 | trace('out: %s', out);
136 | trace('baseDir: %s', baseDir);
137 | trace('mainFile: %s', mainFile);
138 | trace('outFile: %s', outFile);
139 | trace('externals: %s', externals ? 'yes' : 'no');
140 | trace('exclude: %s', exclude);
141 | trace('removeSource: %s', removeSource ? 'yes' : 'no');
142 | trace('comments: %s', comments ? 'yes' : 'no');
143 | trace('emitOnIncludedFileNotFound: %s', emitOnIncludedFileNotFound ? "yes" : "no");
144 | trace('emitOnNoIncludedFileNotFound: %s', emitOnNoIncludedFileNotFound ? "yes" : "no");
145 | trace("headerPath %s", headerPath);
146 | trace("headerText %s", headerText);
147 |
148 | if (!allFiles) {
149 | assert(fs.existsSync(mainFile), 'main does not exist: ' + mainFile);
150 | }
151 |
152 | if (headerPath) {
153 | if (headerPath === "none") {
154 | headerData = "";
155 | } else {
156 | assert(fs.existsSync(headerPath), 'header does not exist: ' + headerPath);
157 | headerData = fs.readFileSync(headerPath, 'utf8') + headerData;
158 | }
159 | } else if (headerText) {
160 | headerData = '/*' + headerText + '*/\n';
161 | }
162 |
163 | let isExclude: (file: string, arg?: boolean) => boolean;
164 | if (typeof exclude === 'function') {
165 | isExclude = exclude;
166 | }
167 | else if (exclude instanceof RegExp) {
168 | isExclude = file => exclude.test(file);
169 | }
170 | else {
171 | isExclude = () => false;
172 | }
173 |
174 | const sourceTypings = glob.sync('**/*.d.ts', { cwd: baseDir }).map(file => path.resolve(baseDir, file));
175 |
176 | // if all files, generate temporally main file
177 | if (allFiles) {
178 | let mainFileContent = "";
179 | trace("## temporally main file ##");
180 | sourceTypings.forEach(file => {
181 | let generatedLine = "export * from './" + path.relative(baseDir, file.substr(0, file.length - 5)).replace(path.sep, "/") + "';";
182 | trace(generatedLine);
183 | mainFileContent += generatedLine + "\n";
184 | });
185 | mainFile = path.resolve(baseDir, "dts-bundle.tmp." + exportName + ".d.ts");
186 | fs.writeFileSync(mainFile, mainFileContent, 'utf8');
187 | }
188 |
189 | trace('\n### find typings ###');
190 |
191 | const inSourceTypings = (file: string) => {
192 | return sourceTypings.indexOf(file) !== -1 || sourceTypings.indexOf(path.join(file, 'index.d.ts')) !== -1;
193 | }; // if file reference is a directory assume commonjs index.d.ts
194 |
195 | trace('source typings (will be included in output if actually used)');
196 |
197 | sourceTypings.forEach(file => trace(' - %s ', file));
198 |
199 | trace('excluded typings (will always be excluded from output)');
200 |
201 | let fileMap: { [name: string]: Result; } = Object.create(null);
202 | let globalExternalImports: string[] = [];
203 | let mainParse: Result; // will be parsed result of first parsed file
204 | let externalTypings: string[] = [];
205 | let inExternalTypings = (file: string) => externalTypings.indexOf(file) !== -1;
206 | {
207 | // recursively parse files, starting from main file,
208 | // following all references and imports
209 | trace('\n### parse files ###');
210 |
211 | let queue: string[] = [mainFile];
212 | let queueSeen: { [name: string]: boolean; } = Object.create(null);
213 |
214 | while (queue.length > 0) {
215 | let target = queue.shift();
216 | if (queueSeen[target]) {
217 | continue;
218 | }
219 | queueSeen[target] = true;
220 |
221 | // parse the file
222 | let parse = parseFile(target);
223 | if (!mainParse) {
224 | mainParse = parse;
225 | }
226 | fileMap[parse.file] = parse;
227 | pushUniqueArr(queue, parse.refs, parse.relativeImports);
228 | }
229 | }
230 |
231 | // map all exports to their file
232 | trace('\n### map exports ###');
233 |
234 | let exportMap = Object.create(null);
235 | Object.keys(fileMap).forEach(file => {
236 | let parse = fileMap[file];
237 | parse.exports.forEach(name => {
238 | assert(!(name in exportMap), 'already got export for: ' + name);
239 | exportMap[name] = parse;
240 | trace('- %s -> %s', name, parse.file);
241 | });
242 | });
243 |
244 | // build list of typings to include in output later
245 | trace('\n### determine typings to include ###');
246 |
247 | let excludedTypings: string[] = [];
248 | let usedTypings: Result[] = [];
249 | let externalDependencies: string[] = []; // lists all source files that we omit due to !externals
250 | {
251 | let queue = [mainParse];
252 | let queueSeen: { [name: string]: boolean; } = Object.create(null);
253 |
254 | trace('queue');
255 | trace(queue);
256 |
257 | while (queue.length > 0) {
258 | let parse = queue.shift();
259 | if (queueSeen[parse.file]) {
260 | continue;
261 | }
262 | queueSeen[parse.file] = true;
263 |
264 | trace('%s (%s)', parse.name, parse.file);
265 |
266 | usedTypings.push(parse);
267 |
268 | parse.externalImports.forEach(name => {
269 | let p = exportMap[name];
270 | if (!externals) {
271 | trace(' - exclude external %s', name);
272 | pushUnique(externalDependencies, !p ? name : p.file);
273 | return;
274 | }
275 | if (isExclude(path.relative(baseDir, p.file), true)) {
276 | trace(' - exclude external filter %s', name);
277 | pushUnique(excludedTypings, p.file);
278 | return;
279 | }
280 | trace(' - include external %s', name);
281 | assert(p, name);
282 | queue.push(p);
283 | });
284 | parse.relativeImports.forEach(file => {
285 | let p = fileMap[file];
286 | if (isExclude(path.relative(baseDir, p.file), false)) {
287 | trace(' - exclude internal filter %s', file);
288 | pushUnique(excludedTypings, p.file);
289 | return;
290 | }
291 | trace(' - import relative %s', file);
292 | assert(p, file);
293 | queue.push(p);
294 | });
295 | }
296 | }
297 |
298 | // rewrite global external modules to a unique name
299 | trace('\n### rewrite global external modules ###');
300 |
301 | usedTypings.forEach(parse => {
302 | trace(parse.name);
303 |
304 | parse.relativeRef.forEach((line, i) => {
305 | line.modified = replaceExternal(line.original, getLibName);
306 | trace(' - %s ==> %s', line.original, line.modified);
307 | });
308 |
309 | parse.importLineRef.forEach((line, i) => {
310 | if (outputAsModuleFolder) {
311 | trace(' - %s was skipped.', line.original);
312 | line.skip = true;
313 | return;
314 | }
315 |
316 | if (importExp.test(line.original)) {
317 | line.modified = replaceImportExport(line.original, getLibName);
318 | } else {
319 | line.modified = replaceImportExportEs6(line.original, getLibName);
320 | }
321 | trace(' - %s ==> %s', line.original, line.modified);
322 | });
323 | });
324 |
325 | // build collected content
326 | trace('\n### build output ###');
327 |
328 | let content = headerData;
329 | if (externalDependencies.length > 0) {
330 | content += '// Dependencies for this module:' + newline;
331 | externalDependencies.forEach(file => {
332 | if (referenceExternals) {
333 | content += formatReference(path.relative(baseDir, file).replace(/\\/g, '/')) + newline;
334 | }
335 | else {
336 | content += '// ' + path.relative(baseDir, file).replace(/\\/g, '/') + newline;
337 | }
338 | });
339 | }
340 |
341 | if ( globalExternalImports.length > 0 ) {
342 | content += newline;
343 | content += globalExternalImports.join(newline) + newline;
344 | }
345 |
346 | content += newline;
347 |
348 | // content += header.stringify(header.importer.packageJSON(pkg)).join(lb) + lb;
349 | // content += lb;
350 |
351 | // add wrapped modules to output
352 | content += usedTypings.filter((parse: Result) => {
353 | // Eliminate all the skipped lines
354 | parse.lines = parse.lines.filter((line: ModLine) => {
355 | return (true !== line.skip);
356 | });
357 |
358 | // filters empty parse objects.
359 | return ( parse.lines.length > 0 );
360 | }).map((parse: Result) => {
361 | if (inSourceTypings(parse.file)) {
362 | return formatModule(parse.file, parse.lines.map(line => {
363 | return getIndenter(parse.indent, indent)(line);
364 | }));
365 | }
366 | else {
367 | return parse.lines.map(line => {
368 | return getIndenter(parse.indent, indent)(line);
369 | }).join(newline) + newline;
370 | }
371 | }).join(newline) + newline;
372 |
373 | // remove internal typings, except the 'regenerated' main typing
374 | if (removeSource) {
375 | trace('\n### remove source typings ###');
376 |
377 | sourceTypings.forEach(p => {
378 | // safety check, only delete .d.ts files, leave our outFile intact for now
379 | if (p !== outFile && dtsExp.test(p) && fs.statSync(p).isFile()) {
380 | trace(' - %s', p);
381 | fs.unlinkSync(p);
382 | }
383 | });
384 | }
385 |
386 | let inUsed = (file: string): boolean => {
387 | return usedTypings.filter(parse => parse.file === file).length !== 0;
388 | };
389 |
390 | let bundleResult: BundleResult = {
391 | fileMap,
392 | includeFilesNotFound: [],
393 | noIncludeFilesNotFound: [],
394 | options
395 | };
396 |
397 | trace('## files not found ##');
398 | for (let p in fileMap) {
399 | let parse = fileMap[p];
400 | if (!parse.fileExists) {
401 | if (inUsed(parse.file)) {
402 | bundleResult.includeFilesNotFound.push(parse.file);
403 | warning(' X Included file NOT FOUND %s ', parse.file)
404 | } else {
405 | bundleResult.noIncludeFilesNotFound.push(parse.file);
406 | trace(' X Not used file not found %s', parse.file);
407 | }
408 | }
409 | }
410 |
411 | // write main file
412 | trace('\n### write output ###');
413 | // write only if there aren't not found files or there are and option "emit file not found" is true.
414 | if ((bundleResult.includeFilesNotFound.length == 0
415 | || (bundleResult.includeFilesNotFound.length > 0 && emitOnIncludedFileNotFound))
416 | && (bundleResult.noIncludeFilesNotFound.length == 0
417 | || (bundleResult.noIncludeFilesNotFound.length > 0 && emitOnNoIncludedFileNotFound))) {
418 |
419 | trace(outFile);
420 | {
421 | let outDir = path.dirname(outFile);
422 | if (!fs.existsSync(outDir)) {
423 | mkdirp.sync(outDir);
424 | }
425 | }
426 |
427 | fs.writeFileSync(outFile, content, 'utf8');
428 | bundleResult.emitted = true;
429 | } else {
430 | warning(" XXX Not emit due to exist files not found.")
431 | trace("See documentation for emitOnIncludedFileNotFound and emitOnNoIncludedFileNotFound options.")
432 | bundleResult.emitted = false;
433 | }
434 |
435 | // print some debug info
436 | if (verbose) {
437 | trace('\n### statistics ###');
438 |
439 | trace('used sourceTypings');
440 | sourceTypings.forEach(p => {
441 | if (inUsed(p)) {
442 | trace(' - %s', p);
443 | }
444 | });
445 |
446 | trace('unused sourceTypings');
447 | sourceTypings.forEach(p => {
448 | if (!inUsed(p)) {
449 | trace(' - %s', p);
450 | }
451 | });
452 |
453 | trace('excludedTypings');
454 | excludedTypings.forEach(p => {
455 | trace(' - %s', p);
456 | });
457 |
458 | trace('used external typings');
459 | externalTypings.forEach(p => {
460 | if (inUsed(p)) {
461 | trace(' - %s', p);
462 | }
463 | });
464 |
465 | trace('unused external typings');
466 | externalTypings.forEach(p => {
467 | if (!inUsed(p)) {
468 | trace(' - %s', p);
469 | }
470 | });
471 |
472 | trace('external dependencies');
473 | externalDependencies.forEach(p => {
474 | trace(' - %s', p);
475 | });
476 | }
477 |
478 | trace('\n### done ###\n');
479 | // remove temporally file.
480 | if (allFiles) {
481 | fs.unlinkSync(mainFile);
482 | }
483 | return bundleResult;
484 |
485 | function stringEndsWith(str: string, suffix: string) {
486 | return str.indexOf(suffix, str.length - suffix.length) !== -1;
487 | }
488 |
489 | function stringStartsWith(str: string, prefix: string) {
490 | return str.slice(0, prefix.length) == prefix;
491 | }
492 |
493 | // Calculate out file path (see #26 https://github.com/TypeStrong/dts-bundle/issues/26)
494 | function calcOutFilePath(out: any, baseDir: any) {
495 | var result = path.resolve(baseDir, out);
496 | // if path start with ~, out parameter is relative from current dir
497 | if (stringStartsWith(out, "~" + path.sep)) {
498 | result = path.resolve(".", out.substr(2));
499 | }
500 | return result;
501 | }
502 |
503 | function traceObject(obj: any) {
504 | if (verbose) {
505 | console.log(obj);
506 | }
507 | }
508 |
509 | function trace(...args: any[]) {
510 | if (verbose) {
511 | console.log(util.format.apply(null, args));
512 | }
513 | }
514 |
515 | function warning(...args: any[]) {
516 | console.log(util.format.apply(null, args));
517 | }
518 |
519 | function getModName(file: string) {
520 | return path.relative(baseDir, path.dirname(file) + path.sep + path.basename(file).replace(/\.d\.ts$/, ''));
521 | }
522 |
523 | function getExpName(file: string) {
524 | if (file === mainFile) {
525 | return exportName;
526 | }
527 | return getExpNameRaw(file);
528 | }
529 |
530 | function getExpNameRaw(file: string) {
531 | return prefix + exportName + separator + cleanupName(getModName(file));
532 | }
533 |
534 | function getLibName(ref: string) {
535 | return getExpNameRaw(mainFile) + separator + prefix + separator + ref;
536 | }
537 |
538 | function cleanupName(name: string) {
539 | return name.replace(/\.\./g, '--').replace(/[\\\/]/g, separator);
540 | }
541 |
542 | function mergeModulesLines(lines: any) {
543 | var i = (outputAsModuleFolder ? '' : indent);
544 | return (lines.length === 0 ? '' : i + lines.join(newline + i)) + newline;
545 | }
546 |
547 | function formatModule(file: string, lines: string[]) {
548 | let out = '';
549 | if (outputAsModuleFolder) {
550 | return mergeModulesLines(lines);
551 | }
552 |
553 | out += 'declare module \'' + getExpName(file) + '\' {' + newline;
554 | out += mergeModulesLines(lines);
555 | out += '}' + newline;
556 | return out;
557 | }
558 |
559 | // main info extractor
560 | function parseFile(file: string): Result {
561 | const name = getModName(file);
562 |
563 | trace('%s (%s)', name, file);
564 |
565 | const res: Result = {
566 | file: file,
567 | name: name,
568 | indent: indent,
569 | exp: getExpName(file),
570 | refs: [], // triple-slash references
571 | externalImports: [], // import()'s like "events"
572 | relativeImports: [], // import()'s like "./foo"
573 | exports: [],
574 | lines: [],
575 | fileExists: true,
576 | // the next two properties contain single-element arrays, which reference the same single-element in .lines,
577 | // in order to be able to replace their contents later in the bundling process.
578 | importLineRef: [],
579 | relativeRef: []
580 | };
581 |
582 | if (!fs.existsSync(file)) {
583 | trace(' X - File not found: %s', file);
584 | res.fileExists = false;
585 | return res;
586 | }
587 | if (fs.lstatSync(file).isDirectory()) { // if file is a directory then lets assume commonjs convention of an index file in the given folder
588 | file = path.join(file, 'index.d.ts');
589 | }
590 | const code = fs.readFileSync(file, 'utf8').replace(bomOptExp, '').replace(/\s*$/, '');
591 | res.indent = detectIndent(code) || indent;
592 |
593 | // buffer multi-line comments, handle JSDoc
594 | let multiComment: string[] = [];
595 | let queuedJSDoc: string[];
596 | let inBlockComment = false;
597 | const popBlock = () => {
598 | if (multiComment.length > 0) {
599 | // jsdoc
600 | if (/^[ \t]*\/\*\*/.test(multiComment[0])) {
601 | // flush but hold
602 | queuedJSDoc = multiComment;
603 | }
604 | else if (comments) {
605 | // flush it
606 | multiComment.forEach(line => res.lines.push({ original: line }));
607 | }
608 | multiComment = [];
609 | }
610 | inBlockComment = false;
611 | };
612 | const popJSDoc = () => {
613 | if (queuedJSDoc) {
614 | queuedJSDoc.forEach(line => {
615 | // fix shabby TS JSDoc output
616 | let match = line.match(/^([ \t]*)(\*.*)/);
617 | if (match) {
618 | res.lines.push({ original: match[1] + ' ' + match[2] });
619 | }
620 | else {
621 | res.lines.push({ original: line });
622 | }
623 | });
624 | queuedJSDoc = null;
625 | }
626 | };
627 |
628 | code.split(/\r?\n/g).forEach((line: any) => {
629 | let match: string[];
630 |
631 | // block comment end
632 | if (/^[((=====)(=*)) \t]*\*+\//.test(line)) {
633 | multiComment.push(line);
634 | popBlock();
635 | return;
636 | }
637 |
638 | // block comment start
639 | if (/^[ \t]*\/\*/.test(line)) {
640 | multiComment.push(line);
641 | inBlockComment = true;
642 |
643 | // single line block comment
644 | if (/\*+\/[ \t]*$/.test(line)) {
645 | popBlock();
646 | }
647 | return;
648 | }
649 |
650 | if (inBlockComment) {
651 | multiComment.push(line);
652 | return;
653 | }
654 |
655 | // blankline
656 | if (/^\s*$/.test(line)) {
657 | res.lines.push({ original: '' });
658 | return;
659 | }
660 |
661 | // reference tag
662 | if (/^\/\/\//.test(line)) {
663 | let ref = extractReference(line);
664 | if (ref) {
665 | let refPath = path.resolve(path.dirname(file), ref);
666 | if (inSourceTypings(refPath)) {
667 | trace(' - reference source typing %s (%s)', ref, refPath);
668 | } else {
669 | let relPath = path.relative(baseDir, refPath).replace(/\\/g, '/');
670 |
671 | trace(' - reference external typing %s (%s) (relative: %s)', ref, refPath, relPath);
672 |
673 | if (!inExternalTypings(refPath)) {
674 | externalTypings.push(refPath);
675 | }
676 | }
677 | pushUnique(res.refs, refPath);
678 | return;
679 | }
680 | }
681 |
682 | // line comments
683 | if (/^\/\//.test(line)) {
684 | if (comments) {
685 | res.lines.push({ original: line });
686 | }
687 | return;
688 | }
689 |
690 | // private member
691 | if (privateExp.test(line)) {
692 | queuedJSDoc = null;
693 | return;
694 | }
695 | popJSDoc();
696 |
697 | // import() statement or es6 import
698 | if ((line.indexOf("from") >= 0 && (match = line.match(importEs6Exp))) ||
699 | (line.indexOf("require") >= 0 && (match = line.match(importExp)))) {
700 | const [_, lead, quote, moduleName, trail] = match;
701 | assert(moduleName);
702 |
703 | const impPath = path.resolve(path.dirname(file), moduleName);
704 |
705 | // filename (i.e. starts with a dot, slash or windows drive letter)
706 | if (fileExp.test(moduleName)) {
707 | // TODO: some module replacing is handled here, whereas the rest is
708 | // done in the "rewrite global external modules" step. It may be
709 | // more clear to do all of it in that step.
710 | let modLine: ModLine = {
711 | original: lead + quote + getExpName(impPath) + trail
712 | };
713 | res.lines.push(modLine);
714 |
715 | let full = path.resolve(path.dirname(file), impPath);
716 | // If full is not an existing file, then let's assume the extension .d.ts
717 | if(!fs.existsSync(full) || fs.existsSync(full + '.d.ts')) {
718 | full += '.d.ts';
719 | }
720 | trace(' - import relative %s (%s)', moduleName, full);
721 |
722 | pushUnique(res.relativeImports, full);
723 | res.importLineRef.push(modLine);
724 | }
725 | // identifier
726 | else {
727 | let modLine: ModLine = {
728 | original: line
729 | };
730 | trace(' - import external %s', moduleName);
731 |
732 | pushUnique(res.externalImports, moduleName);
733 | if (externals) {
734 | res.importLineRef.push(modLine);
735 | }
736 | if (!outputAsModuleFolder) {
737 | res.lines.push(modLine);
738 | } else {
739 | pushUnique(globalExternalImports, line);
740 | }
741 | }
742 | }
743 |
744 | // declaring an external module
745 | // this triggers when we're e.g. parsing external module declarations, such as node.d.ts
746 | else if ((match = line.match(externalExp))) {
747 | let [_, declareModule, lead, moduleName, trail] = match;
748 | assert(moduleName);
749 |
750 | trace(' - declare %s', moduleName);
751 | pushUnique(res.exports, moduleName);
752 | let modLine: ModLine = {
753 | original: line
754 | };
755 | res.relativeRef.push(modLine); // TODO
756 | res.lines.push(modLine);
757 | }
758 | // clean regular lines
759 | else {
760 | // remove public keyword
761 | if ((match = line.match(publicExp))) {
762 | let [_, sp, static1, pub, static2, ident] = match;
763 | line = sp + static1 + static2 + ident;
764 | }
765 | if (inSourceTypings(file)) {
766 | // for internal typings, remove the 'declare' keyword (but leave 'export' intact)
767 | res.lines.push({ original: line.replace(/^(export )?declare /g, '$1') });
768 | }
769 | else {
770 | res.lines.push({ original: line });
771 | }
772 | }
773 | });
774 |
775 | return res;
776 | }
777 | }
778 |
779 | function pushUnique(arr: T[], value: T) {
780 | if (arr.indexOf(value) < 0) {
781 | arr.push(value);
782 | }
783 | return arr;
784 | }
785 |
786 | function pushUniqueArr(arr: T[], ...values: T[][]) {
787 | values.forEach(vs => vs.forEach(v => pushUnique(arr, v)));
788 | return arr;
789 | }
790 |
791 | function formatReference(file: string) {
792 | return '/// ';
793 | }
794 |
795 | function extractReference(tag: string) {
796 | let match = tag.match(referenceTagExp);
797 | if (match) {
798 | return match[2];
799 | }
800 | return null;
801 | }
802 |
803 | function replaceImportExport(line: string, replacer: (str: string) => string) {
804 | let match = line.match(importExp);
805 | if (match) {
806 | assert(match[4]);
807 | if (identifierExp.test(match[3])) {
808 | return match[1] + match[2] + replacer(match[3]) + match[4];
809 | }
810 | }
811 | return line;
812 | }
813 |
814 | function replaceImportExportEs6(line: string, replacer: (str: string) => string) {
815 | if (line.indexOf("from") < 0) {
816 | return line;
817 | }
818 | let match = line.match(importEs6Exp);
819 | if (match) {
820 | assert(match[4]);
821 | if (identifierExp.test(match[3])) {
822 | return match[1] + match[2] + replacer(match[3]) + match[4];
823 | }
824 | }
825 | return line;
826 | }
827 |
828 | function replaceExternal(line: string, replacer: (str: string) => string) {
829 | let match = line.match(externalExp);
830 | if (match) {
831 | let [_, declareModule, beforeIndent, moduleName, afterIdent] = match;
832 | assert(afterIdent);
833 | if (identifierExp.test(moduleName)) {
834 | return declareModule + beforeIndent + replacer(moduleName) + afterIdent;
835 | }
836 | }
837 | return line;
838 | }
839 |
840 | function getIndenter(actual: string, use: string): (line: ModLine) => string {
841 | if (actual === use || !actual) {
842 | return line => line.modified || line.original;
843 | }
844 | return line => (line.modified || line.original).replace(new RegExp('^' + actual + '+', 'g'), match => match.split(actual).join(use));
845 | }
846 |
847 | function optValue(passed: T, def: T): T {
848 | if (typeof passed === 'undefined') {
849 | return def;
850 | }
851 | return passed;
852 | }
853 |
854 | function regexEscape(s: string) {
855 | return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
856 | }
857 |
--------------------------------------------------------------------------------