From 949d9c2b5e21dbcfb644ccc68194fc2f54dc57e7 Mon Sep 17 00:00:00 2001 From: Damian Bielecki Date: Mon, 29 Apr 2019 18:42:24 +0200 Subject: [PATCH] Add export as a function --- .gitignore | 1 + package.json | 11 ++- src/command.ts | 21 ++++++ src/index.ts | 161 ------------------------------------------- src/resolve-paths.ts | 147 +++++++++++++++++++++++++++++++++++++++ src/run.ts | 4 ++ yarn.lock | 74 +++++++++----------- 7 files changed, 211 insertions(+), 208 deletions(-) create mode 100644 src/command.ts delete mode 100644 src/index.ts create mode 100644 src/resolve-paths.ts create mode 100644 src/run.ts diff --git a/.gitignore b/.gitignore index f49eaff..3e9593a 100755 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,4 @@ lib # next.js build output .next +.idea diff --git a/package.json b/package.json index 4b6a64a..4bea9e3 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,11 @@ "name": "tscpaths", "version": "0.0.7", "description": "Replace absolute paths to relative paths after typescript compilation", - "main": "cjs/index.js", - "module": "lib/index.js", - "types": "lib/index.d.ts", + "main": "cjs/resolve-paths.js", + "module": "lib/resolve-paths.js", + "types": "lib/resolve-paths.d.ts", "bin": { - "tscpaths": "cjs/index.js" + "tscpaths": "cjs/run.js" }, "scripts": { "build": "yarn build:esm && yarn build:cjs", @@ -41,7 +41,6 @@ }, "homepage": "https://github.com/joonhocho/tscpaths#readme", "devDependencies": { - "@types/globby": "^8.0.2", "@types/jest": "^24.0.11", "@types/node": "^11.12.0", "jest": "^24.5.0", @@ -54,6 +53,6 @@ }, "dependencies": { "commander": "^2.19.0", - "globby": "^8.0.2" + "globby": "^9.2.0" } } diff --git a/src/command.ts b/src/command.ts new file mode 100644 index 0000000..b238f56 --- /dev/null +++ b/src/command.ts @@ -0,0 +1,21 @@ +// tslint:disable no-console +import * as program from 'commander'; +import { IOptions, resolvePaths } from './resolve-paths'; + +export function command(): void { + program + .version('0.0.1') + .option('-p, --project ', 'path to tsconfig.json') + .option('-s, --src ', 'source root path') + .option('-o, --out ', 'output root path'); + + program.on('--help', () => { + console.log(` + $ tscpath -p tsconfig.json +`); + }); + + program.parse(process.argv); + + resolvePaths(program as IOptions); +} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 446cfaf..0000000 --- a/src/index.ts +++ /dev/null @@ -1,161 +0,0 @@ -#! /usr/bin/env node - -// tslint:disable no-console -import * as program from 'commander'; -import { existsSync, readFileSync, writeFileSync } from 'fs'; -import { sync } from 'globby'; -import { dirname, relative, resolve } from 'path'; -import { loadConfig } from './util'; - -program - .version('0.0.1') - .option('-p, --project ', 'path to tsconfig.json') - .option('-s, --src ', 'source root path') - .option('-o, --out ', 'output root path'); - -program.on('--help', () => { - console.log(` - $ tscpath -p tsconfig.json -`); -}); - -program.parse(process.argv); - -const { project, src, out } = program as { - project?: string; - src?: string; - out?: string; -}; -if (!project) { - throw new Error('--project must be specified'); -} -if (!src) { - throw new Error('--src must be specified'); -} - -const configFile = resolve(process.cwd(), project); -console.log(`tsconfig.json: ${configFile}`); -const srcRoot = resolve(src); -console.log(`src: ${srcRoot}`); - -const outRoot = out && resolve(out); -console.log(`out: ${outRoot}`); - -const { baseUrl, outDir, paths } = loadConfig(configFile); - -if (!baseUrl) { - throw new Error('compilerOptions.baseUrl is not set'); -} -if (!paths) { - throw new Error('compilerOptions.paths is not set'); -} -if (!outDir) { - throw new Error('compilerOptions.outDir is not set'); -} -console.log(`baseUrl: ${baseUrl}`); -console.log(`outDir: ${outDir}`); -console.log(`paths: ${JSON.stringify(paths, null, 2)}`); - -const configDir = dirname(configFile); - -const basePath = resolve(configDir, baseUrl); -console.log(`basePath: ${basePath}`); - -const outPath = outRoot || resolve(basePath, outDir); -console.log(`outPath: ${outPath}`); - -const outFileToSrcFile = (x: string): string => - resolve(srcRoot, relative(outPath, x)); - -const aliases = Object.keys(paths) - .map((alias) => ({ - prefix: alias.replace(/\*$/, ''), - aliasPaths: paths[alias as keyof typeof paths].map((p) => - resolve(basePath, p.replace(/\*$/, '')) - ), - })) - .filter(({ prefix }) => prefix); -console.log(`aliases: ${JSON.stringify(aliases, null, 2)}`); - -const toRelative = (from: string, x: string): string => { - const rel = relative(from, x); - return (rel.startsWith('.') ? rel : `./${rel}`).replace(/\\/g, '/'); -}; - -const exts = ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.json']; - -const absToRel = (modulePath: string, outFile: string): string => { - const alen = aliases.length; - for (let j = 0; j < alen; j += 1) { - const { prefix, aliasPaths } = aliases[j]; - - if (modulePath.startsWith(prefix)) { - const modulePathRel = modulePath.substring(prefix.length); - const srcFile = outFileToSrcFile(outFile); - const outRel = relative(basePath, outFile); - console.log(`${outRel} (source: ${relative(basePath, srcFile)}):`); - console.log(`\timport '${modulePath}'`); - const len = aliasPaths.length; - for (let i = 0; i < len; i += 1) { - const apath = aliasPaths[i]; - const moduleSrc = resolve(apath, modulePathRel); - if ( - existsSync(moduleSrc) || - exts.some((ext) => existsSync(moduleSrc + ext)) - ) { - const rel = toRelative(dirname(srcFile), moduleSrc); - console.log( - `\treplacing '${modulePath}' -> '${rel}' referencing ${relative( - basePath, - moduleSrc - )}` - ); - return rel; - } - } - console.log(`\tcould not replace ${modulePath}`); - } - } - return modulePath; -}; - -const requireRegex = /(?:import|require)\(['"]([^'"]*)['"]\)/g; -const importRegex = /(?:import|from) ['"]([^'"]*)['"]/g; - -const replaceImportStatement = ( - orig: string, - matched: string, - outFile: string -): string => { - const index = orig.indexOf(matched); - return ( - orig.substring(0, index) + - absToRel(matched, outFile) + - orig.substring(index + matched.length) - ); -}; - -const replaceAlias = (text: string, outFile: string): string => - text - .replace(requireRegex, (orig, matched) => - replaceImportStatement(orig, matched, outFile) - ) - .replace(importRegex, (orig, matched) => - replaceImportStatement(orig, matched, outFile) - ); - -// import relative to absolute path -const files = sync(`${outPath}/**/*.{js,jsx,ts,tsx}`, { - dot: true, - noDir: true, -} as any).map((x) => resolve(x)); - -const flen = files.length; -for (let i = 0; i < flen; i += 1) { - const file = files[i]; - const text = readFileSync(file, 'utf8'); - const newText = replaceAlias(text, file); - if (text !== newText) { - writeFileSync(file, newText, 'utf8'); - } -} diff --git a/src/resolve-paths.ts b/src/resolve-paths.ts new file mode 100644 index 0000000..65a298d --- /dev/null +++ b/src/resolve-paths.ts @@ -0,0 +1,147 @@ +// tslint:disable no-console +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { sync } from 'globby'; +import { dirname, relative, resolve } from 'path'; +import { loadConfig } from './util'; + +export interface IOptions { + project?: string; + src?: string; + out?: string; +} + +export function resolvePaths({ project, src, out }: IOptions): void { + if (!project) { + throw new Error('--project must be specified'); + } + if (!src) { + throw new Error('--src must be specified'); + } + + const configFile = resolve(process.cwd(), project); + console.log(`tsconfig.json: ${configFile}`); + const srcRoot = resolve(src); + console.log(`src: ${srcRoot}`); + + const outRoot = out && resolve(out); + console.log(`out: ${outRoot}`); + + const { baseUrl, outDir, paths } = loadConfig(configFile); + + if (!baseUrl) { + throw new Error('compilerOptions.baseUrl is not set'); + } + if (!paths) { + throw new Error('compilerOptions.paths is not set'); + } + if (!outDir) { + throw new Error('compilerOptions.outDir is not set'); + } + console.log(`baseUrl: ${baseUrl}`); + console.log(`outDir: ${outDir}`); + console.log(`paths: ${JSON.stringify(paths, null, 2)}`); + + const configDir = dirname(configFile); + + const basePath = resolve(configDir, baseUrl); + console.log(`basePath: ${basePath}`); + + const outPath = outRoot || resolve(basePath, outDir); + console.log(`outPath: ${outPath}`); + + const outFileToSrcFile = (x: string): string => + resolve(srcRoot, relative(outPath, x)); + + const aliases = Object.keys(paths) + .map((alias) => ({ + prefix: alias.replace(/\*$/, ''), + aliasPaths: paths[alias as keyof typeof paths].map((p) => + resolve(basePath, p.replace(/\*$/, '')) + ), + })) + .filter(({ prefix }) => prefix); + console.log(`aliases: ${JSON.stringify(aliases, null, 2)}`); + + const toRelative = (from: string, x: string): string => { + const rel = relative(from, x); + return (rel.startsWith('.') ? rel : `./${rel}`).replace(/\\/g, '/'); + }; + + const exts = ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.json']; + + const absToRel = (modulePath: string, outFile: string): string => { + const alen = aliases.length; + for (let j = 0; j < alen; j += 1) { + const { prefix, aliasPaths } = aliases[j]; + + if (modulePath.startsWith(prefix)) { + const modulePathRel = modulePath.substring(prefix.length); + const srcFile = outFileToSrcFile(outFile); + const outRel = relative(basePath, outFile); + console.log(`${outRel} (source: ${relative(basePath, srcFile)}):`); + console.log(`\timport '${modulePath}'`); + const len = aliasPaths.length; + for (let i = 0; i < len; i += 1) { + const apath = aliasPaths[i]; + const moduleSrc = resolve(apath, modulePathRel); + if ( + existsSync(moduleSrc) || + exts.some((ext) => existsSync(moduleSrc + ext)) + ) { + const rel = toRelative(dirname(srcFile), moduleSrc); + console.log( + `\treplacing '${modulePath}' -> '${rel}' referencing ${relative( + basePath, + moduleSrc + )}` + ); + return rel; + } + } + console.log(`\tcould not replace ${modulePath}`); + } + } + return modulePath; + }; + + const requireRegex = /(?:import|require)\(['"]([^'"]*)['"]\)/g; + const importRegex = /(?:import|from) ['"]([^'"]*)['"]/g; + + const replaceImportStatement = ( + orig: string, + matched: string, + outFile: string + ): string => { + const index = orig.indexOf(matched); + return ( + orig.substring(0, index) + + absToRel(matched, outFile) + + orig.substring(index + matched.length) + ); + }; + + const replaceAlias = (text: string, outFile: string): string => + text + .replace(requireRegex, (orig, matched) => + replaceImportStatement(orig, matched, outFile) + ) + .replace(importRegex, (orig, matched) => + replaceImportStatement(orig, matched, outFile) + ); + + // import relative to absolute path + const files = sync(`${outPath}/**/*.{js,jsx,ts,tsx}`, { + dot: true, + noDir: true, + } as any).map((x) => resolve(x)); + + const flen = files.length; + for (let i = 0; i < flen; i += 1) { + const file = files[i]; + const text = readFileSync(file, 'utf8'); + const newText = replaceAlias(text, file); + if (text !== newText) { + writeFileSync(file, newText, 'utf8'); + } + } +} diff --git a/src/run.ts b/src/run.ts new file mode 100644 index 0000000..a4725f0 --- /dev/null +++ b/src/run.ts @@ -0,0 +1,4 @@ +#! /usr/bin/env node +import { command } from './command'; + +command(); diff --git a/yarn.lock b/yarn.lock index 93315ed..0f8a7c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -343,26 +343,18 @@ "@types/events@*": version "3.0.0" - resolved "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== -"@types/glob@*": +"@types/glob@^7.1.1": version "7.1.1" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== dependencies: "@types/events" "*" "@types/minimatch" "*" "@types/node" "*" -"@types/globby@^8.0.2": - version "8.0.0" - resolved "https://registry.npmjs.org/@types/globby/-/globby-8.0.0.tgz#7bd10eaf802e1e11afdb1e5436cf472ddf4c0dd2" - integrity sha512-xDtsX5tlctxJzvg29r/LN12z30oJpoFP9cE8eJ8nY5cbSvN0c0RdRHrVlEq4LRh362Sd+JsqxJ3QWw0Wnyto8w== - dependencies: - "@types/glob" "*" - fast-glob "^2.0.2" - "@types/istanbul-lib-coverage@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz#2cc2ca41051498382b43157c8227fea60363f94a" @@ -382,7 +374,7 @@ "@types/minimatch@*": version "3.0.3" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== "@types/node@*", "@types/node@^11.12.0": @@ -512,9 +504,9 @@ array-equal@^1.0.0: resolved "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= -array-union@^1.0.1: +array-union@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" @@ -1008,12 +1000,11 @@ diff@^3.2.0: resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -dir-glob@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034" - integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag== +dir-glob@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== dependencies: - arrify "^1.0.1" path-type "^3.0.0" doctrine@0.7.2: @@ -1213,9 +1204,9 @@ fast-deep-equal@^2.0.1: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= -fast-glob@^2.0.2: +fast-glob@^2.2.6: version "2.2.6" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295" integrity sha512-0BvMaZc1k9F+MeWWMe8pL6YltFzZYcJsYU7D4JyDA6PAczaXvxqQQ/z+mDF7/4Mw01DeUc+i3CTKajnkANkV4w== dependencies: "@mrmlnc/readdir-enhanced" "^2.2.1" @@ -1362,18 +1353,19 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== -globby@^8.0.2: - version "8.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d" - integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w== +globby@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" + integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== dependencies: - array-union "^1.0.1" - dir-glob "2.0.0" - fast-glob "^2.0.2" - glob "^7.1.2" - ignore "^3.3.5" - pify "^3.0.0" - slash "^1.0.0" + "@types/glob" "^7.1.1" + array-union "^1.0.2" + dir-glob "^2.2.2" + fast-glob "^2.2.6" + glob "^7.1.3" + ignore "^4.0.3" + pify "^4.0.1" + slash "^2.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: version "4.1.15" @@ -1492,10 +1484,10 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ignore@^3.3.5: - version "3.3.10" - resolved "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" - integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== +ignore@^4.0.3: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== import-local@^2.0.0: version "2.0.0" @@ -2760,6 +2752,11 @@ pify@^3.0.0: resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pirates@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" @@ -3107,11 +3104,6 @@ sisteransi@^1.0.0: resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.0.tgz#77d9622ff909080f1c19e5f4a1df0c1b0a27b88c" integrity sha512-N+z4pHB4AmUv0SjveWRd6q1Nj5w62m5jodv+GD8lvmbY/83T/rpbJGZOnK5T149OldDj4Db07BSv9xY4K6NTPQ== -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - slash@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"