@jomae/catalog 0.7.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/baseline.d.ts +41 -2
  2. package/dist/baseline.d.ts.map +1 -1
  3. package/dist/baseline.js +52 -10
  4. package/dist/baseline.js.map +1 -1
  5. package/dist/detect.d.ts +26 -0
  6. package/dist/detect.d.ts.map +1 -1
  7. package/dist/detect.js +27 -1
  8. package/dist/detect.js.map +1 -1
  9. package/dist/generated/baseline-history.d.ts.map +1 -1
  10. package/dist/generated/baseline-history.js +17 -5
  11. package/dist/generated/baseline-history.js.map +1 -1
  12. package/dist/generated/baseline.d.ts.map +1 -1
  13. package/dist/generated/baseline.js +411 -35
  14. package/dist/generated/baseline.js.map +1 -1
  15. package/dist/generated/guides.d.ts.map +1 -1
  16. package/dist/generated/guides.js +26 -3
  17. package/dist/generated/guides.js.map +1 -1
  18. package/dist/generated/lint-rules.d.ts +26 -0
  19. package/dist/generated/lint-rules.d.ts.map +1 -0
  20. package/dist/generated/lint-rules.js +361 -0
  21. package/dist/generated/lint-rules.js.map +1 -0
  22. package/dist/generated/sizes.d.ts.map +1 -1
  23. package/dist/generated/sizes.js +408 -38
  24. package/dist/generated/sizes.js.map +1 -1
  25. package/dist/generated/support-claims.d.ts.map +1 -1
  26. package/dist/generated/support-claims.js +34 -3
  27. package/dist/generated/support-claims.js.map +1 -1
  28. package/dist/index.d.ts +5 -3
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +5 -3
  31. package/dist/index.js.map +1 -1
  32. package/dist/lint.d.ts +53 -0
  33. package/dist/lint.d.ts.map +1 -0
  34. package/dist/lint.js +41 -0
  35. package/dist/lint.js.map +1 -0
  36. package/dist/markdown.d.ts +7 -0
  37. package/dist/markdown.d.ts.map +1 -1
  38. package/dist/markdown.js +81 -2
  39. package/dist/markdown.js.map +1 -1
  40. package/dist/rules/abort-controller.d.ts.map +1 -1
  41. package/dist/rules/abort-controller.js +3 -0
  42. package/dist/rules/abort-controller.js.map +1 -1
  43. package/dist/rules/accordion.d.ts.map +1 -1
  44. package/dist/rules/accordion.js +3 -0
  45. package/dist/rules/accordion.js.map +1 -1
  46. package/dist/rules/array-grouping.d.ts.map +1 -1
  47. package/dist/rules/array-grouping.js +1 -0
  48. package/dist/rules/array-grouping.js.map +1 -1
  49. package/dist/rules/aspect-ratio.d.ts.map +1 -1
  50. package/dist/rules/aspect-ratio.js +4 -0
  51. package/dist/rules/aspect-ratio.js.map +1 -1
  52. package/dist/rules/base64.d.ts.map +1 -1
  53. package/dist/rules/base64.js +3 -0
  54. package/dist/rules/base64.js.map +1 -1
  55. package/dist/rules/broadcast-channel.d.ts.map +1 -1
  56. package/dist/rules/broadcast-channel.js +3 -0
  57. package/dist/rules/broadcast-channel.js.map +1 -1
  58. package/dist/rules/carousel.d.ts.map +1 -1
  59. package/dist/rules/carousel.js +5 -0
  60. package/dist/rules/carousel.js.map +1 -1
  61. package/dist/rules/clipboard.d.ts.map +1 -1
  62. package/dist/rules/clipboard.js +3 -0
  63. package/dist/rules/clipboard.js.map +1 -1
  64. package/dist/rules/color-functions.d.ts.map +1 -1
  65. package/dist/rules/color-functions.js +4 -0
  66. package/dist/rules/color-functions.js.map +1 -1
  67. package/dist/rules/container-queries.d.ts.map +1 -1
  68. package/dist/rules/container-queries.js +4 -0
  69. package/dist/rules/container-queries.js.map +1 -1
  70. package/dist/rules/cookie-store.d.ts +3 -0
  71. package/dist/rules/cookie-store.d.ts.map +1 -0
  72. package/dist/rules/cookie-store.js +38 -0
  73. package/dist/rules/cookie-store.js.map +1 -0
  74. package/dist/rules/css-has.d.ts +3 -0
  75. package/dist/rules/css-has.d.ts.map +1 -0
  76. package/dist/rules/css-has.js +35 -0
  77. package/dist/rules/css-has.js.map +1 -0
  78. package/dist/rules/css-nesting.d.ts +3 -0
  79. package/dist/rules/css-nesting.d.ts.map +1 -0
  80. package/dist/rules/css-nesting.js +35 -0
  81. package/dist/rules/css-nesting.js.map +1 -0
  82. package/dist/rules/date-format.d.ts +3 -0
  83. package/dist/rules/date-format.d.ts.map +1 -0
  84. package/dist/rules/date-format.js +33 -0
  85. package/dist/rules/date-format.js.map +1 -0
  86. package/dist/rules/date-time-input.d.ts.map +1 -1
  87. package/dist/rules/date-time-input.js +4 -0
  88. package/dist/rules/date-time-input.js.map +1 -1
  89. package/dist/rules/diacritics.d.ts +3 -0
  90. package/dist/rules/diacritics.d.ts.map +1 -0
  91. package/dist/rules/diacritics.js +34 -0
  92. package/dist/rules/diacritics.js.map +1 -0
  93. package/dist/rules/dialog.d.ts.map +1 -1
  94. package/dist/rules/dialog.js +4 -0
  95. package/dist/rules/dialog.js.map +1 -1
  96. package/dist/rules/discrete-transitions.d.ts.map +1 -1
  97. package/dist/rules/discrete-transitions.js +4 -0
  98. package/dist/rules/discrete-transitions.js.map +1 -1
  99. package/dist/rules/display-names.d.ts +3 -0
  100. package/dist/rules/display-names.d.ts.map +1 -0
  101. package/dist/rules/display-names.js +37 -0
  102. package/dist/rules/display-names.js.map +1 -0
  103. package/dist/rules/drag-and-drop.d.ts.map +1 -1
  104. package/dist/rules/drag-and-drop.js +4 -0
  105. package/dist/rules/drag-and-drop.js.map +1 -1
  106. package/dist/rules/duration-format.d.ts.map +1 -1
  107. package/dist/rules/duration-format.js +3 -0
  108. package/dist/rules/duration-format.js.map +1 -1
  109. package/dist/rules/event-target.d.ts.map +1 -1
  110. package/dist/rules/event-target.js +1 -0
  111. package/dist/rules/event-target.js.map +1 -1
  112. package/dist/rules/fetch.d.ts.map +1 -1
  113. package/dist/rules/fetch.js +4 -0
  114. package/dist/rules/fetch.js.map +1 -1
  115. package/dist/rules/field-sizing.d.ts.map +1 -1
  116. package/dist/rules/field-sizing.js +4 -0
  117. package/dist/rules/field-sizing.js.map +1 -1
  118. package/dist/rules/file-download.d.ts +3 -0
  119. package/dist/rules/file-download.d.ts.map +1 -0
  120. package/dist/rules/file-download.js +40 -0
  121. package/dist/rules/file-download.js.map +1 -0
  122. package/dist/rules/file-drop.d.ts +3 -0
  123. package/dist/rules/file-drop.d.ts.map +1 -0
  124. package/dist/rules/file-drop.js +40 -0
  125. package/dist/rules/file-drop.js.map +1 -0
  126. package/dist/rules/focus-visible.d.ts.map +1 -1
  127. package/dist/rules/focus-visible.js +4 -0
  128. package/dist/rules/focus-visible.js.map +1 -1
  129. package/dist/rules/font-loading.d.ts +3 -0
  130. package/dist/rules/font-loading.d.ts.map +1 -0
  131. package/dist/rules/font-loading.js +33 -0
  132. package/dist/rules/font-loading.js.map +1 -0
  133. package/dist/rules/form-validation.d.ts +3 -0
  134. package/dist/rules/form-validation.d.ts.map +1 -0
  135. package/dist/rules/form-validation.js +40 -0
  136. package/dist/rules/form-validation.js.map +1 -0
  137. package/dist/rules/fullscreen.d.ts.map +1 -1
  138. package/dist/rules/fullscreen.js +3 -0
  139. package/dist/rules/fullscreen.js.map +1 -1
  140. package/dist/rules/height-animation.d.ts.map +1 -1
  141. package/dist/rules/height-animation.js +4 -0
  142. package/dist/rules/height-animation.js.map +1 -1
  143. package/dist/rules/index.d.ts.map +1 -1
  144. package/dist/rules/index.js +50 -0
  145. package/dist/rules/index.js.map +1 -1
  146. package/dist/rules/inert.d.ts.map +1 -1
  147. package/dist/rules/inert.js +6 -0
  148. package/dist/rules/inert.js.map +1 -1
  149. package/dist/rules/intersection-observer.d.ts.map +1 -1
  150. package/dist/rules/intersection-observer.js +1 -0
  151. package/dist/rules/intersection-observer.js.map +1 -1
  152. package/dist/rules/jquery.d.ts +3 -0
  153. package/dist/rules/jquery.d.ts.map +1 -0
  154. package/dist/rules/jquery.js +37 -0
  155. package/dist/rules/jquery.js.map +1 -0
  156. package/dist/rules/lazy-loading.d.ts.map +1 -1
  157. package/dist/rules/lazy-loading.js +4 -0
  158. package/dist/rules/lazy-loading.js.map +1 -1
  159. package/dist/rules/light-dark.d.ts +3 -0
  160. package/dist/rules/light-dark.d.ts.map +1 -0
  161. package/dist/rules/light-dark.js +37 -0
  162. package/dist/rules/light-dark.js.map +1 -0
  163. package/dist/rules/line-clamp.d.ts.map +1 -1
  164. package/dist/rules/line-clamp.js +4 -0
  165. package/dist/rules/line-clamp.js.map +1 -1
  166. package/dist/rules/list-format.d.ts +3 -0
  167. package/dist/rules/list-format.d.ts.map +1 -0
  168. package/dist/rules/list-format.js +40 -0
  169. package/dist/rules/list-format.js.map +1 -0
  170. package/dist/rules/masonry.d.ts.map +1 -1
  171. package/dist/rules/masonry.js +4 -0
  172. package/dist/rules/masonry.js.map +1 -1
  173. package/dist/rules/match-media.d.ts +3 -0
  174. package/dist/rules/match-media.d.ts.map +1 -0
  175. package/dist/rules/match-media.js +36 -0
  176. package/dist/rules/match-media.js.map +1 -0
  177. package/dist/rules/natural-sort.d.ts.map +1 -1
  178. package/dist/rules/natural-sort.js +4 -0
  179. package/dist/rules/natural-sort.js.map +1 -1
  180. package/dist/rules/number-format.d.ts.map +1 -1
  181. package/dist/rules/number-format.js +14 -1
  182. package/dist/rules/number-format.js.map +1 -1
  183. package/dist/rules/page-visibility.d.ts.map +1 -1
  184. package/dist/rules/page-visibility.js +3 -0
  185. package/dist/rules/page-visibility.js.map +1 -1
  186. package/dist/rules/passkeys.d.ts +3 -0
  187. package/dist/rules/passkeys.d.ts.map +1 -0
  188. package/dist/rules/passkeys.js +44 -0
  189. package/dist/rules/passkeys.js.map +1 -0
  190. package/dist/rules/plural-rules.d.ts +3 -0
  191. package/dist/rules/plural-rules.d.ts.map +1 -0
  192. package/dist/rules/plural-rules.js +33 -0
  193. package/dist/rules/plural-rules.js.map +1 -0
  194. package/dist/rules/pointer-events.d.ts +3 -0
  195. package/dist/rules/pointer-events.d.ts.map +1 -0
  196. package/dist/rules/pointer-events.js +43 -0
  197. package/dist/rules/pointer-events.js.map +1 -0
  198. package/dist/rules/popover.d.ts.map +1 -1
  199. package/dist/rules/popover.js +5 -0
  200. package/dist/rules/popover.js.map +1 -1
  201. package/dist/rules/progress-indicator.d.ts +3 -0
  202. package/dist/rules/progress-indicator.d.ts.map +1 -0
  203. package/dist/rules/progress-indicator.js +39 -0
  204. package/dist/rules/progress-indicator.js.map +1 -0
  205. package/dist/rules/random-uuid.d.ts.map +1 -1
  206. package/dist/rules/random-uuid.js +4 -0
  207. package/dist/rules/random-uuid.js.map +1 -1
  208. package/dist/rules/relative-time.d.ts.map +1 -1
  209. package/dist/rules/relative-time.js +4 -0
  210. package/dist/rules/relative-time.js.map +1 -1
  211. package/dist/rules/resizable-panels.d.ts.map +1 -1
  212. package/dist/rules/resizable-panels.js +3 -0
  213. package/dist/rules/resizable-panels.js.map +1 -1
  214. package/dist/rules/resize-observer.d.ts.map +1 -1
  215. package/dist/rules/resize-observer.js +4 -0
  216. package/dist/rules/resize-observer.js.map +1 -1
  217. package/dist/rules/screen-wake-lock.d.ts.map +1 -1
  218. package/dist/rules/screen-wake-lock.js +4 -0
  219. package/dist/rules/screen-wake-lock.js.map +1 -1
  220. package/dist/rules/scroll-animations.d.ts.map +1 -1
  221. package/dist/rules/scroll-animations.js +4 -0
  222. package/dist/rules/scroll-animations.js.map +1 -1
  223. package/dist/rules/scroll-into-view.d.ts +3 -0
  224. package/dist/rules/scroll-into-view.d.ts.map +1 -0
  225. package/dist/rules/scroll-into-view.js +38 -0
  226. package/dist/rules/scroll-into-view.js.map +1 -0
  227. package/dist/rules/scroll-lock.d.ts.map +1 -1
  228. package/dist/rules/scroll-lock.js +3 -0
  229. package/dist/rules/scroll-lock.js.map +1 -1
  230. package/dist/rules/scrollbars.d.ts.map +1 -1
  231. package/dist/rules/scrollbars.js +3 -0
  232. package/dist/rules/scrollbars.js.map +1 -1
  233. package/dist/rules/segmenter.d.ts +3 -0
  234. package/dist/rules/segmenter.d.ts.map +1 -0
  235. package/dist/rules/segmenter.js +45 -0
  236. package/dist/rules/segmenter.js.map +1 -0
  237. package/dist/rules/select.d.ts.map +1 -1
  238. package/dist/rules/select.js +4 -0
  239. package/dist/rules/select.js.map +1 -1
  240. package/dist/rules/server-sent-events.d.ts.map +1 -1
  241. package/dist/rules/server-sent-events.js +4 -0
  242. package/dist/rules/server-sent-events.js.map +1 -1
  243. package/dist/rules/signal-timeout.d.ts +3 -0
  244. package/dist/rules/signal-timeout.d.ts.map +1 -0
  245. package/dist/rules/signal-timeout.js +31 -0
  246. package/dist/rules/signal-timeout.js.map +1 -0
  247. package/dist/rules/smooth-scroll.d.ts.map +1 -1
  248. package/dist/rules/smooth-scroll.js +4 -0
  249. package/dist/rules/smooth-scroll.js.map +1 -1
  250. package/dist/rules/speculation-rules.d.ts +3 -0
  251. package/dist/rules/speculation-rules.d.ts.map +1 -0
  252. package/dist/rules/speculation-rules.js +35 -0
  253. package/dist/rules/speculation-rules.js.map +1 -0
  254. package/dist/rules/sticky.d.ts.map +1 -1
  255. package/dist/rules/sticky.js +4 -0
  256. package/dist/rules/sticky.js.map +1 -1
  257. package/dist/rules/structured-clone.d.ts.map +1 -1
  258. package/dist/rules/structured-clone.js +1 -0
  259. package/dist/rules/structured-clone.js.map +1 -1
  260. package/dist/rules/temporal.d.ts +3 -0
  261. package/dist/rules/temporal.d.ts.map +1 -0
  262. package/dist/rules/temporal.js +34 -0
  263. package/dist/rules/temporal.js.map +1 -0
  264. package/dist/rules/text-wrap-balance.d.ts.map +1 -1
  265. package/dist/rules/text-wrap-balance.js +3 -0
  266. package/dist/rules/text-wrap-balance.js.map +1 -1
  267. package/dist/rules/url-pattern.d.ts +3 -0
  268. package/dist/rules/url-pattern.d.ts.map +1 -0
  269. package/dist/rules/url-pattern.js +40 -0
  270. package/dist/rules/url-pattern.js.map +1 -0
  271. package/dist/rules/url-search-params.d.ts.map +1 -1
  272. package/dist/rules/url-search-params.js +1 -0
  273. package/dist/rules/url-search-params.js.map +1 -1
  274. package/dist/rules/web-animations.d.ts +3 -0
  275. package/dist/rules/web-animations.d.ts.map +1 -0
  276. package/dist/rules/web-animations.js +44 -0
  277. package/dist/rules/web-animations.js.map +1 -0
  278. package/dist/rules/web-crypto.d.ts.map +1 -1
  279. package/dist/rules/web-crypto.js +4 -0
  280. package/dist/rules/web-crypto.js.map +1 -1
  281. package/dist/rules/web-locks.d.ts +3 -0
  282. package/dist/rules/web-locks.d.ts.map +1 -0
  283. package/dist/rules/web-locks.js +39 -0
  284. package/dist/rules/web-locks.js.map +1 -0
  285. package/dist/rules/web-share.d.ts.map +1 -1
  286. package/dist/rules/web-share.js +3 -0
  287. package/dist/rules/web-share.js.map +1 -1
  288. package/dist/rules/with-resolvers.d.ts +3 -0
  289. package/dist/rules/with-resolvers.d.ts.map +1 -0
  290. package/dist/rules/with-resolvers.js +30 -0
  291. package/dist/rules/with-resolvers.js.map +1 -0
  292. package/dist/schema.d.ts +4 -0
  293. package/dist/schema.d.ts.map +1 -1
  294. package/dist/schema.js +34 -0
  295. package/dist/schema.js.map +1 -1
  296. package/dist/tier-diff.d.ts +55 -0
  297. package/dist/tier-diff.d.ts.map +1 -0
  298. package/dist/tier-diff.js +61 -0
  299. package/dist/tier-diff.js.map +1 -0
  300. package/package.json +1 -1
@@ -0,0 +1,34 @@
1
+ export const temporal = {
2
+ id: "temporal",
3
+ title: "Date arithmetic and time zones",
4
+ category: "formatting",
5
+ replaces: ["moment-timezone", "spacetime", "@js-joda/core", "js-joda"],
6
+ featureIds: ["temporal"],
7
+ native: "Temporal",
8
+ human: {
9
+ explainer: "These libraries exist because Date cannot do the job: it has no concept of a time zone beyond the host's, and adding a day across a daylight saving boundary gives the wrong answer. Temporal is the replacement, with ZonedDateTime carrying an IANA zone and arithmetic that respects it. It is not in every engine yet, so this is a plan rather than a deletion, and the honest move today is the official polyfill.",
10
+ snippet: `const meeting = Temporal.ZonedDateTime.from(
11
+ "2026-03-08T01:30:00-05:00[America/New_York]",
12
+ );
13
+
14
+ // Adds a calendar day, not 24 hours, so the DST change is handled.
15
+ meeting.add({ days: 1 }).toString();`,
16
+ mdnUrl: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal",
17
+ },
18
+ agent: {
19
+ when: "doing date arithmetic or working with named time zones",
20
+ unless: [
21
+ "You ship to Safari, or to any engine below Chrome {{chrome:temporal}} or Firefox {{firefox:temporal}}. Temporal is not available everywhere yet, so today this means adding @js-temporal/polyfill rather than removing a dependency, and that polyfill is larger than most of the libraries it would replace.",
22
+ "You only format dates for display. Intl.DateTimeFormat already does that everywhere, and the date-format rule covers it. Temporal is for the arithmetic.",
23
+ "You parse loose or non-ISO input. Temporal is deliberately strict and throws on anything ambiguous, which is the opposite of what moment was liked for.",
24
+ "You depend on moment-timezone's bundled zone database at a pinned version, for example to reproduce a historical calculation. Temporal reads the zone data the engine ships, which moves under you.",
25
+ "The codebase is on moment and the migration is the work. Two date libraries in one bundle is worse than one, so a partial migration costs more than either end state.",
26
+ ],
27
+ snippet: 'Temporal.ZonedDateTime.from("2026-03-08T01:30:00-05:00[America/New_York]").add({ days: 1 });',
28
+ handRolled: [
29
+ "a date rebuilt through UTC offsets with getTimezoneOffset, to move a timestamp into another zone",
30
+ "adding 86400000 milliseconds to a timestamp to mean tomorrow, which is an hour out on the two days a year the offset changes",
31
+ ],
32
+ },
33
+ };
34
+ //# sourceMappingURL=temporal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.js","sourceRoot":"","sources":["../../src/rules/temporal.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAS;IAC5B,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,gCAAgC;IACvC,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,iBAAiB,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,CAAC;IACtE,UAAU,EAAE,CAAC,UAAU,CAAC;IACxB,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE;QACL,SAAS,EACP,0ZAA0Z;QAC5Z,OAAO,EAAE;;;;;qCAKwB;QACjC,MAAM,EACJ,2FAA2F;KAC9F;IACD,KAAK,EAAE;QACL,IAAI,EAAE,wDAAwD;QAC9D,MAAM,EAAE;YACN,+SAA+S;YAC/S,0JAA0J;YAC1J,yJAAyJ;YACzJ,qMAAqM;YACrM,uKAAuK;SACxK;QACD,OAAO,EACL,8FAA8F;QAChG,UAAU,EAAE;YACV,kGAAkG;YAClG,8HAA8H;SAC/H;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"text-wrap-balance.d.ts","sourceRoot":"","sources":["../../src/rules/text-wrap-balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,eAAe,EAAE,IAoC7B,CAAC"}
1
+ {"version":3,"file":"text-wrap-balance.d.ts","sourceRoot":"","sources":["../../src/rules/text-wrap-balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,eAAe,EAAE,IAuC7B,CAAC"}
@@ -31,6 +31,9 @@ p {
31
31
  ],
32
32
  snippet: `h1, h2, h3 { text-wrap: balance; }
33
33
  p { text-wrap: pretty; }`,
34
+ handRolled: [
35
+ "inserting a br or a non-breaking space between the last two words of a heading so it does not orphan one",
36
+ ],
34
37
  },
