Skip to content

Output mode #137

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

Closed
wants to merge 6 commits into from
Closed
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
6 changes: 3 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_multiline_ternary_operation = true
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
Expand Down Expand Up @@ -218,7 +218,7 @@ ij_typescript_align_multiline_extends_list = false
ij_typescript_align_multiline_for = true
ij_typescript_align_multiline_parameters = true
ij_typescript_align_multiline_parameters_in_calls = false
ij_typescript_align_multiline_ternary_operation = false
ij_typescript_align_multiline_ternary_operation = true
ij_typescript_align_object_properties = 0
ij_typescript_align_union_types = false
ij_typescript_align_var_statements = 0
Expand Down Expand Up @@ -363,7 +363,7 @@ ij_typescript_ternary_operation_signs_on_next_line = false
ij_typescript_ternary_operation_wrap = off
ij_typescript_union_types_wrap = on_every_item
ij_typescript_use_chained_calls_group_indents = false
ij_typescript_use_double_quotes = false
ij_typescript_use_double_quotes = true
ij_typescript_use_explicit_js_extension = global
ij_typescript_use_path_mapping = always
ij_typescript_use_public_modifier = false
Expand Down
23 changes: 8 additions & 15 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
name: Node.js CI

on: [ push, pull_request ]
on:
pull_request:
branches: [ master ]
types: [ opened, synchronize, closed ]
push:
branches: [ master ]

jobs:
build:
Expand All @@ -14,25 +19,13 @@ jobs:
- name: Checkout
uses: actions/checkout@v2

- name: Determine Yarn Cache Path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"

- uses: actions/cache@v1
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install Packages
run: yarn install --frozen-lockfile
- name: Install
run: yarn run clean:all && yarn install --frozen-lockfile

- name: Build
run: yarn build
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Yarn
.yarn-cache
./test/yarn.lock

# Built
*.js.map
Expand Down
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
"release": "standard-version",
"--------------": "",
"format": "prettier --write \"{src,test}/**/{*.js,!(*.d).ts}\"",
"clean": "rimraf dist **/*.tsbuildinfo",
"clean:all": "yarn run clean && rimraf node_modules test/node_modules test/.yarn-cache",
"reset": "yarn run clean:all && yarn install",
"clean": "npx rimraf dist **/*.tsbuildinfo",
"clean:all": "yarn run clean && npx rimraf node_modules **/node_modules test/.yarn-cache",
"reset": "yarn run clean:all && yarn install && yarn build",
"-------------- ": "",
"prebuild": "rimraf dist",
"prebuild": "npx rimraf dist",
"install:tests": "cd test && yarn install && cd projects/extras && yarn install",
"prepare": "yarn run install:tests"
},
Expand Down Expand Up @@ -58,11 +58,11 @@
"prettier": "^2.3.2",
"rimraf": "^3.0.2",
"standard-version": "^9.3.1",
"ts-expose-internals": "^4.3.2",
"ts-expose-internals": "^4.4.3",
"ts-jest": "^27.0.4",
"ts-node": "^10.1.0",
"ts-patch": "^1.4.2",
"typescript": "^4.3.5"
"ts-patch": "^1.4.4",
"typescript": "^4.4.3"
},
"peerDependencies": {
"typescript": ">=3.6.5"
Expand Down
31 changes: 19 additions & 12 deletions src/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,37 @@ function getTsProperties(args: Parameters<typeof transformer>) {
let tsInstance: typeof ts;
let compilerOptions: ts.CompilerOptions;
let fileNames: readonly string[] | undefined;
let isTranspileOnly = false;
let isTsNode = false;

const { 0: program, 2: extras, 3: manualTransformOptions } = args;
const [program, pluginConfig, extras, manualTransformOptions] = args;

tsInstance = extras?.ts ?? ts;
compilerOptions = manualTransformOptions?.compilerOptions!;
const config = {
...pluginConfig,
outputMode: pluginConfig?.outputMode === "esm" ? <const>"esm" : <const>"commonjs",
};

const tsNodeProps = getTsNodeRegistrationProperties(tsInstance);
if (tsNodeProps) isTsNode = true;

if (program) {
compilerOptions ??= program.getCompilerOptions();
compilerOptions ??= Object.assign({}, program.getCompilerOptions(), tsNodeProps?.compilerOptions);
} else if (manualTransformOptions) {
fileNames = manualTransformOptions.fileNames;
} else {
const tsNodeProps = getTsNodeRegistrationProperties(tsInstance);
if (!tsNodeProps)
throw new Error(
`Cannot transform without a Program, ts-node instance, or manual parameters supplied. ` +
`Make sure you're using ts-patch or ts-node with transpileOnly.`
);
isTsNode = true;
isTranspileOnly = true;
compilerOptions = tsNodeProps.compilerOptions;
fileNames = tsNodeProps.fileNames;
}

return { tsInstance, compilerOptions, fileNames, isTsNode };
return { tsInstance, compilerOptions, fileNames, isTranspileOnly, config, isTsNode };
}

// endregion
Expand All @@ -68,11 +75,12 @@ export default function transformer(
tsInstance,
compilerOptions,
fileNames,
isTsNode
isTranspileOnly,
isTsNode,
config
} = getTsProperties([ program, pluginConfig, transformerExtras, manualTransformOptions ]);

const rootDirs = compilerOptions.rootDirs?.filter(path.isAbsolute);
const config: TsTransformPathsConfig = pluginConfig ?? {};
const getCanonicalFileName = tsInstance.createGetCanonicalFileName(tsInstance.sys.useCaseSensitiveFileNames);

let emitHost = transformationContext.getEmitHost();
Expand All @@ -82,13 +90,12 @@ export default function transformer(
`No EmitHost found and could not determine files to be processed. Please file an issue with a reproduction!`
);
emitHost = createSyntheticEmitHost(compilerOptions, tsInstance, getCanonicalFileName, fileNames as string[]);
} else if (isTsNode) {
} else if (isTranspileOnly) {
Object.assign(emitHost, { getCompilerOptions: () => compilerOptions });
}

