@depup/webpack 5.110.3-depup.0 → 5.111.1-depup.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 (283) hide show
  1. package/README.md +7 -8
  2. package/changes.json +7 -11
  3. package/lib/APIPlugin.js +26 -11
  4. package/lib/AutomaticPrefetchPlugin.js +1 -1
  5. package/lib/Cache.js +8 -3
  6. package/lib/CacheFacade.js +1 -1
  7. package/lib/CircularModulesPlugin.js +157 -55
  8. package/lib/CleanPlugin.js +2 -2
  9. package/lib/CompatibilityPlugin.js +3 -4
  10. package/lib/Compilation.js +336 -337
  11. package/lib/Compiler.js +213 -51
  12. package/lib/ConstPlugin.js +16 -132
  13. package/lib/CopyPlugin.js +1054 -0
  14. package/lib/DefinePlugin.js +24 -8
  15. package/lib/DependencyTemplate.js +2 -1
  16. package/lib/DotenvPlugin.js +24 -28
  17. package/lib/ErrorHelpers.js +113 -0
  18. package/lib/ExportsInfo.js +20 -16
  19. package/lib/ExternalModule.js +47 -22
  20. package/lib/FileSystemInfo.js +17 -14
  21. package/lib/FlagDependencyExportsPlugin.js +53 -34
  22. package/lib/FlagDependencyUsagePlugin.js +9 -13
  23. package/lib/Generator.js +24 -2
  24. package/lib/HotModuleReplacementPlugin.js +55 -7
  25. package/lib/IgnorePlugin.js +1 -1
  26. package/lib/JavascriptMetaInfoPlugin.js +5 -3
  27. package/lib/LoaderOptionsPlugin.js +1 -1
  28. package/lib/MainTemplate.js +5 -1
  29. package/lib/Module.js +19 -10
  30. package/lib/ModuleGraph.js +6 -9
  31. package/lib/MultiCompiler.js +7 -17
  32. package/lib/MultiWatching.js +1 -1
  33. package/lib/NormalModule.js +135 -50
  34. package/lib/NormalModuleFactory.js +1 -1
  35. package/lib/RuntimeGlobals.js +21 -7
  36. package/lib/RuntimeModule.js +28 -12
  37. package/lib/RuntimePlugin.js +30 -3
  38. package/lib/RuntimeTemplate.js +813 -518
  39. package/lib/SourceMapDevToolPlugin.js +54 -104
  40. package/lib/TemplatedPathPlugin.js +16 -59
  41. package/lib/Watching.js +9 -0
  42. package/lib/WebpackOptionsApply.js +84 -91
  43. package/lib/asset/AssetBytesGenerator.js +7 -1
  44. package/lib/asset/AssetGenerator.js +50 -24
  45. package/lib/asset/AssetModule.js +3 -0
  46. package/lib/asset/AssetSourceGenerator.js +7 -1
  47. package/lib/asset/WebManifestParser.js +7 -5
  48. package/lib/buildChunkGraph.js +11 -15
  49. package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
  50. package/lib/cache/IdleFileCachePlugin.js +2 -2
  51. package/lib/cache/MemoryCachePlugin.js +4 -4
  52. package/lib/cache/MemoryWithGcCachePlugin.js +7 -8
  53. package/lib/cache/PackFileCacheStrategy.js +17 -19
  54. package/lib/cache/getLazyHashedEtag.js +3 -5
  55. package/lib/config/browserslistTargetHandler.js +17 -4
  56. package/lib/config/defaults.js +138 -128
  57. package/lib/config/getClaimedAssetTypes.js +10 -11
  58. package/lib/config/normalization.js +82 -12
  59. package/lib/config/target.js +13 -4
  60. package/lib/container/ContainerReferencePlugin.js +6 -0
  61. package/lib/container/RemoteRuntimeModule.js +9 -0
  62. package/lib/container/declaredRemotes.js +39 -0
  63. package/lib/{ContextExclusionPlugin.js → context/ContextExclusionPlugin.js} +1 -1
  64. package/lib/{ContextModule.js → context/ContextModule.js} +54 -115
  65. package/lib/{ContextModuleFactory.js → context/ContextModuleFactory.js} +19 -21
  66. package/lib/{ContextReplacementPlugin.js → context/ContextReplacementPlugin.js} +4 -4
  67. package/lib/css/CssGenerator.js +27 -11
  68. package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
  69. package/lib/css/CssLoadingRuntimeModule.js +94 -36
  70. package/lib/css/CssModule.js +1 -1
  71. package/lib/css/CssModulesPlugin.js +7 -6
  72. package/lib/css/CssParser.js +162 -31
  73. package/lib/css/CssServerStylesRuntimeModule.js +9 -0
  74. package/lib/css/cssMinify.js +43 -32
  75. package/lib/css/data.js +3514 -869
  76. package/lib/css/syntax.js +6370 -1220
  77. package/lib/debug/ProfilingPlugin.js +7 -4
  78. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
  79. package/lib/dependencies/AMDRuntimeModules.js +18 -0
  80. package/lib/dependencies/CommonJsExportRequireDependency.js +13 -12
  81. package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
  82. package/lib/dependencies/CommonJsImportsParserPlugin.js +5 -5
  83. package/lib/dependencies/CommonJsPlugin.js +19 -3
  84. package/lib/dependencies/CommonJsRequireDependency.js +14 -5
  85. package/lib/dependencies/CommonJsSelfReferenceDependency.js +2 -4
  86. package/lib/dependencies/ContextDependency.js +1 -1
  87. package/lib/dependencies/ContextDependencyHelpers.js +3 -9
  88. package/lib/dependencies/ContextElementDependency.js +1 -1
  89. package/lib/dependencies/CssIcssExportDependency.js +13 -9
  90. package/lib/dependencies/CssIcssImportDependency.js +3 -6
  91. package/lib/dependencies/CssUrlDependency.js +3 -5
  92. package/lib/dependencies/HarmonyCompatibilityDependency.js +67 -22
  93. package/lib/dependencies/HarmonyDetectionParserPlugin.js +3 -4
  94. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +10 -7
  95. package/lib/dependencies/HarmonyExportExpressionDependency.js +47 -33
  96. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +74 -17
  97. package/lib/dependencies/HarmonyExportInitFragment.js +110 -23
  98. package/lib/dependencies/HarmonyExportSpecifierDependency.js +25 -58
  99. package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
  100. package/lib/dependencies/HarmonyImportDependency.js +6 -1
  101. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +111 -17
  102. package/lib/dependencies/HarmonyImportSideEffectDependency.js +3 -4
  103. package/lib/dependencies/HarmonyImportSpecifierDependency.js +40 -3
  104. package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
  105. package/lib/dependencies/HtmlEntryDependency.js +124 -102
  106. package/lib/dependencies/HtmlInlineScriptDependency.js +3 -4
  107. package/lib/dependencies/HtmlInlineStyleDependency.js +3 -4
  108. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
  109. package/lib/dependencies/ImportMetaGlobHelpers.js +1 -1
  110. package/lib/dependencies/ImportMetaMainDependency.js +104 -0
  111. package/lib/dependencies/ImportMetaPlugin.js +67 -25
  112. package/lib/dependencies/ImportParserPlugin.js +1 -1
  113. package/lib/dependencies/LoaderPlugin.js +26 -1
  114. package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
  115. package/lib/dependencies/SystemRuntimeModule.js +9 -0
  116. package/lib/dependencies/URLContextDependency.js +1 -1
  117. package/lib/dependencies/URLDependency.js +6 -5
  118. package/lib/dependencies/WorkerAndWorkletPlugin.js +15 -21
  119. package/lib/dependencies/WorkerDependency.js +7 -7
  120. package/lib/dependencies/WorkletDependency.js +7 -11
  121. package/lib/dll/DelegatedModule.js +18 -1
  122. package/lib/dll/DllReferencePlugin.js +11 -8
  123. package/lib/dll/LibManifestPlugin.js +1 -1
  124. package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
  125. package/lib/errors/DuplicateModulesWarning.js +12 -7
  126. package/lib/errors/EmptyCopyPatternWarning.js +26 -0
  127. package/lib/errors/ExternalStarReexportError.js +44 -0
  128. package/lib/errors/HookWebpackError.js +3 -2
  129. package/lib/errors/MissingSourceMapsWarning.js +36 -0
  130. package/lib/errors/ModuleParseError.js +2 -1
  131. package/lib/errors/UnusedAssetsWarning.js +36 -0
  132. package/lib/errors/UnusedFederationWarning.js +35 -0
  133. package/lib/errors/UnusedModulesWarning.js +38 -0
  134. package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
  135. package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
  136. package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
  137. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
  138. package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
  139. package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
  140. package/lib/hmr/LazyCompilationPlugin.js +3 -5
  141. package/lib/html/HtmlGenerator.js +72 -87
  142. package/lib/html/HtmlModulesPlugin.js +418 -200
  143. package/lib/html/HtmlParser.js +110 -147
  144. package/lib/html/builtinEmbeddedRenderer.js +107 -0
  145. package/lib/html/data.js +142 -7
  146. package/lib/html/htmlMinify.js +92 -122
  147. package/lib/html/syntax.js +1618 -1391
  148. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  149. package/lib/index.js +49 -3
  150. package/lib/javascript/ChunkFormatHelpers.js +4 -3
  151. package/lib/javascript/JavascriptGenerator.js +8 -1
  152. package/lib/javascript/JavascriptModule.js +1 -0
  153. package/lib/javascript/JavascriptModulesPlugin.js +73 -72
  154. package/lib/javascript/JavascriptParser.js +1970 -900
  155. package/lib/javascript/StartupHelpers.js +27 -3
  156. package/lib/javascript/data.js +172 -0
  157. package/lib/javascript/grammar.js +5546 -0
  158. package/lib/javascript/parser.js +1500 -0
  159. package/lib/javascript/regexp.js +1762 -0
  160. package/lib/javascript/regexpData.js +51 -0
  161. package/lib/javascript/syntax.js +9061 -5262
  162. package/lib/json/JsonGenerator.js +7 -1
  163. package/lib/library/ModuleLibraryPlugin.js +171 -132
  164. package/lib/loaders/LoaderRunner.js +137 -9
  165. package/lib/node/NodeWatchFileSystem.js +3 -9
  166. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
  167. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
  168. package/lib/optimize/AggressiveMergingPlugin.js +3 -5
  169. package/lib/optimize/ConcatenatedModule.js +178 -120
  170. package/lib/optimize/ConstExportsPlugin.js +50 -39
  171. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -11
  172. package/lib/optimize/InlineExports.js +20 -123
  173. package/lib/optimize/InnerGraphPlugin.js +7 -13
  174. package/lib/optimize/LimitChunkCountPlugin.js +5 -8
  175. package/lib/optimize/MangleExportsPlugin.js +13 -4
  176. package/lib/optimize/ModuleConcatenationPlugin.js +27 -5
  177. package/lib/optimize/RealContentHashPlugin.js +68 -9
  178. package/lib/optimize/SideEffectsFlagPlugin.js +24 -28
  179. package/lib/optimize/SplitChunksPlugin.js +2 -4
  180. package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
  181. package/lib/performance/BroadContextsPlugin.js +1 -1
  182. package/lib/performance/CacheEffectivenessPlugin.js +7 -7
  183. package/lib/performance/DuplicateModulesPlugin.js +57 -13
  184. package/lib/performance/EvalUsagePlugin.js +5 -2
  185. package/lib/performance/MissingSourceMapsPlugin.js +115 -0
  186. package/lib/performance/PureAnnotationsPlugin.js +6 -3
  187. package/lib/performance/SizeLimitsPlugin.js +2 -4
  188. package/lib/performance/TopLevelThisPlugin.js +5 -4
  189. package/lib/performance/UnusedAssetsPlugin.js +109 -0
  190. package/lib/performance/UnusedFederationPlugin.js +147 -0
  191. package/lib/performance/UnusedModulesPlugin.js +141 -0
  192. package/lib/performance/UnusedReexportsPlugin.js +1 -55
  193. package/lib/performance/isOnlyReexported.js +65 -0
  194. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
  195. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +8 -8
  196. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
  197. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
  198. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
  199. package/lib/prefetch/ResourceHintPlugin.js +18 -23
  200. package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
  201. package/lib/prefetch/StartupAssetHintRuntimeModule.js +16 -10
  202. package/lib/rules/RuleSetCompiler.js +211 -4
  203. package/lib/runtime/AsyncModuleRuntimeModule.js +98 -66
  204. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
  205. package/lib/runtime/BaseUriRuntimeModule.js +9 -0
  206. package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
  207. package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
  208. package/lib/runtime/GetChunkFilenameRuntimeModule.js +12 -4
  209. package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
  210. package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
  211. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
  212. package/lib/runtime/GlobalRuntimeModule.js +11 -4
  213. package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
  214. package/lib/runtime/HelperRuntimeModule.js +10 -0
  215. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +305 -224
  216. package/lib/runtime/NonceRuntimeModule.js +9 -0
  217. package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
  218. package/lib/runtime/PublicPathRuntimeModule.js +9 -0
  219. package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
  220. package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
  221. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
  222. package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
  223. package/lib/runtime/SystemContextRuntimeModule.js +9 -0
  224. package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
  225. package/lib/schemes/DataUriPlugin.js +3 -6
  226. package/lib/schemes/VirtualUrlPlugin.js +1 -1
  227. package/lib/serialization/BinaryMiddleware.js +9 -9
  228. package/lib/serialization/FileMiddleware.js +16 -16
  229. package/lib/serialization/ObjectMiddleware.js +168 -139
  230. package/lib/sharing/ConsumeSharedPlugin.js +12 -0
  231. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
  232. package/lib/sharing/ShareRuntimeModule.js +9 -0
  233. package/lib/sharing/declaredShared.js +47 -0
  234. package/lib/stats/DefaultStatsFactoryPlugin.js +6 -5
  235. package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
  236. package/lib/typescript/TypeScriptPlugin.js +2 -3
  237. package/lib/url/URLParserPlugin.js +6 -8
  238. package/lib/util/LocConverter.js +4 -7
  239. package/lib/util/SourceProcessor.js +91 -91
  240. package/lib/util/async.js +292 -0
  241. package/lib/util/buildDiagnostics.js +69 -0
  242. package/lib/util/chainedImports.js +3 -4
  243. package/lib/util/concatenate.js +4 -4
  244. package/lib/util/createHooksRegistry.js +1 -2
  245. package/lib/util/dataURL.js +2 -3
  246. package/lib/util/deterministicGrouping.js +8 -13
  247. package/lib/util/findGraphRoots.js +6 -13
  248. package/lib/util/fs.js +27 -1
  249. package/lib/util/globUtils.js +1 -1
  250. package/lib/util/handlerKeys.js +40 -0
  251. package/lib/util/hash/wasm-hash.js +3 -4
  252. package/lib/util/identifier.js +20 -0
  253. package/lib/util/internalSerializables.js +5 -1
  254. package/lib/util/registerExternalSerializer.js +6 -45
  255. package/lib/util/semver.js +5 -3
  256. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
  257. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
  258. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -1
  259. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -1
  260. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +12 -4
  261. package/lib/wasm-sync/WebAssemblyGenerator.js +6 -1
  262. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -1
  263. package/lib/wasm-sync/WebAssemblyUtils.js +2 -4
  264. package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
  265. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
  266. package/package.json +55 -46
  267. package/schemas/WebpackOptions.check.js +1 -1
  268. package/schemas/WebpackOptions.json +379 -66
  269. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  270. package/schemas/plugins/ManifestPlugin.check.js +1 -1
  271. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  272. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  273. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  274. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  275. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  276. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  277. package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
  278. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
  279. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  280. package/types.d.ts +1723 -604
  281. package/lib/dependencies/ExportBindingInitFragment.js +0 -191
  282. package/lib/errors/EntrypointOverlapWarning.js +0 -45
  283. package/lib/performance/EntrypointOverlapPlugin.js +0 -122
@@ -0,0 +1,1762 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Alexander Akait @alexander-akait
4
+ */
5
+
6
+ "use strict";
7
+
8
+ // cspell:ignore Uncapturing
9
+
10
+ // The regexp validator, which `lib/javascript/parser.js` installs on first use:
11
+ // only a pattern the host engine itself rejected is re-read through it.
12
+
13
+ const {
14
+ Parser,
15
+ codePointToString,
16
+ isIdentifierChar,
17
+ isIdentifierStart,
18
+ wordsRegexp
19
+ } = require("./parser");
20
+ const {
21
+ UNICODE_BINARY_PROPERTIES,
22
+ UNICODE_BINARY_PROPERTIES_OF_STRINGS,
23
+ UNICODE_GENERAL_CATEGORY_VALUES,
24
+ UNICODE_SCRIPT_VALUES
25
+ } = require("./regexpData");
26
+
27
+ /**
28
+ * @param {EXPECTED_ANY} obj the object to test
29
+ * @returns {boolean} whether it holds any own enumerable key
30
+ */
31
+ const hasProp = (obj) => {
32
+ // eslint-disable-next-line no-unreachable-loop -- the first key is the answer
33
+ for (const _ in obj) return true;
34
+ return false;
35
+ };
36
+
37
+ /**
38
+ * Which disjunction branch a named group sits in, so that the same name in two
39
+ * alternatives of one disjunction is allowed and a repeat in one is not.
40
+ */
41
+ class BranchID {
42
+ /**
43
+ * @param {BranchID | null} parent the enclosing disjunction's branch
44
+ * @param {BranchID | null=} base the set of sibling branches this belongs to
45
+ */
46
+ constructor(parent, base) {
47
+ this.parent = parent;
48
+ /** @type {BranchID} */
49
+ this.base = base || this;
50
+ }
51
+
52
+ /**
53
+ * @param {BranchID} alt the other branch
54
+ * @returns {boolean} whether the two are alternatives of one disjunction
55
+ */
56
+ separatedFrom(alt) {
57
+ /** @type {BranchID | null} */
58
+ let self = this;
59
+ while (self) {
60
+ /** @type {BranchID | null} */
61
+ let other = alt;
62
+ while (other) {
63
+ if (self.base === other.base && self !== other) return true;
64
+ other = other.parent;
65
+ }
66
+ self = self.parent;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ /** @returns {BranchID} the next branch of the same disjunction */
72
+ sibling() {
73
+ return new BranchID(this.parent, this.base);
74
+ }
75
+ }
76
+
77
+ // Which kind of character set a class construct parsed as, so that negating one
78
+ // that can match a string is refused.
79
+ const CHAR_SET_NONE = 0;
80
+ const CHAR_SET_OK = 1;
81
+ const CHAR_SET_STRING = 2;
82
+
83
+ /** @type {Record<number, EXPECTED_ANY>} */
84
+ const unicodePropertyData = {};
85
+
86
+ /**
87
+ * The `\p{...}` name tables for one edition, built on first use: most patterns
88
+ * name no property at all.
89
+ * @param {number} ecmaVersion the edition to answer for
90
+ * @returns {EXPECTED_ANY} its binary, string-valued and non-binary name tables
91
+ */
92
+ const unicodePropertiesFor = (ecmaVersion) => {
93
+ // no edition before 2018 reads a property escape, so acorn has no table for it
94
+ if (ecmaVersion < 9) return undefined;
95
+ const cached = unicodePropertyData[ecmaVersion];
96
+ if (cached !== undefined) return cached;
97
+ const nonBinary = {
98
+ General_Category: wordsRegexp(UNICODE_GENERAL_CATEGORY_VALUES),
99
+ Script: wordsRegexp(UNICODE_SCRIPT_VALUES[ecmaVersion])
100
+ };
101
+ const entry = {
102
+ binary: wordsRegexp(
103
+ `${UNICODE_BINARY_PROPERTIES[ecmaVersion]} ${UNICODE_GENERAL_CATEGORY_VALUES}`
104
+ ),
105
+ binaryOfStrings: wordsRegexp(
106
+ UNICODE_BINARY_PROPERTIES_OF_STRINGS[ecmaVersion]
107
+ ),
108
+ nonBinary
109
+ };
110
+ /** @type {EXPECTED_ANY} */ (nonBinary).Script_Extensions = nonBinary.Script;
111
+ /** @type {EXPECTED_ANY} */ (nonBinary).gc = nonBinary.General_Category;
112
+ /** @type {EXPECTED_ANY} */ (nonBinary).sc = nonBinary.Script;
113
+ /** @type {EXPECTED_ANY} */ (nonBinary).scx = nonBinary.Script;
114
+ unicodePropertyData[ecmaVersion] = entry;
115
+ return entry;
116
+ };
117
+
118
+ /** The cursor a regexp literal is validated through. */
119
+ class RegExpValidationState {
120
+ /**
121
+ * @param {Parser} parser the parser that owns it
122
+ */
123
+ constructor(parser) {
124
+ this.parser = parser;
125
+ this.validFlags = `gim${parser.options.ecmaVersion >= 6 ? "uy" : ""}${
126
+ parser.options.ecmaVersion >= 9 ? "s" : ""
127
+ }${parser.options.ecmaVersion >= 13 ? "d" : ""}${
128
+ parser.options.ecmaVersion >= 15 ? "v" : ""
129
+ }`;
130
+ this.unicodeProperties = unicodePropertiesFor(
131
+ parser.options.ecmaVersion >= 14 ? 14 : parser.options.ecmaVersion
132
+ );
133
+ this.source = "";
134
+ this.flags = "";
135
+ this.start = 0;
136
+ this.switchU = false;
137
+ this.switchV = false;
138
+ this.switchN = false;
139
+ this.pos = 0;
140
+ this.lastIntValue = 0;
141
+ this.lastStringValue = "";
142
+ this.lastAssertionIsQuantifiable = false;
143
+ this.numCapturingParens = 0;
144
+ this.maxBackReference = 0;
145
+ /** @type {EXPECTED_ANY} */
146
+ this.groupNames = Object.create(null);
147
+ /** @type {string[]} */
148
+ this.backReferenceNames = [];
149
+ /** @type {BranchID | null} */
150
+ this.branchID = null;
151
+ }
152
+
153
+ /**
154
+ * @param {number} start where the literal starts in the source
155
+ * @param {string} pattern the pattern's text
156
+ * @param {string} flags the flags' text
157
+ * @returns {void}
158
+ */
159
+ reset(start, pattern, flags) {
160
+ const unicodeSets = flags.includes("v");
161
+ const unicode = flags.includes("u");
162
+ this.start = start | 0;
163
+ this.source = `${pattern}`;
164
+ this.flags = flags;
165
+ if (unicodeSets && this.parser.options.ecmaVersion >= 15) {
166
+ this.switchU = true;
167
+ this.switchV = true;
168
+ this.switchN = true;
169
+ } else {
170
+ this.switchU = unicode && this.parser.options.ecmaVersion >= 6;
171
+ this.switchV = false;
172
+ this.switchN = unicode && this.parser.options.ecmaVersion >= 9;
173
+ }
174
+ }
175
+
176
+ /**
177
+ * @param {string} message what is wrong with the pattern
178
+ * @returns {void}
179
+ */
180
+ raise(message) {
181
+ this.parser.raiseRecoverable(
182
+ this.start,
183
+ `Invalid regular expression: /${this.source}/: ${message}`
184
+ );
185
+ }
186
+
187
+ /**
188
+ * The code point at an index, joining a surrogate pair where the `u` flag
189
+ * asks for code points rather than units.
190
+ * @param {number} i the index to read
191
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
192
+ * @returns {number} the code point, or `-1` past the end
193
+ */
194
+ at(i, forceU) {
195
+ const s = this.source;
196
+ const l = s.length;
197
+ if (i >= l) return -1;
198
+ const c = s.charCodeAt(i);
199
+ if (!(forceU || this.switchU) || c <= 0xd7ff || c >= 0xe000 || i + 1 >= l) {
200
+ return c;
201
+ }
202
+ const next = s.charCodeAt(i + 1);
203
+ return next >= 0xdc00 && next <= 0xdfff ? (c << 10) + next - 0x35fdc00 : c;
204
+ }
205
+
206
+ /**
207
+ * @param {number} i the index to step from
208
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
209
+ * @returns {number} the next index
210
+ */
211
+ nextIndex(i, forceU) {
212
+ const s = this.source;
213
+ const l = s.length;
214
+ if (i >= l) return l;
215
+ const c = s.charCodeAt(i);
216
+ let next;
217
+ if (
218
+ !(forceU || this.switchU) ||
219
+ c <= 0xd7ff ||
220
+ c >= 0xe000 ||
221
+ i + 1 >= l ||
222
+ (next = s.charCodeAt(i + 1)) < 0xdc00 ||
223
+ next > 0xdfff
224
+ ) {
225
+ return i + 1;
226
+ }
227
+ return i + 2;
228
+ }
229
+
230
+ /**
231
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
232
+ * @returns {number} the code point at the cursor
233
+ */
234
+ current(forceU) {
235
+ return this.at(this.pos, forceU);
236
+ }
237
+
238
+ /**
239
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
240
+ * @returns {number} the code point after the cursor
241
+ */
242
+ lookahead(forceU) {
243
+ return this.at(this.nextIndex(this.pos, forceU), forceU);
244
+ }
245
+
246
+ /**
247
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
248
+ * @returns {void}
249
+ */
250
+ advance(forceU) {
251
+ this.pos = this.nextIndex(this.pos, forceU);
252
+ }
253
+
254
+ /**
255
+ * @param {number} ch the code point to consume
256
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
257
+ * @returns {boolean} whether it was there
258
+ */
259
+ eat(ch, forceU) {
260
+ if (this.current(forceU) === ch) {
261
+ this.advance(forceU);
262
+ return true;
263
+ }
264
+ return false;
265
+ }
266
+
267
+ /**
268
+ * @param {number[]} chs the code points to consume, in order
269
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
270
+ * @returns {boolean} whether they were all there
271
+ */
272
+ eatChars(chs, forceU) {
273
+ let pos = this.pos;
274
+ for (const ch of chs) {
275
+ const current = this.at(pos, forceU);
276
+ if (current === -1 || current !== ch) return false;
277
+ pos = this.nextIndex(pos, forceU);
278
+ }
279
+ this.pos = pos;
280
+ return true;
281
+ }
282
+ }
283
+
284
+ /**
285
+ * @param {number} ch the code point
286
+ * @returns {boolean} whether it is `i`, `m` or `s`
287
+ */
288
+ const isRegularExpressionModifier = (ch) =>
289
+ ch === 0x69 || ch === 0x6d || ch === 0x73;
290
+
291
+ /**
292
+ * @param {number} ch the code point
293
+ * @returns {boolean} whether it carries meaning in a pattern
294
+ */
295
+ const isSyntaxCharacter = (ch) =>
296
+ ch === 0x24 ||
297
+ (ch >= 0x28 && ch <= 0x2b) ||
298
+ ch === 0x2e ||
299
+ ch === 0x3f ||
300
+ (ch >= 0x5b && ch <= 0x5e) ||
301
+ (ch >= 0x7b && ch <= 0x7d);
302
+
303
+ /**
304
+ * @param {number} ch the code point
305
+ * @returns {boolean} whether a group name may start with it
306
+ */
307
+ const isRegExpIdentifierStart = (ch) =>
308
+ isIdentifierStart(ch, true) || ch === 0x24 || ch === 0x5f;
309
+
310
+ /**
311
+ * @param {number} ch the code point
312
+ * @returns {boolean} whether a group name may continue with it
313
+ */
314
+ const isRegExpIdentifierPart = (ch) =>
315
+ isIdentifierChar(ch, true) ||
316
+ ch === 0x24 ||
317
+ ch === 0x5f ||
318
+ ch === 0x200c ||
319
+ ch === 0x200d;
320
+
321
+ /**
322
+ * @param {number} ch the code point
323
+ * @returns {boolean} whether it names a built-in character class
324
+ */
325
+ const isCharacterClassEscape = (ch) =>
326
+ ch === 0x64 ||
327
+ ch === 0x44 ||
328
+ ch === 0x73 ||
329
+ ch === 0x53 ||
330
+ ch === 0x77 ||
331
+ ch === 0x57;
332
+
333
+ /**
334
+ * @param {number} ch the code point
335
+ * @returns {boolean} whether it is an ASCII letter
336
+ */
337
+ const isControlLetter = (ch) =>
338
+ (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x61 && ch <= 0x7a);
339
+
340
+ /**
341
+ * @param {number} ch the code point
342
+ * @returns {boolean} whether a property name may contain it
343
+ */
344
+ const isUnicodePropertyNameCharacter = (ch) =>
345
+ isControlLetter(ch) || ch === 0x5f;
346
+
347
+ /**
348
+ * @param {number} ch the code point
349
+ * @returns {boolean} whether a property value may contain it
350
+ */
351
+ const isUnicodePropertyValueCharacter = (ch) =>
352
+ isUnicodePropertyNameCharacter(ch) || isDecimalDigit(ch);
353
+
354
+ /**
355
+ * @param {number} ch the code point
356
+ * @returns {boolean} whether Unicode defines it
357
+ */
358
+ const isValidUnicode = (ch) => ch >= 0 && ch <= 0x10ffff;
359
+
360
+ /**
361
+ * @param {number} ch the code point
362
+ * @returns {boolean} whether it is `0` through `9`
363
+ */
364
+ const isDecimalDigit = (ch) => ch >= 0x30 && ch <= 0x39;
365
+
366
+ /**
367
+ * @param {number} ch the code point
368
+ * @returns {boolean} whether it is a hexadecimal digit
369
+ */
370
+ const isHexDigit = (ch) =>
371
+ (ch >= 0x30 && ch <= 0x39) ||
372
+ (ch >= 0x41 && ch <= 0x46) ||
373
+ (ch >= 0x61 && ch <= 0x66);
374
+
375
+ /**
376
+ * @param {number} ch a hexadecimal digit's code point
377
+ * @returns {number} its value
378
+ */
379
+ const hexToInt = (ch) => {
380
+ if (ch >= 0x41 && ch <= 0x46) return 10 + (ch - 0x41);
381
+ if (ch >= 0x61 && ch <= 0x66) return 10 + (ch - 0x61);
382
+ return ch - 0x30;
383
+ };
384
+
385
+ /**
386
+ * @param {number} ch the code point
387
+ * @returns {boolean} whether it is `0` through `7`
388
+ */
389
+ const isOctalDigit = (ch) => ch >= 0x30 && ch <= 0x37;
390
+
391
+ /**
392
+ * @param {number} ch the code point
393
+ * @returns {boolean} whether doubling it is reserved inside a `v` class
394
+ */
395
+ const isClassSetReservedDoublePunctuatorCharacter = (ch) =>
396
+ ch === 0x21 ||
397
+ (ch >= 0x23 && ch <= 0x26) ||
398
+ (ch >= 0x2a && ch <= 0x2c) ||
399
+ ch === 0x2e ||
400
+ (ch >= 0x3a && ch <= 0x40) ||
401
+ ch === 0x5e ||
402
+ ch === 0x60 ||
403
+ ch === 0x7e;
404
+
405
+ /**
406
+ * @param {number} ch the code point
407
+ * @returns {boolean} whether it carries meaning inside a `v` class
408
+ */
409
+ const isClassSetSyntaxCharacter = (ch) =>
410
+ ch === 0x28 ||
411
+ ch === 0x29 ||
412
+ ch === 0x2d ||
413
+ ch === 0x2f ||
414
+ (ch >= 0x5b && ch <= 0x5d) ||
415
+ (ch >= 0x7b && ch <= 0x7d);
416
+
417
+ /**
418
+ * @param {number} ch the code point
419
+ * @returns {boolean} whether an escape may name it inside a `v` class
420
+ */
421
+ const isClassSetReservedPunctuator = (ch) =>
422
+ ch === 0x21 ||
423
+ ch === 0x23 ||
424
+ ch === 0x25 ||
425
+ ch === 0x26 ||
426
+ ch === 0x2c ||
427
+ ch === 0x2d ||
428
+ (ch >= 0x3a && ch <= 0x3e) ||
429
+ ch === 0x40 ||
430
+ ch === 0x60 ||
431
+ ch === 0x7e;
432
+
433
+ /**
434
+ * The regexp validator, as prototype methods `install` copies onto the parser.
435
+ * It extends `Parser` so each method reads the cursor it is handed through
436
+ * `this`, the way acorn declares them.
437
+ */
438
+ class RegExpValidator extends Parser {
439
+ /**
440
+ * Check a regexp literal's flags.
441
+ * acorn source: https://github.com/acornjs/acorn/blob/8.18.0/acorn/src/regexp.js
442
+ * @param {import("./regexp").RegExpValidationState} state the validation state
443
+ * @returns {void}
444
+ */
445
+ validateRegExpFlags(state) {
446
+ const { validFlags, flags } = state;
447
+
448
+ let u = false;
449
+ let v = false;
450
+
451
+ for (let i = 0; i < flags.length; i++) {
452
+ const flag = flags.charAt(i);
453
+ if (!validFlags.includes(flag)) {
454
+ this.raise(state.start, "Invalid regular expression flag");
455
+ }
456
+ if (flags.includes(flag, i + 1)) {
457
+ this.raise(state.start, "Duplicate regular expression flag");
458
+ }
459
+ if (flag === "u") u = true;
460
+ if (flag === "v") v = true;
461
+ }
462
+ if (this.options.ecmaVersion >= 15 && u && v) {
463
+ this.raise(state.start, "Invalid regular expression flag");
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Check a regexp literal's pattern, re-reading it once a group name shows
469
+ * that the named-capture goal symbol was the right one.
470
+ * @param {import("./regexp").RegExpValidationState} state the validation state
471
+ * @returns {void}
472
+ */
473
+ validateRegExpPattern(state) {
474
+ this.regexp_pattern(state);
475
+
476
+ if (
477
+ !state.switchN &&
478
+ this.options.ecmaVersion >= 9 &&
479
+ hasProp(state.groupNames)
480
+ ) {
481
+ state.switchN = true;
482
+ this.regexp_pattern(state);
483
+ }
484
+ }
485
+
486
+ /**
487
+ * @param {RegExpValidationState} state the validation state
488
+ * @returns {void}
489
+ */
490
+ regexp_pattern(state) {
491
+ state.pos = 0;
492
+ state.lastIntValue = 0;
493
+ state.lastStringValue = "";
494
+ state.lastAssertionIsQuantifiable = false;
495
+ state.numCapturingParens = 0;
496
+ state.maxBackReference = 0;
497
+ state.groupNames = Object.create(null);
498
+ state.backReferenceNames.length = 0;
499
+ state.branchID = null;
500
+
501
+ this.regexp_disjunction(state);
502
+
503
+ if (state.pos !== state.source.length) {
504
+ // Worded as V8 words them, since a caller may match on the text.
505
+ if (state.eat(0x29)) state.raise("Unmatched ')'");
506
+ if (state.eat(0x5d) || state.eat(0x7d)) {
507
+ state.raise("Lone quantifier brackets");
508
+ }
509
+ }
510
+ if (state.maxBackReference > state.numCapturingParens) {
511
+ state.raise("Invalid escape");
512
+ }
513
+ for (const name of state.backReferenceNames) {
514
+ if (!state.groupNames[name]) {
515
+ state.raise("Invalid named capture referenced");
516
+ }
517
+ }
518
+ }
519
+
520
+ /**
521
+ * @param {RegExpValidationState} state the validation state
522
+ * @returns {void}
523
+ */
524
+ regexp_disjunction(state) {
525
+ const trackDisjunction = this.options.ecmaVersion >= 16;
526
+ if (trackDisjunction) state.branchID = new BranchID(state.branchID, null);
527
+ this.regexp_alternative(state);
528
+ while (state.eat(0x7c)) {
529
+ if (trackDisjunction) {
530
+ state.branchID = /** @type {BranchID} */ (state.branchID).sibling();
531
+ }
532
+ this.regexp_alternative(state);
533
+ }
534
+ if (trackDisjunction) {
535
+ state.branchID = /** @type {BranchID} */ (state.branchID).parent;
536
+ }
537
+
538
+ if (this.regexp_eatQuantifier(state, true)) {
539
+ state.raise("Nothing to repeat");
540
+ }
541
+ if (state.eat(0x7b)) state.raise("Lone quantifier brackets");
542
+ }
543
+
544
+ /**
545
+ * @param {RegExpValidationState} state the validation state
546
+ * @returns {void}
547
+ */
548
+ regexp_alternative(state) {
549
+ while (state.pos < state.source.length && this.regexp_eatTerm(state));
550
+ }
551
+
552
+ /**
553
+ * @param {RegExpValidationState} state the validation state
554
+ * @returns {boolean} whether a term was read
555
+ */
556
+ regexp_eatTerm(state) {
557
+ if (this.regexp_eatAssertion(state)) {
558
+ // Only a lookahead may carry a quantifier, and only outside `u` mode.
559
+ if (
560
+ state.lastAssertionIsQuantifiable &&
561
+ this.regexp_eatQuantifier(state) &&
562
+ state.switchU
563
+ ) {
564
+ state.raise("Invalid quantifier");
565
+ }
566
+ return true;
567
+ }
568
+
569
+ if (
570
+ state.switchU
571
+ ? this.regexp_eatAtom(state)
572
+ : this.regexp_eatExtendedAtom(state)
573
+ ) {
574
+ this.regexp_eatQuantifier(state);
575
+ return true;
576
+ }
577
+
578
+ return false;
579
+ }
580
+
581
+ /**
582
+ * @param {RegExpValidationState} state the validation state
583
+ * @returns {boolean} whether an assertion was read
584
+ */
585
+ regexp_eatAssertion(state) {
586
+ const start = state.pos;
587
+ state.lastAssertionIsQuantifiable = false;
588
+
589
+ if (state.eat(0x5e) || state.eat(0x24)) return true;
590
+
591
+ if (state.eat(0x5c)) {
592
+ if (state.eat(0x42) || state.eat(0x62)) return true;
593
+ state.pos = start;
594
+ }
595
+
596
+ if (state.eat(0x28) && state.eat(0x3f)) {
597
+ let lookbehind = false;
598
+ if (this.options.ecmaVersion >= 9) lookbehind = state.eat(0x3c);
599
+ if (state.eat(0x3d) || state.eat(0x21)) {
600
+ this.regexp_disjunction(state);
601
+ if (!state.eat(0x29)) state.raise("Unterminated group");
602
+ state.lastAssertionIsQuantifiable = !lookbehind;
603
+ return true;
604
+ }
605
+ }
606
+
607
+ state.pos = start;
608
+ return false;
609
+ }
610
+
611
+ /**
612
+ * @param {RegExpValidationState} state the validation state
613
+ * @param {boolean=} noError whether to read without reporting
614
+ * @returns {boolean} whether a quantifier was read
615
+ */
616
+ regexp_eatQuantifier(state, noError) {
617
+ if (this.regexp_eatQuantifierPrefix(state, noError)) {
618
+ state.eat(0x3f);
619
+ return true;
620
+ }
621
+ return false;
622
+ }
623
+
624
+ /**
625
+ * @param {RegExpValidationState} state the validation state
626
+ * @param {boolean=} noError whether to read without reporting
627
+ * @returns {boolean} whether a quantifier prefix was read
628
+ */
629
+ regexp_eatQuantifierPrefix(state, noError) {
630
+ return (
631
+ state.eat(0x2a) ||
632
+ state.eat(0x2b) ||
633
+ state.eat(0x3f) ||
634
+ this.regexp_eatBracedQuantifier(state, noError)
635
+ );
636
+ }
637
+
638
+ /**
639
+ * @param {RegExpValidationState} state the validation state
640
+ * @param {boolean=} noError whether to read without reporting
641
+ * @returns {boolean} whether a braced quantifier was read
642
+ */
643
+ regexp_eatBracedQuantifier(state, noError) {
644
+ const start = state.pos;
645
+ if (state.eat(0x7b)) {
646
+ let min = 0;
647
+ let max = -1;
648
+ if (this.regexp_eatDecimalDigits(state)) {
649
+ min = state.lastIntValue;
650
+ if (state.eat(0x2c) && this.regexp_eatDecimalDigits(state)) {
651
+ max = state.lastIntValue;
652
+ }
653
+ if (state.eat(0x7d)) {
654
+ if (max !== -1 && max < min && !noError) {
655
+ state.raise("numbers out of order in {} quantifier");
656
+ }
657
+ return true;
658
+ }
659
+ }
660
+ if (state.switchU && !noError) state.raise("Incomplete quantifier");
661
+ state.pos = start;
662
+ }
663
+ return false;
664
+ }
665
+
666
+ /**
667
+ * @param {RegExpValidationState} state the validation state
668
+ * @returns {boolean} whether an atom was read
669
+ */
670
+ regexp_eatAtom(state) {
671
+ return (
672
+ this.regexp_eatPatternCharacters(state) ||
673
+ state.eat(0x2e) ||
674
+ this.regexp_eatReverseSolidusAtomEscape(state) ||
675
+ this.regexp_eatCharacterClass(state) ||
676
+ this.regexp_eatUncapturingGroup(state) ||
677
+ this.regexp_eatCapturingGroup(state)
678
+ );
679
+ }
680
+
681
+ /**
682
+ * @param {RegExpValidationState} state the validation state
683
+ * @returns {boolean} whether an escape was read
684
+ */
685
+ regexp_eatReverseSolidusAtomEscape(state) {
686
+ const start = state.pos;
687
+ if (state.eat(0x5c)) {
688
+ if (this.regexp_eatAtomEscape(state)) return true;
689
+ state.pos = start;
690
+ }
691
+ return false;
692
+ }
693
+
694
+ /**
695
+ * @param {RegExpValidationState} state the validation state
696
+ * @returns {boolean} whether a non-capturing group was read
697
+ */
698
+ regexp_eatUncapturingGroup(state) {
699
+ const start = state.pos;
700
+ if (state.eat(0x28)) {
701
+ if (state.eat(0x3f)) {
702
+ if (this.options.ecmaVersion >= 16) {
703
+ const addModifiers = this.regexp_eatModifiers(state);
704
+ const hasHyphen = state.eat(0x2d);
705
+ if (addModifiers || hasHyphen) {
706
+ for (let i = 0; i < addModifiers.length; i++) {
707
+ const modifier = addModifiers.charAt(i);
708
+ if (addModifiers.includes(modifier, i + 1)) {
709
+ state.raise("Duplicate regular expression modifiers");
710
+ }
711
+ }
712
+ if (hasHyphen) {
713
+ const removeModifiers = this.regexp_eatModifiers(state);
714
+ if (
715
+ !addModifiers &&
716
+ !removeModifiers &&
717
+ state.current() === 0x3a
718
+ ) {
719
+ state.raise("Invalid regular expression modifiers");
720
+ }
721
+ for (let i = 0; i < removeModifiers.length; i++) {
722
+ const modifier = removeModifiers.charAt(i);
723
+ if (
724
+ removeModifiers.includes(modifier, i + 1) ||
725
+ addModifiers.includes(modifier)
726
+ ) {
727
+ state.raise("Duplicate regular expression modifiers");
728
+ }
729
+ }
730
+ }
731
+ }
732
+ }
733
+ if (state.eat(0x3a)) {
734
+ this.regexp_disjunction(state);
735
+ if (state.eat(0x29)) return true;
736
+ state.raise("Unterminated group");
737
+ }
738
+ }
739
+ state.pos = start;
740
+ }
741
+ return false;
742
+ }
743
+
744
+ /**
745
+ * @param {RegExpValidationState} state the validation state
746
+ * @returns {boolean} whether a capturing group was read
747
+ */
748
+ regexp_eatCapturingGroup(state) {
749
+ if (state.eat(0x28)) {
750
+ if (this.options.ecmaVersion >= 9) {
751
+ this.regexp_groupSpecifier(state);
752
+ } else if (state.current() === 0x3f) {
753
+ state.raise("Invalid group");
754
+ }
755
+ this.regexp_disjunction(state);
756
+ if (state.eat(0x29)) {
757
+ state.numCapturingParens += 1;
758
+ return true;
759
+ }
760
+ state.raise("Unterminated group");
761
+ }
762
+ return false;
763
+ }
764
+
765
+ /**
766
+ * @param {RegExpValidationState} state the validation state
767
+ * @returns {string} the modifiers that were read
768
+ */
769
+ regexp_eatModifiers(state) {
770
+ let modifiers = "";
771
+ let ch = 0;
772
+ while ((ch = state.current()) !== -1 && isRegularExpressionModifier(ch)) {
773
+ modifiers += codePointToString(ch);
774
+ state.advance();
775
+ }
776
+ return modifiers;
777
+ }
778
+
779
+ /**
780
+ * @param {RegExpValidationState} state the validation state
781
+ * @returns {boolean} whether an atom was read
782
+ */
783
+ regexp_eatExtendedAtom(state) {
784
+ return (
785
+ state.eat(0x2e) ||
786
+ this.regexp_eatReverseSolidusAtomEscape(state) ||
787
+ this.regexp_eatCharacterClass(state) ||
788
+ this.regexp_eatUncapturingGroup(state) ||
789
+ this.regexp_eatCapturingGroup(state) ||
790
+ this.regexp_eatInvalidBracedQuantifier(state) ||
791
+ this.regexp_eatExtendedPatternCharacter(state)
792
+ );
793
+ }
794
+
795
+ /**
796
+ * @param {RegExpValidationState} state the validation state
797
+ * @returns {boolean} always false, since a match is an error
798
+ */
799
+ regexp_eatInvalidBracedQuantifier(state) {
800
+ if (this.regexp_eatBracedQuantifier(state, true)) {
801
+ state.raise("Nothing to repeat");
802
+ }
803
+ return false;
804
+ }
805
+
806
+ /**
807
+ * @param {RegExpValidationState} state the validation state
808
+ * @returns {boolean} whether a syntax character was read
809
+ */
810
+ regexp_eatSyntaxCharacter(state) {
811
+ const ch = state.current();
812
+ if (isSyntaxCharacter(ch)) {
813
+ state.lastIntValue = ch;
814
+ state.advance();
815
+ return true;
816
+ }
817
+ return false;
818
+ }
819
+
820
+ /**
821
+ * @param {RegExpValidationState} state the validation state
822
+ * @returns {boolean} whether any pattern character was read
823
+ */
824
+ regexp_eatPatternCharacters(state) {
825
+ const start = state.pos;
826
+ let ch = 0;
827
+ while ((ch = state.current()) !== -1 && !isSyntaxCharacter(ch)) {
828
+ state.advance();
829
+ }
830
+ return state.pos !== start;
831
+ }
832
+
833
+ /**
834
+ * @param {RegExpValidationState} state the validation state
835
+ * @returns {boolean} whether a pattern character was read
836
+ */
837
+ regexp_eatExtendedPatternCharacter(state) {
838
+ const ch = state.current();
839
+ if (
840
+ ch !== -1 &&
841
+ ch !== 0x24 &&
842
+ !(ch >= 0x28 && ch <= 0x2b) &&
843
+ ch !== 0x2e &&
844
+ ch !== 0x3f &&
845
+ ch !== 0x5b &&
846
+ ch !== 0x5e &&
847
+ ch !== 0x7c
848
+ ) {
849
+ state.advance();
850
+ return true;
851
+ }
852
+ return false;
853
+ }
854
+
855
+ /**
856
+ * Read a capture group's name, and report one that another branch of the
857
+ * same disjunction already used.
858
+ * @param {RegExpValidationState} state the validation state
859
+ * @returns {void}
860
+ */
861
+ regexp_groupSpecifier(state) {
862
+ if (state.eat(0x3f)) {
863
+ if (!this.regexp_eatGroupName(state)) state.raise("Invalid group");
864
+ const trackDisjunction = this.options.ecmaVersion >= 16;
865
+ const known = state.groupNames[state.lastStringValue];
866
+ if (known) {
867
+ if (trackDisjunction) {
868
+ for (const altID of known) {
869
+ if (!altID.separatedFrom(state.branchID)) {
870
+ state.raise("Duplicate capture group name");
871
+ }
872
+ }
873
+ } else {
874
+ state.raise("Duplicate capture group name");
875
+ }
876
+ }
877
+ if (trackDisjunction) {
878
+ const branches =
879
+ known || (state.groupNames[state.lastStringValue] = []);
880
+ branches.push(state.branchID);
881
+ } else {
882
+ state.groupNames[state.lastStringValue] = true;
883
+ }
884
+ }
885
+ }
886
+
887
+ /**
888
+ * @param {RegExpValidationState} state the validation state
889
+ * @returns {boolean} whether a group name was read
890
+ */
891
+ regexp_eatGroupName(state) {
892
+ state.lastStringValue = "";
893
+ if (state.eat(0x3c)) {
894
+ if (this.regexp_eatRegExpIdentifierName(state) && state.eat(0x3e)) {
895
+ return true;
896
+ }
897
+ state.raise("Invalid capture group name");
898
+ }
899
+ return false;
900
+ }
901
+
902
+ /**
903
+ * @param {RegExpValidationState} state the validation state
904
+ * @returns {boolean} whether a name was read
905
+ */
906
+ regexp_eatRegExpIdentifierName(state) {
907
+ state.lastStringValue = "";
908
+ if (this.regexp_eatRegExpIdentifierStart(state)) {
909
+ state.lastStringValue += codePointToString(state.lastIntValue);
910
+ while (this.regexp_eatRegExpIdentifierPart(state)) {
911
+ state.lastStringValue += codePointToString(state.lastIntValue);
912
+ }
913
+ return true;
914
+ }
915
+ return false;
916
+ }
917
+
918
+ /**
919
+ * @param {RegExpValidationState} state the validation state
920
+ * @returns {boolean} whether a name start was read
921
+ */
922
+ regexp_eatRegExpIdentifierStart(state) {
923
+ const start = state.pos;
924
+ const forceU = this.options.ecmaVersion >= 11;
925
+ let ch = state.current(forceU);
926
+ state.advance(forceU);
927
+
928
+ if (
929
+ ch === 0x5c &&
930
+ this.regexp_eatRegExpUnicodeEscapeSequence(state, forceU)
931
+ ) {
932
+ ch = state.lastIntValue;
933
+ }
934
+ if (isRegExpIdentifierStart(ch)) {
935
+ state.lastIntValue = ch;
936
+ return true;
937
+ }
938
+
939
+ state.pos = start;
940
+ return false;
941
+ }
942
+
943
+ /**
944
+ * @param {RegExpValidationState} state the validation state
945
+ * @returns {boolean} whether a name character was read
946
+ */
947
+ regexp_eatRegExpIdentifierPart(state) {
948
+ const start = state.pos;
949
+ const forceU = this.options.ecmaVersion >= 11;
950
+ let ch = state.current(forceU);
951
+ state.advance(forceU);
952
+
953
+ if (
954
+ ch === 0x5c &&
955
+ this.regexp_eatRegExpUnicodeEscapeSequence(state, forceU)
956
+ ) {
957
+ ch = state.lastIntValue;
958
+ }
959
+ if (isRegExpIdentifierPart(ch)) {
960
+ state.lastIntValue = ch;
961
+ return true;
962
+ }
963
+
964
+ state.pos = start;
965
+ return false;
966
+ }
967
+
968
+ /**
969
+ * @param {RegExpValidationState} state the validation state
970
+ * @returns {boolean} whether an escape was read
971
+ */
972
+ regexp_eatAtomEscape(state) {
973
+ if (
974
+ this.regexp_eatBackReference(state) ||
975
+ this.regexp_eatCharacterClassEscape(state) ||
976
+ this.regexp_eatCharacterEscape(state) ||
977
+ (state.switchN && this.regexp_eatKGroupName(state))
978
+ ) {
979
+ return true;
980
+ }
981
+ if (state.switchU) {
982
+ // Worded as V8 words them.
983
+ if (state.current() === 0x63) state.raise("Invalid unicode escape");
984
+ state.raise("Invalid escape");
985
+ }
986
+ return false;
987
+ }
988
+
989
+ /**
990
+ * @param {RegExpValidationState} state the validation state
991
+ * @returns {boolean} whether a back reference was read
992
+ */
993
+ regexp_eatBackReference(state) {
994
+ const start = state.pos;
995
+ if (this.regexp_eatDecimalEscape(state)) {
996
+ const n = state.lastIntValue;
997
+ if (state.switchU) {
998
+ if (n > state.maxBackReference) state.maxBackReference = n;
999
+ return true;
1000
+ }
1001
+ if (n <= state.numCapturingParens) return true;
1002
+ state.pos = start;
1003
+ }
1004
+ return false;
1005
+ }
1006
+
1007
+ /**
1008
+ * @param {RegExpValidationState} state the validation state
1009
+ * @returns {boolean} whether a named back reference was read
1010
+ */
1011
+ regexp_eatKGroupName(state) {
1012
+ if (state.eat(0x6b)) {
1013
+ if (this.regexp_eatGroupName(state)) {
1014
+ state.backReferenceNames.push(state.lastStringValue);
1015
+ return true;
1016
+ }
1017
+ state.raise("Invalid named reference");
1018
+ }
1019
+ return false;
1020
+ }
1021
+
1022
+ /**
1023
+ * @param {RegExpValidationState} state the validation state
1024
+ * @returns {boolean} whether a character escape was read
1025
+ */
1026
+ regexp_eatCharacterEscape(state) {
1027
+ return (
1028
+ this.regexp_eatControlEscape(state) ||
1029
+ this.regexp_eatCControlLetter(state) ||
1030
+ this.regexp_eatZero(state) ||
1031
+ this.regexp_eatHexEscapeSequence(state) ||
1032
+ this.regexp_eatRegExpUnicodeEscapeSequence(state, false) ||
1033
+ (!state.switchU && this.regexp_eatLegacyOctalEscapeSequence(state)) ||
1034
+ this.regexp_eatIdentityEscape(state)
1035
+ );
1036
+ }
1037
+
1038
+ /**
1039
+ * @param {RegExpValidationState} state the validation state
1040
+ * @returns {boolean} whether a `\c` escape was read
1041
+ */
1042
+ regexp_eatCControlLetter(state) {
1043
+ const start = state.pos;
1044
+ if (state.eat(0x63)) {
1045
+ if (this.regexp_eatControlLetter(state)) return true;
1046
+ state.pos = start;
1047
+ }
1048
+ return false;
1049
+ }
1050
+
1051
+ /**
1052
+ * @param {RegExpValidationState} state the validation state
1053
+ * @returns {boolean} whether a `\0` escape was read
1054
+ */
1055
+ regexp_eatZero(state) {
1056
+ if (state.current() === 0x30 && !isDecimalDigit(state.lookahead())) {
1057
+ state.lastIntValue = 0;
1058
+ state.advance();
1059
+ return true;
1060
+ }
1061
+ return false;
1062
+ }
1063
+
1064
+ /**
1065
+ * @param {RegExpValidationState} state the validation state
1066
+ * @returns {boolean} whether a control escape was read
1067
+ */
1068
+ regexp_eatControlEscape(state) {
1069
+ const ch = state.current();
1070
+ if (ch === 0x74) {
1071
+ state.lastIntValue = 0x09;
1072
+ state.advance();
1073
+ return true;
1074
+ }
1075
+ if (ch === 0x6e) {
1076
+ state.lastIntValue = 0x0a;
1077
+ state.advance();
1078
+ return true;
1079
+ }
1080
+ if (ch === 0x76) {
1081
+ state.lastIntValue = 0x0b;
1082
+ state.advance();
1083
+ return true;
1084
+ }
1085
+ if (ch === 0x66) {
1086
+ state.lastIntValue = 0x0c;
1087
+ state.advance();
1088
+ return true;
1089
+ }
1090
+ if (ch === 0x72) {
1091
+ state.lastIntValue = 0x0d;
1092
+ state.advance();
1093
+ return true;
1094
+ }
1095
+ return false;
1096
+ }
1097
+
1098
+ /**
1099
+ * @param {RegExpValidationState} state the validation state
1100
+ * @returns {boolean} whether a control letter was read
1101
+ */
1102
+ regexp_eatControlLetter(state) {
1103
+ const ch = state.current();
1104
+ if (isControlLetter(ch)) {
1105
+ state.lastIntValue = ch % 0x20;
1106
+ state.advance();
1107
+ return true;
1108
+ }
1109
+ return false;
1110
+ }
1111
+
1112
+ /**
1113
+ * @param {RegExpValidationState} state the validation state
1114
+ * @param {boolean=} forceU whether to read as if the `u` flag were set
1115
+ * @returns {boolean} whether an escape was read
1116
+ */
1117
+ regexp_eatRegExpUnicodeEscapeSequence(state, forceU) {
1118
+ const start = state.pos;
1119
+ const switchU = forceU || state.switchU;
1120
+
1121
+ if (state.eat(0x75)) {
1122
+ if (this.regexp_eatFixedHexDigits(state, 4)) {
1123
+ const lead = state.lastIntValue;
1124
+ if (switchU && lead >= 0xd800 && lead <= 0xdbff) {
1125
+ const leadSurrogateEnd = state.pos;
1126
+ if (
1127
+ state.eat(0x5c) &&
1128
+ state.eat(0x75) &&
1129
+ this.regexp_eatFixedHexDigits(state, 4)
1130
+ ) {
1131
+ const trail = state.lastIntValue;
1132
+ if (trail >= 0xdc00 && trail <= 0xdfff) {
1133
+ state.lastIntValue =
1134
+ (lead - 0xd800) * 0x400 + (trail - 0xdc00) + 0x10000;
1135
+ return true;
1136
+ }
1137
+ }
1138
+ state.pos = leadSurrogateEnd;
1139
+ state.lastIntValue = lead;
1140
+ }
1141
+ return true;
1142
+ }
1143
+ if (
1144
+ switchU &&
1145
+ state.eat(0x7b) &&
1146
+ this.regexp_eatHexDigits(state) &&
1147
+ state.eat(0x7d) &&
1148
+ isValidUnicode(state.lastIntValue)
1149
+ ) {
1150
+ return true;
1151
+ }
1152
+ if (switchU) state.raise("Invalid unicode escape");
1153
+ state.pos = start;
1154
+ }
1155
+
1156
+ return false;
1157
+ }
1158
+
1159
+ /**
1160
+ * @param {RegExpValidationState} state the validation state
1161
+ * @returns {boolean} whether an identity escape was read
1162
+ */
1163
+ regexp_eatIdentityEscape(state) {
1164
+ if (state.switchU) {
1165
+ if (this.regexp_eatSyntaxCharacter(state)) return true;
1166
+ if (state.eat(0x2f)) {
1167
+ state.lastIntValue = 0x2f;
1168
+ return true;
1169
+ }
1170
+ return false;
1171
+ }
1172
+
1173
+ const ch = state.current();
1174
+ if (ch !== 0x63 && (!state.switchN || ch !== 0x6b)) {
1175
+ state.lastIntValue = ch;
1176
+ state.advance();
1177
+ return true;
1178
+ }
1179
+
1180
+ return false;
1181
+ }
1182
+
1183
+ /**
1184
+ * @param {RegExpValidationState} state the validation state
1185
+ * @returns {boolean} whether a decimal escape was read
1186
+ */
1187
+ regexp_eatDecimalEscape(state) {
1188
+ state.lastIntValue = 0;
1189
+ let ch = state.current();
1190
+ if (ch >= 0x31 && ch <= 0x39) {
1191
+ do {
1192
+ state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30);
1193
+ state.advance();
1194
+ } while ((ch = state.current()) >= 0x30 && ch <= 0x39);
1195
+ return true;
1196
+ }
1197
+ return false;
1198
+ }
1199
+
1200
+ /**
1201
+ * @param {RegExpValidationState} state the validation state
1202
+ * @returns {number} which kind of character set was read
1203
+ */
1204
+ regexp_eatCharacterClassEscape(state) {
1205
+ const ch = state.current();
1206
+
1207
+ if (isCharacterClassEscape(ch)) {
1208
+ state.lastIntValue = -1;
1209
+ state.advance();
1210
+ return CHAR_SET_OK;
1211
+ }
1212
+
1213
+ let negate = false;
1214
+ if (
1215
+ state.switchU &&
1216
+ this.options.ecmaVersion >= 9 &&
1217
+ ((negate = ch === 0x50) || ch === 0x70)
1218
+ ) {
1219
+ state.lastIntValue = -1;
1220
+ state.advance();
1221
+ let result;
1222
+ if (
1223
+ state.eat(0x7b) &&
1224
+ (result = this.regexp_eatUnicodePropertyValueExpression(state)) &&
1225
+ state.eat(0x7d)
1226
+ ) {
1227
+ if (negate && result === CHAR_SET_STRING) {
1228
+ state.raise("Invalid property name");
1229
+ }
1230
+ return result;
1231
+ }
1232
+ state.raise("Invalid property name");
1233
+ }
1234
+
1235
+ return CHAR_SET_NONE;
1236
+ }
1237
+
1238
+ /**
1239
+ * @param {RegExpValidationState} state the validation state
1240
+ * @returns {number} which kind of character set was read
1241
+ */
1242
+ regexp_eatUnicodePropertyValueExpression(state) {
1243
+ const start = state.pos;
1244
+
1245
+ if (this.regexp_eatUnicodePropertyName(state) && state.eat(0x3d)) {
1246
+ const name = state.lastStringValue;
1247
+ if (this.regexp_eatUnicodePropertyValue(state)) {
1248
+ const value = state.lastStringValue;
1249
+ this.regexp_validateUnicodePropertyNameAndValue(state, name, value);
1250
+ return CHAR_SET_OK;
1251
+ }
1252
+ }
1253
+ state.pos = start;
1254
+
1255
+ if (this.regexp_eatLoneUnicodePropertyNameOrValue(state)) {
1256
+ const nameOrValue = state.lastStringValue;
1257
+ return this.regexp_validateUnicodePropertyNameOrValue(state, nameOrValue);
1258
+ }
1259
+ return CHAR_SET_NONE;
1260
+ }
1261
+
1262
+ /**
1263
+ * @param {RegExpValidationState} state the validation state
1264
+ * @param {string} name the property's name
1265
+ * @param {string} value the value asked for
1266
+ * @returns {void}
1267
+ */
1268
+ regexp_validateUnicodePropertyNameAndValue(state, name, value) {
1269
+ if (
1270
+ !Object.prototype.hasOwnProperty.call(
1271
+ state.unicodeProperties.nonBinary,
1272
+ name
1273
+ )
1274
+ ) {
1275
+ state.raise("Invalid property name");
1276
+ }
1277
+ if (!state.unicodeProperties.nonBinary[name].test(value)) {
1278
+ state.raise("Invalid property value");
1279
+ }
1280
+ }
1281
+
1282
+ /**
1283
+ * @param {RegExpValidationState} state the validation state
1284
+ * @param {string} nameOrValue the lone name
1285
+ * @returns {number} which kind of character set it names
1286
+ */
1287
+ regexp_validateUnicodePropertyNameOrValue(state, nameOrValue) {
1288
+ if (state.unicodeProperties.binary.test(nameOrValue)) return CHAR_SET_OK;
1289
+ if (
1290
+ state.switchV &&
1291
+ state.unicodeProperties.binaryOfStrings.test(nameOrValue)
1292
+ ) {
1293
+ return CHAR_SET_STRING;
1294
+ }
1295
+ state.raise("Invalid property name");
1296
+ return CHAR_SET_NONE;
1297
+ }
1298
+
1299
+ /**
1300
+ * @param {RegExpValidationState} state the validation state
1301
+ * @returns {boolean} whether a property name was read
1302
+ */
1303
+ regexp_eatUnicodePropertyName(state) {
1304
+ let ch = 0;
1305
+ state.lastStringValue = "";
1306
+ while (isUnicodePropertyNameCharacter((ch = state.current()))) {
1307
+ state.lastStringValue += codePointToString(ch);
1308
+ state.advance();
1309
+ }
1310
+ return state.lastStringValue !== "";
1311
+ }
1312
+
1313
+ /**
1314
+ * @param {RegExpValidationState} state the validation state
1315
+ * @returns {boolean} whether a property value was read
1316
+ */
1317
+ regexp_eatUnicodePropertyValue(state) {
1318
+ let ch = 0;
1319
+ state.lastStringValue = "";
1320
+ while (isUnicodePropertyValueCharacter((ch = state.current()))) {
1321
+ state.lastStringValue += codePointToString(ch);
1322
+ state.advance();
1323
+ }
1324
+ return state.lastStringValue !== "";
1325
+ }
1326
+
1327
+ /**
1328
+ * @param {RegExpValidationState} state the validation state
1329
+ * @returns {boolean} whether a lone name was read
1330
+ */
1331
+ regexp_eatLoneUnicodePropertyNameOrValue(state) {
1332
+ return this.regexp_eatUnicodePropertyValue(state);
1333
+ }
1334
+
1335
+ /**
1336
+ * @param {RegExpValidationState} state the validation state
1337
+ * @returns {boolean} whether a character class was read
1338
+ */
1339
+ regexp_eatCharacterClass(state) {
1340
+ if (state.eat(0x5b)) {
1341
+ const negate = state.eat(0x5e);
1342
+ const result = this.regexp_classContents(state);
1343
+ if (!state.eat(0x5d)) state.raise("Unterminated character class");
1344
+ if (negate && result === CHAR_SET_STRING) {
1345
+ state.raise("Negated character class may contain strings");
1346
+ }
1347
+ return true;
1348
+ }
1349
+ return false;
1350
+ }
1351
+
1352
+ /**
1353
+ * @param {RegExpValidationState} state the validation state
1354
+ * @returns {number} which kind of character set the contents are
1355
+ */
1356
+ regexp_classContents(state) {
1357
+ if (state.current() === 0x5d) return CHAR_SET_OK;
1358
+ if (state.switchV) return this.regexp_classSetExpression(state);
1359
+ this.regexp_nonEmptyClassRanges(state);
1360
+ return CHAR_SET_OK;
1361
+ }
1362
+
1363
+ /**
1364
+ * @param {RegExpValidationState} state the validation state
1365
+ * @returns {void}
1366
+ */
1367
+ regexp_nonEmptyClassRanges(state) {
1368
+ while (this.regexp_eatClassAtom(state)) {
1369
+ const left = state.lastIntValue;
1370
+ if (state.eat(0x2d) && this.regexp_eatClassAtom(state)) {
1371
+ const right = state.lastIntValue;
1372
+ if (state.switchU && (left === -1 || right === -1)) {
1373
+ state.raise("Invalid character class");
1374
+ }
1375
+ if (left !== -1 && right !== -1 && left > right) {
1376
+ state.raise("Range out of order in character class");
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ /**
1383
+ * @param {RegExpValidationState} state the validation state
1384
+ * @returns {boolean} whether a class atom was read
1385
+ */
1386
+ regexp_eatClassAtom(state) {
1387
+ const start = state.pos;
1388
+
1389
+ if (state.eat(0x5c)) {
1390
+ if (this.regexp_eatClassEscape(state)) return true;
1391
+ if (state.switchU) {
1392
+ // Worded as V8 words them.
1393
+ const escaped = state.current();
1394
+ if (escaped === 0x63 || isOctalDigit(escaped)) {
1395
+ state.raise("Invalid class escape");
1396
+ }
1397
+ state.raise("Invalid escape");
1398
+ }
1399
+ state.pos = start;
1400
+ }
1401
+
1402
+ const ch = state.current();
1403
+ if (ch !== 0x5d) {
1404
+ state.lastIntValue = ch;
1405
+ state.advance();
1406
+ return true;
1407
+ }
1408
+
1409
+ return false;
1410
+ }
1411
+
1412
+ /**
1413
+ * @param {RegExpValidationState} state the validation state
1414
+ * @returns {boolean} whether a class escape was read
1415
+ */
1416
+ regexp_eatClassEscape(state) {
1417
+ const start = state.pos;
1418
+
1419
+ if (state.eat(0x62)) {
1420
+ state.lastIntValue = 0x08;
1421
+ return true;
1422
+ }
1423
+
1424
+ if (state.switchU && state.eat(0x2d)) {
1425
+ state.lastIntValue = 0x2d;
1426
+ return true;
1427
+ }
1428
+
1429
+ if (!state.switchU && state.eat(0x63)) {
1430
+ if (this.regexp_eatClassControlLetter(state)) return true;
1431
+ state.pos = start;
1432
+ }
1433
+
1434
+ return Boolean(
1435
+ this.regexp_eatCharacterClassEscape(state) ||
1436
+ this.regexp_eatCharacterEscape(state)
1437
+ );
1438
+ }
1439
+
1440
+ /**
1441
+ * @param {RegExpValidationState} state the validation state
1442
+ * @returns {number} which kind of character set was read
1443
+ */
1444
+ regexp_classSetExpression(state) {
1445
+ let result = CHAR_SET_OK;
1446
+ let subResult;
1447
+ if (this.regexp_eatClassSetRange(state)) {
1448
+ // A range is its own operand, so nothing more binds to it here.
1449
+ } else if ((subResult = this.regexp_eatClassSetOperand(state))) {
1450
+ if (subResult === CHAR_SET_STRING) result = CHAR_SET_STRING;
1451
+ const start = state.pos;
1452
+ while (state.eatChars([0x26, 0x26])) {
1453
+ if (
1454
+ state.current() !== 0x26 &&
1455
+ (subResult = this.regexp_eatClassSetOperand(state))
1456
+ ) {
1457
+ if (subResult !== CHAR_SET_STRING) result = CHAR_SET_OK;
1458
+ continue;
1459
+ }
1460
+ state.raise("Invalid character in character class");
1461
+ }
1462
+ if (start !== state.pos) return result;
1463
+ while (state.eatChars([0x2d, 0x2d])) {
1464
+ if (this.regexp_eatClassSetOperand(state)) continue;
1465
+ state.raise("Invalid character in character class");
1466
+ }
1467
+ if (start !== state.pos) return result;
1468
+ } else {
1469
+ state.raise("Invalid character in character class");
1470
+ }
1471
+ for (;;) {
1472
+ if (this.regexp_eatClassSetRange(state)) continue;
1473
+ subResult = this.regexp_eatClassSetOperand(state);
1474
+ if (!subResult) return result;
1475
+ if (subResult === CHAR_SET_STRING) result = CHAR_SET_STRING;
1476
+ }
1477
+ }
1478
+
1479
+ /**
1480
+ * @param {RegExpValidationState} state the validation state
1481
+ * @returns {boolean} whether a range was read
1482
+ */
1483
+ regexp_eatClassSetRange(state) {
1484
+ const start = state.pos;
1485
+ if (this.regexp_eatClassSetCharacter(state)) {
1486
+ const left = state.lastIntValue;
1487
+ if (state.eat(0x2d) && this.regexp_eatClassSetCharacter(state)) {
1488
+ const right = state.lastIntValue;
1489
+ if (left !== -1 && right !== -1 && left > right) {
1490
+ state.raise("Range out of order in character class");
1491
+ }
1492
+ return true;
1493
+ }
1494
+ state.pos = start;
1495
+ }
1496
+ return false;
1497
+ }
1498
+
1499
+ /**
1500
+ * @param {RegExpValidationState} state the validation state
1501
+ * @returns {number | null} which kind of character set was read
1502
+ */
1503
+ regexp_eatClassSetOperand(state) {
1504
+ if (this.regexp_eatClassSetCharacter(state)) return CHAR_SET_OK;
1505
+ return (
1506
+ this.regexp_eatClassStringDisjunction(state) ||
1507
+ this.regexp_eatNestedClass(state)
1508
+ );
1509
+ }
1510
+
1511
+ /**
1512
+ * @param {RegExpValidationState} state the validation state
1513
+ * @returns {number | null} which kind of character set was read
1514
+ */
1515
+ regexp_eatNestedClass(state) {
1516
+ const start = state.pos;
1517
+ if (state.eat(0x5b)) {
1518
+ const negate = state.eat(0x5e);
1519
+ const result = this.regexp_classContents(state);
1520
+ if (state.eat(0x5d)) {
1521
+ if (negate && result === CHAR_SET_STRING) {
1522
+ state.raise("Negated character class may contain strings");
1523
+ }
1524
+ return result;
1525
+ }
1526
+ state.pos = start;
1527
+ }
1528
+ if (state.eat(0x5c)) {
1529
+ const result = this.regexp_eatCharacterClassEscape(state);
1530
+ if (result) return result;
1531
+ state.pos = start;
1532
+ }
1533
+ return null;
1534
+ }
1535
+
1536
+ /**
1537
+ * @param {RegExpValidationState} state the validation state
1538
+ * @returns {number | null} which kind of character set was read
1539
+ */
1540
+ regexp_eatClassStringDisjunction(state) {
1541
+ const start = state.pos;
1542
+ if (state.eatChars([0x5c, 0x71])) {
1543
+ if (state.eat(0x7b)) {
1544
+ const result = this.regexp_classStringDisjunctionContents(state);
1545
+ if (state.eat(0x7d)) return result;
1546
+ } else {
1547
+ // Worded as V8 words it.
1548
+ state.raise("Invalid escape");
1549
+ }
1550
+ state.pos = start;
1551
+ }
1552
+ return null;
1553
+ }
1554
+
1555
+ /**
1556
+ * @param {RegExpValidationState} state the validation state
1557
+ * @returns {number} which kind of character set was read
1558
+ */
1559
+ regexp_classStringDisjunctionContents(state) {
1560
+ let result = this.regexp_classString(state);
1561
+ while (state.eat(0x7c)) {
1562
+ if (this.regexp_classString(state) === CHAR_SET_STRING) {
1563
+ result = CHAR_SET_STRING;
1564
+ }
1565
+ }
1566
+ return result;
1567
+ }
1568
+
1569
+ /**
1570
+ * @param {RegExpValidationState} state the validation state
1571
+ * @returns {number} which kind of character set was read
1572
+ */
1573
+ regexp_classString(state) {
1574
+ let count = 0;
1575
+ while (this.regexp_eatClassSetCharacter(state)) count++;
1576
+ return count === 1 ? CHAR_SET_OK : CHAR_SET_STRING;
1577
+ }
1578
+
1579
+ /**
1580
+ * @param {RegExpValidationState} state the validation state
1581
+ * @returns {boolean} whether a character was read
1582
+ */
1583
+ regexp_eatClassSetCharacter(state) {
1584
+ const start = state.pos;
1585
+ if (state.eat(0x5c)) {
1586
+ if (
1587
+ this.regexp_eatCharacterEscape(state) ||
1588
+ this.regexp_eatClassSetReservedPunctuator(state)
1589
+ ) {
1590
+ return true;
1591
+ }
1592
+ if (state.eat(0x62)) {
1593
+ state.lastIntValue = 0x08;
1594
+ return true;
1595
+ }
1596
+ state.pos = start;
1597
+ return false;
1598
+ }
1599
+ const ch = state.current();
1600
+ if (
1601
+ ch < 0 ||
1602
+ (ch === state.lookahead() &&
1603
+ isClassSetReservedDoublePunctuatorCharacter(ch))
1604
+ ) {
1605
+ return false;
1606
+ }
1607
+ if (isClassSetSyntaxCharacter(ch)) return false;
1608
+ state.advance();
1609
+ state.lastIntValue = ch;
1610
+ return true;
1611
+ }
1612
+
1613
+ /**
1614
+ * @param {RegExpValidationState} state the validation state
1615
+ * @returns {boolean} whether a reserved punctuator was read
1616
+ */
1617
+ regexp_eatClassSetReservedPunctuator(state) {
1618
+ const ch = state.current();
1619
+ if (isClassSetReservedPunctuator(ch)) {
1620
+ state.lastIntValue = ch;
1621
+ state.advance();
1622
+ return true;
1623
+ }
1624
+ return false;
1625
+ }
1626
+
1627
+ /**
1628
+ * @param {RegExpValidationState} state the validation state
1629
+ * @returns {boolean} whether a control letter was read
1630
+ */
1631
+ regexp_eatClassControlLetter(state) {
1632
+ const ch = state.current();
1633
+ if (isDecimalDigit(ch) || ch === 0x5f) {
1634
+ state.lastIntValue = ch % 0x20;
1635
+ state.advance();
1636
+ return true;
1637
+ }
1638
+ return false;
1639
+ }
1640
+
1641
+ /**
1642
+ * @param {RegExpValidationState} state the validation state
1643
+ * @returns {boolean} whether a hex escape was read
1644
+ */
1645
+ regexp_eatHexEscapeSequence(state) {
1646
+ const start = state.pos;
1647
+ if (state.eat(0x78)) {
1648
+ if (this.regexp_eatFixedHexDigits(state, 2)) return true;
1649
+ if (state.switchU) state.raise("Invalid escape");
1650
+ state.pos = start;
1651
+ }
1652
+ return false;
1653
+ }
1654
+
1655
+ /**
1656
+ * @param {RegExpValidationState} state the validation state
1657
+ * @returns {boolean} whether any digits were read
1658
+ */
1659
+ regexp_eatDecimalDigits(state) {
1660
+ const start = state.pos;
1661
+ let ch = 0;
1662
+ state.lastIntValue = 0;
1663
+ while (isDecimalDigit((ch = state.current()))) {
1664
+ state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30);
1665
+ state.advance();
1666
+ }
1667
+ return state.pos !== start;
1668
+ }
1669
+
1670
+ /**
1671
+ * @param {RegExpValidationState} state the validation state
1672
+ * @returns {boolean} whether any digits were read
1673
+ */
1674
+ regexp_eatHexDigits(state) {
1675
+ const start = state.pos;
1676
+ let ch = 0;
1677
+ state.lastIntValue = 0;
1678
+ while (isHexDigit((ch = state.current()))) {
1679
+ state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch);
1680
+ state.advance();
1681
+ }
1682
+ return state.pos !== start;
1683
+ }
1684
+
1685
+ /**
1686
+ * Read a legacy octal escape, which names only `0` through `377`.
1687
+ * @param {RegExpValidationState} state the validation state
1688
+ * @returns {boolean} whether one was read
1689
+ */
1690
+ regexp_eatLegacyOctalEscapeSequence(state) {
1691
+ if (this.regexp_eatOctalDigit(state)) {
1692
+ const n1 = state.lastIntValue;
1693
+ if (this.regexp_eatOctalDigit(state)) {
1694
+ const n2 = state.lastIntValue;
1695
+ state.lastIntValue =
1696
+ n1 <= 3 && this.regexp_eatOctalDigit(state)
1697
+ ? n1 * 64 + n2 * 8 + state.lastIntValue
1698
+ : n1 * 8 + n2;
1699
+ } else {
1700
+ state.lastIntValue = n1;
1701
+ }
1702
+ return true;
1703
+ }
1704
+ return false;
1705
+ }
1706
+
1707
+ /**
1708
+ * @param {RegExpValidationState} state the validation state
1709
+ * @returns {boolean} whether a digit was read
1710
+ */
1711
+ regexp_eatOctalDigit(state) {
1712
+ const ch = state.current();
1713
+ if (isOctalDigit(ch)) {
1714
+ state.lastIntValue = ch - 0x30;
1715
+ state.advance();
1716
+ return true;
1717
+ }
1718
+ state.lastIntValue = 0;
1719
+ return false;
1720
+ }
1721
+
1722
+ /**
1723
+ * @param {RegExpValidationState} state the validation state
1724
+ * @param {number} length exactly how many digits to read
1725
+ * @returns {boolean} whether that many were there
1726
+ */
1727
+ regexp_eatFixedHexDigits(state, length) {
1728
+ const start = state.pos;
1729
+ state.lastIntValue = 0;
1730
+ for (let i = 0; i < length; ++i) {
1731
+ const ch = state.current();
1732
+ if (!isHexDigit(ch)) {
1733
+ state.pos = start;
1734
+ return false;
1735
+ }
1736
+ state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch);
1737
+ state.advance();
1738
+ }
1739
+ return true;
1740
+ }
1741
+ }
1742
+
1743
+ /**
1744
+ * Copy the validator onto the parser's prototype, leaving alone any name the
1745
+ * parser (or something that patched it) already declares.
1746
+ * @param {typeof Parser} target the parser class to extend
1747
+ * @returns {void}
1748
+ */
1749
+ const install = (target) => {
1750
+ for (const name of Object.getOwnPropertyNames(RegExpValidator.prototype)) {
1751
+ if (name === "constructor") continue;
1752
+ if (Object.prototype.hasOwnProperty.call(target.prototype, name)) continue;
1753
+ /** @type {EXPECTED_ANY} */
1754
+ (target.prototype)[name] = /** @type {EXPECTED_ANY} */ (
1755
+ RegExpValidator.prototype
1756
+ )[name];
1757
+ }
1758
+ };
1759
+
1760
+ module.exports.RegExpValidationState = RegExpValidationState;
1761
+ module.exports.RegExpValidator = RegExpValidator;
1762
+ module.exports.install = install;