Merge pull request #8418 from webpack/types/misc

Preliminary work before typing the parsers
This commit is contained in:
Tobias Koppers 2018-11-29 15:48:56 +01:00 committed by GitHub
commit 5fb6c5ea18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 163 additions and 28 deletions

View File

@ -8,11 +8,14 @@
const parseJson = require("json-parse-better-errors");
const JsonExportsDependency = require("./dependencies/JsonExportsDependency");
class JsonParser {
constructor(options) {
this.options = options;
}
/** @typedef {import("./NormalModule").ParserState} ParserState */
class JsonParser {
/**
* @param {string} source the source to parse
* @param {ParserState} state the parser state
* @returns {ParserState} the parser state
*/
parse(source, state) {
const data = parseJson(source[0] === "\ufeff" ? source.slice(1) : source);
state.module.buildInfo.jsonData = data;

View File

@ -42,6 +42,14 @@ const makeSerializable = require("./util/makeSerializable");
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("./util/createHash").Hash} Hash */
/**
* @typedef {Object} ParserState
* @property {NormalModule} current
* @property {NormalModule} module
* @property {Compilation} compilation
* @property {TODO} options
*/
const EARLY_RETURN_ERROR = new Error("flags early return is not an error");
/**

View File

@ -6,6 +6,7 @@
"use strict";
const path = require("path");
const NORMALIZE_SLASH_DIRECTION_REGEXP = /\\/g;
const PATH_CHARS_REGEXP = /[-[\]{}()*+?.,\\^$|#\s]/g;
const SEPARATOR_REGEXP = /[/\\]$/;
@ -13,18 +14,38 @@ const FRONT_OR_BACK_BANG_REGEXP = /^!|!$/g;
const INDEX_JS_REGEXP = /\/index.js(!|\?|\(query\))/g;
const MATCH_RESOURCE_REGEXP = /!=!/;
/**
* @param {string} request the request
* @returns {string} the normalized request
*/
const normalizeBackSlashDirection = request => {
return request.replace(NORMALIZE_SLASH_DIRECTION_REGEXP, "/");
};
/**
* @param {string} path the path to match
* @returns {RegExp} the path matcher
*/
const createRegExpForPath = path => {
const regexpTypePartial = path.replace(PATH_CHARS_REGEXP, "\\$&");
return new RegExp(`(^|!)${regexpTypePartial}`, "g");
};
class RequestShortener {
constructor(directory) {
directory = normalizeBackSlashDirection(directory);
/**
* @param {string} dir the directory
*/
constructor(dir) {
/** @type {RegExp | null} */
this.currentDirectoryRegExp = null;
/** @type {RegExp | null} */
this.parentDirectoryRegExp = null;
/** @type {RegExp | null} */
this.buildinsRegExp = null;
/** @type {boolean} */
this.buildinsAsModule = false;
let directory = normalizeBackSlashDirection(dir);
if (SEPARATOR_REGEXP.test(directory)) {
directory = directory.substr(0, directory.length - 1);
}
@ -38,6 +59,7 @@ class RequestShortener {
const parentDirectory = endsWithSeparator
? dirname.substr(0, dirname.length - 1)
: dirname;
if (parentDirectory && parentDirectory !== directory) {
this.parentDirectoryRegExp = createRegExpForPath(parentDirectory);
}
@ -51,11 +73,18 @@ class RequestShortener {
this.buildinsRegExp = createRegExpForPath(buildins);
}
/** @type {Map<string, string>} */
this.cache = new Map();
}
/**
* @param {string | undefined | null} request the request to shorten
* @returns {string | undefined | null} the shortened request
*/
shorten(request) {
if (!request) return request;
if (!request) {
return request;
}
const cacheEntry = this.cache.get(request);
if (cacheEntry !== undefined) {
return cacheEntry;

View File

@ -10,15 +10,23 @@ const { HookMap, SyncHook, SyncWaterfallHook } = require("tapable");
/** @typedef {import("enhanced-resolve/lib/Resolver")} Resolver */
/**
* @typedef {Object} ResolverCache
* @property {WeakMap<Object, Resolver>} direct
* @property {Map<string, Resolver>} stringified
*/
module.exports = class ResolverFactory {
constructor() {
this.hooks = Object.freeze({
/** @type {HookMap<Object>} */
resolveOptions: new HookMap(
() => new SyncWaterfallHook(["resolveOptions"])
),
/** @type {HookMap<Resolver, Object>} */
resolver: new HookMap(() => new SyncHook(["resolver", "resolveOptions"]))
});
/** @type {Map<string, { direct: WeakMap<Object, Resolver>, stringified: Map<string, Resolver> }>} */
/** @type {Map<string, ResolverCache>} */
this.cache = new Map();
}
@ -37,7 +45,9 @@ module.exports = class ResolverFactory {
this.cache.set(type, typedCaches);
}
const cachedResolver = typedCaches.direct.get(resolveOptions);
if (cachedResolver) return cachedResolver;
if (cachedResolver) {
return cachedResolver;
}
const ident = JSON.stringify(resolveOptions);
const resolver = typedCaches.stringified.get(ident);
if (resolver) {

View File

@ -12,6 +12,9 @@ const NullDependency = require("./NullDependency");
/** @typedef {import("../ModuleGraph")} ModuleGraph */
class JsonExportsDependency extends NullDependency {
/**
* @param {string[]} exports export names
*/
constructor(exports) {
super();
this.exports = exports;

View File

@ -5,24 +5,72 @@
"use strict";
const TOMBSTONE = {};
const UNDEFINED_MARKER = {};
const TOMBSTONE = Symbol("tombstone");
const UNDEFINED_MARKER = Symbol("undefined");
/**
* @template T
* @typedef {T | true | undefined} Cell<T>
*/
/**
* @template T
* @typedef {T | true | typeof TOMBSTONE | typeof UNDEFINED_MARKER} InternalCell<T>
*/
/**
* @template K
* @template V
* @param {[K, InternalCell<V>]} pair the internal cell
* @returns {[K, Cell<V>]} its safe representation
*/
const extractPair = pair => {
const key = pair[0];
const val = pair[1];
if (val === UNDEFINED_MARKER || val === TOMBSTONE) {
return [key, undefined];
} else {
return /** @type {[K, Cell<V>]} */ (pair);
}
};
/**
* @template K
* @template V
*/
class StackedSetMap {
/**
* @param {Map<K, V>[]=} parentStack an optional parent
*/
constructor(parentStack) {
this.stack = parentStack === undefined ? [] : parentStack.slice();
/** @type {Map<K, InternalCell<V>>} */
this.map = new Map();
/** @type {Map<K, InternalCell<V>>[]} */
this.stack = parentStack === undefined ? [] : parentStack.slice();
this.stack.push(this.map);
}
/**
* @param {K} item the item to add
* @returns {void}
*/
add(item) {
this.map.set(item, true);
}
/**
* @param {K} item the key of the element to add
* @param {V} value the value of the element to add
* @returns {void}
*/
set(item, value) {
this.map.set(item, value === undefined ? UNDEFINED_MARKER : value);
}
/**
* @param {K} item the item to delete
* @returns {void}
*/
delete(item) {
if (this.stack.length > 1) {
this.map.set(item, TOMBSTONE);
@ -31,11 +79,17 @@ class StackedSetMap {
}
}
/**
* @param {K} item the item to test
* @returns {boolean} true if the item exists in this set
*/
has(item) {
const topValue = this.map.get(item);
if (topValue !== undefined) return topValue !== TOMBSTONE;
if (topValue !== undefined) {
return topValue !== TOMBSTONE;
}
if (this.stack.length > 1) {
for (var i = this.stack.length - 2; i >= 0; i--) {
for (let i = this.stack.length - 2; i >= 0; i--) {
const value = this.stack[i].get(item);
if (value !== undefined) {
this.map.set(item, value);
@ -47,6 +101,10 @@ class StackedSetMap {
return false;
}
/**
* @param {K} item the key of the element to return
* @returns {Cell<V>} the value of the element
*/
get(item) {
const topValue = this.map.get(item);
if (topValue !== undefined) {
@ -55,7 +113,7 @@ class StackedSetMap {
: topValue;
}
if (this.stack.length > 1) {
for (var i = this.stack.length - 2; i >= 0; i--) {
for (let i = this.stack.length - 2; i >= 0; i--) {
const value = this.stack[i].get(item);
if (value !== undefined) {
this.map.set(item, value);
@ -86,22 +144,17 @@ class StackedSetMap {
asArray() {
this._compress();
return Array.from(this.map.entries(), pair => pair[0]);
return Array.from(this.map.keys());
}
asSet() {
return new Set(this.asArray());
this._compress();
return new Set(this.map.keys());
}
asPairArray() {
this._compress();
return Array.from(
this.map.entries(),
pair =>
/** @type {[TODO, TODO]} */ (pair[1] === UNDEFINED_MARKER
? [pair[0], undefined]
: pair)
);
return Array.from(this.map.entries(), extractPair);
}
asMap() {

View File

@ -5,23 +5,50 @@
"use strict";
module.exports = class TrackingSet {
/**
* @template T
* @template U
* @typedef {import("./StackedSetMap")<T,U>} StackedSetMap<T,U>
*/
/**
* @template T
* @template U
*/
class TrackingSet {
/**
* @param {StackedSetMap<T,U>} set the set to track
*/
constructor(set) {
/** @type {StackedSetMap<T,U>} */
this.set = set;
/** @type {Set<T>} */
this.set2 = new Set();
this.stack = set.stack;
}
/**
* @param {T} item the item to add
* @returns {void}
*/
add(item) {
this.set2.add(item);
return this.set.add(item);
this.set.add(item);
}
/**
* @param {T} item the item to delete
* @returns {void}
*/
delete(item) {
this.set2.delete(item);
return this.set.delete(item);
this.set.delete(item);
}
/**
* @param {T} item the item to test
* @returns {boolean} true if the item exists in this set
*/
has(item) {
return this.set.has(item);
}
@ -33,4 +60,6 @@ module.exports = class TrackingSet {
getAddedItems() {
return this.set2;
}
};
}
module.exports = TrackingSet;