Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

fix: infer TS module format from package.json #1580

Merged
merged 3 commits into from
Oct 2, 2023
Merged
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
34 changes: 31 additions & 3 deletions src/runtimes/node/bundlers/nft/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import { cachedReadFile, getPathWithExtension } from '../../../../utils/fs.js'
import { minimatch } from '../../../../utils/matching.js'
import { getBasePath } from '../../utils/base_path.js'
import { filterExcludedPaths, getPathsOfIncludedFiles } from '../../utils/included_files.js'
import { MODULE_FORMAT, MODULE_FILE_EXTENSION, tsExtensions } from '../../utils/module_format.js'
import { MODULE_FORMAT, MODULE_FILE_EXTENSION, tsExtensions, ModuleFormat } from '../../utils/module_format.js'
import { getNodeSupportMatrix } from '../../utils/node_version.js'
import { getModuleFormat as getTSModuleFormat } from '../../utils/tsconfig.js'
import { getClosestPackageJson } from '../../utils/package_json.js'
import { getModuleFormat as getModuleFormatFromTsConfig } from '../../utils/tsconfig.js'
import type { GetSrcFilesFunction, BundleFunction } from '../types.js'

import { processESM } from './es_modules.js'
Expand Down Expand Up @@ -85,6 +86,33 @@ const getIgnoreFunction = (config: FunctionConfig) => {
}
}

/**
* Returns the module format that should be used when transpiling a TypeScript
* file.
*/
const getTSModuleFormat = async (mainFile: string, repositoryRoot?: string): Promise<ModuleFormat> => {
const fromTsConfig = getModuleFormatFromTsConfig(mainFile, repositoryRoot)

// If we can infer the module type from a `tsconfig.json` file, use that.
if (fromTsConfig !== undefined) {
return fromTsConfig
}

// At this point, we need to infer the module type from the `type` field in
// the closest `package.json`.
try {
const packageJSON = await getClosestPackageJson(dirname(mainFile), repositoryRoot)

if (packageJSON?.contents.type === 'module') {
return MODULE_FORMAT.ESM
}
} catch {
// no-op
}

return MODULE_FORMAT.COMMONJS
}

const traceFilesAndTranspile = async function ({
basePath,
cache,
Expand All @@ -107,7 +135,7 @@ const traceFilesAndTranspile = async function ({
runtimeAPIVersion: number
}) {
const isTypeScript = tsExtensions.has(extname(mainFile))
const tsFormat = isTypeScript ? getTSModuleFormat(mainFile, repositoryRoot) : MODULE_FORMAT.COMMONJS
const tsFormat = isTypeScript ? await getTSModuleFormat(mainFile, repositoryRoot) : MODULE_FORMAT.COMMONJS
const tsAliases = new Map<string, string>()
const tsRewrites = new Map<string, string>()

Expand Down
17 changes: 12 additions & 5 deletions src/runtimes/node/utils/tsconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,29 @@ import { MODULE_FORMAT } from './module_format.js'

const esmModuleValues = new Set(['es6', 'es2015', 'es2020', 'es2022', 'esnext', 'node16', 'nodenext'])

// Returns the module format that should be used for a TypeScript file at a
// given path, by reading the associated `tsconfig.json` file if it exists.
/**
* Looks for a `tsconfig.json` file on a given path and, if one exists, returns
* the module format inferred from the `module` property. If no file is found
* or if no `module` property is defined, the function returns `undefined`.
*/
export const getModuleFormat = (path: string, boundary?: string) => {
const file = getTsconfig(path)

if (!file) {
return MODULE_FORMAT.COMMONJS
return
}

// If there is a boundary defined and the file we found is outside of it,
// discard the file.
if (boundary !== undefined && relative(boundary, dirname(file.path)).startsWith('..')) {
return MODULE_FORMAT.COMMONJS
return
}

const moduleProp = file.config.compilerOptions?.module?.toLowerCase() ?? ''
const moduleProp = file.config.compilerOptions?.module

if (!moduleProp) {
return
}

return esmModuleValues.has(moduleProp) ? MODULE_FORMAT.ESM : MODULE_FORMAT.COMMONJS
}