diff --git a/.gitignore b/.gitignore index 2de8774..35f90be 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ /test/build !/test/src/typings/*.d.ts /test/src/**/*.d.ts +!/test/src/inline_imports/*.d.ts /test/src/**/*.js /test/src/**/*.js.map diff --git a/lib/index.ts b/lib/index.ts index 6e744c4..694b116 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,6 +17,8 @@ const bomOptExp = /^\uFEFF?/; const externalExp = /^([ \t]*declare module )(['"])(.+?)(\2[ \t]*{?.*)$/; const importExp = /^([ \t]*(?:export )?(?:import .+? )= require\()(['"])(.+?)(\2\);.*)$/; const importEs6Exp = /^([ \t]*(?:export|import) ?(?:(?:\* (?:as [^ ,]+)?)|.*)?,? ?(?:[^ ,]+ ?,?)(?:\{(?:[^ ,]+ ?,?)*\})? ?from )(['"])([^ ,]+)(\2;.*)$/; +const importEs6SideEffectExp = /^([ \t]*import )(['"])(.+?)(\2;.*)$/; +const importEs6InlineExp = /^(.*?import\()(['"])(.+?)(\2\).*)$/; const referenceTagExp = /^[ \t]*\/\/\/[ \t]*.*$/; const identifierExp = /^\w+(?:[\.-]\w+)*$/; const fileExp = /^([\./].*|.:.*)$/; @@ -183,7 +185,7 @@ export function bundle(options: Options): BundleResult { mainFileContent += generatedLine + "\n"; }); mainFile = path.resolve(baseDir, "dts-bundle.tmp." + exportName + ".d.ts"); - fs.writeFileSync(mainFile, mainFileContent, 'utf8'); + fs.writeFileSync(mainFile, mainFileContent, { encoding: 'utf8' }); } trace('\n### find typings ###'); @@ -424,7 +426,7 @@ export function bundle(options: Options): BundleResult { } } - fs.writeFileSync(outFile, content, 'utf8'); + fs.writeFileSync(outFile, content, { encoding: 'utf8' }); bundleResult.emitted = true; } else { warning(" XXX Not emit due to exist files not found.") @@ -587,7 +589,7 @@ export function bundle(options: Options): BundleResult { if (fs.lstatSync(file).isDirectory()) { // if file is a directory then lets assume commonjs convention of an index file in the given folder file = path.join(file, 'index.d.ts'); } - const code = fs.readFileSync(file, 'utf8').replace(bomOptExp, '').replace(/\s*$/, ''); + const code = fs.readFileSync(file, { encoding: 'utf8' }).replace(bomOptExp, '').replace(/\s*$/, ''); res.indent = detectIndent(code) || indent; // buffer multi-line comments, handle JSDoc @@ -696,36 +698,51 @@ export function bundle(options: Options): BundleResult { // import() statement or es6 import if ((line.indexOf("from") >= 0 && (match = line.match(importEs6Exp))) || + (line.indexOf("import") >=0 && (match = line.match(importEs6InlineExp))) || + (line.indexOf("import") >=0 && (match = line.match(importEs6SideEffectExp))) || (line.indexOf("require") >= 0 && (match = line.match(importExp)))) { const [_, lead, quote, moduleName, trail] = match; assert(moduleName); const impPath = path.resolve(path.dirname(file), moduleName); + let full = path.resolve(path.dirname(file), impPath); // combine with above line? // filename (i.e. starts with a dot, slash or windows drive letter) if (fileExp.test(moduleName)) { - // TODO: some module replacing is handled here, whereas the rest is - // done in the "rewrite global external modules" step. It may be - // more clear to do all of it in that step. - let modLine: ModLine = { - original: lead + quote + getExpName(impPath) + trail - }; - res.lines.push(modLine); + let assumeExists; - let full = path.resolve(path.dirname(file), impPath); // If full is not an existing file, then let's assume the extension .d.ts - if(!fs.existsSync(full) || fs.existsSync(full + '.d.ts')) { + if (fs.existsSync(full + '.d.ts')) { full += '.d.ts'; + assumeExists = true; + } else { + assumeExists = fs.existsSync(full); } - trace(' - import relative %s (%s)', moduleName, full); - pushUnique(res.relativeImports, full); - res.importLineRef.push(modLine); + if (!assumeExists) { // probably a resource typescript doesn't know how to handle + res.lines.push({ original: line }); // TOD: still transform the path? + + } else { + // TODO: some module replacing is handled here, whereas the rest is + // done in the "rewrite global external modules" step. It may be + // more clear to do all of it in that step. + let modLine: ModLine = { + original: removeDeclares( + lead + quote + getExpName(impPath) + trail + ) + }; + res.lines.push(modLine); + + trace(' - import relative %s (%s)', moduleName, full); + + pushUnique(res.relativeImports, full); + res.importLineRef.push(modLine); + } } // identifier else { let modLine: ModLine = { - original: line + original: removeDeclares(line) }; trace(' - import external %s', moduleName); @@ -750,7 +767,7 @@ export function bundle(options: Options): BundleResult { trace(' - declare %s', moduleName); pushUnique(res.exports, moduleName); let modLine: ModLine = { - original: line + original: inSourceTypings(file) ? removeDeclares(line) : line }; res.relativeRef.push(modLine); // TODO res.lines.push(modLine); @@ -762,13 +779,10 @@ export function bundle(options: Options): BundleResult { let [_, sp, static1, pub, static2, ident] = match; line = sp + static1 + static2 + ident; } - if (inSourceTypings(file)) { - // for internal typings, remove the 'declare' keyword (but leave 'export' intact) - res.lines.push({ original: line.replace(/^(export )?declare /g, '$1') }); - } - else { - res.lines.push({ original: line }); - } + + res.lines.push({ + original: inSourceTypings(file) ? removeDeclares(line) : line + }); } }); @@ -825,6 +839,12 @@ function replaceImportExportEs6(line: string, replacer: (str: string) => string) return line; } +function removeDeclares(line: string) { + return line + .replace(/^(export )?declare /g, '$1') + .replace(/^\s*declare (const|let|module)/g, '$1') +} + function replaceExternal(line: string, replacer: (str: string) => string) { let match = line.match(externalExp); if (match) { diff --git a/package.json b/package.json index 548e1fe..242bfec 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "dts-bundle", - "version": "0.7.3", + "name": "@arshaw/dts-bundle", + "version": "0.7.3-fork", "description": "Export TypeScript .d.ts files as an external module definition", "keywords": [ "typescript", diff --git a/test/expected/es6/foo-mx.d.ts b/test/expected/es6/foo-mx.d.ts index 98d2d3c..a8d2b82 100644 --- a/test/expected/es6/foo-mx.d.ts +++ b/test/expected/es6/foo-mx.d.ts @@ -5,6 +5,7 @@ declare module 'foo-mx' { import { A } from "foo-mx/lib/subC"; import { bar } from "foo-mx/lib/subD"; import { foo as buzz } from "foo-mx/lib/subE"; + import "foo-mx/lib/subF"; export function indexA(): subB.A; export function indexB(): subB.B; export function indexC(): A; @@ -60,3 +61,15 @@ declare module 'foo-mx/lib/subE' { export function bar(): A; } +declare module 'foo-mx/lib/subF' { + export interface A { + name: string; + } + export class B { + name: string; + } + export default function test(): A; + export function foo(): A; + export function bar(): A; +} + diff --git a/test/expected/inline_imports/foo-mx.d.ts b/test/expected/inline_imports/foo-mx.d.ts new file mode 100644 index 0000000..0d96ab6 --- /dev/null +++ b/test/expected/inline_imports/foo-mx.d.ts @@ -0,0 +1,13 @@ + +declare module 'foo-mx' { + const _default: import('foo-mx/lib').Plugin; + export default _default; +} + +declare module 'foo-mx/lib' { + export interface Plugin { + name: string + action: any + } +} + diff --git a/test/src/es6/index.ts b/test/src/es6/index.ts index 39c8bc3..7d10140 100644 --- a/test/src/es6/index.ts +++ b/test/src/es6/index.ts @@ -4,6 +4,7 @@ import * as subB from "./sub"; import subC, {A} from "./lib/subC"; import {bar} from "./lib/subD"; import {foo as buzz} from "./lib/subE"; +import "./lib/subF"; export function indexA() { return subA(); diff --git a/test/src/es6/lib/subF.ts b/test/src/es6/lib/subF.ts new file mode 100644 index 0000000..d71c07f --- /dev/null +++ b/test/src/es6/lib/subF.ts @@ -0,0 +1,11 @@ +export interface A { + name: string; +} + +export class B { + name: string; +} + +export default function test(): A { return null; } +export function foo(): A { return null; } +export function bar(): A { return null; } diff --git a/test/src/inline_imports/index.d.ts b/test/src/inline_imports/index.d.ts new file mode 100644 index 0000000..70848c3 --- /dev/null +++ b/test/src/inline_imports/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import('./lib').Plugin; +export default _default; \ No newline at end of file diff --git a/test/src/inline_imports/lib.d.ts b/test/src/inline_imports/lib.d.ts new file mode 100644 index 0000000..ad5a276 --- /dev/null +++ b/test/src/inline_imports/lib.d.ts @@ -0,0 +1,4 @@ +export interface Plugin { + name: string + action: any +} \ No newline at end of file diff --git a/test/test.js b/test/test.js index 25f95dc..5c3f539 100644 --- a/test/test.js +++ b/test/test.js @@ -384,6 +384,50 @@ describe('dts bundle', function () { assert.strictEqual(getFile(actualFile), getFile(expectedFile)); }); + (function testit(name, assertion, run) { + var buildDir = path.resolve(__dirname, 'src', 'inline_imports'); + var call = function (done) { + var testDir = path.join(tmpDir, name); + var expDir = path.join(expectDir, name); + + mkdirp.sync(testDir); + + ncp.ncp(buildDir, testDir, function (err) { + if (err) { + done(err); + return; + } + assertion(testDir, expDir); + done(); + }); + }; + + var label = 'bundle ' + name; + + if (run === 'skip') { + it.skip(label, call); + } + else if (run === 'only') { + it.only(label, call); + } + else { + it(label, call); + } + })('inline_imports', function (actDir, expDir) { + var result = dts.bundle({ + name: 'foo-mx', + main: path.join(actDir, 'index.d.ts'), + newline: '\n', + verbose: true, + headerPath: "none" + }); + var name = 'foo-mx.d.ts'; + var actualFile = path.join(actDir, name); + assert.isTrue(result.emitted, "not emit " + actualFile); + var expectedFile = path.join(expDir, name); + assert.strictEqual(getFile(actualFile), getFile(expectedFile)); + }); + (function testit(name, assertion, run) { var buildDir = path.resolve(__dirname, 'build', 'es6'); var call = function (done) { @@ -431,6 +475,7 @@ describe('dts bundle', function () { 'lib/subC.d.ts', 'lib/subD.d.ts', 'lib/subE.d.ts', + 'lib/subF.d.ts', 'sub.d.ts' ]); assert.strictEqual(getFile(actualFile), getFile(expectedFile)); @@ -478,6 +523,7 @@ describe('dts bundle', function () { 'lib/subC.d.ts', 'lib/subD.d.ts', 'lib/subE.d.ts', + 'lib/subF.d.ts', 'sub.d.ts' ]); assert.strictEqual(getFile(actualFile), getFile(expectedFile));