UNPKG

6.33 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 class SetDeprecatedArray extends Set {}
169 exports.arrayToSetDeprecation(SetDeprecatedArray.prototype, name);
170 return SetDeprecatedArray;
171};
172
173exports.soonFrozenObjectDeprecation = (obj, name, code, note = "") => {
174 const message = `${name} will be frozen in future, all modifications are deprecated.${
175 note && `\n${note}`
176 }`;
177 return new Proxy(obj, {
178 set: util.deprecate(
179 (target, property, value, receiver) =>
180 Reflect.set(target, property, value, receiver),
181 message,
182 code
183 ),
184 defineProperty: util.deprecate(
185 (target, property, descriptor) =>
186 Reflect.defineProperty(target, property, descriptor),
187 message,
188 code
189 ),
190 deleteProperty: util.deprecate(
191 (target, property) => Reflect.deleteProperty(target, property),
192 message,
193 code
194 ),
195 setPrototypeOf: util.deprecate(
196 (target, proto) => Reflect.setPrototypeOf(target, proto),
197 message,
198 code
199 )
200 });
201};
202
203/**
204 * @template T
205 * @param {T} obj object
206 * @param {string} message deprecation message
207 * @param {string} code deprecation code
208 * @returns {T} object with property access deprecated
209 */
210const deprecateAllProperties = (obj, message, code) => {
211 const newObj = {};
212 const descriptors = Object.getOwnPropertyDescriptors(obj);
213 for (const name of Object.keys(descriptors)) {
214 const descriptor = descriptors[name];
215 if (typeof descriptor.value === "function") {
216 Object.defineProperty(newObj, name, {
217 ...descriptor,
218 value: util.deprecate(descriptor.value, message, code)
219 });
220 } else if (descriptor.get || descriptor.set) {
221 Object.defineProperty(newObj, name, {
222 ...descriptor,
223 get: descriptor.get && util.deprecate(descriptor.get, message, code),
224 set: descriptor.set && util.deprecate(descriptor.set, message, code)
225 });
226 } else {
227 let value = descriptor.value;
228 Object.defineProperty(newObj, name, {
229 configurable: descriptor.configurable,
230 enumerable: descriptor.enumerable,
231 get: util.deprecate(() => value, message, code),
232 set: descriptor.writable
233 ? util.deprecate(v => (value = v), message, code)
234 : undefined
235 });
236 }
237 }
238 return /** @type {T} */ (newObj);
239};
240exports.deprecateAllProperties = deprecateAllProperties;
241
242/**
243 * @template T
244 * @param {T} fakeHook fake hook implementation
245 * @param {string=} message deprecation message (not deprecated when unset)
246 * @param {string=} code deprecation code (not deprecated when unset)
247 * @returns {FakeHook<T>} fake hook which redirects
248 */
249exports.createFakeHook = (fakeHook, message, code) => {
250 if (message && code) {
251 fakeHook = deprecateAllProperties(fakeHook, message, code);
252 }
253 return Object.freeze(
254 Object.assign(fakeHook, { _fakeHook: /** @type {true} */ (true) })
255 );
256};
257
\No newline at end of file