mirror of https://github.com/webpack/webpack.git
Merge pull request #7755 from webpack/tooling/inherit-types
Tooling: inherit types from base class
This commit is contained in:
commit
945a9514ca
|
|
@ -9,6 +9,7 @@
|
|||
!buildin/*.js
|
||||
!benchmark/**/*.js
|
||||
!test/*.js
|
||||
!tooling/*.js
|
||||
!test/**/webpack.config.js
|
||||
!examples/**/webpack.config.js
|
||||
!schemas/**/*.js
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const DelegatedSourceDependency = require("./dependencies/DelegatedSourceDepende
|
|||
const DelegatedExportsDependency = require("./dependencies/DelegatedExportsDependency");
|
||||
|
||||
/** @typedef {import("./dependencies/ModuleDependency")} ModuleDependency */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class DelegatedModule extends Module {
|
||||
constructor(sourceRequest, data, type, userRequest, originalRequest) {
|
||||
|
|
@ -99,6 +100,10 @@ class DelegatedModule extends Module {
|
|||
return 42;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update(this.type);
|
||||
hash.update(JSON.stringify(this.request));
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ class DependenciesBlock {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies, from "crypto" module
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
const { RawSource } = require("webpack-sources");
|
||||
const Module = require("./Module");
|
||||
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class DllModule extends Module {
|
||||
constructor(context, dependencies, name, type) {
|
||||
super("javascript/dynamic", context);
|
||||
|
|
@ -44,6 +46,10 @@ class DllModule extends Module {
|
|||
return 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update("dll module");
|
||||
hash.update(this.name || "");
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ const Module = require("./Module");
|
|||
const WebpackMissingModule = require("./dependencies/WebpackMissingModule");
|
||||
const Template = require("./Template");
|
||||
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class ExternalModule extends Module {
|
||||
constructor(request, type, userRequest) {
|
||||
super("javascript/dynamic", null);
|
||||
|
|
@ -148,6 +150,10 @@ class ExternalModule extends Module {
|
|||
return 42;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update(this.externalType);
|
||||
hash.update(JSON.stringify(this.request));
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@
|
|||
*/
|
||||
"use strict";
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
/** @typedef {import("./NormalModule")} NormalModule */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("./Dependency").DependencyTemplate} DependencyTemplate */
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -18,8 +19,8 @@ class Generator {
|
|||
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Module} module module for which the code should be generated
|
||||
* @param {Map<Function, TODO>} dependencyTemplates mapping from dependencies to templates
|
||||
* @param {NormalModule} module module for which the code should be generated
|
||||
* @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates
|
||||
* @param {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @param {string} type which kind of code should be generated
|
||||
* @returns {Source} generated code
|
||||
|
|
@ -35,6 +36,13 @@ class ByTypeGenerator extends Generator {
|
|||
this.map = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NormalModule} module module for which the code should be generated
|
||||
* @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates
|
||||
* @param {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @param {string} type which kind of code should be generated
|
||||
* @returns {Source} generated code
|
||||
*/
|
||||
generate(module, dependencyTemplates, runtimeTemplate, type) {
|
||||
const generator = this.map[type];
|
||||
if (!generator) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const Template = require("./Template");
|
|||
/** @typedef {import("./Chunk")} Chunk */
|
||||
/** @typedef {import("./RequestShortener")} RequestShortener */
|
||||
/** @typedef {import("./WebpackError")} WebpackError */
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
const EMPTY_RESOLVE_OPTIONS = {};
|
||||
|
||||
|
|
@ -298,6 +299,10 @@ class Module extends DependenciesBlock {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update(`${this.id}`);
|
||||
hash.update(JSON.stringify(this.usedExports));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ const Module = require("./Module");
|
|||
const Template = require("./Template");
|
||||
const { RawSource } = require("webpack-sources");
|
||||
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
class MultiModule extends Module {
|
||||
constructor(context, dependencies, name) {
|
||||
super("javascript/dynamic", context);
|
||||
|
|
@ -45,6 +47,10 @@ class MultiModule extends Module {
|
|||
return 16 + this.dependencies.length * 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update("multi module");
|
||||
hash.update(this.name || "");
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ const ModuleWarning = require("./ModuleWarning");
|
|||
const createHash = require("./util/createHash");
|
||||
const contextify = require("./util/identifier").contextify;
|
||||
|
||||
/** @typedef {import("./util/createHash").Hash} Hash */
|
||||
|
||||
const asString = buf => {
|
||||
if (Buffer.isBuffer(buf)) {
|
||||
return buf.toString("utf-8");
|
||||
|
|
@ -527,6 +529,10 @@ class NormalModule extends Module {
|
|||
return this._source ? this._source.size() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
hash.update(this._buildHash);
|
||||
super.updateHash(hash);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
const Template = require("./Template");
|
||||
|
||||
/** @typedef {import("./Module")} Module */
|
||||
|
||||
module.exports = class RuntimeTemplate {
|
||||
constructor(outputOptions, requestShortener) {
|
||||
this.outputOptions = outputOptions || {};
|
||||
|
|
@ -188,6 +190,16 @@ module.exports = class RuntimeTemplate {
|
|||
return `${promise || "Promise.resolve()"}.then(${getModuleFunction})`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Object} options options object
|
||||
* @param {boolean=} options.update whether a new variable should be created or the existing one updated
|
||||
* @param {Module} options.module the module
|
||||
* @param {string} options.request the request that should be printed as comment
|
||||
* @param {string} options.importVar name of the import variable
|
||||
* @param {Module} options.originModule module in which the statement is emitted
|
||||
* @returns {string} the import statement
|
||||
*/
|
||||
importStatement({ update, module, request, importVar, originModule }) {
|
||||
if (!module) {
|
||||
return this.missingModuleStatement({
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ const createHash = require("../util/createHash");
|
|||
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../Compilation")} Compilation */
|
||||
/** @typedef {import("../util/createHash").Hash} Hash */
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConcatenationEntry
|
||||
|
|
@ -1180,6 +1181,10 @@ class ConcatenatedModule extends Module {
|
|||
return nameWithNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Hash} hash the hash used to track dependencies
|
||||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash) {
|
||||
for (const info of this._orderedConcatenationList) {
|
||||
switch (info.type) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ const WebAssemblyExportImportedDependency = require("../dependencies/WebAssembly
|
|||
|
||||
/** @typedef {import("../Module")} Module */
|
||||
/** @typedef {import("./WebAssemblyUtils").UsedWasmDependency} UsedWasmDependency */
|
||||
/** @typedef {import("../NormalModule")} NormalModule */
|
||||
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../Dependency").DependencyTemplate} DependencyTemplate */
|
||||
|
||||
/**
|
||||
* @typedef {(ArrayBuffer) => ArrayBuffer} ArrayBufferTransform
|
||||
|
|
@ -366,7 +370,14 @@ class WebAssemblyGenerator extends Generator {
|
|||
this.options = options;
|
||||
}
|
||||
|
||||
generate(module) {
|
||||
/**
|
||||
* @param {NormalModule} module module for which the code should be generated
|
||||
* @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates
|
||||
* @param {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @param {string} type which kind of code should be generated
|
||||
* @returns {Source} generated code
|
||||
*/
|
||||
generate(module, dependencyTemplates, runtimeTemplate, type) {
|
||||
let bin = module.originalSource().source();
|
||||
bin = preprocess(bin);
|
||||
|
||||
|
|
@ -398,7 +409,10 @@ class WebAssemblyGenerator extends Generator {
|
|||
const externalExports = new Set(
|
||||
module.dependencies
|
||||
.filter(d => d instanceof WebAssemblyExportImportedDependency)
|
||||
.map(d => d.exportName)
|
||||
.map(d => {
|
||||
const wasmDep = /** @type {WebAssemblyExportImportedDependency} */ (d);
|
||||
return wasmDep.exportName;
|
||||
})
|
||||
);
|
||||
|
||||
/** @type {t.Instruction[]} */
|
||||
|
|
|
|||
|
|
@ -10,8 +10,20 @@ const { RawSource } = require("webpack-sources");
|
|||
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
|
||||
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
|
||||
|
||||
/** @typedef {import("../NormalModule")} NormalModule */
|
||||
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("webpack-sources").Source} Source */
|
||||
/** @typedef {import("../Dependency").DependencyTemplate} DependencyTemplate */
|
||||
|
||||
class WebAssemblyJavascriptGenerator extends Generator {
|
||||
generate(module, dependencyTemplates, runtimeTemplate) {
|
||||
/**
|
||||
* @param {NormalModule} module module for which the code should be generated
|
||||
* @param {Map<Function, DependencyTemplate>} dependencyTemplates mapping from dependencies to templates
|
||||
* @param {RuntimeTemplate} runtimeTemplate the runtime template
|
||||
* @param {string} type which kind of code should be generated
|
||||
* @returns {Source} generated code
|
||||
*/
|
||||
generate(module, dependencyTemplates, runtimeTemplate, type) {
|
||||
const initIdentifer = Array.isArray(module.usedExports)
|
||||
? Template.numberToIdentifer(module.usedExports.length)
|
||||
: "__webpack_init__";
|
||||
|
|
@ -21,6 +33,7 @@ class WebAssemblyJavascriptGenerator extends Generator {
|
|||
const initParams = [];
|
||||
let index = 0;
|
||||
for (const dep of module.dependencies) {
|
||||
const depAsAny = /** @type {any} */ (dep);
|
||||
if (dep.module) {
|
||||
let importData = importedModules.get(dep.module);
|
||||
if (importData === undefined) {
|
||||
|
|
@ -29,7 +42,8 @@ class WebAssemblyJavascriptGenerator extends Generator {
|
|||
(importData = {
|
||||
importVar: `m${index}`,
|
||||
index,
|
||||
request: dep.userRequest,
|
||||
request:
|
||||
"userRequest" in depAsAny ? depAsAny.userRequest : undefined,
|
||||
names: new Set(),
|
||||
reexports: []
|
||||
})
|
||||
|
|
|
|||
|
|
@ -128,10 +128,10 @@
|
|||
"pretest": "yarn lint",
|
||||
"prelint": "yarn setup",
|
||||
"lint": "yarn code-lint && yarn schema-lint && yarn type-lint",
|
||||
"code-lint": "eslint --cache setup lib bin hot buildin benchmark \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\"",
|
||||
"code-lint": "eslint --cache setup lib bin hot buildin benchmark tooling \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\"",
|
||||
"type-lint": "tsc --pretty",
|
||||
"fix": "yarn code-lint --fix",
|
||||
"pretty": "prettier --write \"setup/**/*.js\" \"lib/**/*.js\" \"bin/*.js\" \"hot/*.js\" \"buildin/*.js\" \"benchmark/**/*.js\" \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\" \"declarations.d.ts\" \"tsconfig.json\"",
|
||||
"pretty": "prettier --write \"setup/**/*.js\" \"lib/**/*.js\" \"bin/*.js\" \"hot/*.js\" \"buildin/*.js\" \"benchmark/**/*.js\" \"tooling/*.js\" \"test/*.js\" \"test/**/webpack.config.js\" \"examples/**/webpack.config.js\" \"schemas/**/*.js\" \"declarations.d.ts\" \"tsconfig.json\"",
|
||||
"schema-lint": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.lint.js\" --no-verbose",
|
||||
"benchmark": "node --max-old-space-size=4096 --trace-deprecation node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.benchmark.js\" --runInBand",
|
||||
"cover": "yarn cover:init && yarn cover:all && yarn cover:report",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const ts = require("typescript");
|
||||
const program = require("./typescript-program");
|
||||
|
||||
// When --override is set, base jsdoc will override sub class jsdoc
|
||||
// Elsewise on a conflict it will create a merge conflict in the file
|
||||
const override = process.argv.includes("--override");
|
||||
|
||||
// When --write is set, files will be written in place
|
||||
// Elsewise it only prints outdated files
|
||||
const doWrite = process.argv.includes("--write");
|
||||
|
||||
const typeChecker = program.getTypeChecker();
|
||||
|
||||
/**
|
||||
* @param {ts.ClassDeclaration} node the class declaration
|
||||
* @returns {Set<ts.ClassDeclaration>} the base class declarations
|
||||
*/
|
||||
const getBaseClasses = node => {
|
||||
/** @type {Set<ts.ClassDeclaration>} */
|
||||
const decls = new Set();
|
||||
if (node.heritageClauses) {
|
||||
for (const clause of node.heritageClauses) {
|
||||
for (const clauseType of clause.types) {
|
||||
const type = typeChecker.getTypeAtLocation(clauseType);
|
||||
if (ts.isClassDeclaration(type.symbol.valueDeclaration))
|
||||
decls.add(type.symbol.valueDeclaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
return decls;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {ts.ClassDeclaration} classNode the class declaration
|
||||
* @param {string} memberName name of the member
|
||||
* @returns {ts.MethodDeclaration | null} base class member declaration when found
|
||||
*/
|
||||
const findDeclarationInBaseClass = (classNode, memberName) => {
|
||||
for (const baseClass of getBaseClasses(classNode)) {
|
||||
for (const node of baseClass.members) {
|
||||
if (ts.isMethodDeclaration(node)) {
|
||||
if (node.name.getText() === memberName) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
const result = findDeclarationInBaseClass(baseClass, memberName);
|
||||
if (result) return result;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const libPath = path.resolve(__dirname, "../lib");
|
||||
|
||||
for (const sourceFile of program.getSourceFiles()) {
|
||||
let file = sourceFile.fileName;
|
||||
if (
|
||||
file.toLowerCase().startsWith(libPath.replace(/\\/g, "/").toLowerCase())
|
||||
) {
|
||||
const updates = [];
|
||||
sourceFile.forEachChild(node => {
|
||||
if (ts.isClassDeclaration(node)) {
|
||||
for (const member of node.members) {
|
||||
if (ts.isMethodDeclaration(member)) {
|
||||
const baseDecl = findDeclarationInBaseClass(
|
||||
node,
|
||||
member.name.getText()
|
||||
);
|
||||
if (baseDecl) {
|
||||
const memberAsAny = /** @type {any} */ (member);
|
||||
const baseDeclAsAny = /** @type {any} */ (baseDecl);
|
||||
const currentJsDoc = memberAsAny.jsDoc && memberAsAny.jsDoc[0];
|
||||
const baseJsDoc = baseDeclAsAny.jsDoc && baseDeclAsAny.jsDoc[0];
|
||||
const currentJsDocText = currentJsDoc && currentJsDoc.getText();
|
||||
let baseJsDocText = baseJsDoc && baseJsDoc.getText();
|
||||
if (baseJsDocText) {
|
||||
baseJsDocText = baseJsDocText.replace(
|
||||
/\t \* @abstract\r?\n/g,
|
||||
""
|
||||
);
|
||||
if (!currentJsDocText) {
|
||||
// add js doc
|
||||
updates.push({
|
||||
member: member.name.getText(),
|
||||
start: member.getStart(),
|
||||
end: member.getStart(),
|
||||
content: baseJsDocText + "\n\t"
|
||||
});
|
||||
} else if (
|
||||
baseJsDocText &&
|
||||
currentJsDocText !== baseJsDocText
|
||||
) {
|
||||
// update js doc
|
||||
if (override || !doWrite) {
|
||||
updates.push({
|
||||
member: member.name.getText(),
|
||||
start: currentJsDoc.getStart(),
|
||||
end: currentJsDoc.getEnd(),
|
||||
content: baseJsDocText
|
||||
});
|
||||
} else {
|
||||
updates.push({
|
||||
member: member.name.getText(),
|
||||
start: currentJsDoc.getStart() - 1,
|
||||
end: currentJsDoc.getEnd(),
|
||||
content: `<<<<<<< original comment\n\t${currentJsDocText}\n=======\n\t${baseJsDocText}\n>>>>>>> comment from base class`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (updates.length > 0) {
|
||||
if (doWrite) {
|
||||
let fileContent = fs.readFileSync(file, "utf-8");
|
||||
updates.sort((a, b) => {
|
||||
return b.start - a.start;
|
||||
});
|
||||
for (const update of updates) {
|
||||
fileContent =
|
||||
fileContent.substr(0, update.start) +
|
||||
update.content +
|
||||
fileContent.substr(update.end);
|
||||
}
|
||||
console.log(`${file} ${updates.length} JSDoc comments added/updated`);
|
||||
fs.writeFileSync(file, fileContent, "utf-8");
|
||||
} else {
|
||||
console.log(file);
|
||||
for (const update of updates) {
|
||||
console.log(
|
||||
`* ${update.member} should have this JSDoc:\n\t${update.content}`
|
||||
);
|
||||
}
|
||||
console.log();
|
||||
}
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const ts = require("typescript");
|
||||
|
||||
const rootPath = path.resolve(__dirname, "..");
|
||||
const configPath = path.resolve(__dirname, "../tsconfig.json");
|
||||
const configContent = fs.readFileSync(configPath, "utf-8");
|
||||
const configJsonFile = ts.parseJsonText(configPath, configContent);
|
||||
const parsedConfig = ts.parseJsonSourceFileConfigFileContent(
|
||||
configJsonFile,
|
||||
ts.sys,
|
||||
rootPath,
|
||||
{ noEmit: true }
|
||||
);
|
||||
const { fileNames, options } = parsedConfig;
|
||||
|
||||
module.exports = ts.createProgram(fileNames, options);
|
||||
|
|
@ -12,5 +12,5 @@
|
|||
"types": ["node"],
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["declarations.d.ts", "bin/*.js", "lib/**/*.js"]
|
||||
"include": ["declarations.d.ts", "bin/*.js", "lib/**/*.js", "tooling/**/*.js"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue