From e0307a8e54c882776fc5aed8d3f78704fb943cf8 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Mon, 24 Jun 2019 14:09:25 -0400 Subject: [PATCH 1/5] fix incorrect args to readFileSync/writeFileSync --- lib/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index 6e744c4..4474d39 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -183,7 +183,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 +424,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 +587,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 From 94cc5a4557795a8daf1c16e3f54241e537b9d686 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jun 2019 09:55:42 -0400 Subject: [PATCH 2/5] correctly handle ES6 inline imports in .d.ts files --- .gitignore | 1 + lib/index.ts | 19 +++++++--- test/expected/inline_imports/foo-mx.d.ts | 13 +++++++ test/src/inline_imports/index.d.ts | 2 ++ test/src/inline_imports/lib.d.ts | 4 +++ test/test.js | 44 ++++++++++++++++++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 test/expected/inline_imports/foo-mx.d.ts create mode 100644 test/src/inline_imports/index.d.ts create mode 100644 test/src/inline_imports/lib.d.ts 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 4474d39..0b60ce5 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,6 +17,7 @@ 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 importEs6InlineExp = /^(.*?import\()(['"])(.+?)(\2\).*)$/; const referenceTagExp = /^[ \t]*\/\/\/[ \t]*.*$/; const identifierExp = /^\w+(?:[\.-]\w+)*$/; const fileExp = /^([\./].*|.:.*)$/; @@ -696,6 +697,7 @@ 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("require") >= 0 && (match = line.match(importExp)))) { const [_, lead, quote, moduleName, trail] = match; assert(moduleName); @@ -708,7 +710,9 @@ export function bundle(options: Options): BundleResult { // 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 + original: removeDeclares( + lead + quote + getExpName(impPath) + trail + ) }; res.lines.push(modLine); @@ -725,7 +729,7 @@ export function bundle(options: Options): BundleResult { // identifier else { let modLine: ModLine = { - original: line + original: removeDeclares(line) }; trace(' - import external %s', moduleName); @@ -763,8 +767,9 @@ export function bundle(options: Options): BundleResult { 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') }); + res.lines.push({ + original: removeDeclares(line) + }); } else { res.lines.push({ original: line }); @@ -825,6 +830,12 @@ function replaceImportExportEs6(line: string, replacer: (str: string) => string) return line; } +function removeDeclares(line: string) { + return line + .replace(/^(export )?declare /g, '$1') + .replace(/^declare (const|let)/g, '$1') +} + function replaceExternal(line: string, replacer: (str: string) => string) { let match = line.match(externalExp); if (match) { 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/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..69869c1 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) { From c1197f83bde2a0371a381c16c29ad00a5ea0b18e Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Tue, 25 Jun 2019 15:18:57 -0400 Subject: [PATCH 3/5] correctly handle side-effect-only typescript imports --- lib/index.ts | 41 +++++++++++++++++++++++------------ test/expected/es6/foo-mx.d.ts | 13 +++++++++++ test/src/es6/index.ts | 1 + test/src/es6/lib/subF.ts | 11 ++++++++++ test/test.js | 2 ++ 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 test/src/es6/lib/subF.ts diff --git a/lib/index.ts b/lib/index.ts index 0b60ce5..a43be6a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,6 +17,7 @@ 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+)*$/; @@ -698,33 +699,45 @@ 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: removeDeclares( - 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 { 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/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/test.js b/test/test.js index 69869c1..5c3f539 100644 --- a/test/test.js +++ b/test/test.js @@ -475,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)); @@ -522,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)); From 148ba0992fc9ad8a1e5088be0d9c34e82b6e0a22 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 24 Jul 2019 16:27:43 -0400 Subject: [PATCH 4/5] some fixes --- lib/index.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/index.ts b/lib/index.ts index a43be6a..694b116 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -767,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); @@ -779,14 +779,10 @@ export function bundle(options: Options): BundleResult { let [_, sp, static1, pub, static2, ident] = match; line = sp + static1 + static2 + ident; } - if (inSourceTypings(file)) { - res.lines.push({ - original: removeDeclares(line) - }); - } - else { - res.lines.push({ original: line }); - } + + res.lines.push({ + original: inSourceTypings(file) ? removeDeclares(line) : line + }); } }); @@ -846,7 +842,7 @@ function replaceImportExportEs6(line: string, replacer: (str: string) => string) function removeDeclares(line: string) { return line .replace(/^(export )?declare /g, '$1') - .replace(/^declare (const|let)/g, '$1') + .replace(/^\s*declare (const|let|module)/g, '$1') } function replaceExternal(line: string, replacer: (str: string) => string) { From 19535ca93226c19d3a1dd339dec7eaf4b6a75ac0 Mon Sep 17 00:00:00 2001 From: Adam Shaw Date: Wed, 24 Jul 2019 16:30:46 -0400 Subject: [PATCH 5/5] rename package/version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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",