Skip to content

Commit 62641d9

Browse files
authored
Refactor codebase into separate files, and enable importsNotUsedAsValues: error (#1266)
1 parent 5c6efa4 commit 62641d9

File tree

12 files changed

+371
-356
lines changed

12 files changed

+371
-356
lines changed

src/bin.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,10 @@ import { join, resolve, dirname, parse as parsePath } from 'path';
44
import { inspect } from 'util';
55
import Module = require('module');
66
import arg = require('arg');
7+
import { parse, createRequire } from './util';
78
import { EVAL_FILENAME, EvalState, createRepl, ReplService } from './repl';
8-
import {
9-
VERSION,
10-
TSError,
11-
parse,
12-
register,
13-
createRequire,
14-
TSInternal,
15-
} from './index';
9+
import { VERSION, TSError, register } from './index';
10+
import type { TSInternal } from './ts-compiler-types';
1611

1712
/**
1813
* Main `bin` functionality.

src/configuration.ts

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
import { resolve, dirname } from 'path';
2+
import type * as _ts from 'typescript';
3+
import { CreateOptions, DEFAULTS, TSCommon, TsConfigOptions } from './index';
4+
import { getDefaultTsconfigJsonForNodeVersion } from './tsconfigs';
5+
import { createRequire } from './util';
6+
7+
/**
8+
* TypeScript compiler option values required by `ts-node` which cannot be overridden.
9+
*/
10+
const TS_NODE_COMPILER_OPTIONS = {
11+
sourceMap: true,
12+
inlineSourceMap: false,
13+
inlineSources: true,
14+
declaration: false,
15+
noEmit: false,
16+
outDir: '.ts-node',
17+
};
18+
19+
/*
20+
* Do post-processing on config options to support `ts-node`.
21+
*/
22+
function fixConfig(ts: TSCommon, config: _ts.ParsedCommandLine) {
23+
// Delete options that *should not* be passed through.
24+
delete config.options.out;
25+
delete config.options.outFile;
26+
delete config.options.composite;
27+
delete config.options.declarationDir;
28+
delete config.options.declarationMap;
29+
delete config.options.emitDeclarationOnly;
30+
31+
// Target ES5 output by default (instead of ES3).
32+
if (config.options.target === undefined) {
33+
config.options.target = ts.ScriptTarget.ES5;
34+
}
35+
36+
// Target CommonJS modules by default (instead of magically switching to ES6 when the target is ES6).
37+
if (config.options.module === undefined) {
38+
config.options.module = ts.ModuleKind.CommonJS;
39+
}
40+
41+
return config;
42+
}
43+
44+
/**
45+
* Load TypeScript configuration. Returns the parsed TypeScript config and
46+
* any `ts-node` options specified in the config file.
47+
*
48+
* Even when a tsconfig.json is not loaded, this function still handles merging
49+
* compilerOptions from various sources: API, environment variables, etc.
50+
*
51+
* @internal
52+
*/
53+
export function readConfig(
54+
cwd: string,
55+
ts: TSCommon,
56+
rawApiOptions: CreateOptions
57+
): {
58+
/**
59+
* Path of tsconfig file if one was loaded
60+
*/
61+
configFilePath: string | undefined;
62+
/**
63+
* Parsed TypeScript configuration with compilerOptions merged from all other sources (env vars, etc)
64+
*/
65+
config: _ts.ParsedCommandLine;
66+
/**
67+
* ts-node options pulled from `tsconfig.json`, NOT merged with any other sources. Merging must happen outside
68+
* this function.
69+
*/
70+
tsNodeOptionsFromTsconfig: TsConfigOptions;
71+
} {
72+
let config: any = { compilerOptions: {} };
73+
let basePath = cwd;
74+
let configFilePath: string | undefined = undefined;
75+
const projectSearchDir = resolve(cwd, rawApiOptions.projectSearchDir ?? cwd);
76+
77+
const {
78+
fileExists = ts.sys.fileExists,
79+
readFile = ts.sys.readFile,
80+
skipProject = DEFAULTS.skipProject,
81+
project = DEFAULTS.project,
82+
} = rawApiOptions;
83+
84+
// Read project configuration when available.
85+
if (!skipProject) {
86+
configFilePath = project
87+
? resolve(cwd, project)
88+
: ts.findConfigFile(projectSearchDir, fileExists);
89+
90+
if (configFilePath) {
91+
const result = ts.readConfigFile(configFilePath, readFile);
92+
93+
// Return diagnostics.
94+
if (result.error) {
95+
return {
96+
configFilePath,
97+
config: { errors: [result.error], fileNames: [], options: {} },
98+
tsNodeOptionsFromTsconfig: {},
99+
};
100+
}
101+
102+
config = result.config;
103+
basePath = dirname(configFilePath);
104+
}
105+
}
106+
107+
// Fix ts-node options that come from tsconfig.json
108+
const tsNodeOptionsFromTsconfig: TsConfigOptions = Object.assign(
109+
{},
110+
filterRecognizedTsConfigTsNodeOptions(config['ts-node'])
111+
);
112+
113+
// Remove resolution of "files".
114+
const files =
115+
rawApiOptions.files ?? tsNodeOptionsFromTsconfig.files ?? DEFAULTS.files;
116+
if (!files) {
117+
config.files = [];
118+
config.include = [];
119+
}
120+
121+
// Only if a config file is *not* loaded, load an implicit configuration from @tsconfig/bases
122+
const skipDefaultCompilerOptions = configFilePath != null;
123+
const defaultCompilerOptionsForNodeVersion = skipDefaultCompilerOptions
124+
? undefined
125+
: {
126+
...getDefaultTsconfigJsonForNodeVersion(ts).compilerOptions,
127+
types: ['node'],
128+
};
129+
130+
// Merge compilerOptions from all sources
131+
config.compilerOptions = Object.assign(
132+
{},
133+
// automatically-applied options from @tsconfig/bases
134+
defaultCompilerOptionsForNodeVersion,
135+
// tsconfig.json "compilerOptions"
136+
config.compilerOptions,
137+
// from env var
138+
DEFAULTS.compilerOptions,
139+
// tsconfig.json "ts-node": "compilerOptions"
140+
tsNodeOptionsFromTsconfig.compilerOptions,
141+
// passed programmatically
142+
rawApiOptions.compilerOptions,
143+
// overrides required by ts-node, cannot be changed
144+
TS_NODE_COMPILER_OPTIONS
145+
);
146+
147+
const fixedConfig = fixConfig(
148+
ts,
149+
ts.parseJsonConfigFileContent(
150+
config,
151+
{
152+
fileExists,
153+
readFile,
154+
readDirectory: ts.sys.readDirectory,
155+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
156+
},
157+
basePath,
158+
undefined,
159+
configFilePath
160+
)
161+
);
162+
163+
if (tsNodeOptionsFromTsconfig.require) {
164+
// Modules are found relative to the tsconfig file, not the `dir` option
165+
const tsconfigRelativeRequire = createRequire(configFilePath!);
166+
tsNodeOptionsFromTsconfig.require = tsNodeOptionsFromTsconfig.require.map(
167+
(path: string) => {
168+
return tsconfigRelativeRequire.resolve(path);
169+
}
170+
);
171+
}
172+
173+
return { configFilePath, config: fixedConfig, tsNodeOptionsFromTsconfig };
174+
}
175+
176+
/**
177+
* Given the raw "ts-node" sub-object from a tsconfig, return an object with only the properties
178+
* recognized by "ts-node"
179+
*/
180+
function filterRecognizedTsConfigTsNodeOptions(
181+
jsonObject: any
182+
): TsConfigOptions {
183+
if (jsonObject == null) return jsonObject;
184+
const {
185+
compiler,
186+
compilerHost,
187+
compilerOptions,
188+
emit,
189+
files,
190+
ignore,
191+
ignoreDiagnostics,
192+
logError,
193+
preferTsExts,
194+
pretty,
195+
require,
196+
skipIgnore,
197+
transpileOnly,
198+
typeCheck,
199+
transpiler,
200+
} = jsonObject as TsConfigOptions;
201+
const filteredTsConfigOptions = {
202+
compiler,
203+
compilerHost,
204+
compilerOptions,
205+
emit,
206+
files,
207+
ignore,
208+
ignoreDiagnostics,
209+
logError,
210+
preferTsExts,
211+
pretty,
212+
require,
213+
skipIgnore,
214+
transpileOnly,
215+
typeCheck,
216+
transpiler,
217+
};
218+
// Use the typechecker to make sure this implementation has the correct set of properties
219+
const catchExtraneousProps: keyof TsConfigOptions = (null as any) as keyof typeof filteredTsConfigOptions;
220+
const catchMissingProps: keyof typeof filteredTsConfigOptions = (null as any) as keyof TsConfigOptions;
221+
return filteredTsConfigOptions;
222+
}

src/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { sync as rimrafSync } from 'rimraf';
2828
import type _createRequire from 'create-require';
2929
const createRequire: typeof _createRequire = require('create-require');
3030
import { pathToFileURL } from 'url';
31-
import Module = require('module');
31+
import type * as Module from 'module';
3232
import { PassThrough } from 'stream';
3333
import * as getStream from 'get-stream';
3434
import { once } from 'lodash';

0 commit comments

Comments
 (0)