Skip to content

Commit c00942f

Browse files
committed
changes
1 parent e8f2bd0 commit c00942f

16 files changed

+345
-185
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ tsconfig.schemastore-schema.json
1212
/website/static/api
1313
/tsconfig.tsbuildinfo
1414
/temp
15+
/.tmp

development-docs/caches.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Lots of caching in ts-node.
2+
3+
## Caches
4+
5+
### FS cache:
6+
caches results of primitive ts.sys.readFile, etc operations
7+
Shared across compiler and config loader
8+
9+
### fileContents (and fileVersions) cache:
10+
sits in front of fs cache.
11+
Node.js module loading mechanism reads file contents from disk. That's put into this cache.
12+
13+
### Output cache:
14+
Caches the emitted JS syntax from compilation.
15+
Has appended //# sourcemap comments.
16+
source-map-support reads from here before fallback to filesystem.
17+
18+
### source-map-support cache:
19+
caches fs.readFile calls
20+
overlayed by output cache above
21+
overlayed by sourcesContents from parsed sourcemaps
22+
23+
### SourceFile cache: (does not exist today)
24+
for Compiler API codepath
25+
to avoid re-parsing SourceFile repeatedly
26+
27+
## Questions
28+
29+
If both:
30+
- source-map-support caches a sourcesContents string of a .ts file
31+
- cachedFsReader caches the same .ts file from disk
32+
...which is used by source-map-support? Does it matter since they should be identical?

dist-raw/node-cjs-helpers.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

dist-raw/node-cjs-loader-utils.js

Lines changed: 112 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -3,131 +3,136 @@
33
// Each function and variable below must have a comment linking to the source in node's github repo.
44

55
const path = require('path');
6-
const packageJsonReader = require('./node-package-json-reader');
76
const {JSONParse} = require('./node-primordials');
87
const {normalizeSlashes} = require('../dist/util');
98

