feat: refactoring project

This commit is contained in:
Carlos
2024-11-23 14:56:07 -05:00
parent f0c2a50c18
commit 1c6db5818d
2351 changed files with 39323 additions and 60326 deletions

View File

@@ -11,11 +11,11 @@ const NormalModule = require("../NormalModule");
// data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
// http://www.ietf.org/rfc/rfc2397.txt
const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64))?,(.*)$/i;
const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64)?)?,(.*)$/i;
/**
* @param {string} uri data URI
* @returns {Buffer|null} decoded data
* @returns {Buffer | null} decoded data
*/
const decodeDataURI = uri => {
const match = URIRegEx.exec(uri);

View File

@@ -15,17 +15,37 @@ const createHash = require("../util/createHash");
const { mkdirp, dirname, join } = require("../util/fs");
const memoize = require("../util/memoize");
/** @typedef {import("http").IncomingMessage} IncomingMessage */
/** @typedef {import("http").RequestOptions} RequestOptions */
/** @typedef {import("net").Socket} Socket */
/** @typedef {import("stream").Readable} Readable */
/** @typedef {import("../../declarations/plugins/schemes/HttpUriPlugin").HttpUriPluginOptions} HttpUriPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../FileSystemInfo").Snapshot} Snapshot */
/** @typedef {import("../Module").BuildInfo} BuildInfo */
/** @typedef {import("../NormalModuleFactory").ResourceDataWithData} ResourceDataWithData */
/** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */
const getHttp = memoize(() => require("http"));
const getHttps = memoize(() => require("https"));
/**
* @param {typeof import("http") | typeof import("https")} request request
* @param {string | { toString: () => string } | undefined} proxy proxy
* @returns {function(URL, RequestOptions, function(IncomingMessage): void): EventEmitter} fn
*/
const proxyFetch = (request, proxy) => (url, options, callback) => {
const eventEmitter = new EventEmitter();
const doRequest = socket =>
/**
* @param {Socket=} socket socket
* @returns {void}
*/
const doRequest = socket => {
request
.get(url, { ...options, ...(socket && { socket }) }, callback)
.on("error", eventEmitter.emit.bind(eventEmitter, "error"));
};
if (proxy) {
const { hostname: host, port } = new URL(proxy);
@@ -59,8 +79,9 @@ const proxyFetch = (request, proxy) => (url, options, callback) => {
return eventEmitter;
};
/** @type {(() => void)[] | undefined} */
let inProgressWrite = undefined;
/** @typedef {() => void} InProgressWriteItem */
/** @type {InProgressWriteItem[] | undefined} */
let inProgressWrite;
const validate = createSchemaValidation(
require("../../schemas/plugins/schemes/HttpUriPlugin.check.js"),
@@ -87,7 +108,7 @@ const toSafePath = str =>
const computeIntegrity = content => {
const hash = createHash("sha512");
hash.update(content);
const integrity = "sha512-" + hash.digest("base64");
const integrity = `sha512-${hash.digest("base64")}`;
return integrity;
};
@@ -138,8 +159,8 @@ const parseCacheControl = (cacheControl, requestTime) => {
if (cacheControl) {
const parsed = parseKeyValuePairs(cacheControl);
if (parsed["no-cache"]) storeCache = storeLock = false;
if (parsed["max-age"] && !isNaN(+parsed["max-age"])) {
validUntil = requestTime + +parsed["max-age"] * 1000;
if (parsed["max-age"] && !Number.isNaN(Number(parsed["max-age"]))) {
validUntil = requestTime + Number(parsed["max-age"]) * 1000;
}
if (parsed["must-revalidate"]) validUntil = 0;
}
@@ -157,21 +178,22 @@ const parseCacheControl = (cacheControl, requestTime) => {
* @property {string} contentType
*/
const areLockfileEntriesEqual = (a, b) => {
return (
a.resolved === b.resolved &&
a.integrity === b.integrity &&
a.contentType === b.contentType
);
};
/**
* @param {LockfileEntry} a first lockfile entry
* @param {LockfileEntry} b second lockfile entry
* @returns {boolean} true when equal, otherwise false
*/
const areLockfileEntriesEqual = (a, b) =>
a.resolved === b.resolved &&
a.integrity === b.integrity &&
a.contentType === b.contentType;
/**
* @param {LockfileEntry} entry lockfile entry
* @returns {`resolved: ${string}, integrity: ${string}, contentType: ${*}`} stringified entry
*/
const entryToString = entry => {
return `resolved: ${entry.resolved}, integrity: ${entry.integrity}, contentType: ${entry.contentType}`;
};
const entryToString = entry =>
`resolved: ${entry.resolved}, integrity: ${entry.integrity}, contentType: ${entry.contentType}`;
class Lockfile {
constructor() {
@@ -233,17 +255,17 @@ class Lockfile {
/**
* @template R
* @param {function(function(Error=, R=): void): void} fn function
* @returns {function(function((Error | null)=, R=): void): void} cached function
* @param {function(function(Error | null, R=): void): void} fn function
* @returns {function(function(Error | null, R=): void): void} cached function
*/
const cachedWithoutKey = fn => {
let inFlight = false;
/** @type {Error | undefined} */
let cachedError = undefined;
let cachedError;
/** @type {R | undefined} */
let cachedResult = undefined;
/** @type {(function(Error=, R=): void)[] | undefined} */
let cachedCallbacks = undefined;
let cachedResult;
/** @type {(function(Error| null, R=): void)[] | undefined} */
let cachedCallbacks;
return callback => {
if (inFlight) {
if (cachedResult !== undefined) return callback(null, cachedResult);
@@ -267,14 +289,22 @@ const cachedWithoutKey = fn => {
/**
* @template T
* @template R
* @param {function(T, function(Error=, R=): void): void} fn function
* @param {function(T, function(Error=, R=): void): void=} forceFn function for the second try
* @returns {(function(T, function((Error | null)=, R=): void): void) & { force: function(T, function((Error | null)=, R=): void): void }} cached function
* @param {function(T, function(Error | null, R=): void): void} fn function
* @param {function(T, function(Error | null, R=): void): void=} forceFn function for the second try
* @returns {(function(T, function(Error | null, R=): void): void) & { force: function(T, function(Error | null, R=): void): void }} cached function
*/
const cachedWithKey = (fn, forceFn = fn) => {
/** @typedef {{ result?: R, error?: Error, callbacks?: (function((Error | null)=, R=): void)[], force?: true }} CacheEntry */
/** @type {Map<T, CacheEntry>} */
/**
* @template R
* @typedef {{ result?: R, error?: Error, callbacks?: (function(Error | null, R=): void)[], force?: true }} CacheEntry
*/
/** @type {Map<T, CacheEntry<R>>} */
const cache = new Map();
/**
* @param {T} arg arg
* @param {function(Error | null, R=): void} callback callback
* @returns {void}
*/
const resultFn = (arg, callback) => {
const cacheEntry = cache.get(arg);
if (cacheEntry !== undefined) {
@@ -285,7 +315,7 @@ const cachedWithKey = (fn, forceFn = fn) => {
else cacheEntry.callbacks.push(callback);
return;
}
/** @type {CacheEntry} */
/** @type {CacheEntry<R>} */
const newCacheEntry = {
result: undefined,
error: undefined,
@@ -301,6 +331,11 @@ const cachedWithKey = (fn, forceFn = fn) => {
if (callbacks !== undefined) for (const cb of callbacks) cb(err, result);
});
};
/**
* @param {T} arg arg
* @param {function(Error | null, R=): void} callback callback
* @returns {void}
*/
resultFn.force = (arg, callback) => {
const cacheEntry = cache.get(arg);
if (cacheEntry !== undefined && cacheEntry.force) {
@@ -311,7 +346,7 @@ const cachedWithKey = (fn, forceFn = fn) => {
else cacheEntry.callbacks.push(callback);
return;
}
/** @type {CacheEntry} */
/** @type {CacheEntry<R>} */
const newCacheEntry = {
result: undefined,
error: undefined,
@@ -331,6 +366,24 @@ const cachedWithKey = (fn, forceFn = fn) => {
return resultFn;
};
/**
* @typedef {object} LockfileCache
* @property {Lockfile} lockfile lockfile
* @property {Snapshot} snapshot snapshot
*/
/**
* @typedef {object} ResolveContentResult
* @property {LockfileEntry} entry lockfile entry
* @property {Buffer} content content
* @property {boolean} storeLock need store lockfile
*/
/** @typedef {{ storeCache: boolean, storeLock: boolean, validUntil: number, etag: string | undefined, fresh: boolean }} FetchResultMeta */
/** @typedef {FetchResultMeta & { location: string }} RedirectFetchResult */
/** @typedef {FetchResultMeta & { entry: LockfileEntry, content: Buffer }} ContentFetchResult */
/** @typedef {RedirectFetchResult | ContentFetchResult} FetchResult */
class HttpUriPlugin {
/**
* @param {HttpUriPluginOptions} options options
@@ -352,7 +405,7 @@ class HttpUriPlugin {
*/
apply(compiler) {
const proxy =
this._proxy || process.env["http_proxy"] || process.env["HTTP_PROXY"];
this._proxy || process.env.http_proxy || process.env.HTTP_PROXY;
const schemes = [
{
scheme: "http",
@@ -363,11 +416,14 @@ class HttpUriPlugin {
fetch: proxyFetch(getHttps(), proxy)
}
];
/** @type {LockfileCache} */
let lockfileCache;
compiler.hooks.compilation.tap(
"HttpUriPlugin",
(compilation, { normalModuleFactory }) => {
const intermediateFs = compiler.intermediateFileSystem;
const intermediateFs =
/** @type {IntermediateFileSystem} */
(compiler.intermediateFileSystem);
const fs = compilation.inputFileSystem;
const cache = compilation.getCache("webpack.HttpUriPlugin");
const logger = compilation.getLogger("webpack.HttpUriPlugin");
@@ -385,7 +441,7 @@ class HttpUriPlugin {
const cacheLocation =
this._cacheLocation !== undefined
? this._cacheLocation
: lockfileLocation + ".data";
: `${lockfileLocation}.data`;
const upgrade = this._upgrade || false;
const frozen = this._frozen || false;
const hashFunction = "sha512";
@@ -431,7 +487,7 @@ class HttpUriPlugin {
const getLockfile = cachedWithoutKey(
/**
* @param {function((Error | null)=, Lockfile=): void} callback callback
* @param {function(Error | null, Lockfile=): void} callback callback
* @returns {void}
*/
callback => {
@@ -448,14 +504,14 @@ class HttpUriPlugin {
[],
buffer ? [] : [lockfileLocation],
{ timestamp: true },
(err, snapshot) => {
(err, s) => {
if (err) return callback(err);
const lockfile = buffer
? Lockfile.parse(buffer.toString("utf-8"))
: new Lockfile();
lockfileCache = {
lockfile,
snapshot
snapshot: /** @type {Snapshot} */ (s)
};
callback(null, lockfile);
}
@@ -477,8 +533,10 @@ class HttpUriPlugin {
}
);
/** @type {Map<string, LockfileEntry | "ignore" | "no-cache"> | undefined} */
let lockfileUpdates = undefined;
/** @typedef {Map<string, LockfileEntry | "ignore" | "no-cache">} LockfileUpdates */
/** @type {LockfileUpdates | undefined} */
let lockfileUpdates;
/**
* @param {Lockfile} lockfile lockfile instance
@@ -519,6 +577,13 @@ class HttpUriPlugin {
}
};
/**
* @param {Lockfile} lockfile lockfile
* @param {string} url url
* @param {ResolveContentResult} result result
* @param {function(Error | null, ResolveContentResult=): void} callback callback
* @returns {void}
*/
const storeResult = (lockfile, url, result, callback) => {
if (result.storeLock) {
storeLockEntry(lockfile, url, result.entry);
@@ -541,12 +606,16 @@ class HttpUriPlugin {
for (const { scheme, fetch } of schemes) {
/**
*
* @param {string} url URL
* @param {string} integrity integrity
* @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer, storeLock: boolean }=): void} callback callback
* @param {string | null} integrity integrity
* @param {function(Error | null, ResolveContentResult=): void} callback callback
*/
const resolveContent = (url, integrity, callback) => {
/**
* @param {Error | null} err error
* @param {TODO} result result result
* @returns {void}
*/
const handleResult = (err, result) => {
if (err) return callback(err);
if ("location" in result) {
@@ -555,41 +624,37 @@ class HttpUriPlugin {
integrity,
(err, innerResult) => {
if (err) return callback(err);
const { entry, content, storeLock } =
/** @type {ResolveContentResult} */ (innerResult);
callback(null, {
entry: innerResult.entry,
content: innerResult.content,
storeLock: innerResult.storeLock && result.storeLock
entry,
content,
storeLock: storeLock && result.storeLock
});
}
);
} else {
if (
!result.fresh &&
integrity &&
result.entry.integrity !== integrity &&
!verifyIntegrity(result.content, integrity)
) {
return fetchContent.force(url, handleResult);
}
return callback(null, {
entry: result.entry,
content: result.content,
storeLock: result.storeLock
});
}
if (
!result.fresh &&
integrity &&
result.entry.integrity !== integrity &&
!verifyIntegrity(result.content, integrity)
) {
return fetchContent.force(url, handleResult);
}
return callback(null, {
entry: result.entry,
content: result.content,
storeLock: result.storeLock
});
};
fetchContent(url, handleResult);
};
/** @typedef {{ storeCache: boolean, storeLock: boolean, validUntil: number, etag: string | undefined, fresh: boolean }} FetchResultMeta */
/** @typedef {FetchResultMeta & { location: string }} RedirectFetchResult */
/** @typedef {FetchResultMeta & { entry: LockfileEntry, content: Buffer }} ContentFetchResult */
/** @typedef {RedirectFetchResult | ContentFetchResult} FetchResult */
/**
* @param {string} url URL
* @param {FetchResult | RedirectFetchResult} cachedResult result from cache
* @param {function((Error | null)=, FetchResult=): void} callback callback
* @param {FetchResult | RedirectFetchResult | undefined} cachedResult result from cache
* @param {function(Error | null, FetchResult=): void} callback callback
* @returns {void}
*/
const fetchContentRaw = (url, cachedResult, callback) => {
@@ -600,14 +665,14 @@ class HttpUriPlugin {
headers: {
"accept-encoding": "gzip, deflate, br",
"user-agent": "webpack",
"if-none-match": cachedResult
? cachedResult.etag || null
: null
"if-none-match": /** @type {TODO} */ (
cachedResult ? cachedResult.etag || null : null
)
}
},
res => {
const etag = res.headers["etag"];
const location = res.headers["location"];
const etag = res.headers.etag;
const location = res.headers.location;
const cacheControl = res.headers["cache-control"];
const { storeLock, storeCache, validUntil } = parseCacheControl(
cacheControl,
@@ -662,23 +727,21 @@ class HttpUriPlugin {
);
};
if (res.statusCode === 304) {
const result = /** @type {FetchResult} */ (cachedResult);
if (
cachedResult.validUntil < validUntil ||
cachedResult.storeLock !== storeLock ||
cachedResult.storeCache !== storeCache ||
cachedResult.etag !== etag
result.validUntil < validUntil ||
result.storeLock !== storeLock ||
result.storeCache !== storeCache ||
result.etag !== etag
) {
return finishWith(cachedResult);
} else {
logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
return callback(null, {
...cachedResult,
fresh: true
});
return finishWith(result);
}
logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
return callback(null, { ...result, fresh: true });
}
if (
location &&
res.statusCode &&
res.statusCode >= 301 &&
res.statusCode <= 308
) {
@@ -695,22 +758,23 @@ class HttpUriPlugin {
cachedResult.etag !== etag
) {
return finishWith(result);
} else {
logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
return callback(null, {
...result,
fresh: true,
storeLock,
storeCache,
validUntil,
etag
});
}
logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
return callback(null, {
...result,
fresh: true,
storeLock,
storeCache,
validUntil,
etag
});
}
const contentType = res.headers["content-type"] || "";
/** @type {Buffer[]} */
const bufferArr = [];
const contentEncoding = res.headers["content-encoding"];
/** @type {Readable} */
let stream = res;
if (contentEncoding === "gzip") {
stream = stream.pipe(createGunzip());
@@ -762,9 +826,10 @@ class HttpUriPlugin {
const fetchContent = cachedWithKey(
/**
* @param {string} url URL
* @param {function((Error | null)=, { validUntil: number, etag?: string, entry: LockfileEntry, content: Buffer, fresh: boolean } | { validUntil: number, etag?: string, location: string, fresh: boolean }=): void} callback callback
* @param {function(Error | null, { validUntil: number, etag?: string, entry: LockfileEntry, content: Buffer, fresh: boolean } | { validUntil: number, etag?: string, location: string, fresh: boolean }=): void} callback callback
* @returns {void}
*/ (url, callback) => {
*/
(url, callback) => {
cache.get(url, null, (err, cachedResult) => {
if (err) return callback(err);
if (cachedResult) {
@@ -777,25 +842,32 @@ class HttpUriPlugin {
(url, callback) => fetchContentRaw(url, undefined, callback)
);
/**
* @param {string} uri uri
* @returns {boolean} true when allowed, otherwise false
*/
const isAllowed = uri => {
for (const allowed of allowedUris) {
if (typeof allowed === "string") {
if (uri.startsWith(allowed)) return true;
} else if (typeof allowed === "function") {
if (allowed(uri)) return true;
} else {
if (allowed.test(uri)) return true;
} else if (allowed.test(uri)) {
return true;
}
}
return false;
};
/** @typedef {{ entry: LockfileEntry, content: Buffer }} Info */
const getInfo = cachedWithKey(
/**
* @param {string} url the url
* @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer }=): void} callback callback
* @param {function(Error | null, Info=): void} callback callback
* @returns {void}
*/
// eslint-disable-next-line no-loop-func
(url, callback) => {
if (!isAllowed(url)) {
return callback(
@@ -806,8 +878,9 @@ class HttpUriPlugin {
)
);
}
getLockfile((err, lockfile) => {
getLockfile((err, _lockfile) => {
if (err) return callback(err);
const lockfile = /** @type {Lockfile} */ (_lockfile);
const entryOrString = lockfile.entries.get(url);
if (!entryOrString) {
if (frozen) {
@@ -819,14 +892,24 @@ class HttpUriPlugin {
}
resolveContent(url, null, (err, result) => {
if (err) return callback(err);
storeResult(lockfile, url, result, callback);
storeResult(
/** @type {Lockfile} */
(lockfile),
url,
/** @type {ResolveContentResult} */
(result),
callback
);
});
return;
}
if (typeof entryOrString === "string") {
const entryTag = entryOrString;
resolveContent(url, null, (err, result) => {
resolveContent(url, null, (err, _result) => {
if (err) return callback(err);
const result =
/** @type {ResolveContentResult} */
(_result);
if (!result.storeLock || entryTag === "ignore")
return callback(null, result);
if (frozen) {
@@ -850,8 +933,11 @@ Remove this line from the lockfile to force upgrading.`
return;
}
let entry = entryOrString;
/**
* @param {Buffer=} lockedContent locked content
*/
const doFetch = lockedContent => {
resolveContent(url, entry.integrity, (err, result) => {
resolveContent(url, entry.integrity, (err, _result) => {
if (err) {
if (lockedContent) {
logger.warn(
@@ -865,6 +951,9 @@ Remove this line from the lockfile to force upgrading.`
}
return callback(err);
}
const result =
/** @type {ResolveContentResult} */
(_result);
if (!result.storeLock) {
// When the lockfile entry should be no-cache
// we need to update the lockfile
@@ -919,12 +1008,16 @@ Remove this line from the lockfile to force upgrading.`
const key = getCacheKey(entry.resolved);
const filePath = join(intermediateFs, cacheLocation, key);
fs.readFile(filePath, (err, result) => {
const content = /** @type {Buffer} */ (result);
if (err) {
if (err.code === "ENOENT") return doFetch();
return callback(err);
}
const continueWithCachedContent = result => {
const content = /** @type {Buffer} */ (result);
/**
* @param {Buffer | undefined} _result result
* @returns {void}
*/
const continueWithCachedContent = _result => {
if (!upgrade) {
// When not in upgrade mode, we accept the result from the lockfile cache
return callback(null, { entry, content });
@@ -932,6 +1025,7 @@ Remove this line from the lockfile to force upgrading.`
return doFetch(content);
};
if (!verifyIntegrity(content, entry.integrity)) {
/** @type {Buffer | undefined} */
let contentWithChangedEol;
let isEolChanged = false;
try {
@@ -942,7 +1036,7 @@ Remove this line from the lockfile to force upgrading.`
contentWithChangedEol,
entry.integrity
);
} catch (e) {
} catch (_err) {
// ignore
}
if (isEolChanged) {
@@ -969,10 +1063,14 @@ This will avoid that the end of line sequence is changed by git on Windows.`;
);
intermediateFs.writeFile(
filePath,
contentWithChangedEol,
/** @type {Buffer} */
(contentWithChangedEol),
err => {
if (err) return callback(err);
continueWithCachedContent(contentWithChangedEol);
continueWithCachedContent(
/** @type {Buffer} */
(contentWithChangedEol)
);
}
);
return;
@@ -994,15 +1092,14 @@ Lockfile corrupted (${
Run build with un-frozen lockfile to automatically fix lockfile.`
)
);
} else {
// "fix" the lockfile entry to the correct integrity
// the content has priority over the integrity value
entry = {
...entry,
integrity: computeIntegrity(content)
};
storeLockEntry(lockfile, url, entry);
}
// "fix" the lockfile entry to the correct integrity
// the content has priority over the integrity value
entry = {
...entry,
integrity: computeIntegrity(content)
};
storeLockEntry(lockfile, url, entry);
}
continueWithCachedContent(result);
});
@@ -1013,9 +1110,15 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
}
);
/**
* @param {URL} url url
* @param {ResourceDataWithData} resourceData resource data
* @param {function(Error | null, true | void): void} callback callback
*/
const respondWithUrlModule = (url, resourceData, callback) => {
getInfo(url.href, (err, result) => {
getInfo(url.href, (err, _result) => {
if (err) return callback(err);
const result = /** @type {Info} */ (_result);
resourceData.resource = url.href;
resourceData.path = url.origin + url.pathname;
resourceData.query = url.search;
@@ -1051,7 +1154,7 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
return callback();
}
respondWithUrlModule(
new URL(resourceData.resource, data.context + "/"),
new URL(resourceData.resource, `${data.context}/`),
resourceData,
callback
);
@@ -1059,13 +1162,15 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
const hooks = NormalModule.getCompilationHooks(compilation);
hooks.readResourceForScheme
.for(scheme)
.tapAsync("HttpUriPlugin", (resource, module, callback) => {
return getInfo(resource, (err, result) => {
.tapAsync("HttpUriPlugin", (resource, module, callback) =>
getInfo(resource, (err, _result) => {
if (err) return callback(err);
module.buildInfo.resourceIntegrity = result.entry.integrity;
const result = /** @type {Info} */ (_result);
/** @type {BuildInfo} */
(module.buildInfo).resourceIntegrity = result.entry.integrity;
callback(null, result.content);
});
});
})
);
hooks.needBuild.tapAsync(
"HttpUriPlugin",
(module, context, callback) => {
@@ -1073,11 +1178,13 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
module.resource &&
module.resource.startsWith(`${scheme}://`)
) {
getInfo(module.resource, (err, result) => {
getInfo(module.resource, (err, _result) => {
if (err) return callback(err);
const result = /** @type {Info} */ (_result);
if (
result.entry.integrity !==
module.buildInfo.resourceIntegrity
/** @type {BuildInfo} */
(module.buildInfo).resourceIntegrity
) {
return callback(null, true);
}
@@ -1103,7 +1210,9 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
);
const writeDone = () => {
const nextOperation = inProgressWrite.shift();
const nextOperation =
/** @type {InProgressWriteItem[]} */
(inProgressWrite).shift();
if (nextOperation) {
nextOperation();
} else {
@@ -1119,19 +1228,25 @@ Run build with un-frozen lockfile to automatically fix lockfile.`
const lockfile = buffer
? Lockfile.parse(buffer.toString("utf-8"))
: new Lockfile();
for (const [key, value] of lockfileUpdates) {
for (const [key, value] of /** @type {LockfileUpdates} */ (
lockfileUpdates
)) {
lockfile.entries.set(key, value);
}
intermediateFs.writeFile(tempFile, lockfile.toString(), err => {
if (err) {
writeDone();
return intermediateFs.unlink(tempFile, () => callback(err));
return (
/** @type {NonNullable<IntermediateFileSystem["unlink"]>} */
(intermediateFs.unlink)(tempFile, () => callback(err))
);
}
intermediateFs.rename(tempFile, lockfileLocation, err => {
if (err) {
writeDone();
return intermediateFs.unlink(tempFile, () =>
callback(err)
return (
/** @type {NonNullable<IntermediateFileSystem["unlink"]>} */
(intermediateFs.unlink)(tempFile, () => callback(err))
);
}
writeDone();