Skip to content

Commit

Permalink
feat(utils): resolveAliases
Browse files Browse the repository at this point in the history
Signed-off-by: Lexus Drumgold <unicornware@flexdevelopment.llc>
  • Loading branch information
unicornware committed Sep 4, 2022
1 parent 13141ee commit 8802abd
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
80 changes: 80 additions & 0 deletions src/utils/__tests__/resolve-aliases.functional.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* @file Functional Tests - resolveAliases
* @module mkbuild/utils/tests/functional/resolveAliases
*/

import path from 'node:path'
import type { OutputFile, Statement } from 'src/interfaces'
import { createMatchPath, loadConfig } from 'tsconfig-paths'
import resolveAlias from '../resolve-alias'
import testSubject from '../resolve-aliases'

vi.mock('pathe')

vi.mock('tsconfig-paths', async () => {
type Actual = typeof import('tsconfig-paths')
const path: string = 'tsconfig-paths'

const { createMatchPath, loadConfig } = await vi.importActual<Actual>(path)

return {
createMatchPath: vi.fn(createMatchPath),
loadConfig: vi.fn(loadConfig)
}
})

vi.mock('../resolve-alias', async () => {
type Actual = typeof import('../resolve-alias')
const path: string = '../resolve-alias'

const { default: resolveAlias } = await vi.importActual<Actual>(path)

return { default: vi.fn(resolveAlias) }
})

describe('functional:utils/resolveAliases', () => {
describe('noop', () => {
it('should do nothing if output content is undefined', async () => {
// Act
await testSubject({} as OutputFile)

// Expect
expect(loadConfig).toHaveBeenCalledTimes(0)
expect(createMatchPath).toHaveBeenCalledTimes(0)
expect(resolveAlias).toHaveBeenCalledTimes(0)
})

it('should do nothing if statements is empty array', async () => {
// Act
await testSubject({ contents: 'contents' } as OutputFile)

// Expect
expect(loadConfig).toHaveBeenCalledTimes(0)
expect(createMatchPath).toHaveBeenCalledTimes(0)
expect(resolveAlias).toHaveBeenCalledTimes(0)
})
})

describe('resolve', () => {
it('should resolve path aliases in output content', async () => {
const statements: Pick<Statement, 'code' | 'specifier'>[] = [
{
code: "import { MODULE_EXTENSIONS } from 'src/config/constants'",
specifier: 'src/config/constants'
}
]
const output: Pick<OutputFile, 'contents' | 'src'> = {
contents: statements[0]!.code,
src: path.resolve('utils/resolve-alias.ts')
}

// Act
await testSubject(output, statements)

// Expect
expect(loadConfig).toHaveBeenCalledTimes(1)
expect(createMatchPath).toHaveBeenCalledTimes(1)
expect(resolveAlias).toHaveBeenCalledTimes(statements.length)
})
})
})
73 changes: 73 additions & 0 deletions src/utils/resolve-aliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* @file Utilities - resolveAliases
* @module mkbuild/utils/resolveAliases
*/

import type { BuildOptions, OutputFile, Statement } from 'src/interfaces'
import type { ConfigLoaderResult, MatchPath } from 'tsconfig-paths'
import resolveAlias from './resolve-alias'

/**
* Resolves path aliases in `output.contents`.
*
* @see https://github.com/dividab/tsconfig-paths
*
* @async
*
* @param {Pick<OutputFile, 'contents' | 'src'>} output - Output file object
* @param {string | undefined} [output.contents] - Output file content
* @param {string} output.src - Full path to source file
* @param {Pick<Statement, 'code' | 'specifier'>[]} [statements=[]] - `import`,
* `require`, and `export` statements in `output.contents`
* @param {BuildOptions['cwd']} [cwd=process.cwd()] - Root project directory
* @return {Promise<void>} Nothing when complete
*/
const resolveAliases = async (
output: Pick<OutputFile, 'contents' | 'src'>,
statements: Pick<Statement, 'code' | 'specifier'>[] = [],
cwd: BuildOptions['cwd'] = process.cwd()
): Promise<string | undefined> => {
if (!output.contents || statements.length === 0) return output.contents

const { createMatchPath, loadConfig } = await import('tsconfig-paths')

/**
* `tsconfig-paths` config loader result.
*
* @const {ConfigLoaderResult} tsconfig
*/
const tsconfig: ConfigLoaderResult = loadConfig(cwd)

if (tsconfig.resultType === 'success') {
/**
* Matches a path alias.
*
* @const {MatchPath} matcher
*/
const matcher: MatchPath = createMatchPath(
tsconfig.absoluteBaseUrl,
tsconfig.paths,
tsconfig.mainFields,
tsconfig.addMatchAll
)

for (const statement of statements) {
/**
* {@link statement.code} before path alias replacement.
*
* @const {string} code
*/
const code: string = statement.code

// resolve path alias
resolveAlias(statement, output.src, matcher)

// replace code in output content
output.contents = output.contents.replace(code, statement.code)
}
}

return output.contents
}

export default resolveAliases

0 comments on commit 8802abd

Please sign in to comment.