deprecation.js 6.7 KB

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