10-
module.exports.assertScriptCanLoadAsCJSImpl = assertScriptCanLoadAsCJSImpl;
9+
/** @param {ReturnType<typeof import('./node-package-json-reader').createNodePackageJsonReader>} packageJsonReader */
10+
function createNodeCjsLoaderUtils(packageJsonReader) {
1111

12-
/**
13-
* copied from Module._extensions['.js']
14-
* https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120
15-
* @param {import('../src/index').Service} service
16-
* @param {NodeJS.Module} module
17-
* @param {string} filename
18-
*/
19-
function assertScriptCanLoadAsCJSImpl(service, module, filename) {
20-
const pkg = readPackageScope(filename);
12+
/**
13+
* copied from Module._extensions['.js']
14+
* https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120
15+
* @param {import('../src/index').Service} service
16+
* @param {NodeJS.Module} module
17+
* @param {string} filename
18+
*/
19+
function assertScriptCanLoadAsCJSImpl(service, module, filename) {
20+
const pkg = readPackageScope(filename);
2121

22-
// ts-node modification: allow our configuration to override
23-
const tsNodeClassification = service.moduleTypeClassifier.classifyModule(normalizeSlashes(filename));
24-
if(tsNodeClassification.moduleType === 'cjs') return;
22+
// ts-node modification: allow our configuration to override
23+
const tsNodeClassification = service.moduleTypeClassifier.classifyModule(normalizeSlashes(filename));
24+
if(tsNodeClassification.moduleType === 'cjs') return;
2525

26-
// Function require shouldn't be used in ES modules.
27-
if (tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) {
28-
const parentPath = module.parent && module.parent.filename;
29-
const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null;
30-
throw createErrRequireEsm(filename, parentPath, packageJsonPath);
26+
// Function require shouldn't be used in ES modules.
27+
if (tsNodeClassification.moduleType === 'esm' || (pkg && pkg.data && pkg.data.type === 'module')) {
28+
const parentPath = module.parent && module.parent.filename;
29+
const packageJsonPath = pkg ? path.resolve(pkg.path, 'package.json') : null;
30+
throw createErrRequireEsm(filename, parentPath, packageJsonPath);
31+
}
3132
}
32-
}
3333

34-
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L285-L301
35-
function readPackageScope(checkPath) {
36-
const rootSeparatorIndex = checkPath.indexOf(path.sep);
37-
let separatorIndex;
38-
while (
39-
(separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex
40-
) {
41-
checkPath = checkPath.slice(0, separatorIndex);
42-
if (checkPath.endsWith(path.sep + 'node_modules'))
43-
return false;
44-
const pjson = readPackage(checkPath);
45-
if (pjson) return {
46-
path: checkPath,
47-
data: pjson
48-
};
34+
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L285-L301
35+
function readPackageScope(checkPath) {
36+
const rootSeparatorIndex = checkPath.indexOf(path.sep);
37+
let separatorIndex;
38+
while (
39+
(separatorIndex = checkPath.lastIndexOf(path.sep)) > rootSeparatorIndex
40+
) {
41+
checkPath = checkPath.slice(0, separatorIndex);
42+
if (checkPath.endsWith(path.sep + 'node_modules'))
43+
return false;
44+
const pjson = readPackage(checkPath);
45+
if (pjson) return {
46+
path: checkPath,
47+
data: pjson
48+
};
49+
}
50+
return false;
4951
}
50-
return false;
51-
}
5252

53-
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249
54-
const packageJsonCache = new Map();
53+
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249
54+
const packageJsonCache = new Map();
5555

56-
// Copied from https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L275-L304
57-
function readPackage(requestPath) {
58-
const jsonPath = path.resolve(requestPath, 'package.json');
56+
// Copied from https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L275-L304
57+
function readPackage(requestPath) {
58+
const jsonPath = path.resolve(requestPath, 'package.json');
5959

60-
const existing = packageJsonCache.get(jsonPath);
61-
if (existing !== undefined) return existing;
60+
const existing = packageJsonCache.get(jsonPath);
61+
if (existing !== undefined) return existing;
6262

63-
const result = packageJsonReader.read(jsonPath);
64-
const json = result.containsKeys === false ? '{}' : result.string;
65-
if (json === undefined) {
66-
packageJsonCache.set(jsonPath, false);
67-
return false;
68-
}
63+
const result = packageJsonReader.read(jsonPath);
64+
const json = result.containsKeys === false ? '{}' : result.string;
65+
if (json === undefined) {
66+
packageJsonCache.set(jsonPath, false);
67+
return false;
68+
}
6969

70-
try {
71-
const parsed = JSONParse(json);
72-
const filtered = {
73-
name: parsed.name,
74-
main: parsed.main,
75-
exports: parsed.exports,
76-
imports: parsed.imports,
77-
type: parsed.type
78-
};
79-
packageJsonCache.set(jsonPath, filtered);
80-
return filtered;
81-
} catch (e) {
82-
e.path = jsonPath;
83-
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
84-
throw e;
70+
try {
71+
const parsed = JSONParse(json);
72+
const filtered = {
73+
name: parsed.name,
74+
main: parsed.main,
75+
exports: parsed.exports,
76+
imports: parsed.imports,
77+
type: parsed.type
78+
};
79+
packageJsonCache.set(jsonPath, filtered);
80+
return filtered;
81+
} catch (e) {
82+
e.path = jsonPath;
83+
e.message = 'Error parsing ' + jsonPath + ': ' + e.message;
84+
throw e;
85+
}
8586
}
86-
}
8787

88-
// Native ERR_REQUIRE_ESM Error is declared here:
89-
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L1294-L1313
90-
// Error class factory is implemented here:
91-
// function E: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L323-L341
92-
// function makeNodeErrorWithCode: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L251-L278
93-
// The code below should create an error that matches the native error as closely as possible.
94-
// Third-party libraries which attempt to catch the native ERR_REQUIRE_ESM should recognize our imitation error.
95-
function createErrRequireEsm(filename, parentPath, packageJsonPath) {
96-
const code = 'ERR_REQUIRE_ESM'
97-
const err = new Error(getMessage(filename, parentPath, packageJsonPath))
98-
// Set `name` to be used in stack trace, generate stack trace with that name baked in, then re-declare the `name` field.
99-
// This trick is copied from node's source.
100-
err.name = `Error [${ code }]`
101-
err.stack
102-
Object.defineProperty(err, 'name', {
103-
value: 'Error',
104-
enumerable: false,
105-
writable: true,
106-
configurable: true
107-
})
108-
err.code = code
109-
return err
88+
// Native ERR_REQUIRE_ESM Error is declared here:
89+
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L1294-L1313
90+
// Error class factory is implemented here:
91+
// function E: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L323-L341
92+
// function makeNodeErrorWithCode: https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/errors.js#L251-L278
93+
// The code below should create an error that matches the native error as closely as possible.
94+
// Third-party libraries which attempt to catch the native ERR_REQUIRE_ESM should recognize our imitation error.
95+
function createErrRequireEsm(filename, parentPath, packageJsonPath) {
96+
const code = 'ERR_REQUIRE_ESM'
97+
const err = new Error(getMessage(filename, parentPath, packageJsonPath))
98+
// Set `name` to be used in stack trace, generate stack trace with that name baked in, then re-declare the `name` field.
99+
// This trick is copied from node's source.
100+
err.name = `Error [${ code }]`
101+
err.stack
102+
Object.defineProperty(err, 'name', {
103+
value: 'Error',
104+
enumerable: false,
105+
writable: true,
106+
configurable: true
107+
})
108+
err.code = code
109+
return err
110110

111-
// Copy-pasted from https://github.com/nodejs/node/blob/b533fb3508009e5f567cc776daba8fbf665386a6/lib/internal/errors.js#L1293-L1311
112-
// so that our error message is identical to the native message.
113-
function getMessage(filename, parentPath = null, packageJsonPath = null) {
114-
const ext = path.extname(filename)
115-
let msg = `Must use import to load ES Module: ${filename}`;
116-
if (parentPath && packageJsonPath) {
117-
const path = require('path');
118-
const basename = path.basename(filename) === path.basename(parentPath) ?
119-
filename : path.basename(filename);
120-
msg +=
121-
'\nrequire() of ES modules is not supported.\nrequire() of ' +
122-
`${filename} ${parentPath ? `from ${parentPath} ` : ''}` +
123-
`is an ES module file as it is a ${ext} file whose nearest parent ` +
124-
`package.json contains "type": "module" which defines all ${ext} ` +
125-
'files in that package scope as ES modules.\nInstead ' +
126-
'change the requiring code to use ' +
127-
'import(), or remove "type": "module" from ' +
128-
`${packageJsonPath}.\n`;
111+
// Copy-pasted from https://github.com/nodejs/node/blob/b533fb3508009e5f567cc776daba8fbf665386a6/lib/internal/errors.js#L1293-L1311
112+
// so that our error message is identical to the native message.
113+
function getMessage(filename, parentPath = null, packageJsonPath = null) {
114+
const ext = path.extname(filename)
115+
let msg = `Must use import to load ES Module: ${filename}`;
116+
if (parentPath && packageJsonPath) {
117+
const path = require('path');
118+
const basename = path.basename(filename) === path.basename(parentPath) ?
119+
filename : path.basename(filename);
120+
msg +=
121+
'\nrequire() of ES modules is not supported.\nrequire() of ' +
122+
`${filename} ${parentPath ? `from ${parentPath} ` : ''}` +
123+
`is an ES module file as it is a ${ext} file whose nearest parent ` +
124+
`package.json contains "type": "module" which defines all ${ext} ` +
125+
'files in that package scope as ES modules.\nInstead ' +
126+
'change the requiring code to use ' +
127+
'import(), or remove "type": "module" from ' +
128+
`${packageJsonPath}.\n`;
129+
return msg;
130+
}
129131
return msg;
130132
}
131-
return msg;
132133
}
134+
135+
return {assertScriptCanLoadAsCJSImpl};
133136
}
137+
138+
module.exports.createNodeCjsLoaderUtils = createNodeCjsLoaderUtils;

dist-raw/node-esm-default-get-format.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const experimentalJsonModules = getOptionValue('--experimental-json-modules');
1515
const experimentalSpeciferResolution =
1616
getOptionValue('--experimental-specifier-resolution');
1717
const experimentalWasmModules = getOptionValue('--experimental-wasm-modules');
18-
const { getPackageType } = require('./node-esm-resolve-implementation.js').createResolve({tsExtensions: [], jsExtensions: []});
1918
const { URL, fileURLToPath } = require('url');
2019
const { ERR_UNKNOWN_FILE_EXTENSION } = require('./node-errors').codes;
2120

@@ -41,6 +40,9 @@ if (experimentalWasmModules)
4140
if (experimentalJsonModules)
4241
extensionFormatMap['.json'] = legacyExtensionFormatMap['.json'] = 'json';
4342

43+
function createDefaultGetFormat(getPackageType) {
44+
45+
// Intentionally unindented to simplify the diff
4446
function defaultGetFormat(url, context, defaultGetFormatUnused) {
4547
if (StringPrototypeStartsWith(url, 'node:')) {
4648
return { format: 'builtin' };
@@ -80,4 +82,7 @@ function defaultGetFormat(url, context, defaultGetFormatUnused) {
8082
}
8183
return { format: null };
8284
}
83-
exports.defaultGetFormat = defaultGetFormat;
85+
return {defaultGetFormat};
86+
}
87+
88+
exports.createDefaultGetFormat = createDefaultGetFormat;

dist-raw/node-esm-resolve-implementation.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,26 @@ const {
9595
const CJSModule = Module;
9696

9797
// const packageJsonReader = require('internal/modules/package_json_reader');
98-
const packageJsonReader = require('./node-package-json-reader');
98+
99+
const { createDefaultGetFormat } = require('./node-esm-default-get-format');
100+
99101
const userConditions = getOptionValue('--conditions');
100102
const DEFAULT_CONDITIONS = ObjectFreeze(['node', 'import', ...userConditions]);
101103
const DEFAULT_CONDITIONS_SET = new SafeSet(DEFAULT_CONDITIONS);
102104

103105
const pendingDeprecation = getOptionValue('--pending-deprecation');
104106

107+
/**
108+
* @param {{
109+
* tsExtensions: string[];
110+
* jsExtensions: string[];
111+
* preferTsExts: boolean;
112+
* packageJsonReader: ReturnType<import('./node-package-json-reader').createNodePackageJsonReader>;
113+
* }} opts
114+
*/
105115
function createResolve(opts) {
106-
// TODO receive cached fs implementations here
107-
const {tsExtensions, jsExtensions, preferTsExts} = opts;
116+
const {tsExtensions, jsExtensions, preferTsExts, packageJsonReader} = opts;
117+
const {defaultGetFormat} = createDefaultGetFormat(getPackageType);
108118

109119
const emittedPackageWarnings = new SafeSet();
110120
function emitFolderMapDeprecation(match, pjsonUrl, isExports, base) {
@@ -971,7 +981,8 @@ return {
971981
encodedSepRegEx,
972982
getPackageType,
973983
packageExportsResolve,
974-
packageImportsResolve
984+
packageImportsResolve,
985+
defaultGetFormat
975986
};
976987
}
977988
module.exports = {

dist-raw/node-internal-fs.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
const fs = require('fs');
22

3-
// In node's core, this is implemented in C
4-
// https://github.com/nodejs/node/blob/v15.3.0/src/node_file.cc#L891-L985
5-
function internalModuleReadJSON(path) {
6-
let string
7-
try {
8-
string = fs.readFileSync(path, 'utf8')
9-
} catch (e) {
10-
if (e.code === 'ENOENT') return []
11-
throw e
3+
function createNodeInternalModuleReadJSON() {
4+
// In node's core, this is implemented in C
5+
// https://github.com/nodejs/node/blob/v15.3.0/src/node_file.cc#L891-L985
6+
function internalModuleReadJSON(path) {
7+
let string
8+
try {
9+
string = fs.readFileSync(path, 'utf8')
10+
} catch (e) {
11+
if (e.code === 'ENOENT') return []
12+
throw e
13+
}
14+
// Node's implementation checks for the presence of relevant keys: main, name, type, exports, imports
15+
// Node does this for performance to skip unnecessary parsing.
16+
// This would slow us down and, based on our usage, we can skip it.
17+
const containsKeys = true
18+
return [string, containsKeys]
1219
}
13-
// Node's implementation checks for the presence of relevant keys: main, name, type, exports, imports
14-
// Node does this for performance to skip unnecessary parsing.
15-
// This would slow us down and, based on our usage, we can skip it.
16-
const containsKeys = true
17-
return [string, containsKeys]
20+
21+
return internalModuleReadJSON;
1822
}
1923

20-
module.exports = {
21-
internalModuleReadJSON
22-
};
24+
module.exports.createNodeInternalModuleReadJSON = createNodeInternalModuleReadJSON;

0 commit comments

Comments
 (0)