const { configFile, paths } = compilerOptions;
// TODO - Remove typecast when tryParsePatterns is recognized (probably after ts v4.4)
const { tryParsePatterns } = tsInstance as any;
const tryParsePatterns: typeof ts.tryParsePatterns | undefined = tsInstance.tryParsePatterns;

const tsTransformPathsContext: TsTransformPathsContext = {
compilerOptions,
Expand All @@ -100,6 +107,7 @@ export default function transformer(
transformationContext,
tsInstance,
emitHost,
isTranspileOnly,
isTsNode,
tsThreeInstance: cast<TypeScriptThree>(tsInstance),
excludeMatchers: config.exclude?.map((globPattern) => new Minimatch(globPattern, { matchBase: true })),
Expand All @@ -108,8 +116,7 @@ export default function transformer(
pathsPatterns:
paths &&
(tryParsePatterns
? // TODO - Remove typecast when pathPatterns is recognized (probably after ts v4.4)
(configFile?.configFileSpecs as any)?.pathPatterns || tryParsePatterns(paths)
? configFile?.configFileSpecs?.pathPatterns || tryParsePatterns(paths)
: tsInstance.getOwnKeys(paths)),
};

Expand Down
7 changes: 5 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ts, { CompilerOptions, EmitHost, Pattern, SourceFile } from "typescript";
import { PluginConfig } from "ts-patch";
import { HarmonyFactory } from "./utils/harmony-factory";
import { IMinimatch } from "minimatch";
import { RequireSome } from "./utils";

/* ****************************************************************************************************************** */
// region: TS Types
Expand All @@ -22,6 +23,7 @@ export type ImportOrExportClause = ts.ImportDeclaration["importClause"] | ts.Exp
export interface TsTransformPathsConfig extends PluginConfig {
readonly useRootDirs?: boolean;
readonly exclude?: string[];
readonly outputMode?: "commonjs" | "esm";
}

// endregion
Expand All @@ -41,16 +43,17 @@ export interface TsTransformPathsContext {
readonly tsThreeInstance: TypeScriptThree;
readonly tsFactory?: ts.NodeFactory;
readonly program?: ts.Program | tsThree.Program;
readonly config: TsTransformPathsConfig;
readonly config: RequireSome<TsTransformPathsConfig, "outputMode">;
readonly compilerOptions: CompilerOptions;
readonly elisionMap: Map<ts.SourceFile, Map<ImportOrExportDeclaration, ImportOrExportDeclaration>>;
readonly transformationContext: ts.TransformationContext;
readonly rootDirs?: string[];
readonly excludeMatchers: IMinimatch[] | undefined;
readonly outputFileNamesCache: Map<SourceFile, string>;
readonly pathsPatterns: (string | Pattern)[] | undefined;
readonly pathsPatterns: readonly (string | Pattern)[] | undefined;
readonly emitHost: EmitHost;
readonly isTsNode: boolean;
readonly isTranspileOnly: boolean;
}

export interface VisitorContext extends TsTransformPathsContext {
Expand Down
2 changes: 2 additions & 0 deletions src/utils/general-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export const isBaseDir = (baseDir: string, testDir: string): boolean => {
return relative ? !relative.startsWith("..") && !path.isAbsolute(relative) : true;
};
export const maybeAddRelativeLocalPrefix = (p: string) => (p[0] === "." ? p : `./${p}`);

export type RequireSome<T, K extends keyof T> = T & Pick<Required<T>, K>;
23 changes: 14 additions & 9 deletions src/utils/resolve-module-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { VisitorContext } from "../types";
import { isBaseDir, isURL, maybeAddRelativeLocalPrefix } from "./general-utils";
import * as path from "path";
import { removeFileExtension, removeSuffix, ResolvedModuleFull, SourceFile } from "typescript";
import { getOutputDirForSourceFile } from "./ts-helpers";
import { getOutputPathForSourceFile } from "./ts-helpers";

/* ****************************************************************************************************************** */
// region: Types
Expand Down Expand Up @@ -63,9 +63,9 @@ function getPathDetail(moduleName: string, resolvedModule: ResolvedModuleFull) {
// prettier-ignore
const indexType =
implicitPackageIndex ? IndexType.ImplicitPackage :
baseNameNoExtension === 'index' && resolvedBaseNameNoExtension === 'index' ? IndexType.Explicit :
baseNameNoExtension !== 'index' && resolvedBaseNameNoExtension === 'index' ? IndexType.Implicit :
IndexType.NonIndex;
baseNameNoExtension === 'index' && resolvedBaseNameNoExtension === 'index' ? IndexType.Explicit :
baseNameNoExtension !== 'index' && resolvedBaseNameNoExtension === 'index' ? IndexType.Implicit :
IndexType.NonIndex;

if (indexType === IndexType.Implicit) {
baseName = void 0;
Expand Down Expand Up @@ -121,6 +121,7 @@ function getResolvedSourceFile(context: VisitorContext, fileName: string): Sourc
*/
export function resolveModuleName(context: VisitorContext, moduleName: string): ResolvedModule | undefined {
const { tsInstance, compilerOptions, sourceFile, config, rootDirs } = context;
const useEsmOutput = !context.isDeclarationFile && context.config.outputMode === "esm";

// Attempt to resolve with TS Compiler API
const { resolvedModule, failedLookupLocations } = tsInstance.resolveModuleName(
Expand All @@ -143,18 +144,22 @@ export function resolveModuleName(context: VisitorContext, moduleName: string):

const resolvedSourceFile = getResolvedSourceFile(context, resolvedModule.resolvedFileName);

const { indexType, resolvedBaseNameNoExtension, resolvedFileName, implicitPackageIndex, extName, resolvedDir } =
getPathDetail(moduleName, resolvedModule);
const pathDetail = getPathDetail(moduleName, resolvedModule);
const { indexType, resolvedBaseNameNoExtension, resolvedFileName, implicitPackageIndex, resolvedDir } = pathDetail;
let extName = pathDetail.extName;

/* Determine output filename */
let outputBaseName = resolvedBaseNameNoExtension ?? "";

if (indexType === IndexType.Implicit) outputBaseName = outputBaseName.replace(/(\/index$)|(^index$)/, "");
const moduleFileOutputPath = getOutputPathForSourceFile(context, resolvedSourceFile);
if (useEsmOutput) extName = path.extname(moduleFileOutputPath);
else if (indexType === IndexType.Implicit) outputBaseName = outputBaseName.replace(/(\/index$)|(^index$)/, "");

if (outputBaseName && extName) outputBaseName = `${outputBaseName}${extName}`;

/* Determine output dir */
let srcFileOutputDir = getOutputDirForSourceFile(context, sourceFile);
let moduleFileOutputDir = implicitPackageIndex ? resolvedDir : getOutputDirForSourceFile(context, resolvedSourceFile);
let srcFileOutputDir = path.dirname(getOutputPathForSourceFile(context, sourceFile));
let moduleFileOutputDir = implicitPackageIndex ? resolvedDir : path.dirname(moduleFileOutputPath);

// Handle rootDirs remapping
if (config.useRootDirs && rootDirs) {
Expand Down
3 changes: 2 additions & 1 deletion src/utils/resolve-path-update-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export function resolvePathAndUpdateNode(
updaterFn: (newPath: ts.StringLiteral) => ts.Node | undefined
): ts.Node | undefined {
const { sourceFile, tsInstance, factory } = context;
const { outputMode } = context.config;
const { normalizePath } = tsInstance;

/* Handle JSDoc statement tags */
Expand All @@ -36,7 +37,7 @@ export function resolvePathAndUpdateNode(

/* Resolve Module */
// Skip if no paths match found
if (!isModulePathsMatch(context, moduleName)) return node;
if (outputMode !== "esm" && !isModulePathsMatch(context, moduleName)) return node;

const res = resolveModuleName(context, moduleName);
if (!res) return node;
Expand Down
12 changes: 4 additions & 8 deletions src/utils/ts-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import ts, { GetCanonicalFileName, SourceFile } from "typescript";
import path from "path";
import { VisitorContext } from "../types";
import type { REGISTER_INSTANCE } from "ts-node";

Expand All @@ -10,9 +9,8 @@ import type { REGISTER_INSTANCE } from "ts-node";
/**
* Determine output file path for source file
*/
export function getOutputDirForSourceFile(context: VisitorContext, sourceFile: SourceFile): string {
export function getOutputPathForSourceFile(context: VisitorContext, sourceFile: SourceFile): string {
const {
tsInstance,
emitHost,
outputFileNamesCache,
compilerOptions,
Expand All @@ -34,11 +32,9 @@ export function getOutputDirForSourceFile(context: VisitorContext, sourceFile: S
`https://github.com/LeDDGroup/typescript-transform-paths/issues`
);

const res = path.dirname(outputPath);
outputFileNamesCache.set(sourceFile, outputPath);

outputFileNamesCache.set(sourceFile, res);

return tsInstance.normalizePath(res);
return outputPath;
}

/**
Expand All @@ -49,7 +45,7 @@ export function isModulePathsMatch(context: VisitorContext, moduleName: string):
pathsPatterns,
tsInstance: { matchPatternOrExact },
} = context;
return !!(pathsPatterns && matchPatternOrExact(pathsPatterns as readonly string[], moduleName));
return !!(pathsPatterns && matchPatternOrExact(pathsPatterns, moduleName));
}

/**
Expand Down
1 change: 0 additions & 1 deletion test/.yarnrc

This file was deleted.

2 changes: 1 addition & 1 deletion test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"prepare": "node prepare.js"
},
"devDependencies": {
"typescript-transform-paths": "link:../src",
"typescript-transform-paths": "link:../",
"ts-expose-internals": "^4.1.2",
"typescript": "npm:typescript@latest",
"typescript-three": "npm:[email protected]",
Expand Down
2 changes: 1 addition & 1 deletion test/projects/extras/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"name": "@tests/extras",
"version": "0.0.0",
"dependencies": {
"typescript-transform-paths": "link:../../../"
"typescript-transform-paths": "*"
}
}
4 changes: 2 additions & 2 deletions test/projects/general/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"esModuleInterop": true,

"plugins": [
{ "transform": "../../src/index.ts" },
{ "transform": "../../src/index.ts", "afterDeclarations": true }
{ "transform": "../../../src/index.ts" },
{ "transform": "../../../src/index.ts", "afterDeclarations": true }
]
}
}
2 changes: 1 addition & 1 deletion test/projects/project-ref/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"name": "@tests/project-ref",
"version": "0.0.0",
"dependencies": {
"typescript-transform-paths": "link:../../../"
"typescript-transform-paths": "*"
}
}
Loading