UNPKG

6.45 kBJavaScriptView Raw
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const util = require("util");
9
10/** @type {Map<string, Function>} */
11const deprecationCache = new Map();
12
13/**
14 * @typedef {Object} FakeHookMarker
15 * @property {true} _fakeHook it's a fake hook
16 */
17
18/** @template T @typedef {T & FakeHookMarker} FakeHook<T> */
19
20/**
21 * @param {string} message deprecation message
22 * @param {string} code deprecation code
23 * @returns {Function} function to trigger deprecation
24 */
25const createDeprecation = (message, code) => {
26 const cached = deprecationCache.get(message);
27 if (cached !== undefined) return cached;
28 const fn = util.deprecate(
29 () => {},
30 message,
31 "DEP_WEBPACK_DEPRECATION_" + code
32 );
33 deprecationCache.set(message, fn);
34 return fn;
35};
36
37const COPY_METHODS = [
38 "concat",
39 "entry",
40 "filter",
41 "find",
42 "findIndex",
43 "includes",
44 "indexOf",
45 "join",
46 "lastIndexOf",
47 "map",
48 "reduce",
49 "reduceRight",
50 "slice",
51 "some"
52];
53
54const DISABLED_METHODS = [
55 "copyWithin",
56 "entries",
57 "fill",
58 "keys",
59 "pop",
60 "reverse",
61 "shift",
62 "splice",
63 "sort",
64 "unshift"
65];
66
67/**
68 * @param {any} set new set
69 * @param {string} name property name
70 * @returns {void}
71 */
72exports.arrayToSetDeprecation = (set, name) => {
73 for (const method of COPY_METHODS) {
74 if (set[method]) continue;
75 const d = createDeprecation(
76 `${name} was changed from Array to Set (using Array method '${method}' is deprecated)`,
77 "ARRAY_TO_SET"
78 );
79 /**
80 * @deprecated
81 * @this {Set}
82 * @returns {number} count
83 */
84 set[method] = function () {
85 d();
86 const array = Array.from(this);
87 return Array.prototype[method].apply(array, arguments);
88 };
89 }
90 const dPush = createDeprecation(
91 `${name} was changed from Array to Set (using Array method 'push' is deprecated)`,
92 "ARRAY_TO_SET_PUSH"
93 );
94 const dLength = createDeprecation(
95 `${name} was changed from Array to Set (using Array property 'length' is deprecated)`,
96 "ARRAY_TO_SET_LENGTH"
97 );
98 const dIndexer = createDeprecation(
99 `${name} was changed from Array to Set (indexing Array is deprecated)`,
100 "ARRAY_TO_SET_INDEXER"
101 );
102 /**
103 * @deprecated
104 * @this {Set}
105 * @returns {number} count
106 */
107 set.push = function () {
108 dPush();
109 for (const item of Array.from(arguments)) {
110 this.add(item);
111 }
112 return this.size;
113 };
114 for (const method of DISABLED_METHODS) {
115 if (set[method]) continue;
116 set[method] = () => {
117 throw new Error(
118 `${name} was changed from Array to Set (using Array method '${method}' is not possible)`
119 );
120 };
121 }
122 const createIndexGetter = index => {
123 /**
124 * @this {Set} a Set
125 * @returns {any} the value at this location
126 */
127 const fn = function () {
128 dIndexer();
129 let i = 0;
130 for (const item of this) {
131 if (i++ === index) return item;
132 }
133 return undefined;
134 };
135 return fn;
136 };
137 const defineIndexGetter = index => {
138 Object.defineProperty(set, index, {
139 get: createIndexGetter(index),
140 set(value) {
141 throw new Error(
142 `${name} was changed from Array to Set (indexing Array with write is not possible)`
143 );
144 }
145 });
146 };
147 defineIndexGetter(0);
148 let indexerDefined = 1;
149 Object.defineProperty(set, "length", {
150 get() {
151 dLength();
152 const length = this.size;
153 for (indexerDefined; indexerDefined < length + 1; indexerDefined++) {
154 defineIndexGetter(indexerDefined);
155 }
156 return length;
157 },
158 set(value) {
159 throw new Error(
160 `${name} was changed from Array to Set (writing to Array property 'length' is not possible)`
161 );
162 }
163 });
164 set[Symbol.isConcatSpreadable] = true;
165};
166
167exports.createArrayToSetDeprecationSet = name => {
168 let initialized = false;
169 class SetDeprecatedArray extends Set {
170 constructor(items) {
171 super(items);
172 if (!initialized) {
173 initialized = true;
174 exports.arrayToSetDeprecation(SetDeprecatedArray.prototype, name);
175 }
176 }
177 }
178 return SetDeprecatedArray;
179};
180
181exports.soonFrozenObjectDeprecation = (obj, name, code, note = "") => {
182 const message = `${name} will be frozen in future, all modifications are deprecated.${
183 note && `\n${note}`
184 }`;
185 return new Proxy(obj, {
186 set: util.deprecate(
187 (target, property, value, receiver) =>
188 Reflect.set(target, property, value, receiver),
189 message,
190 code
191 ),
192 defineProperty: util.deprecate(
193 (target, property, descriptor) =>
194 Reflect.defineProperty(target, property, descriptor),
195 message,
196 code
197 ),
198 deleteProperty: util.deprecate(
199 (target, property) => Reflect.deleteProperty(target, property),
200 message,
201 code
202 ),
203 setPrototypeOf: util.deprecate(
204 (target, proto) => Reflect.setPrototypeOf(target, proto),
205 message,
206 code
207 )
208 });
209};
210
211/**
212 * @template T
213 * @param {T} obj object
214 * @param {string} message deprecation message
215 * @param {string} code deprecation code
216 * @returns {T} object with property access deprecated
217 */
218const deprecateAllProperties = (obj, message, code) => {
219 const newObj = {};
220 const descriptors = Object.getOwnPropertyDescriptors(obj);
221 for (const name of Object.keys(descriptors)) {
222 const descriptor = descriptors[name];
223 if (typeof descriptor.value === "function") {
224 Object.defineProperty(newObj, name, {
225 ...descriptor,
226 value: util.deprecate(descriptor.value, message, code)
227 });
228 } else if (descriptor.get || descriptor.set) {
229 Object.defineProperty(newObj, name, {
230 ...descriptor,
231 get: descriptor.get && util.deprecate(descriptor.get, message, code),
232 set: descriptor.set && util.deprecate(descriptor.set, message, code)
233 });
234 } else {
235 let value = descriptor.value;
236 Object.defineProperty(newObj, name, {
237 configurable: descriptor.configurable,
238 enumerable: descriptor.enumerable,
239 get: util.deprecate(() => value, message, code),
240 set: descriptor.writable
241 ? util.deprecate(v => (value = v), message, code)
242 : undefined
243 });
244 }
245 }
246 return /** @type {T} */ (newObj);
247};
248exports.deprecateAllProperties = deprecateAllProperties;
249
250/**
251 * @template T
252 * @param {T} fakeHook fake hook implementation
253 * @param {string=} message deprecation message (not deprecated when unset)
254 * @param {string=} code deprecation code (not deprecated when unset)
255 * @returns {FakeHook<T>} fake hook which redirects
256 */
257exports.createFakeHook = (fakeHook, message, code) => {
258 if (message && code) {
259 fakeHook = deprecateAllProperties(fakeHook, message, code);
260 }
261 return Object.freeze(
262 Object.assign(fakeHook, { _fakeHook: /** @type {true} */ (true) })
263 );
264};
265
\No newline at end of file