diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2023-10-31 15:37:35 +0800 |
| commit | d5f14083061f2ce6a42313188443a42e30796320 (patch) | |
| tree | cc6a9889e08b29595a76a33b9e7b4ef84866468b /node_modules/webpack/lib/serialization/ObjectMiddleware.js | |
| parent | b1a6ea021f29f182b62f9f81024a3d8ac8621b7f (diff) | |
added make browserlist(autoprefixer) work fixed
Diffstat (limited to 'node_modules/webpack/lib/serialization/ObjectMiddleware.js')
| -rw-r--r-- | node_modules/webpack/lib/serialization/ObjectMiddleware.js | 765 |
1 files changed, 765 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/serialization/ObjectMiddleware.js b/node_modules/webpack/lib/serialization/ObjectMiddleware.js new file mode 100644 index 00000000..31890dfe --- /dev/null +++ b/node_modules/webpack/lib/serialization/ObjectMiddleware.js @@ -0,0 +1,765 @@ +/* + MIT License http://www.opensource.org/licenses/mit-license.php +*/ + +"use strict"; + +const createHash = require("../util/createHash"); +const ArraySerializer = require("./ArraySerializer"); +const DateObjectSerializer = require("./DateObjectSerializer"); +const ErrorObjectSerializer = require("./ErrorObjectSerializer"); +const MapObjectSerializer = require("./MapObjectSerializer"); +const NullPrototypeObjectSerializer = require("./NullPrototypeObjectSerializer"); +const PlainObjectSerializer = require("./PlainObjectSerializer"); +const RegExpObjectSerializer = require("./RegExpObjectSerializer"); +const SerializerMiddleware = require("./SerializerMiddleware"); +const SetObjectSerializer = require("./SetObjectSerializer"); + +/** @typedef {typeof import("../util/Hash")} Hash */ +/** @typedef {import("./types").ComplexSerializableType} ComplexSerializableType */ +/** @typedef {import("./types").PrimitiveSerializableType} PrimitiveSerializableType */ + +/** @typedef {new (...params: any[]) => any} Constructor */ + +/* + +Format: + +File -> Section* +Section -> ObjectSection | ReferenceSection | EscapeSection | OtherSection + +ObjectSection -> ESCAPE ( + number:relativeOffset (number > 0) | + string:request (string|null):export +) Section:value* ESCAPE ESCAPE_END_OBJECT +ReferenceSection -> ESCAPE number:relativeOffset (number < 0) +EscapeSection -> ESCAPE ESCAPE_ESCAPE_VALUE (escaped value ESCAPE) +EscapeSection -> ESCAPE ESCAPE_UNDEFINED (escaped value ESCAPE) +OtherSection -> any (except ESCAPE) + +Why using null as escape value? +Multiple null values can merged by the BinaryMiddleware, which makes it very efficient +Technically any value can be used. + +*/ + +/** + * @typedef {Object} ObjectSerializerContext + * @property {function(any): void} write + * @property {function(any): void} setCircularReference + */ + +/** + * @typedef {Object} ObjectDeserializerContext + * @property {function(): any} read + * @property {function(any): void} setCircularReference + */ + +/** + * @typedef {Object} ObjectSerializer + * @property {function(any, ObjectSerializerContext): void} serialize + * @property {function(ObjectDeserializerContext): any} deserialize + */ + +/** + * @template T + * @param {Set<T>} set set + * @param {number} size count of items to keep + */ +const setSetSize = (set, size) => { + let i = 0; + for (const item of set) { + if (i++ >= size) { + set.delete(item); + } + } +}; + +/** + * @template K, X + * @param {Map<K, X>} map map + * @param {number} size count of items to keep + */ +const setMapSize = (map, size) => { + let i = 0; + for (const item of map.keys()) { + if (i++ >= size) { + map.delete(item); + } + } +}; + +/** + * @param {Buffer} buffer buffer + * @param {string | Hash} hashFunction hash function to use + * @returns {string} hash + */ +const toHash = (buffer, hashFunction) => { + const hash = createHash(hashFunction); + hash.update(buffer); + return /** @type {string} */ (hash.digest("latin1")); +}; + +const ESCAPE = null; +const ESCAPE_ESCAPE_VALUE = null; +const ESCAPE_END_OBJECT = true; +const ESCAPE_UNDEFINED = false; + +const CURRENT_VERSION = 2; + +/** @type {Map<Constructor, { request?: string, name?: string | number | null, serializer?: ObjectSerializer }>} */ +const serializers = new Map(); +/** @type {Map<string | number, ObjectSerializer>} */ +const serializerInversed = new Map(); + +/** @type {Set<string>} */ +const loadedRequests = new Set(); + +const NOT_SERIALIZABLE = {}; + +const jsTypes = new Map(); +jsTypes.set(Object, new PlainObjectSerializer()); +jsTypes.set(Array, new ArraySerializer()); +jsTypes.set(null, new NullPrototypeObjectSerializer()); +jsTypes.set(Map, new MapObjectSerializer()); +jsTypes.set(Set, new SetObjectSerializer()); +jsTypes.set(Date, new DateObjectSerializer()); +jsTypes.set(RegExp, new RegExpObjectSerializer()); +jsTypes.set(Error, new ErrorObjectSerializer(Error)); +jsTypes.set(EvalError, new ErrorObjectSerializer(EvalError)); +jsTypes.set(RangeError, new ErrorObjectSerializer(RangeError)); +jsTypes.set(ReferenceError, new ErrorObjectSerializer(ReferenceError)); +jsTypes.set(SyntaxError, new ErrorObjectSerializer(SyntaxError)); +jsTypes.set(TypeError, new ErrorObjectSerializer(TypeError)); + +// If in a sandboxed environment (e. g. jest), this escapes the sandbox and registers +// real Object and Array types to. These types may occur in the wild too, e. g. when +// using Structured Clone in postMessage. +if (exports.constructor !== Object) { + const Obj = /** @type {typeof Object} */ (exports.constructor); + const Fn = /** @type {typeof Function} */ (Obj.constructor); + for (const [type, config] of Array.from(jsTypes)) { + if (type) { + const Type = new Fn(`return ${type.name};`)(); + jsTypes.set(Type, config); + } + } +} + +{ + let i = 1; + for (const [type, serializer] of jsTypes) { + serializers.set(type, { + request: "", + name: i++, + serializer + }); + } +} + +for (const { request, name, serializer } of serializers.values()) { + serializerInversed.set( + `${request}/${name}`, + /** @type {ObjectSerializer} */ (serializer) + ); +} + +/** @type {Map<RegExp, (request: string) => boolean>} */ +const loaders = new Map(); + +/** + * @typedef {ComplexSerializableType[]} DeserializedType + * @typedef {PrimitiveSerializableType[]} SerializedType + * @extends {SerializerMiddleware<DeserializedType, SerializedType>} + */ +class ObjectMiddleware extends SerializerMiddleware { + /** + * @param {function(any): void} extendContext context extensions + * @param {string | Hash} hashFunction hash function to use + */ + constructor(extendContext, hashFunction = "md4") { + super(); + this.extendContext = extendContext; + this._hashFunction = hashFunction; + } + /** + * @param {RegExp} regExp RegExp for which the request is tested + * @param {function(string): boolean} loader loader to load the request, returns true when successful + * @returns {void} + */ + static registerLoader(regExp, loader) { + loaders.set(regExp, loader); + } + + /** + * @param {Constructor} Constructor the constructor + * @param {string} request the request which will be required when deserializing + * @param {string | null} name the name to make multiple serializer unique when sharing a request + * @param {ObjectSerializer} serializer the serializer + * @returns {void} + */ + static register(Constructor, request, name, serializer) { + const key = request + "/" + name; + + if (serializers.has(Constructor)) { + throw new Error( + `ObjectMiddleware.register: serializer for ${Constructor.name} is already registered` + ); + } + + if (serializerInversed.has(key)) { + throw new Error( + `ObjectMiddleware.register: serializer for ${key} is already registered` + ); + } + + serializers.set(Constructor, { + request, + name, + serializer + }); + + serializerInversed.set(key, serializer); + } + + /** + * @param {Constructor} Constructor the constructor + * @returns {void} + */ + static registerNotSerializable(Constructor) { + if (serializers.has(Constructor)) { + throw new Error( + `ObjectMiddleware.registerNotSerializable: serializer for ${Constructor.name} is already registered` + ); + } + + serializers.set(Constructor, NOT_SERIALIZABLE); + } + + static getSerializerFor(object) { + const proto = Object.getPrototypeOf(object); + let c; + if (proto === null) { + // Object created with Object.create(null) + c = null; + } else { + c = proto.constructor; + if (!c) { + throw new Error( + "Serialization of objects with prototype without valid constructor property not possible" + ); + } + } + const config = serializers.get(c); + + if (!config) throw new Error(`No serializer registered for ${c.name}`); + if (config === NOT_SERIALIZABLE) throw NOT_SERIALIZABLE; + + return config; + } + + /** + * @param {string} request request + * @param {TODO} name name + * @returns {ObjectSerializer} serializer + */ + static getDeserializerFor(request, name) { + const key = request + "/" + name; + const serializer = serializerInversed.get(key); + + if (serializer === undefined) { + throw new Error(`No deserializer registered for ${key}`); + } + + return serializer; + } + + /** + * @param {string} request request + * @param {TODO} name name + * @returns {ObjectSerializer} serializer + */ + static _getDeserializerForWithoutError(request, name) { + const key = request + "/" + name; + const serializer = serializerInversed.get(key); + return serializer; + } + + /** + * @param {DeserializedType} data data + * @param {Object} context context object + * @returns {SerializedType|Promise<SerializedType>} serialized data + */ + serialize(data, context) { + /** @type {any[]} */ + let result = [CURRENT_VERSION]; + let currentPos = 0; + let referenceable = new Map(); + const addReferenceable = item => { + referenceable.set(item, currentPos++); + }; + let bufferDedupeMap = new Map(); + const dedupeBuffer = buf => { + const len = buf.length; + const entry = bufferDedupeMap.get(len); + if (entry === undefined) { + bufferDedupeMap.set(len, buf); + return buf; + } + if (Buffer.isBuffer(entry)) { + if (len < 32) { + if (buf.equals(entry)) { + return entry; + } + bufferDedupeMap.set(len, [entry, buf]); + return buf; + } else { + const hash = toHash(entry, this._hashFunction); + const newMap = new Map(); + newMap.set(hash, entry); + bufferDedupeMap.set(len, newMap); + const hashBuf = toHash(buf, this._hashFunction); + if (hash === hashBuf) { + return entry; + } + return buf; + } + } else if (Array.isArray(entry)) { + if (entry.length < 16) { + for (const item of entry) { + if (buf.equals(item)) { + return item; + } + } + entry.push(buf); + return buf; + } else { + const newMap = new Map(); + const hash = toHash(buf, this._hashFunction); + let found; + for (const item of entry) { + const itemHash = toHash(item, this._hashFunction); + newMap.set(itemHash, item); + if (found === undefined && itemHash === hash) found = item; + } + bufferDedupeMap.set(len, newMap); + if (found === undefined) { + newMap.set(hash, buf); + return buf; + } else { + return found; + } + } + } else { + const hash = toHash(buf, this._hashFunction); + const item = entry.get(hash); + if (item !== undefined) { + return item; + } + entry.set(hash, buf); + return buf; + } + }; + let currentPosTypeLookup = 0; + let objectTypeLookup = new Map(); + const cycleStack = new Set(); + const stackToString = item => { + const arr = Array.from(cycleStack); + arr.push(item); + return arr + .map(item => { + if (typeof item === "string") { + if (item.length > 100) { + return `String ${JSON.stringify(item.slice(0, 100)).slice( + 0, + -1 + )}..."`; + } + return `String ${JSON.stringify(item)}`; + } + try { + const { request, name } = ObjectMiddleware.getSerializerFor(item); + if (request) { + return `${request}${name ? `.${name}` : ""}`; + } + } catch (e) { + // ignore -> fallback + } + if (typeof item === "object" && item !== null) { + if (item.constructor) { + if (item.constructor === Object) + return `Object { ${Object.keys(item).join(", ")} }`; + if (item.constructor === Map) return `Map { ${item.size} items }`; + if (item.constructor === Array) + return `Array { ${item.length} items }`; + if (item.constructor === Set) return `Set { ${item.size} items }`; + if (item.constructor === RegExp) return item.toString(); + return `${item.constructor.name}`; + } + return `Object [null prototype] { ${Object.keys(item).join( + ", " + )} }`; + } + if (typeof item === "bigint") { + return `BigInt ${item}n`; + } + try { + return `${item}`; + } catch (e) { + return `(${e.message})`; + } + }) + .join(" -> "); + }; + let hasDebugInfoAttached; + let ctx = { + write(value, key) { + try { + process(value); + } catch (e) { + if (e !== NOT_SERIALIZABLE) { + if (hasDebugInfoAttached === undefined) + hasDebugInfoAttached = new WeakSet(); + if (!hasDebugInfoAttached.has(e)) { + e.message += `\nwhile serializing ${stackToString(value)}`; + hasDebugInfoAttached.add(e); + } + } + throw e; + } + }, + setCircularReference(ref) { + addReferenceable(ref); + }, + snapshot() { + return { + length: result.length, + cycleStackSize: cycleStack.size, + referenceableSize: referenceable.size, + currentPos, + objectTypeLookupSize: objectTypeLookup.size, + currentPosTypeLookup + }; + }, + rollback(snapshot) { + result.length = snapshot.length; + setSetSize(cycleStack, snapshot.cycleStackSize); + setMapSize(referenceable, snapshot.referenceableSize); + currentPos = snapshot.currentPos; + setMapSize(objectTypeLookup, snapshot.objectTypeLookupSize); + currentPosTypeLookup = snapshot.currentPosTypeLookup; + }, + ...context + }; + this.extendContext(ctx); + const process = item => { + if (Buffer.isBuffer(item)) { + // check if we can emit a reference + const ref = referenceable.get(item); + if (ref !== undefined) { + result.push(ESCAPE, ref - currentPos); + return; + } + const alreadyUsedBuffer = dedupeBuffer(item); + if (alreadyUsedBuffer !== item) { + const ref = referenceable.get(alreadyUsedBuffer); + if (ref !== undefined) { + referenceable.set(item, ref); + result.push(ESCAPE, ref - currentPos); + return; + } + item = alreadyUsedBuffer; + } + addReferenceable(item); + + result.push(item); + } else if (item === ESCAPE) { + result.push(ESCAPE, ESCAPE_ESCAPE_VALUE); + } else if ( + typeof item === "object" + // We don't have to check for null as ESCAPE is null and this has been checked before + ) { + // check if we can emit a reference + const ref = referenceable.get(item); + if (ref !== undefined) { + result.push(ESCAPE, ref - currentPos); + return; + } + + if (cycleStack.has(item)) { + throw new Error( + `This is a circular references. To serialize circular references use 'setCircularReference' somewhere in the circle during serialize and deserialize.` + ); + } + + const { request, name, serializer } = + ObjectMiddleware.getSerializerFor(item); + const key = `${request}/${name}`; + const lastIndex = objectTypeLookup.get(key); + + if (lastIndex === undefined) { + objectTypeLookup.set(key, currentPosTypeLookup++); + + result.push(ESCAPE, request, name); + } else { + result.push(ESCAPE, currentPosTypeLookup - lastIndex); + } + + cycleStack.add(item); + + try { + serializer.serialize(item, ctx); + } finally { + cycleStack.delete(item); + } + + result.push(ESCAPE, ESCAPE_END_OBJECT); + + addReferenceable(item); + } else if (typeof item === "string") { + if (item.length > 1) { + // short strings are shorter when not emitting a reference (this saves 1 byte per empty string) + // check if we can emit a reference + const ref = referenceable.get(item); + if (ref !== undefined) { + result.push(ESCAPE, ref - currentPos); + return; + } + addReferenceable(item); + } + + if (item.length > 102400 && context.logger) { + context.logger.warn( + `Serializing big strings (${Math.round( + item.length / 1024 + )}kiB) impacts deserialization performance (consider using Buffer instead and decode when needed)` + ); + } + + result.push(item); + } else if (typeof item === "function") { + if (!SerializerMiddleware.isLazy(item)) + throw new Error("Unexpected function " + item); + /** @type {SerializedType} */ + const serializedData = + SerializerMiddleware.getLazySerializedValue(item); + if (serializedData !== undefined) { + if (typeof serializedData === "function") { + result.push(serializedData); + } else { + throw new Error("Not implemented"); + } + } else if (SerializerMiddleware.isLazy(item, this)) { + throw new Error("Not implemented"); + } else { + const data = SerializerMiddleware.serializeLazy(item, data => + this.serialize([data], context) + ); + SerializerMiddleware.setLazySerializedValue(item, data); + result.push(data); + } + } else if (item === undefined) { + result.push(ESCAPE, ESCAPE_UNDEFINED); + } else { + result.push(item); + } + }; + + try { + for (const item of data) { + process(item); + } + return result; + } catch (e) { + if (e === NOT_SERIALIZABLE) return null; + + throw e; + } finally { + // Get rid of these references to avoid leaking memory + // This happens because the optimized code v8 generates + // is optimized for our "ctx.write" method so it will reference + // it from e. g. Dependency.prototype.serialize -(IC)-> ctx.write + data = + result = + referenceable = + bufferDedupeMap = + objectTypeLookup = + ctx = + undefined; + } + } + + /** + * @param {SerializedType} data data + * @param {Object} context context object + * @returns {DeserializedType|Promise<DeserializedType>} deserialized data + */ + deserialize(data, context) { + let currentDataPos = 0; + const read = () => { + if (currentDataPos >= data.length) + throw new Error("Unexpected end of stream"); + + return data[currentDataPos++]; + }; + + if (read() !== CURRENT_VERSION) + throw new Error("Version mismatch, serializer changed"); + + let currentPos = 0; + let referenceable = []; + const addReferenceable = item => { + referenceable.push(item); + currentPos++; + }; + let currentPosTypeLookup = 0; + let objectTypeLookup = []; + let result = []; + let ctx = { + read() { + return decodeValue(); + }, + setCircularReference(ref) { + addReferenceable(ref); + }, + ...context + }; + this.extendContext(ctx); + const decodeValue = () => { + const item = read(); + + if (item === ESCAPE) { + const nextItem = read(); + + if (nextItem === ESCAPE_ESCAPE_VALUE) { + return ESCAPE; + } else if (nextItem === ESCAPE_UNDEFINED) { + return undefined; + } else if (nextItem === ESCAPE_END_OBJECT) { + throw new Error( + `Unexpected end of object at position ${currentDataPos - 1}` + ); + } else { + const request = nextItem; + let serializer; + + if (typeof request === "number") { + if (request < 0) { + // relative reference + return referenceable[currentPos + request]; + } + serializer = objectTypeLookup[currentPosTypeLookup - request]; + } else { + if (typeof request !== "string") { + throw new Error( + `Unexpected type (${typeof request}) of request ` + + `at position ${currentDataPos - 1}` + ); + } + const name = read(); + + serializer = ObjectMiddleware._getDeserializerForWithoutError( + request, + name + ); + + if (serializer === undefined) { + if (request && !loadedRequests.has(request)) { + let loaded = false; + for (const [regExp, loader] of loaders) { + if (regExp.test(request)) { + if (loader(request)) { + loaded = true; + break; + } + } + } + if (!loaded) { + require(request); + } + + loadedRequests.add(request); + } + + serializer = ObjectMiddleware.getDeserializerFor(request, name); + } + + objectTypeLookup.push(serializer); + currentPosTypeLookup++; + } + try { + const item = serializer.deserialize(ctx); + const end1 = read(); + + if (end1 !== ESCAPE) { + throw new Error("Expected end of object"); + } + + const end2 = read(); + + if (end2 !== ESCAPE_END_OBJECT) { + throw new Error("Expected end of object"); + } + + addReferenceable(item); + + return item; + } catch (err) { + // As this is only for error handling, we omit creating a Map for + // faster access to this information, as this would affect performance + // in the good case + let serializerEntry; + for (const entry of serializers) { + if (entry[1].serializer === serializer) { + serializerEntry = entry; + break; + } + } + const name = !serializerEntry + ? "unknown" + : !serializerEntry[1].request + ? serializerEntry[0].name + : serializerEntry[1].name + ? `${serializerEntry[1].request} ${serializerEntry[1].name}` + : serializerEntry[1].request; + err.message += `\n(during deserialization of ${name})`; + throw err; + } + } + } else if (typeof item === "string") { + if (item.length > 1) { + addReferenceable(item); + } + + return item; + } else if (Buffer.isBuffer(item)) { + addReferenceable(item); + + return item; + } else if (typeof item === "function") { + return SerializerMiddleware.deserializeLazy( + item, + data => this.deserialize(data, context)[0] + ); + } else { + return item; + } + }; + + try { + while (currentDataPos < data.length) { + result.push(decodeValue()); + } + return result; + } finally { + // Get rid of these references to avoid leaking memory + // This happens because the optimized code v8 generates + // is optimized for our "ctx.read" method so it will reference + // it from e. g. Dependency.prototype.deserialize -(IC)-> ctx.read + result = referenceable = data = objectTypeLookup = ctx = undefined; + } + } +} + +module.exports = ObjectMiddleware; +module.exports.NOT_SERIALIZABLE = NOT_SERIALIZABLE; |
