From e6d7ae4cd8d81a4a818aa1d0665fadc77f945c8e Mon Sep 17 00:00:00 2001 From: dhkatz Date: Fri, 23 Aug 2019 00:39:17 -0700 Subject: [PATCH] Relatively feature complete release, more tests --- CHANGELOG.md | 8 ++- package-lock.json | 85 +++----------------------- package.json | 5 +- src/index.ts | 60 +++++++++++-------- test/index.test.ts | 146 ++++++++++++++++++++++++++++++++++----------- 5 files changed, 161 insertions(+), 143 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b81a8ab..d673243 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ This file uses change log convention from [Keep a CHANGELOG]. ## [Unreleased] +## [1.0.0] - 2019-08-23 +### Added +- Added support for `require()` and `import()` call imports. +- Added a lot more tests to raise the coverage of the plugin. + ## [0.2.1] - 2019-08-22 ### Changed - Updated testing and CI @@ -45,7 +50,8 @@ This file uses change log convention from [Keep a CHANGELOG]. [Keep a CHANGELOG]: http://keepachangelog.com [Semantic Versioning]: http://semver.org/ -[unreleased]: https://github.com/dhkatz/gulp-ts-alias/compare/0.2.1...HEAD +[unreleased]: https://github.com/dhkatz/gulp-ts-alias/compare/1.0.0...HEAD +[1.0.0]: https://github.com/dhkatz/gulp-ts-alias/compare/0.2.1...1.0.0 [0.2.1]: https://github.com/dhkatz/gulp-ts-alias/compare/0.2.0...0.2.1 [0.2.0]: https://github.com/dhkatz/gulp-ts-alias/compare/0.1.5...0.2.0 [0.1.5]: https://github.com/dhkatz/gulp-ts-alias/compare/0.1.4...0.1.5 diff --git a/package-lock.json b/package-lock.json index 8df494f..428ba77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gulp-ts-alias", - "version": "0.2.1", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -460,15 +460,6 @@ "@babel/types": "^7.3.0" } }, - "@types/event-stream": { - "version": "3.3.34", - "resolved": "https://registry.npmjs.org/@types/event-stream/-/event-stream-3.3.34.tgz", - "integrity": "sha512-LLiivgWKii4JeMzFy3trrxqkRrVSdue8WmbXyHuSJLwNrhIQU5MTrc65jhxEPwMyh5HR1xevSdD+k2nnSRKw9g==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -1379,12 +1370,6 @@ "webidl-conversions": "^4.0.2" } }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -1489,29 +1474,6 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - }, - "dependencies": { - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - } - } - }, "exec-sh": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", @@ -1775,12 +1737,6 @@ "map-cache": "^0.2.2" } }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3751,6 +3707,12 @@ "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", "dev": true }, + "o-stream": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/o-stream/-/o-stream-0.2.2.tgz", + "integrity": "sha512-V3j76KU3g/Gyl8rpdi2z72rn5zguMvTCQgAXfBe3pxEefKqXmOUOD7mvx/mNjykdxGqDVfpSoo8r+WdrkWg/1Q==", + "dev": true + }, "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -3963,15 +3925,6 @@ "pify": "^3.0.0" } }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "~2.3" - } - }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -4609,15 +4562,6 @@ "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2" - } - }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -4683,15 +4627,6 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - }, "string-length": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", @@ -4793,12 +4728,6 @@ "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", "dev": true }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, "tmpl": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", diff --git a/package.json b/package.json index 2f97336..7a8ffd1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gulp-ts-alias", - "version": "0.2.1", + "version": "1.0.0", "description": "Use Gulp to resolve Typescript path aliases during compilation.", "main": "./lib/index.js", "types": "./lib/index.d.ts", @@ -41,13 +41,12 @@ "registry": "https://registry.npmjs.org" }, "devDependencies": { - "@types/event-stream": "^3.3.34", "@types/jest": "^24.0.0", "@types/vinyl": "^2.0.2", "coveralls": "^3.0.6", - "event-stream": "^3.3.4", "jest": "^24.9.0", "merge2": "^1.2.3", + "o-stream": "^0.2.2", "ts-jest": "^24.0.2", "tslint": "^5.12.1", "tslint-eslint-rules": "^5.4.0", diff --git a/src/index.ts b/src/index.ts index 65cb5c7..3640b5d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,9 @@ import path from 'path'; - import PluginError from 'plugin-error'; +import ObjectStream, { EnteredArgs } from 'o-stream'; import File = require('vinyl'); -// @ts-ignore -import * as map from 'map-stream'; - export interface FileData { path: string; index: number; @@ -49,13 +46,19 @@ function parseImports(file: ReadonlyArray, dir: string): FileData[] { } function findImport(line: string): string | null { - const matches = line.match(/from (["'])(.*?)\1/); + const matches = line.match(/from (["'])(.*?)\1/) || line.match(/import\((["'])(.*?)\1\)/) || line.match(/require\((["'])(.*?)\1\)/); if (!matches) { return null; } - if (matches.length > 3) { + const multiple = [/from (["'])(.*?)\1/g, /import\((["'])(.*?)\1\)/g, /require\((["'])(.*?)\1\)/g].some((exp) => { + const results = line.match(exp); + + return results && results.length > 1; + }) + + if (multiple) { throw new PluginError('gulp-ts-alias', 'Multiple imports on the same line are currently not supported!'); } @@ -145,34 +148,39 @@ const aliasPlugin: AliasPlugin = (pluginOptions: PluginOptions) => { compilerOptions.baseUrl = './'; } - return map((file: File, cb: (error: any, file?: any) => void) => { - if (file.isNull() || !file.contents) { - return cb(null, file); - } + return ObjectStream.transform({ + onEntered: (args: EnteredArgs) => { + const file = args.object; - if (file.isStream()) { - return cb(new PluginError('gulp-ts-alias', 'Streaming is not supported.')); - } + if (file.isStream()) { + throw new PluginError('gulp-ts-alias', 'Streaming is not supported.'); + } - const contents: Buffer | NodeJS.ReadableStream | null = file.contents; + if (file.isNull() || !file.contents) { + args.output.push(file); + return; + } - if (contents === null) { - return cb(null, file); - } + if (!file.path) { + throw new PluginError('gulp-ts-alias', 'Received file with no path. Files must have path to be resolved.'); + } - const lines = contents.toString().split('\n'); - const imports = parseImports(lines, file.path); + const lines = file.contents.toString().split('\n'); + const imports = parseImports(lines, file.path); - if (imports.length === 0) { - return cb(null, file); - } + if (imports.length === 0) { + args.output.push(file); - const resolved = resolveImports(lines, imports, compilerOptions); + return; + } - file.contents = Buffer.from(resolved.join('\n')); + const resolved = resolveImports(lines, imports, compilerOptions); - cb(null, file); - }); + file.contents = Buffer.from(resolved.join('\n')); + + args.output.push(file); + } + }) }; export default aliasPlugin; diff --git a/test/index.test.ts b/test/index.test.ts index 9ed2cce..4a018cf 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,4 +1,4 @@ -import Stream from 'event-stream'; +import ObjectStream, { EnteredArgs } from 'o-stream'; import File from 'vinyl'; import plugin, { PluginOptions, CompilerOptions } from '../src'; @@ -11,44 +11,120 @@ interface TestCase { } // tslint:disable-next-line:object-literal-key-quotes -const compilerOptions: CompilerOptions = { paths: { 'MyAlias': ['MyAliasFolder/MyAliasClass'] } }; +const compilerOptions: CompilerOptions = { paths: { 'MyAlias': ['MyAliasFolder/MyAliasClass'] }, baseUrl: './src' }; -const run = (test: TestCase): void => { - const input = new File({ contents: Buffer.from(test.input), path: test.path }); +const run = async (test: TestCase): Promise => { + return new Promise((resolve, reject) => { + const input = new File({ contents: Buffer.from(test.input), path: test.path }); + const stream = ObjectStream.fromArray([input]); - Stream.readArray([input]) - .pipe(plugin(test.pluginOptions)) - .pipe(Stream.mapSync((file: File, cb: (error: any, file?: any) => void) => { - const contents: Buffer | NodeJS.ReadableStream | null = file.contents; - - if (contents === null) { - return cb(null, file); - } - })); + stream + .pipe(plugin(test.pluginOptions)) + .pipe(ObjectStream.transform({ + onEntered: (args: EnteredArgs) => { + try { + expect(args.object.contents.toString()).toEqual(test.expected); + } catch (error) { + reject(error); + } + }, + onEnded: () => { resolve(); }, + })).on('error', (error: Error) => reject(error)); + }); }; -it('should throw with no config', (done) => { - expect(() => { - run({ - pluginOptions: { configuration: undefined! }, - path: undefined, - input: '', - expected: '', - }); - }).toThrow(); - - done(); +it('should work with compilerOptions', async () => { + return run({ + pluginOptions: { configuration: compilerOptions }, + path: './src/FileFolder/InnerFileFolder/File.ts', + input: ` +import A from "./asdf"; +import B from "./MyAlias"; +import C from "MyAlias"; +import D from "express"; +`, + expected: ` +import A from "./asdf"; +import B from "./MyAlias"; +import C from "../../MyAliasFolder/MyAliasClass"; +import D from "express"; +` + }); +}); + +it('should work with tsconfig', async () => { + return run({ + pluginOptions: { configuration: { compilerOptions } }, + path: './src/FileFolder/InnerFileFolder/File.ts', + input: ` +import A from "./asdf"; +import B from "./MyAlias"; +import C from "MyAlias"; +`, + expected: ` +import A from "./asdf"; +import B from "./MyAlias"; +import C from "../../MyAliasFolder/MyAliasClass"; +` + }); +}); + +it('should support dynamic imports', async () => { + return run({ + pluginOptions: { configuration: compilerOptions }, + path: './src/FileFolder/InnerFileFolder/File.ts', + input: ` +import("MyAlias").then(test => test()); +`, + expected: ` +import("../../MyAliasFolder/MyAliasClass").then(test => test()); +` + }); +}); + +it('should support require imports', async () => { + return run({ + pluginOptions: { configuration: compilerOptions }, + path: './src/FileFolder/InnerFileFolder/File.ts', + input: ` +const A = require("./asdf"); +const B = require("./MyAlias"); +const C = require("MyAlias"); +`, + expected: ` +const A = require("./asdf"); +const B = require("./MyAlias"); +const C = require("../../MyAliasFolder/MyAliasClass"); +` + }); +}); + +it('should throw with multiple imports on one line', async () => { + return expect(run({ + pluginOptions: { configuration: { compilerOptions } }, + path: './src/FileFolder/InnerFileFolder/File.ts', + input: ` +import A from "./asdf"; import B from "./MyAlias"; +import C from "MyAlias"; +`, + expected: '' + })).rejects.toThrow(); +}); + +it('should throw with no config', async () => { + await expect(run({ + pluginOptions: { configuration: undefined! }, + path: undefined, + input: '', + expected: '', + })).rejects.toThrow(); }); -it('should throw with no path', (done: jest.DoneCallback) => { - expect(() => { - run({ - pluginOptions: { configuration: compilerOptions }, - path: undefined, - input: '', - expected: '', - }); - }).toThrow(); - - done(); +it('should throw with no path', async () => { + await expect(run({ + pluginOptions: { configuration: compilerOptions }, + path: undefined, + input: '', + expected: '', + })).rejects.toThrow() });