Skip to content

Commit 396766c

Browse files
committed
feat: Add support for ts 5.7+ (closes #174)
1 parent 1bd211d commit 396766c

File tree

11 files changed

+441
-348
lines changed

11 files changed

+441
-348
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
"ts-node": "^10.9.1",
7575
"ts-patch": "^3.2.1",
7676
"tsconfig-paths": "^4.2.0",
77-
"typescript": "^5.5.2",
77+
"typescript": "5.5.2",
7878
"ts-next": "npm:typescript@beta",
7979
"ts-expose-internals": "npm:ts-expose-internals@5.4.5"
8080
},

projects/core/src/actions/patch.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export function patch(moduleNameOrNames: string | string[], opts?: Partial<Insta
5454
const { 1: moduleFile } = entry;
5555
const tsModule = getTsModule(tsPackage, moduleFile, { skipCache: true });
5656

57-
const { moduleName, modulePath } = tsModule;
57+
const { moduleName, modulePath, moduleContentFilePath } = tsModule;
5858
log(
5959
[ '~', `Patching ${chalk.blueBright(moduleName)} in ${chalk.blueBright(path.dirname(modulePath ))}` ],
6060
LogLevel.verbose
@@ -68,12 +68,12 @@ export function patch(moduleNameOrNames: string | string[], opts?: Partial<Insta
6868
[
6969
'~',
7070
`Writing patched ${chalk.blueBright(moduleName)} to ` +
71-
`${chalk.blueBright(modulePath)}${loadedFromCache ? ' (cached)' : ''}`
71+
`${chalk.blueBright(moduleContentFilePath)}${loadedFromCache ? ' (cached)' : ''}`
7272
],
7373
LogLevel.verbose
7474
);
7575

76-
writeFileWithLock(tsModule.modulePath, js!);
76+
writeFileWithLock(moduleContentFilePath, js!);
7777
if (dts) writeFileWithLock(tsModule.dtsPath!, dts!);
7878

7979
log([ '+', chalk.green(`Successfully patched ${chalk.bold.yellow(moduleName)}.\r\n`) ], LogLevel.verbose);

projects/core/src/actions/unpatch.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,14 @@ export function unpatch(moduleNameOrNames: string | string[], opts?: Partial<Ins
6969
throw new Error(`Cannot find backup file: ${backupPath}. Try reinstalling typescript.`);
7070

7171
const moduleDir = path.dirname(tsModule.modulePath);
72-
const destPath = path.join(moduleDir, path.basename(backupPath));
72+
73+
/* Determine destination path (Need to use moduleContentPath if we're working with a cached module file */
74+
const baseFileName = path.basename(backupPath);
75+
const destPathName = baseFileName === tsModule.moduleName
76+
? path.basename(tsModule.moduleContentFilePath)
77+
: baseFileName;
78+
79+
const destPath = path.join(moduleDir, destPathName);
7380

7481
copyFileWithLock(backupPath, destPath);
7582
}

projects/core/src/module/module-file.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import fs from 'fs';
22
import { PatchDetail } from '../patch/patch-detail';
33
import path from 'path';
44
import { getHash, withFileLock } from '../utils';
5+
import { TsModule } from './ts-module';
56

67

78
/* ****************************************************************************************************************** */
@@ -22,6 +23,7 @@ export interface ModuleFile {
2223
moduleName: string
2324
patchDetail?: PatchDetail
2425
filePath: string
26+
contentFilePath: string
2527
get content(): string
2628

2729
getHash(): string
@@ -99,17 +101,21 @@ function readFile(filePath: string, headersOnly?: boolean) {
99101
/* ****************************************************************************************************************** */
100102

101103
export function getModuleFile(filePath: string, loadFullContent?: boolean): ModuleFile {
102-
let { headerLines, content } = readFile(filePath, !loadFullContent);
104+
/* Determine shim redirect file - see: https://github.com/nonara/ts-patch/issues/174 */
105+
const moduleName = path.basename(filePath);
106+
const contentFilePath = TsModule.getContentFilePathForModulePath(filePath);
103107

104108
/* Get PatchDetail */
109+
let { headerLines, content } = readFile(contentFilePath, !loadFullContent);
105110
const patchDetail = PatchDetail.fromHeader(headerLines);
106111

107112
return {
108-
moduleName: path.basename(filePath),
113+
moduleName,
109114
filePath,
115+
contentFilePath,
110116
patchDetail,
111117
get content() {
112-
if (content == null) content = readFile(this.filePath, false).content;
118+
if (content == null) content = readFile(this.contentFilePath, false).content;
113119
return content!;
114120
},
115121
getHash(): string {

projects/core/src/module/ts-module.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,30 @@ import { cachedFilePatchedPrefix } from '../config';
1212
/* ****************************************************************************************************************** */
1313

1414
export namespace TsModule {
15-
export const names = <const>['tsc.js', 'tsserverlibrary.js', 'typescript.js', 'tsserver.js'];
15+
export const names = <const>[ 'tsc.js', 'tsserverlibrary.js', 'typescript.js', 'tsserver.js' ];
16+
17+
export const contentFileMap: Record<string, string> = {
18+
'tsc.js': '_tsc.js',
19+
'tsserver.js': '_tsserver.js'
20+
} satisfies Partial<Record<typeof names[number], string>>;
21+
22+
export function getContentFileName(moduleName: typeof names[number]): string {
23+
return contentFileMap[moduleName] || moduleName;
24+
}
25+
26+
/* Determine shim redirect file - see: https://github.com/nonara/ts-patch/issues/174 */
27+
export function getContentFilePathForModulePath(modulePath: string): string {
28+
const baseName = path.basename(modulePath);
29+
if (!names.includes(baseName as any)) throw new TspError(`Invalid module path: ${modulePath}`);
30+
31+
const redirectFile = contentFileMap[baseName];
32+
const maybeModuleContentPath = redirectFile && path.join(path.dirname(modulePath), redirectFile);
33+
const moduleContentPath = maybeModuleContentPath && fs.existsSync(maybeModuleContentPath)
34+
? maybeModuleContentPath
35+
: modulePath;
36+
37+
return moduleContentPath;
38+
}
1639
}
1740

1841
// endregion
@@ -30,6 +53,7 @@ export interface TsModule {
3053

3154
moduleName: TsModule.Name;
3255
modulePath: string;
56+
moduleContentFilePath: string;
3357
moduleFile: ModuleFile;
3458
dtsPath: string | undefined;
3559

@@ -113,6 +137,7 @@ export function getTsModule(
113137
moduleName,
114138
modulePath,
115139
moduleFile,
140+
moduleContentFilePath: moduleFile.contentFilePath,
116141
dtsPath,
117142

118143
cacheKey,

projects/core/src/patch/get-patched-source.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function getPatchedSource(tsModule: TsModule, options?: GetPatchedSourceO
3333
/* Write backup if not patched */
3434
if (!tsModule.isPatched) {
3535
for (const [ key, backupPath ] of Object.entries(backupCachePaths)) {
36-
const srcPath = key === 'dts' ? tsModule.dtsPath : tsModule.modulePath;
36+
const srcPath = key === 'dts' ? tsModule.dtsPath : tsModule.moduleContentFilePath;
3737
if (key === 'dts' && options?.skipDts) continue;
3838
if (!srcPath) continue;
3939

test/assets/projects/transform/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"main": "src/index.ts",
44
"dependencies": {
55
"esm": "^3.2.25",
6-
"ts-node" : "^10.9.1"
6+
"ts-node" : "^10.9.1",
7+
"semver" : "^7.6.3"
78
}
89
}

test/assets/projects/transform/run-transform.js

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const path = require('path');
2+
const semver = require('semver');
23

34

45
/* ****************************************************************************************************************** *
@@ -9,24 +10,36 @@ function getTransformedFile(transformerKind) {
910
process.env.TSP_SKIP_CACHE = true;
1011
const tsInstance = require('ts-patch/compiler');
1112

12-
console.log('TS version: ', tsInstance.version);
13+
console.log(`'TS version: ${tsInstance.version}\nNode Version: ${process.version.slice(1)}`);
1314

1415
const configPath = path.join(__dirname, `tsconfig.${transformerKind}.json`);
1516
const configText = tsInstance.sys.readFile(configPath);
16-
const configParseResult = tsInstance.parseConfigFileTextToJson(configPath, configText);
17-
const config = configParseResult.config;
1817

19-
config.compilerOptions.noEmit = false;
20-
config.compilerOptions.skipLibCheck = true;
21-
config.compilerOptions.outDir = 'dist';
18+
/* Parse config */
19+
let compilerOptions;
20+
if (semver.lt(tsInstance.version, '5.5.0', { includePrerelease: false })) {
21+
const configParseResult = tsInstance.parseConfigFileTextToJson(configPath, configText);
22+
compilerOptions = configParseResult.config.compilerOptions;
23+
} else {
24+
const configSourceFile = tsInstance.createSourceFile(configPath, configText, tsInstance.ScriptTarget.Latest);
25+
const configParseResult = tsInstance.parseJsonSourceFileConfigFileContent(configSourceFile, tsInstance.sys, path.dirname(configPath), undefined, configPath);
26+
compilerOptions = configParseResult.options;
27+
}
28+
29+
/* Overwrite options */
30+
Object.assign(compilerOptions, {
31+
noEmit: false,
32+
skipLibCheck: true,
33+
outDir: 'dist',
34+
});
2235

2336
const emittedFiles = new Map();
2437

2538
const writeFile = (fileName, content) => emittedFiles.set(fileName, content);
2639

2740
const program = tsInstance.createProgram({
2841
rootNames: [ path.join(__dirname, 'src', 'index.ts') ],
29-
options: config.compilerOptions,
42+
options: compilerOptions,
3043
});
3144

3245
program.emit(undefined, writeFile);

test/tests/actions.test.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import ts from 'typescript';
1717
/* ****************************************************************************************************************** */
1818

1919
const verboseMode = !!process.env.VERBOSE;
20+
// const verboseMode = true;
2021

2122
/* Options to use with install/uninstall */
2223
const testingPackageManagers = [
@@ -43,7 +44,10 @@ function getModulesSources(tsPackage: TsPackage, moduleNames?: string[]) {
4344
return new Map(moduleNames.map(name => {
4445
const modulePath = tsPackage.getModulePath(name);
4546
const dtsPath = modulePath.replace(/\.js$/, '.d.ts');
46-
const js = fs.readFileSync(modulePath, 'utf-8');
47+
48+
const moduleContentPath = TsModule.getContentFilePathForModulePath(modulePath);
49+
50+
const js = fs.readFileSync(moduleContentPath, 'utf-8');
4751
const dts = fs.existsSync(dtsPath) ? fs.readFileSync(dtsPath, 'utf-8') : undefined;
4852

4953
return [ name, { js, dts } ];
@@ -192,7 +196,7 @@ describe(`TSP Actions`, () => {
192196
const dtsFilePath = path.join(tsDir, 'typescript.d.ts');
193197

194198
const compilerOptions = Object.assign(ts.getDefaultCompilerOptions(), {
195-
target: 'ES2018',
199+
target: ts.ScriptTarget.ES2018,
196200
lib: [ 'es2018' ],
197201
skipDefaultLibCheck: true
198202
});
@@ -255,7 +259,8 @@ describe(`TSP Actions`, () => {
255259
expect(src).toBe(origSrcEntry.dts);
256260
}
257261

258-
const src = fs.readFileSync(m.modulePath, 'utf-8');
262+
const contentFilePath = TsModule.getContentFilePathForModulePath(m.modulePath);
263+
const src = fs.readFileSync(contentFilePath, 'utf-8');
259264
expect(src).toBe(origSrcEntry.js);
260265
}
261266
});

test/tests/transformer.test.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ describe(`Transformer`, () => {
2626
let loaderResolve: (value?: unknown) => void;
2727
let loaderPromise = new Promise(resolve => loaderResolve = resolve);
2828
beforeAll(() => {
29-
const prepRes = prepareTestProject({ projectName: 'transform', packageManager: 'yarn' });
29+
const prepRes = prepareTestProject({
30+
projectName: 'transform',
31+
packageManager: 'yarn',
32+
tsVersion: '5.5.2',
33+
});
3034
projectPath = prepRes.tmpProjectPath;
3135
loaderResolve();
3236
});
@@ -35,6 +39,6 @@ describe(`Transformer`, () => {
3539
await loaderPromise;
3640

3741
const res = execSync(`node run-transform.js ${transformerKind}`, { cwd: projectPath });
38-
expect(res.toString('utf8')).toMatch(new RegExp(`^var a = "after-${transformerKind}";?$`, 'm'));
42+
expect(res.toString('utf8')).toMatch(new RegExp(`^(?:var|const) a = "after-${transformerKind}";?$`, 'm'));
3943
});
4044
});

0 commit comments

Comments
 (0)