Skip to content

Commit b1435c6

Browse files
committed
enable tscheck on sources
1 parent 3379820 commit b1435c6

File tree

7 files changed

+247
-40
lines changed

7 files changed

+247
-40
lines changed

src/Error.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
1+
// @ts-check
12
const STRIP_FILENAME_RE = /^[^:]+: /;
23

4+
/**
5+
* @typedef { Error & { hideStack?: boolean, codeFrame?: string } } BabelLoaderError
6+
*/
7+
/**
8+
* Format the error for display.
9+
* @param {BabelLoaderError} err
10+
* @returns {BabelLoaderError}
11+
*/
312
const format = err => {
413
if (err instanceof SyntaxError) {
514
err.name = "SyntaxError";
@@ -17,6 +26,9 @@ const format = err => {
1726
};
1827

1928
class LoaderError extends Error {
29+
/**
30+
* @param {BabelLoaderError} err
31+
*/
2032
constructor(err) {
2133
super();
2234

src/cache.js

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// @ts-check
12
/**
23
* Filesystem Cache
34
*
@@ -17,6 +18,26 @@ const { sync: findUpSync } = require("find-up");
1718
const { env } = process;
1819
const transform = require("./transform");
1920
const serialize = require("./serialize");
21+
/**
22+
* @typedef {object} FileSystemInfoEntry
23+
* @property {number} safeTime
24+
* @property {number} timestamp
25+
*/
26+
/**
27+
* @typedef {object} WebpackLogger
28+
* @property {function(string): void} debug
29+
* @property {function(string): void} info
30+
* @property {function(string): void} warn
31+
* @property {function(string): void} error
32+
*/
33+
/**
34+
* @typedef {object} WebpackHash
35+
* @property {(data: string | Buffer, inputEncoding?: string) => WebpackHash} update
36+
*/
37+
38+
/**
39+
* @type {string | null}
40+
*/
2041
let defaultCacheDirectory = null;
2142

2243
const gunzip = promisify(zlib.gunzip);
@@ -35,8 +56,8 @@ const findRootPackageJSON = () => {
3556
* Read the contents from the compressed file.
3657
*
3758
* @async
38-
* @params {String} filename
39-
* @params {Boolean} compress
59+
* @param {string} filename
60+
* @param {boolean} compress
4061
*/
4162
const read = async function (filename, compress) {
4263
const data = await readFile(filename + (compress ? ".gz" : ""));
@@ -49,9 +70,9 @@ const read = async function (filename, compress) {
4970
* Write contents into a compressed file.
5071
*
5172
* @async
52-
* @params {String} filename
53-
* @params {Boolean} compress
54-
* @params {String} result
73+
* @param {string} filename
74+
* @param {boolean} compress
75+
* @param {any} result
5576
*/
5677
const write = async function (filename, compress, result) {
5778
const content = JSON.stringify(result);
@@ -63,17 +84,23 @@ const write = async function (filename, compress, result) {
6384
/**
6485
* Build the filename for the cached file
6586
*
66-
* @params {String} source File source code
67-
* @params {Object} options Options used
68-
*
69-
* @return {String}
87+
* @param {string} source File source code
88+
* @param {string} identifier Unique identifier to bust cache
89+
* @param {Object} options Options used
90+
* @param {any} hash Hash function returned by `LoaderContext.utils.createHash`
91+
* @return {string}
7092
*/
7193
const filename = function (source, identifier, options, hash) {
7294
hash.update(serialize([options, source, identifier]));
7395

7496
return hash.digest("hex") + ".json";
7597
};
7698

99+
/**
100+
* Add timestamps to external dependencies.
101+
* @param {import("./transform").TransformResult["externalDependencies"]} externalDependencies
102+
* @param {(filename: string) => Promise<FileSystemInfoEntry>} getFileTimestamp
103+
*/
77104
const addTimestamps = async function (externalDependencies, getFileTimestamp) {
78105
for (const depAndEmptyTimestamp of externalDependencies) {
79106
try {
@@ -86,6 +113,12 @@ const addTimestamps = async function (externalDependencies, getFileTimestamp) {
86113
}
87114
};
88115

116+
/**
117+
* Check if any external dependencies have been modified.
118+
* @param {import("./transform").TransformResult["externalDependencies"]} externalDepsWithTimestamp
119+
* @param {(filename: string) => Promise<FileSystemInfoEntry>} getFileTimestamp
120+
* @returns {Promise<boolean>}
121+
*/
89122
const areExternalDependenciesModified = async function (
90123
externalDepsWithTimestamp,
91124
getFileTimestamp,
@@ -108,8 +141,17 @@ const areExternalDependenciesModified = async function (
108141
/**
109142
* Handle the cache
110143
*
111-
* @params {String} directory
112-
* @params {Object} params
144+
* @param {string} directory
145+
* @param {Object} params
146+
* @param {string} params.source - The source code to transform.
147+
* @param {import(".").NormalizedOptions} [params.options] - Options used for transformation.
148+
* @param {string} params.cacheIdentifier - Unique identifier to bust cache.
149+
* @param {string} [params.cacheDirectory] - Directory to store cached files.
150+
* @param {boolean} [params.cacheCompression] - Whether to compress cached files.
151+
* @param {WebpackHash} params.hash - Hash function to use for the cache filename.
152+
* @param {(filename: string) => Promise<FileSystemInfoEntry>} params.getFileTimestamp - Function to get file timestamps.
153+
* @param {WebpackLogger} params.logger
154+
* @returns {Promise<null | import("./transform").TransformResult>}
113155
*/
114156
const handleCache = async function (directory, params) {
115157
const {
@@ -170,6 +212,10 @@ const handleCache = async function (directory, params) {
170212
// return it to the user asap and write it in cache
171213
logger.debug(`applying Babel transform`);
172214
const result = await transform(source, options);
215+
if (!result) {
216+
logger.debug(`no result from Babel transform, skipping cache write`);
217+
return null;
218+
}
173219
await addTimestamps(result.externalDependencies, getFileTimestamp);
174220

175221
try {
@@ -191,12 +237,16 @@ const handleCache = async function (directory, params) {
191237
* Retrieve file from cache, or create a new one for future reads
192238
*
193239
* @async
194-
* @param {Object} params
195-
* @param {String} params.cacheDirectory Directory to store cached files
196-
* @param {String} params.cacheIdentifier Unique identifier to bust cache
197-
* @param {Boolean} params.cacheCompression Whether compressing cached files
198-
* @param {String} params.source Original contents of the file to be cached
199-
* @param {Object} params.options Options to be given to the transform fn
240+
* @param {object} params
241+
* @param {string} params.cacheDirectory Directory to store cached files
242+
* @param {string} params.cacheIdentifier Unique identifier to bust cache
243+
* @param {boolean} params.cacheCompression Whether compressing cached files
244+
* @param {string} params.source Original contents of the file to be cached
245+
* @param {import(".").NormalizedOptions} params.options Options to be given to the transform fn
246+
* @param {function} params.transform Transform function to apply to the file
247+
* @param {WebpackHash} params.hash Hash function to use for the cache filename
248+
* @param {function(string): Promise<FileSystemInfoEntry>} params.getFileTimestamp Function to get file timestamps
249+
* @param {WebpackLogger} params.logger Logger instance
200250
*
201251
* @example
202252
*
@@ -212,7 +262,7 @@ const handleCache = async function (directory, params) {
212262
* });
213263
*/
214264

215-
module.exports = async function (params) {
265+
module.exports = async function cache(params) {
216266
let directory;
217267

218268
if (typeof params.cacheDirectory === "string") {
@@ -225,13 +275,23 @@ module.exports = async function (params) {
225275
return await handleCache(directory, params);
226276
};
227277

278+
/**
279+
* Find the cache directory for babel-loader.
280+
* @param {string} name "babel-loader"
281+
* @returns {string}
282+
*/
228283
function findCacheDir(name) {
229284
if (env.CACHE_DIR && !["true", "false", "1", "0"].includes(env.CACHE_DIR)) {
230285
return path.join(env.CACHE_DIR, name);
231286
}
232-
const rootPkgJSONPath = path.dirname(findRootPackageJSON());
287+
const rootPkgJSONPath = findRootPackageJSON();
233288
if (rootPkgJSONPath) {
234-
return path.join(rootPkgJSONPath, "node_modules", ".cache", name);
289+
return path.join(
290+
path.dirname(rootPkgJSONPath),
291+
"node_modules",
292+
".cache",
293+
name,
294+
);
235295
}
236296
return os.tmpdir();
237297
}

src/index.js

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,37 @@
1+
// @ts-check
2+
/**
3+
* @typedef {object} LoaderOnlyOptions
4+
* @property {string} [cacheDirectory]
5+
* @property {string} [cacheIdentifier]
6+
* @property {boolean} [cacheCompression]
7+
* @property {string} [customize] The absolute path of a file that exports a
8+
* @property {Array<string>} [metadataSubscribers] Names of subscribers registered in the loader context
9+
*/
10+
11+
/**
12+
* @typedef {import("webpack").LoaderContext<LoaderOptions>} BabelLoaderContext
13+
* @typedef {string} BabelLoaderSource Parameters<import("webpack").LoaderDefinitionFunction>[0]
14+
* @typedef {string} BabelLoaderInputSourceMap Parameters<import("webpack").LoaderDefinitionFunction>[1]
15+
*
16+
* @todo Consider exporting these types from @babel/core
17+
* @typedef {Awaited<ReturnType<import("@babel/core").loadPartialConfigAsync>>} PartialConfig
18+
* @typedef {PartialConfig['options']} NormalizedOptions
19+
*/
20+
21+
/**
22+
* @typedef {(babel: typeof import("@babel/core")) => BabelOverrideHooks} BabelLoaderWrapper
23+
* @typedef {object} BabelOverrideHooks
24+
* @property {(this: BabelLoaderContext, loaderOptions: LoaderOptions, params: { source: BabelLoaderSource, map: BabelLoaderInputSourceMap }) => Promise<{ custom: any, loader: LoaderOptions }>} customOptions
25+
* @property {(this: BabelLoaderContext, config: PartialConfig, params: { source: BabelLoaderSource, map: BabelLoaderInputSourceMap, customOptions: any }) => Promise<PartialConfig['options']>} config
26+
* @property {(this: BabelLoaderContext, result: import("./transform").TransformResult, params: { source: BabelLoaderSource, map: BabelLoaderInputSourceMap, customOptions: any, config: PartialConfig, options: PartialConfig['options'] }) => Promise<import("./transform").TransformResult>} result
27+
*/
28+
/**
29+
* @typedef {import("@babel/core").InputOptions & LoaderOnlyOptions} LoaderOptions
30+
*/
31+
32+
/**
33+
* @type {import("@babel/core")}
34+
*/
135
let babel;
236
try {
337
babel = require("@babel/core");
@@ -23,38 +57,66 @@ const { version } = require("../package.json");
2357
const cache = require("./cache");
2458
const transform = require("./transform");
2559
const injectCaller = require("./injectCaller");
26-
const schema = require("./schema");
60+
const schema = require("./schema.json");
2761

2862
const { isAbsolute } = require("path");
2963
const { promisify } = require("util");
3064

65+
/**
66+
* Invoke a metadata subscriber registered in the loader context.
67+
* @param {string} subscriber
68+
* @param {unknown} metadata
69+
* @param {import("webpack").LoaderContext<LoaderOptions>} context
70+
*/
3171
function subscribe(subscriber, metadata, context) {
72+
// @ts-expect-error subscriber is a custom function
3273
if (context[subscriber]) {
74+
// @ts-expect-error subscriber is a custom function
3375
context[subscriber](metadata);
3476
}
3577
}
3678

3779
module.exports = makeLoader();
3880
module.exports.custom = makeLoader;
3981

82+
/**
83+
* @param {BabelLoaderWrapper} [callback]
84+
*/
4085
function makeLoader(callback) {
4186
const overrides = callback ? callback(babel) : undefined;
4287

43-
return function (source, inputSourceMap) {
88+
/**
89+
* @this {BabelLoaderContext}
90+
* @param {BabelLoaderSource} source
91+
* @param {BabelLoaderInputSourceMap} inputSourceMap
92+
*/
93+
const webpackLoader = function (source, inputSourceMap) {
4494
// Make the loader async
4595
const callback = this.async();
4696

4797
loader.call(this, source, inputSourceMap, overrides).then(
98+
// @ts-expect-error (FixMe): Argument of type 'string | EncodedSourceMap' is not assignable to parameter of type 'string | Buffer<ArrayBufferLike>'.
4899
args => callback(null, ...args),
49100
err => callback(err),
50101
);
51102
};
103+
104+
return webpackLoader;
52105
}
53106

107+
/**
108+
* Babel loader
109+
* @this {BabelLoaderContext}
110+
* @param {BabelLoaderSource} source The source code to transform
111+
* @param {BabelLoaderInputSourceMap} inputSourceMap
112+
* @param {BabelOverrideHooks} overrides
113+
* @returns
114+
*/
54115
async function loader(source, inputSourceMap, overrides) {
55116
const filename = this.resourcePath;
56117
const logger = this.getLogger("babel-loader");
57118

119+
// @ts-expect-error TS does not treat schema.json/properties/cacheDirectory/type as a constant string literal
58120
let loaderOptions = this.getOptions(schema);
59121

60122
if (loaderOptions.customize != null) {
@@ -72,6 +134,7 @@ async function loader(source, inputSourceMap, overrides) {
72134
}
73135

74136
logger.debug(`loading customize override: '${loaderOptions.customize}'`);
137+
75138
let override = require(loaderOptions.customize);
76139
if (override.__esModule) override = override.default;
77140

@@ -182,12 +245,21 @@ async function loader(source, inputSourceMap, overrides) {
182245
metadataSubscribers = [],
183246
} = loaderOptions;
184247

248+
/**
249+
* @type {import("./transform").TransformResult}
250+
*/
185251
let result;
186252
if (cacheDirectory) {
187253
logger.debug("cache is enabled");
188-
const getFileTimestamp = promisify((path, cb) => {
189-
this._compilation.fileSystemInfo.getFileTimestamp(path, cb);
190-
});
254+
const getFileTimestamp = promisify(
255+
/**
256+
* @param {string} path
257+
* @param {(err: import("webpack").WebpackError | null, fileTimestamp: import("./cache").FileSystemInfoEntry) => void} cb
258+
*/
259+
(path, cb) => {
260+
this._compilation.fileSystemInfo.getFileTimestamp(path, cb);
261+
},
262+
);
191263
const hash = this.utils.createHash(
192264
this._compilation.outputOptions.hashFunction,
193265
);

src/injectCaller.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
// @ts-check
2+
/**
3+
* Inject babel-loader caller information into the Babel options.
4+
* @param {import("@babel/core").InputOptions} opts
5+
* @param {string} target
6+
* @returns {import("@babel/core").InputOptions}
7+
*/
18
module.exports = function injectCaller(opts, target) {
2-
return Object.assign({}, opts, {
9+
return {
10+
...opts,
311
caller: Object.assign(
412
{
513
name: "babel-loader",
@@ -19,5 +27,5 @@ module.exports = function injectCaller(opts, target) {
1927
},
2028
opts.caller,
2129
),
22-
});
30+
};
2331
};

0 commit comments

Comments
 (0)