Skip to content

Support AMD imports with baseUrl and without paths in ts config #580

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import path from 'path'
import { TransformCallback, Transform } from 'stream'
import ts from 'typescript'
import fs from 'fs'
import { builtinModules } from 'module'

import File = require('vinyl')

Expand Down Expand Up @@ -42,12 +44,15 @@ function findImports(line: string): string[] | null {
function resolveImports(
file: ReadonlyArray<string>,
imports: FileData[],
options: ts.CompilerOptions
options: ts.CompilerOptions,
nodeModules: string[]
): string[] {
const { baseUrl, paths, cwd } = options

const base = path.join(cwd as string, path.relative(cwd as string, baseUrl || './'))

const aliases: { [key: string]: string[] | undefined } = {}
for (const alias in paths) {
for (const alias in paths || {}) {
/* istanbul ignore else */
if (paths.hasOwnProperty(alias)) {
let resolved = alias
Expand Down Expand Up @@ -82,11 +87,17 @@ function resolveImports(
}
}

if (resolved.length < 1 && /^\w/.test(imported.import) && !paths) {
const dirName = imported.import.split('/')[0]
if (!nodeModules.includes(dirName) && !builtinModules.includes(dirName)) {
resolved = path.join(base, './' + imported.import)
}
}

if (resolved.length < 1) {
continue
}

const base = path.join(cwd as string, path.relative(cwd as string, baseUrl || './'))
const current = path.relative(base, path.dirname(imported.path))
const target = path.relative(base, resolved)

Expand Down Expand Up @@ -133,14 +144,21 @@ const alias: AliasPlugin = ({ config, cwd }: PluginOptions) => {

const compilerOptions = resolveConfig(config, cwd)

if (!compilerOptions.paths) {
throw new Error("Unable to find the 'paths' property in the supplied configuration!")
if (!compilerOptions.paths && !compilerOptions.baseUrl) {
throw new Error(
"Unable to find the 'paths' or 'baseUrl' property in the supplied configuration!"
)
}

if (compilerOptions.baseUrl === undefined || compilerOptions.baseUrl === '.') {
compilerOptions.baseUrl = './'
}

let nodeModules: string[] = []
if (!compilerOptions.paths && compilerOptions.baseUrl) {
nodeModules = fs.readdirSync(path.join(cwd, 'node_modules'))
}

compilerOptions.cwd = cwd

return new Transform({
Expand Down Expand Up @@ -168,7 +186,7 @@ const alias: AliasPlugin = ({ config, cwd }: PluginOptions) => {
return callback(undefined, file)
}

const resolved = resolveImports(lines, imports, compilerOptions)
const resolved = resolveImports(lines, imports, compilerOptions, nodeModules)

file.contents = Buffer.from(resolved.join('\n'))

Expand Down
22 changes: 20 additions & 2 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,9 @@ const tests: Record<string, Test> = {
error: "Could not find a valid 'tsconfig.json'",
},
["should error with no 'paths' in config"]: {
options: { config: { ...config, paths: undefined } },
options: { config: { paths: undefined, baseUrl: undefined } },
path: './src/pages/Page.ts',
error: "Unable to find the 'paths' property in the supplied configuration!",
error: "Unable to find the 'paths' or 'baseUrl' property in the supplied configuration!",
},
["should error with no 'path' supplied"]: {
options: { config },
Expand All @@ -145,6 +145,24 @@ const tests: Record<string, Test> = {
output: '',
error: 'Received file with no path. Files must have path to be resolved.',
},
['should replace to relative path when config with baseUrl but without Paths']: {
options: { config: { baseUrl: './src' } },
path: './src/pages/Page.ts',
input: "import {Grid} from 'components/grid'",
output: "import {Grid} from '../components/grid'",
},
['should ignore node module']: {
options: { config: { baseUrl: './src' } },
path: './src/pages/Page.ts',
input: "import File from 'vinyl'",
output: "import File from 'vinyl'",
},
['should ignore builtin module']: {
options: { config: { baseUrl: './src' } },
path: './src/pages/Page.ts',
input: "import assert from 'assert'",
output: "import assert from 'assert'",
},
}

const run = async (test: Test): Promise<void> => {
Expand Down