35
38
  guides: ["improve-text-layout-and-legibility"],
36
39
  };
@@ -1 +1 @@
1
- {"version":3,"file":"text-wrap-balance.js","sourceRoot":"","sources":["../../src/rules/text-wrap-balance.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,mBAAmB;IACvB,KAAK,EAAE,mBAAmB;IAC1B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,qBAAqB,EAAE,cAAc,CAAC;IACjD,UAAU,EAAE,CAAC,mBAAmB,CAAC;IACjC,MAAM,EAAE,oBAAoB;IAC5B,KAAK,EAAE;QACL,SAAS,EACP,qbAAqb;QACvb,OAAO,EAAE;;;;;;;;;;;EAWX;QACE,MAAM,EAAE,4DAA4D;KACrE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,gFAAgF;QACtF,MAAM,EAAE;YACN,4JAA4J;YAC5J,mKAAmK;YACnK,gIAAgI;YAChI,gJAAgJ;SACjJ;QACD,OAAO,EAAE;yBACY;KACtB;IACD,MAAM,EAAE,CAAC,oCAAoC,CAAC;CAC/C,CAAC"}
1
+ {"version":3,"file":"text-wrap-balance.js","sourceRoot":"","sources":["../../src/rules/text-wrap-balance.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,mBAAmB;IACvB,KAAK,EAAE,mBAAmB;IAC1B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,qBAAqB,EAAE,cAAc,CAAC;IACjD,UAAU,EAAE,CAAC,mBAAmB,CAAC;IACjC,MAAM,EAAE,oBAAoB;IAC5B,KAAK,EAAE;QACL,SAAS,EACP,qbAAqb;QACvb,OAAO,EAAE;;;;;;;;;;;EAWX;QACE,MAAM,EAAE,4DAA4D;KACrE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,gFAAgF;QACtF,MAAM,EAAE;YACN,4JAA4J;YAC5J,mKAAmK;YACnK,gIAAgI;YAChI,gJAAgJ;SACjJ;QACD,OAAO,EAAE;yBACY;QACrB,UAAU,EAAE;YACV,0GAA0G;SAC3G;KACF;IACD,MAAM,EAAE,CAAC,oCAAoC,CAAC;CAC/C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "../schema.ts";
2
+ export declare const urlPattern: Rule;
3
+ //# sourceMappingURL=url-pattern.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-pattern.d.ts","sourceRoot":"","sources":["../../src/rules/url-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,UAAU,EAAE,IAuCxB,CAAC"}
@@ -0,0 +1,40 @@
1
+ export const urlPattern = {
2
+ id: "urlpattern",
3
+ title: "Matching URL patterns",
4
+ category: "async-data",
5
+ replaces: ["path-to-regexp", "url-pattern", "route-parser"],
6
+ featureIds: ["urlpattern"],
7
+ native: "URLPattern",
8
+ human: {
9
+ explainer: 'These libraries compile a route string such as "/users/:id" into a regular expression and hand back the named groups when it matches. URLPattern is that same idea built in, with one extra: it matches every part of a URL, so protocol, hostname and search can take part in the pattern rather than only the path. A match returns an object keyed by URL part, each with its own groups.',
10
+ snippet: `const pattern = new URLPattern({ pathname: "/users/:id/posts/:postId" });
11
+
12
+ pattern.test("https://example.com/users/42/posts/7"); // true
13
+
14
+ const match = pattern.exec("https://example.com/users/42/posts/7");
15
+ match.pathname.groups; // { id: "42", postId: "7" }
16
+
17
+ // Other parts of the URL can take part too.
18
+ new URLPattern({ hostname: ":tenant.example.com" })
19
+ .exec("https://acme.example.com/")
20
+ .hostname.groups; // { tenant: "acme" }`,
21
+ mdnUrl: "https://developer.mozilla.org/en-US/docs/Web/API/URLPattern",
22
+ },
23
+ agent: {
24
+ when: "matching a URL against a route pattern and reading the named parameters",
25
+ unless: [
26
+ 'You build URLs from the pattern as well as matching them. path-to-regexp\'s compile() turns "/users/:id" plus params back into a path, and URLPattern only goes in the matching direction.',
27
+ "You are replacing the matcher inside a router you do not control. Express and React Router depend on path-to-regexp directly, so it stays in the tree regardless of what your own code uses.",
28
+ "Your routes rely on path-to-regexp syntax that does not carry over, such as its custom match patterns or its handling of unnamed groups. The two syntaxes are close enough to look interchangeable and different enough to break quietly.",
29
+ "The code runs on a server runtime that has no URLPattern global, which is the case for Node before it shipped one.",
30
+ ],
31
+ snippet: `const pattern = new URLPattern({ pathname: "/users/:id" });
32
+ const match = pattern.exec(url);
33
+ const id = match?.pathname.groups.id;`,
34
+ handRolled: [
35
+ "a hand-written regex per route with named capture groups, and a loop testing each against the path",
36
+ 'pathname.split("/") compared segment by segment to work out which route matched and pull out an id',
37
+ ],
38
+ },
39
+ };
40
+ //# sourceMappingURL=url-pattern.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-pattern.js","sourceRoot":"","sources":["../../src/rules/url-pattern.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,UAAU,GAAS;IAC9B,EAAE,EAAE,YAAY;IAChB,KAAK,EAAE,uBAAuB;IAC9B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,gBAAgB,EAAE,aAAa,EAAE,cAAc,CAAC;IAC3D,UAAU,EAAE,CAAC,YAAY,CAAC;IAC1B,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE;QACL,SAAS,EACP,8XAA8X;QAChY,OAAO,EAAE;;;;;;;;;;0CAU6B;QACtC,MAAM,EAAE,6DAA6D;KACtE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,yEAAyE;QAC/E,MAAM,EAAE;YACN,4LAA4L;YAC5L,8LAA8L;YAC9L,2OAA2O;YAC3O,oHAAoH;SACrH;QACD,OAAO,EAAE;;sCAEyB;QAClC,UAAU,EAAE;YACV,oGAAoG;YACpG,oGAAoG;SACrG;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"url-search-params.d.ts","sourceRoot":"","sources":["../../src/rules/url-search-params.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,eAAe,EAAE,IAyC7B,CAAC"}
1
+ {"version":3,"file":"url-search-params.d.ts","sourceRoot":"","sources":["../../src/rules/url-search-params.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,eAAe,EAAE,IA0C7B,CAAC"}
@@ -38,5 +38,6 @@ params.get("page");
38
38
  params.getAll("tag");
39
39
  new URLSearchParams({ q: "css" }).toString();`,
40
40
  },
41
+ lintRule: "unicorn/prefer-url-search-parameters",
41
42
  };
42
43
  //# sourceMappingURL=url-search-params.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-search-params.js","sourceRoot":"","sources":["../../src/rules/url-search-params.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,mBAAmB;IACvB,KAAK,EAAE,sBAAsB;IAC7B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC/D,UAAU,EAAE,EAAE;IACd,cAAc,EAAE;QACd,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE,YAAY;QACxB,IAAI,EAAE,6aAA6a;KACpb;IACD,MAAM,EAAE,yCAAyC;IACjD,KAAK,EAAE;QACL,SAAS,EACP,ybAAyb;QAC3b,OAAO,EAAE;;;;;;;;0BAQa;QACtB,MAAM,EAAE,kEAAkE;KAC3E;IACD,KAAK,EAAE;QACL,IAAI,EAAE,4DAA4D;QAClE,MAAM,EAAE;YACN,4JAA4J;YAC5J,0JAA0J;YAC1J,oJAAoJ;YACpJ,mKAAmK;YACnK,iHAAiH;YACjH,6QAA6Q;SAC9Q;QACD,OAAO,EAAE;;;8CAGiC;KAC3C;CACF,CAAC"}
1
+ {"version":3,"file":"url-search-params.js","sourceRoot":"","sources":["../../src/rules/url-search-params.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,EAAE,EAAE,mBAAmB;IACvB,KAAK,EAAE,sBAAsB;IAC7B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,WAAW,CAAC;IAC/D,UAAU,EAAE,EAAE;IACd,cAAc,EAAE;QACd,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE,YAAY;QACxB,IAAI,EAAE,6aAA6a;KACpb;IACD,MAAM,EAAE,yCAAyC;IACjD,KAAK,EAAE;QACL,SAAS,EACP,ybAAyb;QAC3b,OAAO,EAAE;;;;;;;;0BAQa;QACtB,MAAM,EAAE,kEAAkE;KAC3E;IACD,KAAK,EAAE;QACL,IAAI,EAAE,4DAA4D;QAClE,MAAM,EAAE;YACN,4JAA4J;YAC5J,0JAA0J;YAC1J,oJAAoJ;YACpJ,mKAAmK;YACnK,iHAAiH;YACjH,6QAA6Q;SAC9Q;QACD,OAAO,EAAE;;;8CAGiC;KAC3C;IACD,QAAQ,EAAE,sCAAsC;CACjD,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "../schema.ts";
2
+ export declare const webAnimations: Rule;
3
+ //# sourceMappingURL=web-animations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-animations.d.ts","sourceRoot":"","sources":["../../src/rules/web-animations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,aAAa,EAAE,IA4C3B,CAAC"}
@@ -0,0 +1,44 @@
1
+ export const webAnimations = {
2
+ id: "web-animations",
3
+ title: "Animating from JavaScript",
4
+ category: "animation",
5
+ replaces: ["animejs", "popmotion", "velocity-animate"],
6
+ featureIds: ["web-animations"],
7
+ native: "element.animate()",
8
+ human: {
9
+ explainer: "These libraries run their own tick loop, working out each frame's values in JavaScript and writing them to the element's style. element.animate() hands the same keyframes to the engine that already runs CSS animations, so transforms and opacity are animated off the main thread and keep going while JavaScript is busy. It returns an Animation with play, pause, reverse, cancel and finish on it, plus a finished promise to await.",
10
+ snippet: `const animation = card.animate(
11
+ [
12
+ { transform: "translateY(12px)", opacity: 0 },
13
+ { transform: "none", opacity: 1 },
14
+ ],
15
+ { duration: 240, easing: "cubic-bezier(0.2, 0, 0, 1)", fill: "both" },
16
+ );
17
+
18
+ await animation.finished;
19
+
20
+ // The same handle drives it afterwards.
21
+ animation.reverse();`,
22
+ mdnUrl: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API",
23
+ },
24
+ agent: {
25
+ when: "animating an element's styles from JavaScript and needing a handle to control it",
26
+ unless: [
27
+ "You animate something that is not a CSS property on an element: a number in a counter, a canvas, a scroll offset, an SVG path's shape. anime.js animates arbitrary object properties, where element.animate() only writes styles.",
28
+ "The motion is spring-based or driven by a gesture's velocity. Web Animations takes a duration and an easing curve, so anything that has to respond to how fast a finger was moving is still the library's job.",
29
+ "You sequence many elements on one timeline with staggers and relative offsets. That timeline is the reason a lot of people install anime.js, and composing it by hand means computing every delay yourself.",
30
+ "A plain CSS transition or @keyframes would do. Reaching for element.animate() to fade one element in trades a declarative rule for a script that has to run first.",
31
+ "You animate to an intrinsic size such as height: auto, which is interpolate-size and calc-size rather than either approach here.",
32
+ ],
33
+ snippet: `const animation = card.animate(
34
+ [{ opacity: 0 }, { opacity: 1 }],
35
+ { duration: 240, fill: "both" },
36
+ );
37
+ await animation.finished;`,
38
+ handRolled: [
39
+ "a requestAnimationFrame loop interpolating a style property between two values, with its own easing function",
40
+ "a chain of setTimeout calls stepping an element's style to fake a keyframe sequence",
41
+ ],
42
+ },
43
+ };
44
+ //# sourceMappingURL=web-animations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-animations.js","sourceRoot":"","sources":["../../src/rules/web-animations.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAS;IACjC,EAAE,EAAE,gBAAgB;IACpB,KAAK,EAAE,2BAA2B;IAClC,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,CAAC,SAAS,EAAE,WAAW,EAAE,kBAAkB,CAAC;IACtD,UAAU,EAAE,CAAC,gBAAgB,CAAC;IAC9B,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE;QACL,SAAS,EACP,8aAA8a;QAChb,OAAO,EAAE;;;;;;;;;;;qBAWQ;QACjB,MAAM,EACJ,qEAAqE;KACxE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,kFAAkF;QACxF,MAAM,EAAE;YACN,mOAAmO;YACnO,gNAAgN;YAChN,6MAA6M;YAC7M,oKAAoK;YACpK,kIAAkI;SACnI;QACD,OAAO,EAAE;;;;0BAIa;QACtB,UAAU,EAAE;YACV,8GAA8G;YAC9G,qFAAqF;SACtF;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-crypto.d.ts","sourceRoot":"","sources":["../../src/rules/web-crypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,SAAS,EAAE,IA+BvB,CAAC"}
1
+ {"version":3,"file":"web-crypto.d.ts","sourceRoot":"","sources":["../../src/rules/web-crypto.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,SAAS,EAAE,IAmCvB,CAAC"}
@@ -27,6 +27,10 @@ export const webCrypto = {
27
27
  ],
28
28
  snippet: `const bytes = new TextEncoder().encode(text);
29
29
  const digest = await crypto.subtle.digest("SHA-256", bytes);`,
30
+ handRolled: [
31
+ "a session token, nonce or password-reset key built from Math.random(), which is not a cryptographic source and is predictable from earlier outputs",
32
+ "a SHA-256 or HMAC implementation pasted into the project as a single file of bit-shifting helpers",
33
+ ],
30
34
  },
31
35
  };
32
36
  //# sourceMappingURL=web-crypto.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-crypto.js","sourceRoot":"","sources":["../../src/rules/web-crypto.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAS;IAC7B,EAAE,EAAE,YAAY;IAChB,KAAK,EAAE,wBAAwB;IAC/B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,aAAa,CAAC;IACnD,UAAU,EAAE,CAAC,kBAAkB,CAAC;IAChC,MAAM,EAAE,eAAe;IACvB,KAAK,EAAE;QACL,SAAS,EACP,qbAAqb;QACvb,OAAO,EAAE;;;;;;EAMX;QACE,MAAM,EAAE,+DAA+D;KACxE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,8DAA8D;QACpE,MAAM,EAAE;YACN,yJAAyJ;YACzJ,kKAAkK;YAClK,kHAAkH;YAClH,2KAA2K;YAC3K,wJAAwJ;SACzJ;QACD,OAAO,EAAE;6DACgD;KAC1D;CACF,CAAC"}
1
+ {"version":3,"file":"web-crypto.js","sourceRoot":"","sources":["../../src/rules/web-crypto.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAS;IAC7B,EAAE,EAAE,YAAY;IAChB,KAAK,EAAE,wBAAwB;IAC/B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,aAAa,CAAC;IACnD,UAAU,EAAE,CAAC,kBAAkB,CAAC;IAChC,MAAM,EAAE,eAAe;IACvB,KAAK,EAAE;QACL,SAAS,EACP,qbAAqb;QACvb,OAAO,EAAE;;;;;;EAMX;QACE,MAAM,EAAE,+DAA+D;KACxE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,8DAA8D;QACpE,MAAM,EAAE;YACN,yJAAyJ;YACzJ,kKAAkK;YAClK,kHAAkH;YAClH,2KAA2K;YAC3K,wJAAwJ;SACzJ;QACD,OAAO,EAAE;6DACgD;QACzD,UAAU,EAAE;YACV,oJAAoJ;YACpJ,mGAAmG;SACpG;KACF;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "../schema.ts";
2
+ export declare const webLocks: Rule;
3
+ //# sourceMappingURL=web-locks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-locks.d.ts","sourceRoot":"","sources":["../../src/rules/web-locks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,QAAQ,EAAE,IAsCtB,CAAC"}
@@ -0,0 +1,39 @@
1
+ export const webLocks = {
2
+ id: "web-locks",
3
+ title: "Mutexes and critical sections",
4
+ category: "async-data",
5
+ replaces: ["async-mutex", "await-lock", "mutexify", "p-mutex"],
6
+ featureIds: ["web-locks"],
7
+ native: "navigator.locks.request()",
8
+ human: {
9
+ explainer: "These packages stop two callers entering the same critical section at once by queueing them behind a promise chain held in module memory. navigator.locks.request() does the same queueing, with one difference that decides whether it fits: the browser owns the lock, so it also serialises across every tab, iframe and worker on the origin. The lock is released when your callback's promise settles, including when it throws, so there is no release() to forget.",
10
+ snippet: `await navigator.locks.request("sync-outbox", async () => {
11
+ await flushPendingWrites();
12
+ });
13
+
14
+ // Many readers, one writer, same as a read/write lock.
15
+ await navigator.locks.request("cache", { mode: "shared" }, async () => {
16
+ return readCache();
17
+ });`,
18
+ mdnUrl: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Locks_API",
19
+ },
20
+ agent: {
21
+ when: "serialising async work so two callers cannot run the same section at once",
22
+ unless: [
23
+ "The code also runs on the server. navigator.locks is a browser API, so anything shared with Node keeps the library. This is the common case for code under a framework that renders on both.",
24
+ "You want the lock scoped to your module. Lock names are strings shared by the whole origin, so an unrelated script picking the same name now blocks you, and a name like 'lock' or 'queue' is a collision waiting to happen. An async-mutex instance is private to whoever holds the reference.",
25
+ "You need a semaphore that admits more than one holder at a time. Web Locks offers exclusive and shared only, where async-mutex ships a counting Semaphore.",
26
+ "The same task can request a lock it already holds. Web Locks is not reentrant, so a nested request for the same name waits for a release that cannot happen until the nested call returns.",
27
+ "The page runs on an opaque origin or outside a secure context: a sandboxed iframe without allow-same-origin, a data: or blob: document, or plain http away from localhost. navigator.locks is still present there, so a presence check passes and request() then rejects with a SecurityError. async-mutex has no such limit.",
28
+ "You support browsers below Chrome {{chrome:web-locks}}, Firefox {{firefox:web-locks}} or Safari {{safari:web-locks}}, and calling into an undefined navigator.locks throws rather than degrading.",
29
+ ],
30
+ snippet: `await navigator.locks.request("sync-outbox", async () => {
31
+ await flushPendingWrites();
32
+ });`,
33
+ handRolled: [
34
+ "a boolean flag guarding an async section, set before the work and cleared in a finally",
35
+ "a promise chained onto the previous one in a module-level variable, so calls run one at a time",
36
+ ],
37
+ },
38
+ };
39
+ //# sourceMappingURL=web-locks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-locks.js","sourceRoot":"","sources":["../../src/rules/web-locks.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAS;IAC5B,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,+BAA+B;IACtC,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,CAAC;IAC9D,UAAU,EAAE,CAAC,WAAW,CAAC;IACzB,MAAM,EAAE,2BAA2B;IACnC,KAAK,EAAE;QACL,SAAS,EACP,4cAA4c;QAC9c,OAAO,EAAE;;;;;;;IAOT;QACA,MAAM,EAAE,gEAAgE;KACzE;IACD,KAAK,EAAE;QACL,IAAI,EAAE,2EAA2E;QACjF,MAAM,EAAE;YACN,8LAA8L;YAC9L,iSAAiS;YACjS,4JAA4J;YAC5J,4LAA4L;YAC5L,+TAA+T;YAC/T,mMAAmM;SACpM;QACD,OAAO,EAAE;;IAET;QACA,UAAU,EAAE;YACV,wFAAwF;YACxF,gGAAgG;SACjG;KACF;CACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"web-share.d.ts","sourceRoot":"","sources":["../../src/rules/web-share.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,QAAQ,EAAE,IA4BtB,CAAC"}
1
+ {"version":3,"file":"web-share.d.ts","sourceRoot":"","sources":["../../src/rules/web-share.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,QAAQ,EAAE,IA+BtB,CAAC"}
@@ -23,6 +23,9 @@ export const webShare = {
23
23
  "You need to share a file the person doesn't already have a URL for. That needs the file-sharing variant of the API, which has narrower browser support again.",
24
24
  ],
25
25
  snippet: "await navigator.share({ title: document.title, url: location.href });",
26
+ handRolled: [
27
+ "a share menu built from hardcoded intent URLs for each network, opened with window.open",
28
+ ],
26
29
  },
27
30
  };
28
31
  //# sourceMappingURL=web-share.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"web-share.js","sourceRoot":"","sources":["../../src/rules/web-share.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAS;IAC5B,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,uBAAuB;IAC9B,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,CAAC,aAAa,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;IACnE,UAAU,EAAE,CAAC,OAAO,CAAC;IACrB,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE;QACL,SAAS,EACP,kSAAkS;QACpS,OAAO,EAAE;;;;;EAKX;QACE,MAAM,EAAE,kEAAkE;KAC3E;IACD,KAAK,EAAE;QACL,IAAI,EAAE,0FAA0F;QAChG,MAAM,EAAE;YACN,kLAAkL;YAClL,yFAAyF;YACzF,+JAA+J;SAChK;QACD,OAAO,EACL,uEAAuE;KAC1E;CACF,CAAC"}
1
+ {"version":3,"file":"web-share.js","sourceRoot":"","sources":["../../src/rules/web-share.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAS;IAC5B,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,uBAAuB;IAC9B,QAAQ,EAAE,aAAa;IACvB,QAAQ,EAAE,CAAC,aAAa,EAAE,oBAAoB,EAAE,kBAAkB,CAAC;IACnE,UAAU,EAAE,CAAC,OAAO,CAAC;IACrB,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE;QACL,SAAS,EACP,kSAAkS;QACpS,OAAO,EAAE;;;;;EAKX;QACE,MAAM,EAAE,kEAAkE;KAC3E;IACD,KAAK,EAAE;QACL,IAAI,EAAE,0FAA0F;QAChG,MAAM,EAAE;YACN,kLAAkL;YAClL,yFAAyF;YACzF,+JAA+J;SAChK;QACD,OAAO,EACL,uEAAuE;QACzE,UAAU,EAAE;YACV,yFAAyF;SAC1F;KACF;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from "../schema.ts";
2
+ export declare const withResolvers: Rule;
3
+ //# sourceMappingURL=with-resolvers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-resolvers.d.ts","sourceRoot":"","sources":["../../src/rules/with-resolvers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC,eAAO,MAAM,aAAa,EAAE,IA8B3B,CAAC"}
@@ -0,0 +1,30 @@
1
+ export const withResolvers = {
2
+ id: "promise-withresolvers",
3
+ title: "Deferred promises",
4
+ category: "async-data",
5
+ replaces: ["p-defer", "defer-promise"],
6
+ featureIds: ["promise-withresolvers"],
7
+ native: "Promise.withResolvers()",
8
+ human: {
9
+ explainer: "A deferred is a promise with its resolve and reject pulled out, so something outside the executor can settle it later. Writing one by hand means declaring two variables, assigning them inside a new Promise, and trusting that the executor ran first. Promise.withResolvers() returns the promise and both functions in one object, which is the whole of what these packages do.",
10
+ snippet: `const { promise, resolve, reject } = Promise.withResolvers();
11
+
12
+ socket.addEventListener("message", (event) => resolve(event.data));
13
+ socket.addEventListener("error", reject);
14
+
15
+ const firstMessage = await promise;`,
16
+ mdnUrl: "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers",
17
+ },
18
+ agent: {
19
+ when: "creating a promise that something else will resolve or reject later",
20
+ unless: [
21
+ "The promise can settle inside its own executor. A deferred passed around is often a sign the async boundary sits in the wrong place, and starting the work inside new Promise needs neither this nor the package.",
22
+ "The package arrived as a transitive dependency. p-defer is pulled in by a good deal of the sindresorhus ecosystem, so removing your own import may not remove it from the tree.",
23
+ "You support browsers below Chrome {{chrome:promise-withresolvers}}, Firefox {{firefox:promise-withresolvers}} or Safari {{safari:promise-withresolvers}}, or a server runtime that predates it.",
24
+ "You need more than the three fields, such as a settled flag or a timeout, in which case you are writing a small class and the package is not what it costs.",
25
+ ],
26
+ snippet: "const { promise, resolve, reject } = Promise.withResolvers();",
27
+ },
28
+ lintRule: "unicorn/prefer-promise-with-resolvers",
29
+ };
30
+ //# sourceMappingURL=with-resolvers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-resolvers.js","sourceRoot":"","sources":["../../src/rules/with-resolvers.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAS;IACjC,EAAE,EAAE,uBAAuB;IAC3B,KAAK,EAAE,mBAAmB;IAC1B,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE,CAAC,SAAS,EAAE,eAAe,CAAC;IACtC,UAAU,EAAE,CAAC,uBAAuB,CAAC;IACrC,MAAM,EAAE,yBAAyB;IACjC,KAAK,EAAE;QACL,SAAS,EACP,sXAAsX;QACxX,OAAO,EAAE;;;;;oCAKuB;QAChC,MAAM,EACJ,wGAAwG;KAC3G;IACD,KAAK,EAAE;QACL,IAAI,EAAE,qEAAqE;QAC3E,MAAM,EAAE;YACN,mNAAmN;YACnN,iLAAiL;YACjL,iMAAiM;YACjM,6JAA6J;SAC9J;QACD,OAAO,EAAE,+DAA+D;KACzE;IACD,QAAQ,EAAE,uCAAuC;CAClD,CAAC"}
package/dist/schema.d.ts CHANGED
@@ -59,8 +59,10 @@ export declare const ruleSchema: z.ZodObject<{
59
59
  when: z.ZodString;
60
60
  unless: z.ZodArray<z.ZodString>;
61
61
  snippet: z.ZodString;
62
+ handRolled: z.ZodOptional<z.ZodArray<z.ZodString>>;
62
63
  }, z.core.$strip>;
63
64
  guides: z.ZodOptional<z.ZodArray<z.ZodString>>;
65
+ lintRule: z.ZodOptional<z.ZodString>;
64
66
  manualBaseline: z.ZodOptional<z.ZodObject<{
65
67
  status: z.ZodEnum<{
66
68
  limited: "limited";
@@ -98,8 +100,10 @@ export declare const catalogSchema: z.ZodArray<z.ZodObject<{
98
100
  when: z.ZodString;
99
101
  unless: z.ZodArray<z.ZodString>;
100
102
  snippet: z.ZodString;
103
+ handRolled: z.ZodOptional<z.ZodArray<z.ZodString>>;
101
104
  }, z.core.$strip>;
102
105
  guides: z.ZodOptional<z.ZodArray<z.ZodString>>;
106
+ lintRule: z.ZodOptional<z.ZodString>;
103
107
  manualBaseline: z.ZodOptional<z.ZodObject<{
104
108
  status: z.ZodEnum<{
105
109
  limited: "limited";
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;GAIG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;EAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAmDlE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;iBAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+FnB,CAAC;AAEL,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2BxB,CAAC;AAEH,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,EAAE,CAEnD"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;GAIG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB;;;;;EAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAmDlE;;;;GAIG;AACH,eAAO,MAAM,oBAAoB;;;;;;;;iBAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqInB,CAAC;AAEL,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA2BxB,CAAC;AAEH,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,EAAE,CAEnD"}
package/dist/schema.js CHANGED
@@ -120,6 +120,22 @@ export const ruleSchema = z
120
120
  .array(z.string().min(1))
121
121
  .min(1, "every rule must state when the dependency is still correct"),
122
122
  snippet: z.string().min(1),
123
+ /**
124
+ * Shapes someone writes by hand instead of using the native feature,
125
+ * one short description each.
126
+ *
127
+ * This is the half of the problem `replaces` cannot see. A hand-written
128
+ * focus trap installs nothing, so no package.json match can ever fire,
129
+ * and the shapes worth naming here are multi-line and stateful, which is
130
+ * why no linter has them either. Where a linter does cover the shape,
131
+ * name it in `lintRule` instead: this field is for the ones that need a
132
+ * person or a model to recognise.
133
+ *
134
+ * Prose, deliberately, and read rather than matched. An agent compares
135
+ * what it is looking at against these, then reads `unless` before
136
+ * deciding, the same as for any other finding.
137
+ */
138
+ handRolled: z.array(z.string().min(1)).min(1).optional(),
123
139
  }),
124
140
  /**
125
141
  * IDs of GoogleChrome/modern-web-guidance guides that cover the
@@ -130,6 +146,24 @@ export const ruleSchema = z
130
146
  * is renamed upstream fails a test instead of shipping as a dead link.
131
147
  */
132
148
  guides: z.array(slug).optional(),
149
+ /**
150
+ * A lint rule that already checks this shape, as `<prefix>/<name>`, e.g.
151
+ * `unicorn/prefer-structured-clone`.
152
+ *
153
+ * Same philosophy as `guides`: references, never copies. Where a linter
154
+ * checks something mechanically, this catalog says so and points at it
155
+ * rather than growing a second implementation of the same check. It also
156
+ * tells a reader which migrations they can automate today and which need
157
+ * judgment, which is a question nothing else answers.
158
+ *
159
+ * Resolved against the snapshot in generated/lint-rules.ts, so a rule
160
+ * renamed upstream fails the freshness check instead of shipping as a dead
161
+ * link.
162
+ */
163
+ lintRule: z
164
+ .string()
165
+ .regex(/^[a-z0-9-]+\/[a-z0-9-]+$/, "expected a lint rule as <prefix>/<name>")
166
+ .optional(),
133
167
  manualBaseline: manualBaselineSchema.optional(),
134
168
  })
135
169
  .superRefine((rule, ctx) => {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { BaselineStatus } from "./schema.ts";
2
+ /**
3
+ * Compares two Baseline snapshots and says which rules changed tier.
4
+ *
5
+ * Pure, and deliberately takes plain maps rather than reaching for
6
+ * `web-features` itself: the caller holds the committed snapshot and the live
7
+ * package, and this only has to know how to subtract one from the other. That
8
+ * keeps it inside the same purity walk as the rest of the catalog and makes
9
+ * it testable without a network or a filesystem.
10
+ */
11
+ /** The shape both the committed snapshot and web-features agree on. */
12
+ export interface TierEntry {
13
+ baseline: "high" | "low" | false;
14
+ }
15
+ /** web-features' own shape, named so callers need no positional cast. */
16
+ export type LiveFeatures = Readonly<Record<string, {
17
+ status?: {
18
+ baseline?: "high" | "low" | false;
19
+ };
20
+ }>>;
21
+ export type TierDirection = "promotion" | "regression" | "missing";
22
+ interface TierChangeBase {
23
+ ruleId: string;
24
+ featureId: string;
25
+ from: BaselineStatus;
26
+ }
27
+ /**
28
+ * A discriminated union rather than a nullable `to`, because "gone from the
29
+ * live data" has no destination tier and a shared shape forces every consumer
30
+ * to write a null branch it can never reach. Narrowing on `direction` hands
31
+ * the report builder a `to` it can print without checking.
32
+ */
33
+ export type TierChange = (TierChangeBase & {
34
+ direction: "promotion" | "regression";
35
+ to: BaselineStatus;
36
+ }) | (TierChangeBase & {
37
+ direction: "missing";
38
+ });
39
+ export declare function tierOf(baseline: "high" | "low" | false | undefined): BaselineStatus;
40
+ /**
41
+ * Every tier move among the features some rule actually requires.
42
+ *
43
+ * A feature present in the committed snapshot and absent from the live data
44
+ * is reported as `missing` rather than skipped. That is what an upstream
45
+ * rename looks like, and skipping it would drop the one case most likely to
46
+ * need a person: the rule keeps rendering a tier from a feature ID that no
47
+ * longer exists, and `check:freshness` only fails once the snapshot is
48
+ * regenerated without it.
49
+ */
50
+ export declare function diffTiers(rules: readonly {
51
+ id: string;
52
+ featureIds: readonly string[];
53
+ }[], committed: Readonly<Record<string, TierEntry>>, live: LiveFeatures): TierChange[];
54
+ export {};
55
+ //# sourceMappingURL=tier-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tier-diff.d.ts","sourceRoot":"","sources":["../src/tier-diff.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AAEH,uEAAuE;AACvE,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;CAClC;AAED,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG,QAAQ,CACjC,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAA;KAAE,CAAA;CAAE,CAAC,CACnE,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,CAAC;AAEnE,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,cAAc,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAClB,CAAC,cAAc,GAAG;IAChB,SAAS,EAAE,WAAW,GAAG,YAAY,CAAC;IACtC,EAAE,EAAE,cAAc,CAAC;CACpB,CAAC,GACF,CAAC,cAAc,GAAG;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,CAAC,CAAC;AAUhD,wBAAgB,MAAM,CACpB,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAC3C,cAAc,CAKhB;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,EAC/D,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,EAC9C,IAAI,EAAE,YAAY,GACjB,UAAU,EAAE,CAMd"}
@@ -0,0 +1,61 @@
1
+ /** Higher is better supported, so a rise in rank is a promotion. */
2
+ const RANK = {
3
+ unknown: 0,
4
+ limited: 1,
5
+ newly: 2,
6
+ widely: 3,
7
+ };
8
+ export function tierOf(baseline) {
9
+ if (baseline === "high")
10
+ return "widely";
11
+ if (baseline === "low")
12
+ return "newly";
13
+ if (baseline === false)
14
+ return "limited";
15
+ return "unknown";
16
+ }
17
+ /**
18
+ * Every tier move among the features some rule actually requires.
19
+ *
20
+ * A feature present in the committed snapshot and absent from the live data
21
+ * is reported as `missing` rather than skipped. That is what an upstream
22
+ * rename looks like, and skipping it would drop the one case most likely to
23
+ * need a person: the rule keeps rendering a tier from a feature ID that no
24
+ * longer exists, and `check:freshness` only fails once the snapshot is
25
+ * regenerated without it.
26
+ */
27
+ export function diffTiers(rules, committed, live) {
28
+ return rules.flatMap((rule) => rule.featureIds
29
+ .map((featureId) => compare(rule.id, featureId, committed, live))
30
+ .filter((change) => change !== null));
31
+ }
32
+ /** One feature of one rule, or null when there is nothing to report. */
33
+ function compare(ruleId, featureId, committed, live) {
34
+ // One lookup each, rather than a presence check plus a cast undoing what
35
+ // the check established. Neither the generated snapshot nor web-features
36
+ // sets a key to an explicit undefined, so the two read the same.
37
+ const entry = committed[featureId];
38
+ if (entry === undefined)
39
+ return null;
40
+ const from = tierOf(entry.baseline);
41
+ const liveEntry = live[featureId];
42
+ if (liveEntry === undefined) {
43
+ return { ruleId, featureId, direction: "missing", from };
44
+ }
45
+ // `?? false` to match how refresh-baseline.ts writes the snapshot. A
46
+ // feature web-features publishes with no status at all, masonry today,
47
+ // becomes `false` there and would read as `unknown` here, so the two
48
+ // disagreed by construction and the report opened with a regression that
49
+ // was never real. Read it the same way the writer does.
50
+ const to = tierOf(liveEntry.status?.baseline ?? false);
51
+ if (to === from)
52
+ return null;
53
+ return {
54
+ ruleId,
55
+ featureId,
56
+ direction: RANK[to] > RANK[from] ? "promotion" : "regression",
57
+ from,
58
+ to,
59
+ };
60
+ }
61
+ //# sourceMappingURL=tier-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tier-diff.js","sourceRoot":"","sources":["../src/tier-diff.ts"],"names":[],"mappings":"AA2CA,oEAAoE;AACpE,MAAM,IAAI,GAAmC;IAC3C,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,MAAM,EAAE,CAAC;CACV,CAAC;AAEF,MAAM,UAAU,MAAM,CACpB,QAA4C;IAE5C,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,QAAQ,CAAC;IACzC,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,SAAS,CAAC;IACzC,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CACvB,KAA+D,EAC/D,SAA8C,EAC9C,IAAkB;IAElB,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAC5B,IAAI,CAAC,UAAU;SACZ,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;SAChE,MAAM,CAAC,CAAC,MAAM,EAAwB,EAAE,CAAC,MAAM,KAAK,IAAI,CAAC,CAC7D,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,SAAS,OAAO,CACd,MAAc,EACd,SAAiB,EACjB,SAA8C,EAC9C,IAAkB;IAElB,yEAAyE;IACzE,yEAAyE;IACzE,iEAAiE;IACjE,MAAM,KAAK,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAEpC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;IAClC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC3D,CAAC;IAED,qEAAqE;IACrE,uEAAuE;IACvE,qEAAqE;IACrE,yEAAyE;IACzE,wDAAwD;IACxD,MAAM,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,IAAI,KAAK,CAAC,CAAC;IACvD,IAAI,EAAE,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAE7B,OAAO;QACL,MAAM;QACN,SAAS;QACT,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY;QAC7D,IAAI;QACJ,EAAE;KACH,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jomae/catalog",
3
- "version": "0.7.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "The rule catalog behind youmightnotneed. Maps npm packages to the CSS, HTML, or Web API that replaces them.",
6
6
  "license": "MIT",