@depup/webpack 5.109.0-depup.0 → 5.110.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.
- package/README.md +7 -7
- package/bin/webpack.js +12 -0
- package/changes.json +10 -10
- package/lib/APIPlugin.js +123 -17
- package/lib/AsyncDependenciesBlock.js +10 -7
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/BannerPlugin.js +10 -6
- package/lib/CacheFacade.js +6 -6
- package/lib/Chunk.js +14 -11
- package/lib/ChunkGraph.js +43 -32
- package/lib/ChunkGroup.js +7 -7
- package/lib/ChunkTemplate.js +35 -44
- package/lib/CircularModulesPlugin.js +205 -28
- package/lib/CleanPlugin.js +15 -16
- package/lib/CodeGenerationResults.js +11 -8
- package/lib/CompatibilityPlugin.js +38 -7
- package/lib/Compilation.js +709 -414
- package/lib/Compiler.js +69 -42
- package/lib/ConcatenationScope.js +117 -8
- package/lib/ConditionalInitFragment.js +3 -3
- package/lib/ConstPlugin.js +13 -11
- package/lib/ContextExclusionPlugin.js +1 -1
- package/lib/ContextModule.js +146 -54
- package/lib/ContextModuleFactory.js +46 -14
- package/lib/ContextReplacementPlugin.js +12 -14
- package/lib/DefinePlugin.js +168 -57
- package/lib/DependenciesBlock.js +9 -6
- package/lib/Dependency.js +36 -16
- package/lib/DependencyTemplate.js +11 -12
- package/lib/DependencyTemplates.js +3 -3
- package/lib/DotenvPlugin.js +50 -13
- package/lib/DynamicEntryPlugin.js +8 -4
- package/lib/EntryOptionPlugin.js +8 -4
- package/lib/EntryPlugin.js +2 -2
- package/lib/Entrypoint.js +6 -2
- package/lib/EnvironmentPlugin.js +2 -2
- package/lib/EvalDevToolModulePlugin.js +8 -4
- package/lib/EvalSourceMapDevToolPlugin.js +15 -8
- package/lib/ExportsInfo.js +123 -19
- package/lib/ExportsInfoApiPlugin.js +2 -4
- package/lib/ExternalModule.js +242 -84
- package/lib/ExternalModuleFactoryPlugin.js +97 -38
- package/lib/ExternalsPlugin.js +10 -6
- package/lib/FileSystemInfo.js +116 -42
- package/lib/FlagAllModulesAsUsedPlugin.js +2 -3
- package/lib/FlagDependencyExportsPlugin.js +76 -19
- package/lib/FlagDependencyUsagePlugin.js +63 -57
- package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
- package/lib/Generator.js +36 -15
- package/lib/HotModuleReplacementPlugin.js +16 -44
- package/lib/IgnorePlugin.js +8 -4
- package/lib/IgnoreWarningsPlugin.js +2 -2
- package/lib/InitFragment.js +28 -36
- package/lib/JavascriptMetaInfoPlugin.js +35 -4
- package/lib/LazyBarrel.js +3 -4
- package/lib/LibraryTemplatePlugin.js +10 -6
- package/lib/LoaderOptionsPlugin.js +7 -3
- package/lib/LoaderTargetPlugin.js +1 -1
- package/lib/MainTemplate.js +49 -42
- package/lib/ManifestPlugin.js +12 -11
- package/lib/Module.js +62 -33
- package/lib/ModuleFactory.js +3 -3
- package/lib/ModuleFilenameHelpers.js +22 -6
- package/lib/ModuleGraph.js +195 -21
- package/lib/ModuleGraphConnection.js +6 -13
- package/lib/ModuleInfoHeaderPlugin.js +8 -10
- package/lib/ModuleTemplate.js +62 -63
- package/lib/MultiCompiler.js +130 -64
- package/lib/MultiStats.js +40 -9
- package/lib/MultiWatching.js +3 -3
- package/lib/NoEmitOnErrorsPlugin.js +1 -1
- package/lib/NodeStuffPlugin.js +29 -19
- package/lib/NormalModule.js +221 -156
- package/lib/NormalModuleFactory.js +563 -112
- package/lib/NormalModuleReplacementPlugin.js +5 -8
- package/lib/NullFactory.js +6 -2
- package/lib/OptionsApply.js +7 -3
- package/lib/Parser.js +7 -3
- package/lib/PlatformPlugin.js +2 -2
- package/lib/PrefetchPlugin.js +1 -1
- package/lib/ProgressPlugin.js +16 -13
- package/lib/ProvidePlugin.js +3 -5
- package/lib/RawModule.js +25 -17
- package/lib/RecordIdsPlugin.js +3 -3
- package/lib/RequestShortener.js +1 -1
- package/lib/ResolverFactory.js +2 -2
- package/lib/RuntimeGlobals.js +22 -10
- package/lib/RuntimeModule.js +29 -19
- package/lib/RuntimePlugin.js +346 -256
- package/lib/RuntimeTemplate.js +2792 -352
- package/lib/SelfModuleFactory.js +7 -3
- package/lib/SourceMapDevToolModuleOptionsPlugin.js +6 -2
- package/lib/SourceMapDevToolPlugin.js +30 -20
- package/lib/Stats.js +3 -4
- package/lib/Template.js +55 -25
- package/lib/TemplatedPathPlugin.js +96 -14
- package/lib/UseStrictPlugin.js +4 -6
- package/lib/WarnCaseSensitiveModulesPlugin.js +4 -4
- package/lib/WarnDeprecatedOptionPlugin.js +1 -1
- package/lib/WarnNoModeSetPlugin.js +1 -1
- package/lib/WatchIgnorePlugin.js +8 -6
- package/lib/Watching.js +8 -8
- package/lib/WebpackIsIncludedPlugin.js +2 -4
- package/lib/WebpackOptionsApply.js +308 -18
- package/lib/WebpackOptionsDefaulter.js +6 -2
- package/lib/asset/AssetBytesGenerator.js +12 -10
- package/lib/asset/AssetBytesParser.js +2 -4
- package/lib/asset/AssetGenerator.js +188 -95
- package/lib/asset/AssetModule.js +7 -3
- package/lib/asset/AssetModulesPlugin.js +110 -38
- package/lib/asset/AssetParser.js +9 -7
- package/lib/asset/AssetSourceGenerator.js +60 -13
- package/lib/asset/AssetSourceParser.js +2 -4
- package/lib/asset/RawDataUrlModule.js +24 -16
- package/lib/asset/WebManifestGenerator.js +8 -10
- package/lib/asset/WebManifestParser.js +24 -10
- package/lib/async-modules/AsyncModuleHelpers.js +2 -2
- package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
- package/lib/async-modules/InferAsyncModulesPlugin.js +2 -2
- package/lib/async-modules/isGeneratorLowered.js +4 -4
- package/lib/buildChunkGraph.js +36 -27
- package/lib/bun/BunTargetPlugin.js +1 -1
- package/lib/cache/AddBuildDependenciesPlugin.js +1 -1
- package/lib/cache/AddManagedPathsPlugin.js +1 -1
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/MemoryCachePlugin.js +18 -10
- package/lib/cache/MemoryWithGcCachePlugin.js +34 -22
- package/lib/cache/PackFileCacheStrategy.js +289 -28
- package/lib/cache/ResolverCachePlugin.js +38 -18
- package/lib/cache/getLazyHashedEtag.js +1 -2
- package/lib/cache/mergeEtags.js +1 -1
- package/lib/cli.js +1 -3
- package/lib/config/browserslistTargetHandler.js +41 -5
- package/lib/config/defaults.js +282 -81
- package/lib/config/defineConfig.js +10 -2
- package/lib/config/getClaimedAssetTypes.js +65 -0
- package/lib/config/normalization.js +36 -16
- package/lib/config/target.js +46 -3
- package/lib/container/ContainerEntryDependency.js +1 -1
- package/lib/container/ContainerEntryModule.js +24 -15
- package/lib/container/ContainerEntryModuleFactory.js +7 -3
- package/lib/container/ContainerPlugin.js +9 -10
- package/lib/container/ContainerReferencePlugin.js +6 -2
- package/lib/container/FallbackDependency.js +1 -1
- package/lib/container/FallbackModule.js +24 -17
- package/lib/container/FallbackModuleFactory.js +7 -3
- package/lib/container/HoistContainerReferencesPlugin.js +53 -66
- package/lib/container/ModuleFederationPlugin.js +7 -18
- package/lib/container/RemoteModule.js +27 -19
- package/lib/container/RemoteRuntimeModule.js +10 -8
- package/lib/container/moduleFederationHooks.js +32 -0
- package/lib/css/CssGenerator.js +178 -44
- package/lib/css/CssInjectStyleRuntimeModule.js +7 -5
- package/lib/css/CssLoadingRuntimeModule.js +82 -36
- package/lib/css/CssModule.js +10 -7
- package/lib/css/CssModulesPlugin.js +197 -106
- package/lib/css/CssParser.js +1248 -618
- package/lib/css/CssServerStylesRuntimeModule.js +54 -0
- package/lib/css/cssMinify.js +168 -0
- package/lib/css/data.js +5324 -0
- package/lib/css/syntax.js +10396 -952
- package/lib/debug/ProfilingPlugin.js +14 -9
- package/lib/deno/DenoTargetPlugin.js +1 -1
- package/lib/dependencies/AMDDefineDependency.js +112 -87
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +30 -17
- package/lib/dependencies/AMDPlugin.js +9 -7
- package/lib/dependencies/AMDRequireArrayDependency.js +5 -5
- package/lib/dependencies/AMDRequireContextDependency.js +2 -2
- package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -1
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +25 -14
- package/lib/dependencies/AMDRequireDependency.js +8 -7
- package/lib/dependencies/AMDRequireItemDependency.js +1 -1
- package/lib/dependencies/AMDRuntimeModules.js +21 -1
- package/lib/dependencies/BuildTimeConstDependency.js +102 -0
- package/lib/dependencies/CachedConstDependency.js +11 -8
- package/lib/dependencies/CommonJsDependencyHelpers.js +67 -46
- package/lib/dependencies/CommonJsExportRequireDependency.js +140 -45
- package/lib/dependencies/CommonJsExportsDependency.js +53 -49
- package/lib/dependencies/CommonJsExportsParserPlugin.js +207 -25
- package/lib/dependencies/CommonJsFullRequireDependency.js +140 -26
- package/lib/dependencies/CommonJsImportsParserPlugin.js +100 -48
- package/lib/dependencies/CommonJsObjectExportDependency.js +188 -0
- package/lib/dependencies/CommonJsPlugin.js +35 -6
- package/lib/dependencies/CommonJsRequireContextDependency.js +5 -6
- package/lib/dependencies/CommonJsRequireDependency.js +156 -27
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +63 -38
- package/lib/dependencies/ConstDependency.js +8 -9
- package/lib/dependencies/ContextDependency.js +12 -8
- package/lib/dependencies/ContextDependencyHelpers.js +14 -9
- package/lib/dependencies/ContextDependencyTemplateAsId.js +4 -4
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +4 -4
- package/lib/dependencies/ContextElementDependency.js +31 -12
- package/lib/dependencies/CreateRequireParserPlugin.js +12 -7
- package/lib/dependencies/CreateScriptUrlDependency.js +4 -4
- package/lib/dependencies/CssIcssExportDependency.js +56 -28
- package/lib/dependencies/CssIcssImportDependency.js +17 -13
- package/lib/dependencies/CssIcssSymbolDependency.js +9 -10
- package/lib/dependencies/CssImportDependency.js +18 -9
- package/lib/dependencies/CssUrlDependency.js +17 -13
- package/lib/dependencies/DllEntryDependency.js +1 -1
- package/lib/dependencies/DynamicExports.js +2 -2
- package/lib/dependencies/ExportBindingInitFragment.js +36 -9
- package/lib/dependencies/ExportsInfoDependency.js +7 -8
- package/lib/dependencies/ExternalModuleDependency.js +9 -5
- package/lib/dependencies/ExternalModuleInitFragment.js +2 -2
- package/lib/dependencies/ExternalModuleInitFragmentDependency.js +8 -5
- package/lib/dependencies/HarmonyAcceptDependency.js +5 -5
- package/lib/dependencies/HarmonyCompatibilityDependency.js +52 -17
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +11 -7
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +15 -11
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +78 -12
- package/lib/dependencies/HarmonyExportExpressionDependency.js +23 -18
- package/lib/dependencies/HarmonyExportHeaderDependency.js +7 -7
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +159 -71
- package/lib/dependencies/HarmonyExportInitFragment.js +18 -6
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +51 -14
- package/lib/dependencies/HarmonyExports.js +7 -4
- package/lib/dependencies/HarmonyImportDependency.js +28 -20
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +31 -24
- package/lib/dependencies/HarmonyImportGuard.js +21 -30
- package/lib/dependencies/HarmonyImportSideEffectDependency.js +38 -9
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +106 -55
- package/lib/dependencies/HarmonyModulesPlugin.js +7 -3
- package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -3
- package/lib/dependencies/HtmlEntryDependency.js +37 -29
- package/lib/dependencies/HtmlInlineHtmlDependency.js +7 -8
- package/lib/dependencies/HtmlInlineScriptDependency.js +11 -8
- package/lib/dependencies/HtmlInlineStyleDependency.js +7 -10
- package/lib/dependencies/HtmlSourceDependency.js +22 -14
- package/lib/dependencies/ImportContextDependency.js +2 -2
- package/lib/dependencies/ImportDependency.js +24 -20
- package/lib/dependencies/ImportEagerDependency.js +6 -9
- package/lib/dependencies/ImportMetaContextDependency.js +2 -2
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +14 -13
- package/lib/dependencies/ImportMetaContextPlugin.js +7 -3
- package/lib/dependencies/ImportMetaGlobDependency.js +2 -2
- package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +2 -3
- package/lib/dependencies/ImportMetaGlobHelpers.js +19 -22
- package/lib/dependencies/ImportMetaHotAcceptDependency.js +1 -1
- package/lib/dependencies/ImportMetaHotDeclineDependency.js +1 -1
- package/lib/dependencies/ImportMetaPlugin.js +154 -71
- package/lib/dependencies/ImportMetaResolveDependency.js +3 -4
- package/lib/dependencies/ImportParserPlugin.js +49 -35
- package/lib/dependencies/ImportPhase.js +12 -5
- package/lib/dependencies/ImportPlugin.js +7 -3
- package/lib/dependencies/ImportWeakDependency.js +6 -9
- package/lib/dependencies/JsonExportsDependency.js +11 -7
- package/lib/dependencies/LoaderDependency.js +2 -2
- package/lib/dependencies/LoaderImportDependency.js +2 -2
- package/lib/dependencies/LoaderPlugin.js +11 -7
- package/lib/dependencies/LocalModuleDependency.js +5 -5
- package/lib/dependencies/LocalModulesHelpers.js +1 -1
- package/lib/dependencies/ModuleDecoratorDependency.js +6 -7
- package/lib/dependencies/ModuleDependency.js +9 -6
- package/lib/dependencies/ModuleDependencyTemplateAsId.js +4 -4
- package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +3 -3
- package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
- package/lib/dependencies/ModuleHotDeclineDependency.js +1 -1
- package/lib/dependencies/ModuleInitFragmentDependency.js +24 -10
- package/lib/dependencies/NullDependency.js +3 -3
- package/lib/dependencies/ProvidedDependency.js +14 -10
- package/lib/dependencies/PureExpressionDependency.js +9 -10
- package/lib/dependencies/RequireContextDependency.js +2 -2
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -4
- package/lib/dependencies/RequireContextPlugin.js +8 -4
- package/lib/dependencies/RequireEnsureDependenciesBlock.js +2 -2
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +5 -8
- package/lib/dependencies/RequireEnsureDependency.js +8 -7
- package/lib/dependencies/RequireEnsurePlugin.js +7 -3
- package/lib/dependencies/RequireHeaderDependency.js +51 -12
- package/lib/dependencies/RequireIncludeDependency.js +6 -6
- package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +2 -3
- package/lib/dependencies/RequireIncludePlugin.js +7 -3
- package/lib/dependencies/RequireJsStuffPlugin.js +7 -3
- package/lib/dependencies/RequireResolveContextDependency.js +2 -2
- package/lib/dependencies/RequireResolveDependency.js +4 -4
- package/lib/dependencies/RequireResolveHeaderDependency.js +4 -4
- package/lib/dependencies/RuntimeRequirementsDependency.js +5 -6
- package/lib/dependencies/StaticExportsDependency.js +2 -2
- package/lib/dependencies/SystemPlugin.js +10 -6
- package/lib/dependencies/SystemRuntimeModule.js +10 -0
- package/lib/dependencies/TopLevelAwaitDependency.js +11 -7
- package/lib/dependencies/URLContextDependency.js +2 -2
- package/lib/dependencies/URLDependency.js +110 -64
- package/lib/dependencies/URLPlugin.js +7 -3
- package/lib/dependencies/UnsupportedDependency.js +4 -4
- package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -4
- package/lib/dependencies/WebAssemblyImportDependency.js +5 -5
- package/lib/dependencies/WebpackIsIncludedDependency.js +6 -6
- package/lib/dependencies/WorkerAndWorkletPlugin.js +46 -28
- package/lib/dependencies/WorkerDependency.js +28 -22
- package/lib/dependencies/WorkletDependency.js +15 -14
- package/lib/dependencies/getFunctionExpression.js +8 -4
- package/lib/dependencies/processExportInfo.js +5 -5
- package/lib/dll/DelegatedModule.js +34 -22
- package/lib/dll/DelegatedModuleFactoryPlugin.js +15 -7
- package/lib/dll/DelegatedPlugin.js +2 -2
- package/lib/dll/DllEntryPlugin.js +2 -2
- package/lib/dll/DllModule.js +22 -15
- package/lib/dll/DllModuleFactory.js +7 -3
- package/lib/dll/DllPlugin.js +7 -5
- package/lib/dll/DllReferencePlugin.js +10 -7
- package/lib/dll/LibManifestPlugin.js +5 -5
- package/lib/electron/ElectronTargetPlugin.js +53 -49
- package/lib/errors/AsyncChunkWaterfallWarning.js +36 -0
- package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
- package/lib/errors/BroadContextsWarning.js +43 -0
- package/lib/errors/BuildCycleError.js +1 -1
- package/lib/errors/CacheEffectivenessWarning.js +55 -0
- package/lib/errors/ChunkRenderError.js +1 -1
- package/lib/errors/CircularDependenciesWarning.js +38 -0
- package/lib/errors/CodeGenerationError.js +1 -1
- package/lib/errors/CommentCompilationWarning.js +1 -1
- package/lib/errors/ConflictingResourceHintsWarning.js +35 -0
- package/lib/errors/DuplicateModulesWarning.js +45 -0
- package/lib/errors/DynamicExportsWarning.js +30 -0
- package/lib/errors/EmbeddedSourceMapsWarning.js +25 -0
- package/lib/errors/EntrypointOverlapWarning.js +45 -0
- package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
- package/lib/errors/EvalUsageWarning.js +28 -0
- package/lib/errors/HookWebpackError.js +5 -5
- package/lib/errors/HotspotsWarning.js +57 -0
- package/lib/errors/IgnoreErrorModuleFactory.js +7 -3
- package/lib/errors/InlinedAssetsWarning.js +36 -0
- package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
- package/lib/errors/LargeModulesWarning.js +45 -0
- package/lib/errors/LegacyJavascriptWarning.js +48 -0
- package/lib/errors/MissingSideEffectsWarning.js +36 -0
- package/lib/errors/MixedExportsWarning.js +41 -0
- package/lib/errors/ModuleDependencyError.js +13 -16
- package/lib/errors/ModuleDependencyWarning.js +5 -15
- package/lib/errors/ModuleHashingError.js +1 -1
- package/lib/errors/ModuleNotFoundError.js +2 -2
- package/lib/errors/ModuleParseError.js +1 -2
- package/lib/errors/ModuleRestoreError.js +1 -1
- package/lib/errors/ModuleStoreError.js +1 -1
- package/lib/errors/NodeStuffInWebError.js +1 -1
- package/lib/errors/OsDependentRuleWarning.js +31 -0
- package/lib/errors/PureAnnotationsWarning.js +36 -0
- package/lib/errors/RedundantDynamicImportWarning.js +31 -0
- package/lib/errors/ScopeHoistingBailoutsWarning.js +41 -0
- package/lib/errors/SplitChunksCappedWarning.js +41 -0
- package/lib/errors/TinyChunksWarning.js +40 -0
- package/lib/errors/TopLevelThisWarning.js +34 -0
- package/lib/errors/UnsplitVendorsWarning.js +42 -0
- package/lib/errors/UnsupportedFeatureWarning.js +1 -1
- package/lib/errors/UnusedAliasesWarning.js +29 -0
- package/lib/errors/UnusedDefinesWarning.js +29 -0
- package/lib/errors/UnusedExternalsWarning.js +29 -0
- package/lib/errors/UnusedReexportsWarning.js +42 -0
- package/lib/errors/UnusedRuleWarning.js +29 -0
- package/lib/errors/WebpackError.js +9 -5
- package/lib/errors/deriveStackFromNestedError.js +90 -0
- package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
- package/lib/esm/ModuleChunkFormatPlugin.js +37 -19
- package/lib/esm/ModuleChunkLoadingPlugin.js +89 -51
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +170 -71
- package/lib/hmr/HotModuleReplacement.runtime.js +24 -5
- package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
- package/lib/hmr/LazyCompilationPlugin.js +45 -24
- package/lib/hmr/lazyCompilationBackend.js +28 -10
- package/lib/hmr/parserHooks.js +56 -0
- package/lib/html/HtmlGenerator.js +299 -79
- package/lib/html/HtmlModule.js +7 -3
- package/lib/html/HtmlModulesPlugin.js +312 -174
- package/lib/html/HtmlParser.js +31 -86
- package/lib/html/data.js +1928 -0
- package/lib/html/htmlMinify.js +288 -0
- package/lib/html/syntax.js +7819 -3331
- package/lib/ids/ChunkModuleIdRangePlugin.js +3 -3
- package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
- package/lib/ids/DeterministicModuleIdsPlugin.js +2 -2
- package/lib/ids/HashedModuleIdsPlugin.js +6 -2
- package/lib/ids/IdHelpers.js +31 -18
- package/lib/ids/NamedChunkIdsPlugin.js +1 -1
- package/lib/ids/NamedModuleIdsPlugin.js +1 -1
- package/lib/ids/NaturalChunkIdsPlugin.js +2 -2
- package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
- package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -3
- package/lib/ids/OccurrenceModuleIdsPlugin.js +7 -3
- package/lib/ids/SyncModuleIdsPlugin.js +4 -4
- package/lib/index.js +10 -0
- package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +3 -3
- package/lib/javascript/BasicEvaluatedExpression.js +18 -14
- package/lib/javascript/ChunkFormatHelpers.js +6 -6
- package/lib/javascript/ChunkHelpers.js +1 -1
- package/lib/javascript/CommonJsChunkFormatPlugin.js +11 -5
- package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
- package/lib/javascript/JavascriptGenerator.js +65 -165
- package/lib/javascript/JavascriptModule.js +9 -3
- package/lib/javascript/JavascriptModulesPlugin.js +181 -162
- package/lib/javascript/JavascriptParser.js +291 -112
- package/lib/javascript/JavascriptParserHelpers.js +10 -7
- package/lib/javascript/ScopeAnalyzer.js +1094 -0
- package/lib/javascript/StartupHelpers.js +55 -9
- package/lib/javascript/syntax.js +3403 -300
- package/lib/json/JsonData.js +8 -4
- package/lib/json/JsonGenerator.js +38 -16
- package/lib/json/JsonModule.js +7 -3
- package/lib/json/JsonModulesPlugin.js +1 -1
- package/lib/json/JsonParser.js +5 -6
- package/lib/library/AbstractLibraryPlugin.js +20 -14
- package/lib/library/AmdLibraryPlugin.js +11 -7
- package/lib/library/AssignLibraryPlugin.js +19 -13
- package/lib/library/EnableLibraryPlugin.js +2 -2
- package/lib/library/ExportPropertyLibraryPlugin.js +15 -8
- package/lib/library/JsonpLibraryPlugin.js +11 -7
- package/lib/library/ModuleLibraryPlugin.js +256 -64
- package/lib/library/SystemLibraryPlugin.js +12 -8
- package/lib/library/UmdLibraryPlugin.js +62 -25
- package/lib/loaders/LoaderRunner.js +14 -1
- package/lib/loaders/loadLoader.js +8 -4
- package/lib/logging/createConsoleLogger.js +7 -4
- package/lib/node/CommonJsChunkLoadingPlugin.js +36 -22
- package/lib/node/NodeEnvironmentPlugin.js +17 -3
- package/lib/node/NodeSourcePlugin.js +1 -1
- package/lib/node/NodeTargetPlugin.js +4 -3
- package/lib/node/NodeTemplatePlugin.js +1 -1
- package/lib/node/NodeWatchFileSystem.js +70 -9
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +35 -38
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +81 -20
- package/lib/node/ReadFileCompileWasmPlugin.js +37 -17
- package/lib/node/RequireChunkLoadingRuntimeModule.js +35 -38
- package/lib/node/nodeConsole.js +7 -3
- package/lib/optimize/AggressiveMergingPlugin.js +21 -17
- package/lib/optimize/AggressiveSplittingPlugin.js +9 -6
- package/lib/optimize/ConcatenatedModule.js +996 -477
- package/lib/optimize/ConstExportsPlugin.js +11 -7
- package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
- package/lib/optimize/FlagIncludedChunksPlugin.js +3 -4
- package/lib/optimize/InlineExports.js +9 -5
- package/lib/optimize/InnerGraph.js +28 -12
- package/lib/optimize/InnerGraphPlugin.js +23 -18
- package/lib/optimize/LimitChunkCountPlugin.js +7 -3
- package/lib/optimize/MangleExportsPlugin.js +7 -8
- package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -3
- package/lib/optimize/MinChunkSizePlugin.js +7 -3
- package/lib/optimize/ModuleConcatenationPlugin.js +124 -59
- package/lib/optimize/RealContentHashPlugin.js +20 -13
- package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
- package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
- package/lib/optimize/RuntimeChunkPlugin.js +2 -2
- package/lib/optimize/SideEffectsFlagPlugin.js +262 -39
- package/lib/optimize/SplitChunksPlugin.js +232 -68
- package/lib/performance/AssetsOverSizeLimitWarning.js +10 -2
- package/lib/performance/AsyncChunkWaterfallsPlugin.js +136 -0
- package/lib/performance/BroadContextsPlugin.js +142 -0
- package/lib/performance/CacheEffectivenessPlugin.js +125 -0
- package/lib/performance/ConflictingResourceHintsPlugin.js +99 -0
- package/lib/performance/DuplicateModulesPlugin.js +93 -0
- package/lib/performance/DuplicatePackagesPlugin.js +119 -0
- package/lib/performance/DuplicatePackagesWarning.js +84 -0
- package/lib/performance/DynamicExportsPlugin.js +120 -0
- package/lib/performance/EmbeddedSourceMapsPlugin.js +71 -0
- package/lib/performance/EntrypointOverlapPlugin.js +122 -0
- package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -1
- package/lib/performance/EvalUsagePlugin.js +115 -0
- package/lib/performance/HotspotsPlugin.js +296 -0
- package/lib/performance/InlinedAssetsPlugin.js +99 -0
- package/lib/performance/LargeModulesPlugin.js +126 -0
- package/lib/performance/LegacyJavascriptPlugin.js +139 -0
- package/lib/performance/MissingSideEffectsPlugin.js +138 -0
- package/lib/performance/MixedExportsPlugin.js +136 -0
- package/lib/performance/OsDependentRuleWarningPlugin.js +178 -0
- package/lib/performance/PureAnnotationsPlugin.js +219 -0
- package/lib/performance/RedundantDynamicImportsPlugin.js +225 -0
- package/lib/performance/RuntimeInLargeChunkWarning.js +27 -0
- package/lib/performance/ScopeHoistingBailoutsPlugin.js +164 -0
- package/lib/performance/SizeLimitsPlugin.js +139 -7
- package/lib/performance/SplitChunksCappedPlugin.js +99 -0
- package/lib/performance/TinyChunksPlugin.js +128 -0
- package/lib/performance/TopLevelThisPlugin.js +208 -0
- package/lib/performance/UnsplitVendorsPlugin.js +112 -0
- package/lib/performance/UnusedAliasesPlugin.js +253 -0
- package/lib/performance/UnusedDefinesPlugin.js +87 -0
- package/lib/performance/UnusedExternalsPlugin.js +110 -0
- package/lib/performance/UnusedReexportsPlugin.js +159 -0
- package/lib/performance/UnusedRuleWarningPlugin.js +105 -0
- package/lib/performance/getModuleSize.js +22 -0
- package/lib/performance/getSourceModules.js +22 -0
- package/lib/performance/hasOnlyUnusedExports.js +40 -0
- package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +24 -10
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +63 -46
- package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +2 -3
- package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
- package/lib/prefetch/ResourceHintPlugin.js +377 -136
- package/lib/prefetch/ResourceHintRuntimeModule.js +1 -21
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +10 -133
- package/lib/prefetch/parseResourceHintOptions.js +31 -4
- package/lib/rules/BasicEffectRulePlugin.js +2 -2
- package/lib/rules/BasicMatcherRulePlugin.js +8 -4
- package/lib/rules/GlobMatcherRulePlugin.js +68 -0
- package/lib/rules/ObjectMatcherRulePlugin.js +12 -5
- package/lib/rules/RuleSetCompiler.js +146 -12
- package/lib/rules/UseEffectRulePlugin.js +18 -11
- package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +11 -1
- package/lib/runtime/AsyncModuleRuntimeModule.js +1 -1
- package/lib/runtime/AutoPublicPathRuntimeModule.js +15 -20
- package/lib/runtime/BaseUriRuntimeModule.js +33 -7
- package/lib/runtime/ChunkNameRuntimeModule.js +10 -0
- package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +11 -1
- package/lib/runtime/CompatRuntimeModule.js +5 -3
- package/lib/runtime/ConcatenationWrapRuntimeModule.js +90 -0
- package/lib/runtime/ConstructRequireRuntimeModule.js +52 -0
- package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +8 -6
- package/lib/runtime/CreateScriptRuntimeModule.js +11 -1
- package/lib/runtime/CreateScriptUrlRuntimeModule.js +11 -1
- package/lib/runtime/DefinePropertyGettersRuntimeModule.js +56 -38
- package/lib/runtime/EnsureChunkRuntimeModule.js +18 -2
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +62 -37
- package/lib/runtime/GetFullHashRuntimeModule.js +12 -2
- package/lib/runtime/GetMainFilenameRuntimeModule.js +12 -2
- package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -2
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +16 -3
- package/lib/runtime/GlobalRuntimeModule.js +18 -0
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +12 -2
- package/lib/runtime/LoadScriptRuntimeModule.js +2 -2
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +23 -6
- package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +22 -6
- package/lib/runtime/NonceRuntimeModule.js +10 -0
- package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -3
- package/lib/runtime/PublicPathRuntimeModule.js +12 -2
- package/lib/runtime/RelativeUrlRuntimeModule.js +11 -1
- package/lib/runtime/RuntimeIdRuntimeModule.js +12 -2
- package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +11 -1
- package/lib/runtime/StartupChunkDependenciesPlugin.js +18 -9
- package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +3 -3
- package/lib/runtime/StartupEntrypointRuntimeModule.js +21 -4
- package/lib/runtime/SystemContextRuntimeModule.js +10 -0
- package/lib/runtime/ToBinaryRuntimeModule.js +1 -1
- package/lib/runtime/WorkerRuntimeModule.js +11 -1
- package/lib/runtime/baseUri.js +63 -0
- package/lib/schemes/DataUriPlugin.js +1 -1
- package/lib/schemes/FileUriPlugin.js +1 -1
- package/lib/schemes/HttpUriPlugin.js +24 -15
- package/lib/schemes/VirtualUrlPlugin.js +13 -7
- package/lib/serialization/AggregateErrorSerializer.js +1 -1
- package/lib/serialization/BinaryMiddleware.js +274 -942
- package/lib/serialization/ErrorObjectSerializer.js +1 -1
- package/lib/serialization/FileMiddleware.js +305 -66
- package/lib/serialization/ObjectMiddleware.js +139 -114
- package/lib/serialization/PlainObjectSerializer.js +19 -16
- package/lib/sharing/ConsumeSharedModule.js +30 -21
- package/lib/sharing/ConsumeSharedPlugin.js +18 -10
- package/lib/sharing/ConsumeSharedRuntimeModule.js +6 -9
- package/lib/sharing/ProvideSharedModule.js +25 -16
- package/lib/sharing/ProvideSharedModuleFactory.js +7 -3
- package/lib/sharing/ProvideSharedPlugin.js +8 -4
- package/lib/sharing/SharePlugin.js +17 -5
- package/lib/sharing/ShareRuntimeModule.js +4 -4
- package/lib/sharing/resolveMatchedConfigs.js +9 -6
- package/lib/sharing/utils.js +1 -3
- package/lib/stats/DefaultStatsFactoryPlugin.js +253 -226
- package/lib/stats/DefaultStatsPresetPlugin.js +17 -8
- package/lib/stats/DefaultStatsPrinterPlugin.js +60 -192
- package/lib/stats/StatsFactory.js +56 -35
- package/lib/stats/StatsPrinter.js +16 -12
- package/lib/typescript/TypeScriptPlugin.js +12 -14
- package/lib/url/URLParserPlugin.js +26 -13
- package/lib/util/AsyncQueue.js +4 -3
- package/lib/util/Hash.js +5 -1
- package/lib/util/LazySet.js +35 -22
- package/lib/util/LocConverter.js +36 -13
- package/lib/util/SourceProcessor.js +1050 -24
- package/lib/util/StringXor.js +1 -1
- package/lib/util/chainedImports.js +9 -5
- package/lib/util/cleverMerge.js +1 -1
- package/lib/util/comparators.js +45 -14
- package/lib/util/concatenate.js +203 -77
- package/lib/util/conventions.js +5 -1
- package/lib/util/createHash.js +2 -2
- package/lib/util/createHooksRegistry.js +8 -10
- package/lib/util/dataURL.js +225 -1
- package/lib/util/extractSourceMap.js +4 -3
- package/lib/util/findCaseMismatch.js +139 -0
- package/lib/util/formatLocation.js +1 -2
- package/lib/util/fs.js +22 -5
- package/lib/util/globUtils.js +298 -24
- package/lib/util/hash/BatchedHash.js +5 -1
- package/lib/util/hash/BulkUpdateHash.js +5 -1
- package/lib/util/hash/DebugHash.js +5 -1
- package/lib/util/hash/hash-digest.js +6 -2
- package/lib/util/identifier.js +25 -1
- package/lib/util/implicitTypeLoaderFallback.js +1 -1
- package/lib/util/internalSerializables.js +6 -0
- package/lib/util/lazyModule.js +56 -0
- package/lib/util/makeSerializable.js +7 -3
- package/lib/util/matchAlias.js +25 -0
- package/lib/util/mimeTypes.js +11 -5
- package/lib/util/nonNumericOnlyHash.js +4 -3
- package/lib/util/parseJson.js +5 -3
- package/lib/util/preloadModuleType.js +32 -0
- package/lib/util/registerExternalSerializer.js +7 -5
- package/lib/util/runtime.js +2 -2
- package/lib/util/semver.js +1 -1
- package/lib/util/serialization.js +28 -28
- package/lib/util/source.js +2 -2
- package/lib/util/traverseDestructuringAssignmentProperties.js +6 -2
- package/lib/wasm/EnableWasmLoadingPlugin.js +10 -8
- package/lib/wasm/wasmModuleFilename.js +54 -0
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +41 -21
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +43 -21
- package/lib/wasm-async/AsyncWasmModule.js +3 -3
- package/lib/wasm-async/AsyncWebAssemblyGenerator.js +4 -5
- package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +57 -17
- package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +34 -18
- package/lib/wasm-async/AsyncWebAssemblyParser.js +9 -8
- package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +34 -8
- package/lib/wasm-sync/SyncWasmModule.js +2 -2
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +18 -13
- package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -5
- package/lib/wasm-sync/WebAssemblyGenerator.js +18 -17
- package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +4 -4
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +7 -7
- package/lib/wasm-sync/WebAssemblyModulesPlugin.js +24 -11
- package/lib/wasm-sync/WebAssemblyParser.js +4 -6
- package/lib/wasm-sync/WebAssemblyUtils.js +2 -2
- package/lib/web/FetchCompileAsyncWasmPlugin.js +101 -19
- package/lib/web/FetchCompileWasmPlugin.js +46 -16
- package/lib/web/JsonpChunkLoadingPlugin.js +47 -23
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +50 -20
- package/lib/web/JsonpTemplatePlugin.js +2 -2
- package/lib/webpack.js +22 -11
- package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +60 -26
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -32
- package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
- package/module.d.ts +1 -0
- package/package.json +37 -30
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +780 -91
- package/schemas/plugins/HtmlParserOptions.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.json +10 -0
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +10 -0
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssParserOptions.check.js +1 -1
- package/types.d.ts +4013 -738
- package/lib/runtime/CommonJsWrapRuntimeModule.js +0 -37
package/lib/css/CssParser.js
CHANGED
|
@@ -15,9 +15,6 @@ const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency
|
|
|
15
15
|
const CssImportDependency = require("../dependencies/CssImportDependency");
|
|
16
16
|
const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
|
17
17
|
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
|
|
18
|
-
const CommentCompilationWarning = require("../errors/CommentCompilationWarning");
|
|
19
|
-
const ModuleDependencyWarning = require("../errors/ModuleDependencyWarning");
|
|
20
|
-
const UnsupportedFeatureWarning = require("../errors/UnsupportedFeatureWarning");
|
|
21
18
|
const WebpackError = require("../errors/WebpackError");
|
|
22
19
|
const ResourceHintPlugin = require("../prefetch/ResourceHintPlugin");
|
|
23
20
|
const LocConverter = require("../util/LocConverter");
|
|
@@ -26,7 +23,9 @@ const {
|
|
|
26
23
|
createMagicCommentContext,
|
|
27
24
|
parseCommentOptionsInRange
|
|
28
25
|
} = require("../util/magicComment");
|
|
26
|
+
const memoize = require("../util/memoize");
|
|
29
27
|
const topologicalSort = require("../util/topologicalSort");
|
|
28
|
+
const { CSS_MODULES_KEYWORDS, CSS_MODULES_KEYWORD_OPTIONS } = require("./data");
|
|
30
29
|
const {
|
|
31
30
|
A,
|
|
32
31
|
NodeType,
|
|
@@ -38,40 +37,83 @@ const {
|
|
|
38
37
|
normalizeUrl,
|
|
39
38
|
rangeEquals,
|
|
40
39
|
rangeEqualsLowerCase,
|
|
40
|
+
skipEscape,
|
|
41
41
|
toLowerCaseIfNeeded,
|
|
42
42
|
unescapeIdentifier
|
|
43
43
|
} = require("./syntax");
|
|
44
44
|
|
|
45
|
+
const getUnsupportedFeatureWarning = memoize(() =>
|
|
46
|
+
require("../errors/UnsupportedFeatureWarning")
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const getModuleDependencyWarning = memoize(() =>
|
|
50
|
+
require("../errors/ModuleDependencyWarning")
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const getCommentCompilationWarning = memoize(() =>
|
|
54
|
+
require("../errors/CommentCompilationWarning")
|
|
55
|
+
);
|
|
56
|
+
|
|
45
57
|
// `SourceProcessor` drives the parse and hands already-built AST nodes to the visitors; positions are read from those nodes' ranges rather than re-scanning the source.
|
|
46
58
|
|
|
47
|
-
/** @
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
/** @
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
59
|
+
/** @import { BuildInfo, BuildMeta } from "../Module" */
|
|
60
|
+
/**
|
|
61
|
+
* @import CssModule, {
|
|
62
|
+
* CssModuleBuildInfo,
|
|
63
|
+
* CssModuleBuildMeta,
|
|
64
|
+
* Inheritance
|
|
65
|
+
* } from "./CssModule"
|
|
66
|
+
*/
|
|
67
|
+
/** @import { ParserState, PreparsedAst } from "../Parser" */
|
|
68
|
+
/**
|
|
69
|
+
* @import {
|
|
70
|
+
* AtRule,
|
|
71
|
+
* Declaration,
|
|
72
|
+
* FunctionNode,
|
|
73
|
+
* Node as AstNode,
|
|
74
|
+
* QualifiedRule,
|
|
75
|
+
* Rule,
|
|
76
|
+
* SimpleBlock,
|
|
77
|
+
* Token,
|
|
78
|
+
* UrlToken,
|
|
79
|
+
* VisitorMap
|
|
80
|
+
* } from "./syntax"
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* @import {
|
|
84
|
+
* CssAutoOrModuleParserOptions
|
|
85
|
+
* } from "../../declarations/WebpackOptions"
|
|
86
|
+
*/
|
|
68
87
|
|
|
69
88
|
/** @typedef {[number, number]} Range */
|
|
70
89
|
/** @typedef {{ line: number, column: number }} Position */
|
|
71
90
|
/** @typedef {{ from: string, items: ({ localName: string, importName: string })[] }} ValueAtRuleImport */
|
|
72
91
|
/** @typedef {{ localName: string, value: string }} ValueAtRuleValue */
|
|
92
|
+
/**
|
|
93
|
+
* What a `@custom-media` name resolves to. `condition` substitutes into any
|
|
94
|
+
* `<media-in-parens>` slot, `type` only at the start of a query, `boolean` is the
|
|
95
|
+
* spec's `true` / `false` (folded into the enclosing query rather than written
|
|
96
|
+
* out — no `<media-in-parens>` is unconditionally true on every engine).
|
|
97
|
+
* @typedef {{ kind: "condition" | "type", text: string } | { kind: "boolean", value: boolean } | { kind: "unsupported" }} CustomMediaValue
|
|
98
|
+
*/
|
|
99
|
+
/** @typedef {CustomMediaValue | { kind: "alias", name: string } | { kind: "or", parts: ({ text: string } | { alias: string })[] }} CustomMediaDefinition */
|
|
100
|
+
/** @typedef {{ name: string, start: number, end: number, invalid: boolean, leading: boolean }} CustomMediaUse */
|
|
101
|
+
/**
|
|
102
|
+
* A `@media` prelude captured as its boolean shape, so a `true` / `false`
|
|
103
|
+
* definition found later can be folded into it. Node ids are recycled per
|
|
104
|
+
* top-level rule, so this holds text and offsets rather than AST nodes.
|
|
105
|
+
* @typedef {{ kind: "text", text: string } | { kind: "ref", text: string, use: CustomMediaUse } | { kind: "group", operand: MediaNode } | { kind: "not", operand: MediaNode } | { kind: "chain", isOr: boolean, terms: MediaNode[] } | { kind: "typed", text: string, rest: MediaNode | null }} MediaNode
|
|
106
|
+
*/
|
|
107
|
+
|
|
108
|
+
/** @type {CustomMediaValue} */
|
|
109
|
+
const CUSTOM_MEDIA_UNSUPPORTED = { kind: "unsupported" };
|
|
110
|
+
/** @type {CustomMediaValue} */
|
|
111
|
+
const CUSTOM_MEDIA_TRUE = { kind: "boolean", value: true };
|
|
112
|
+
/** @type {CustomMediaValue} */
|
|
113
|
+
const CUSTOM_MEDIA_FALSE = { kind: "boolean", value: false };
|
|
73
114
|
|
|
74
115
|
const CC_COLON = ":".charCodeAt(0);
|
|
116
|
+
const CC_FULL_STOP = ".".charCodeAt(0);
|
|
75
117
|
const CC_HYPHEN_MINUS = "-".charCodeAt(0);
|
|
76
118
|
const CC_SEMICOLON = ";".charCodeAt(0);
|
|
77
119
|
const CC_TAB = "\t".charCodeAt(0);
|
|
@@ -82,6 +124,7 @@ const CC_FORM_FEED = "\f".charCodeAt(0);
|
|
|
82
124
|
const CC_LEFT_CURLY = "{".charCodeAt(0);
|
|
83
125
|
const CC_LOWER_V = "v".charCodeAt(0);
|
|
84
126
|
const CC_UPPER_V = "V".charCodeAt(0);
|
|
127
|
+
const CC_REVERSE_SOLIDUS = "\\".charCodeAt(0);
|
|
85
128
|
|
|
86
129
|
// A parsed CSS comment. `loc` is computed on demand — only magic-comment error
|
|
87
130
|
// warnings read it, so comment-heavy CSS skips the per-comment line/col work.
|
|
@@ -102,22 +145,23 @@ const VIEW_TRANSITION_PART_PSEUDO =
|
|
|
102
145
|
/^view-transition-(?:group|image-pair|old|new)$/i;
|
|
103
146
|
const IS_MODULES = /\.modules?\.[^.]+$/i;
|
|
104
147
|
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
["eot", "application/vnd.ms-fontobject"]
|
|
112
|
-
]);
|
|
148
|
+
// Which formats get a preload hint is webpack's call; what each one *is* comes
|
|
149
|
+
// from `mime-db`, not a second copy of the mapping.
|
|
150
|
+
const FONT_EXTENSIONS = new Set(["woff2", "woff", "ttf", "otf", "eot"]);
|
|
151
|
+
|
|
152
|
+
// mime-db is heavy — only load it once a font src actually needs a `type`.
|
|
153
|
+
const getMimeTypes = memoize(() => require("../util/mimeTypes"));
|
|
113
154
|
|
|
114
155
|
/**
|
|
115
156
|
* @param {string} request font url (may carry a query/hash)
|
|
116
157
|
* @returns {string | undefined} preload `type` for a known font extension
|
|
117
158
|
*/
|
|
118
159
|
const fontMimeType = (request) => {
|
|
119
|
-
|
|
120
|
-
|
|
160
|
+
// Off the path only: `font?fallback=.woff2` names no font.
|
|
161
|
+
const resourcePath = parseResource(request).path;
|
|
162
|
+
const extension = path.extname(resourcePath).slice(1).toLowerCase();
|
|
163
|
+
if (!FONT_EXTENSIONS.has(extension)) return undefined;
|
|
164
|
+
return getMimeTypes().lookup(resourcePath);
|
|
121
165
|
};
|
|
122
166
|
|
|
123
167
|
// Skip options for a non-CSS-Modules parse: drop the selector prelude (never
|
|
@@ -166,37 +210,18 @@ const ONLY_WHITESPACE = /^\s+$/;
|
|
|
166
210
|
// Relative request prefix (`./` or `../`) — `isSelfReferenceRequest` per `from`.
|
|
167
211
|
const RELATIVE_REQUEST = /^\.{1,2}\//;
|
|
168
212
|
|
|
169
|
-
/**
|
|
170
|
-
* Returns matches.
|
|
171
|
-
* @param {RegExp} regexp a regexp
|
|
172
|
-
* @param {string} str a string
|
|
173
|
-
* @returns {RegExpExecArray[]} matches
|
|
174
|
-
*/
|
|
175
|
-
const matchAll = (regexp, str) => {
|
|
176
|
-
/** @type {RegExpExecArray[]} */
|
|
177
|
-
const result = [];
|
|
178
|
-
|
|
179
|
-
/** @type {null | RegExpExecArray} */
|
|
180
|
-
let match;
|
|
181
|
-
|
|
182
|
-
while ((match = regexp.exec(str)) !== null) {
|
|
183
|
-
result.push(match);
|
|
184
|
-
}
|
|
185
|
-
return result;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
213
|
/**
|
|
189
214
|
* Range-keyed index over a known-properties table: ASCII-case-folded 31-hash
|
|
190
215
|
* of the name bytes → canonical key(s). Lets the Declaration visitor answer
|
|
191
216
|
* "is this a known property" (and get the canonical lowercase name) without
|
|
192
217
|
* slicing the property name out of the source per declaration.
|
|
193
|
-
* @type {WeakMap<Map<string,
|
|
218
|
+
* @type {WeakMap<Map<string, Map<string, number>>, Map<number, string | string[]>>}
|
|
194
219
|
*/
|
|
195
220
|
const KNOWN_PROPERTY_INDEX_CACHE = new WeakMap();
|
|
196
221
|
|
|
197
222
|
/**
|
|
198
223
|
* Gets (or builds) the hash index for a known-properties table.
|
|
199
|
-
* @param {Map<string,
|
|
224
|
+
* @param {Map<string, Map<string, number>>} knownProperties known properties table
|
|
200
225
|
* @returns {Map<number, string | string[]>} hash → canonical name(s)
|
|
201
226
|
*/
|
|
202
227
|
const getKnownPropertyIndex = (knownProperties) => {
|
|
@@ -230,6 +255,12 @@ const knownPropertyForRange = (index, input, start, end) => {
|
|
|
230
255
|
let h = end - start;
|
|
231
256
|
for (let i = start; i < end; i++) {
|
|
232
257
|
let c = input.charCodeAt(i);
|
|
258
|
+
// The table holds no raw-byte spelling, so re-read the unescaped one.
|
|
259
|
+
// Each pass shortens the name, so an escaped `\` cannot recurse forever.
|
|
260
|
+
if (c === CC_REVERSE_SOLIDUS) {
|
|
261
|
+
const name = unescapeIdentifier(input.slice(start, end));
|
|
262
|
+
return knownPropertyForRange(index, name, 0, name.length);
|
|
263
|
+
}
|
|
233
264
|
if (c >= 65 && c <= 90) c |= 0x20;
|
|
234
265
|
h = ((h << 5) - h + c) | 0;
|
|
235
266
|
}
|
|
@@ -244,291 +275,84 @@ const knownPropertyForRange = (index, input, start, end) => {
|
|
|
244
275
|
return undefined;
|
|
245
276
|
};
|
|
246
277
|
|
|
247
|
-
/**
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
"hiragana-iroha": 1,
|
|
287
|
-
katakana: 1,
|
|
288
|
-
/* cspell:disable-next-line */
|
|
289
|
-
"katakana-iroha": 1,
|
|
290
|
-
|
|
291
|
-
disc: 1,
|
|
292
|
-
circle: 1,
|
|
293
|
-
square: 1,
|
|
294
|
-
"disclosure-open": 1,
|
|
295
|
-
"disclosure-closed": 1,
|
|
296
|
-
|
|
297
|
-
"cjk-earthly-branch": 1,
|
|
298
|
-
"cjk-heavenly-stem": 1,
|
|
299
|
-
|
|
300
|
-
"japanese-informal": 1,
|
|
301
|
-
"japanese-formal": 1,
|
|
302
|
-
|
|
303
|
-
"korean-hangul-formal": 1,
|
|
304
|
-
/* cspell:disable-next-line */
|
|
305
|
-
"korean-hanja-informal": 1,
|
|
306
|
-
/* cspell:disable-next-line */
|
|
307
|
-
"korean-hanja-formal": 1,
|
|
308
|
-
|
|
309
|
-
"simp-chinese-informal": 1,
|
|
310
|
-
"simp-chinese-formal": 1,
|
|
311
|
-
"trad-chinese-informal": 1,
|
|
312
|
-
"trad-chinese-formal": 1,
|
|
313
|
-
"cjk-ideographic": 1,
|
|
314
|
-
|
|
315
|
-
"ethiopic-numeric": 1
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
/** @type {Record<string, number>} */
|
|
319
|
-
const GLOBAL_VALUES = {
|
|
320
|
-
// Global values
|
|
321
|
-
initial: Infinity,
|
|
322
|
-
inherit: Infinity,
|
|
323
|
-
unset: Infinity,
|
|
324
|
-
revert: Infinity,
|
|
325
|
-
"revert-layer": Infinity
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
/** @type {Record<string, number>} */
|
|
329
|
-
const GRID_AREA_OR_COLUMN_OR_ROW = {
|
|
330
|
-
auto: Infinity,
|
|
331
|
-
span: Infinity,
|
|
332
|
-
...GLOBAL_VALUES
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
/** @type {Record<string, number>} */
|
|
336
|
-
const GRID_AUTO_COLUMNS_OR_ROW = {
|
|
337
|
-
"min-content": Infinity,
|
|
338
|
-
"max-content": Infinity,
|
|
339
|
-
auto: Infinity,
|
|
340
|
-
...GLOBAL_VALUES
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
/** @type {Record<string, number>} */
|
|
344
|
-
const GRID_AUTO_FLOW = {
|
|
345
|
-
row: 1,
|
|
346
|
-
column: 1,
|
|
347
|
-
dense: 1,
|
|
348
|
-
...GLOBAL_VALUES
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
/** @type {Record<string, number>} */
|
|
352
|
-
const GRID_TEMPLATE_AREAS = {
|
|
353
|
-
// Special
|
|
354
|
-
none: 1,
|
|
355
|
-
...GLOBAL_VALUES
|
|
356
|
-
};
|
|
357
|
-
|
|
358
|
-
/** @type {Record<string, number>} */
|
|
359
|
-
const GRID_TEMPLATE_COLUMNS_OR_ROWS = {
|
|
360
|
-
none: 1,
|
|
361
|
-
subgrid: 1,
|
|
362
|
-
masonry: 1,
|
|
363
|
-
"max-content": Infinity,
|
|
364
|
-
"min-content": Infinity,
|
|
365
|
-
auto: Infinity,
|
|
366
|
-
...GLOBAL_VALUES
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
/** @type {Record<string, number>} */
|
|
370
|
-
const GRID_TEMPLATE = {
|
|
371
|
-
...GRID_TEMPLATE_AREAS,
|
|
372
|
-
...GRID_TEMPLATE_COLUMNS_OR_ROWS
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
/** @type {Record<string, number>} */
|
|
376
|
-
const GRID = {
|
|
377
|
-
"auto-flow": 1,
|
|
378
|
-
dense: 1,
|
|
379
|
-
...GRID_AUTO_COLUMNS_OR_ROW,
|
|
380
|
-
...GRID_AUTO_FLOW,
|
|
381
|
-
...GRID_TEMPLATE_AREAS,
|
|
382
|
-
...GRID_TEMPLATE_COLUMNS_OR_ROWS
|
|
278
|
+
/**
|
|
279
|
+
* Comma-separated index of the counter-name argument in a counter-reading function, or `-1` when the name isn't one. The name is matched over the raw byte range like the other function-name probes; only an escaped name (rare) pays the unescaped slice.
|
|
280
|
+
* @param {string} input source
|
|
281
|
+
* @param {number} start name start offset
|
|
282
|
+
* @param {number} end name end offset
|
|
283
|
+
* @param {string=} escapedName unescaped name, when the raw range carries an escape
|
|
284
|
+
* @returns {number} argument index of the counter name, or `-1`
|
|
285
|
+
*/
|
|
286
|
+
const counterFunctionNameIndex = (input, start, end, escapedName) => {
|
|
287
|
+
// The `target-counter(url, name, style?)` cross-reference forms (Generated Content for Paged Media) name the counter second; print engines read them.
|
|
288
|
+
if (escapedName !== undefined) {
|
|
289
|
+
if (
|
|
290
|
+
equalsLowerCase(escapedName, "counter") ||
|
|
291
|
+
equalsLowerCase(escapedName, "counters")
|
|
292
|
+
) {
|
|
293
|
+
return 0;
|
|
294
|
+
}
|
|
295
|
+
if (
|
|
296
|
+
equalsLowerCase(escapedName, "target-counter") ||
|
|
297
|
+
equalsLowerCase(escapedName, "target-counters")
|
|
298
|
+
) {
|
|
299
|
+
return 1;
|
|
300
|
+
}
|
|
301
|
+
return -1;
|
|
302
|
+
}
|
|
303
|
+
switch (end - start) {
|
|
304
|
+
case 7:
|
|
305
|
+
return rangeEqualsLowerCase(input, start, end, "counter") ? 0 : -1;
|
|
306
|
+
case 8:
|
|
307
|
+
return rangeEqualsLowerCase(input, start, end, "counters") ? 0 : -1;
|
|
308
|
+
case 14:
|
|
309
|
+
return rangeEqualsLowerCase(input, start, end, "target-counter") ? 1 : -1;
|
|
310
|
+
case 15:
|
|
311
|
+
return rangeEqualsLowerCase(input, start, end, "target-counters")
|
|
312
|
+
? 1
|
|
313
|
+
: -1;
|
|
314
|
+
default:
|
|
315
|
+
return -1;
|
|
316
|
+
}
|
|
383
317
|
};
|
|
384
318
|
|
|
385
319
|
/**
|
|
386
|
-
* Gets known
|
|
320
|
+
* Gets the known-properties table for the enabled scoping options: the
|
|
321
|
+
* properties a `css/module` reads a scoped name out of, each with the keywords
|
|
322
|
+
* of its own grammar (see `tooling/generate-css-data.js`).
|
|
387
323
|
* @param {{ animation?: boolean, container?: boolean, customIdents?: boolean, grid?: boolean }=} options options
|
|
388
|
-
* @returns {Map<string,
|
|
324
|
+
* @returns {Map<string, Map<string, number>>} list of known properties
|
|
389
325
|
*/
|
|
390
326
|
const buildKnownProperties = (options = {}) => {
|
|
391
|
-
/** @type {Map<string,
|
|
327
|
+
/** @type {Map<string, Map<string, number>>} */
|
|
392
328
|
const knownProperties = new Map();
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
infinite: 1,
|
|
407
|
-
// animation-play-state
|
|
408
|
-
paused: 1,
|
|
409
|
-
running: 1,
|
|
410
|
-
// animation-timing-function
|
|
411
|
-
ease: 1,
|
|
412
|
-
"ease-in": 1,
|
|
413
|
-
"ease-out": 1,
|
|
414
|
-
"ease-in-out": 1,
|
|
415
|
-
linear: 1,
|
|
416
|
-
"step-end": 1,
|
|
417
|
-
"step-start": 1,
|
|
418
|
-
// Special
|
|
419
|
-
none: Infinity, // No matter how many times you write none, it will never be an animation name
|
|
420
|
-
...GLOBAL_VALUES
|
|
421
|
-
});
|
|
422
|
-
knownProperties.set("animation-name", {
|
|
423
|
-
// Special
|
|
424
|
-
none: Infinity, // No matter how many times you write none, it will never be an animation name
|
|
425
|
-
...GLOBAL_VALUES
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (options.container) {
|
|
430
|
-
knownProperties.set("container", {
|
|
431
|
-
// container-type
|
|
432
|
-
normal: 1,
|
|
433
|
-
size: 1,
|
|
434
|
-
"inline-size": 1,
|
|
435
|
-
"scroll-state": 1,
|
|
436
|
-
// Special
|
|
437
|
-
none: Infinity,
|
|
438
|
-
...GLOBAL_VALUES
|
|
439
|
-
});
|
|
440
|
-
knownProperties.set("container-name", {
|
|
441
|
-
// Special
|
|
442
|
-
none: Infinity,
|
|
443
|
-
...GLOBAL_VALUES
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
if (options.customIdents) {
|
|
448
|
-
knownProperties.set("list-style", {
|
|
449
|
-
// list-style-position
|
|
450
|
-
inside: 1,
|
|
451
|
-
outside: 1,
|
|
452
|
-
// list-style-type
|
|
453
|
-
...PREDEFINED_COUNTER_STYLES,
|
|
454
|
-
// Special
|
|
455
|
-
none: Infinity,
|
|
456
|
-
...GLOBAL_VALUES
|
|
457
|
-
});
|
|
458
|
-
knownProperties.set("list-style-type", {
|
|
459
|
-
// list-style-type
|
|
460
|
-
...PREDEFINED_COUNTER_STYLES,
|
|
461
|
-
// Special
|
|
462
|
-
none: Infinity,
|
|
463
|
-
...GLOBAL_VALUES
|
|
464
|
-
});
|
|
465
|
-
knownProperties.set("system", {
|
|
466
|
-
cyclic: 1,
|
|
467
|
-
numeric: 1,
|
|
468
|
-
alphabetic: 1,
|
|
469
|
-
symbolic: 1,
|
|
470
|
-
additive: 1,
|
|
471
|
-
fixed: 1,
|
|
472
|
-
extends: 1,
|
|
473
|
-
...PREDEFINED_COUNTER_STYLES
|
|
474
|
-
});
|
|
475
|
-
knownProperties.set("fallback", {
|
|
476
|
-
...PREDEFINED_COUNTER_STYLES
|
|
477
|
-
});
|
|
478
|
-
knownProperties.set("speak-as", {
|
|
479
|
-
auto: 1,
|
|
480
|
-
bullets: 1,
|
|
481
|
-
numbers: 1,
|
|
482
|
-
words: 1,
|
|
483
|
-
"spell-out": 1,
|
|
484
|
-
...PREDEFINED_COUNTER_STYLES
|
|
485
|
-
});
|
|
486
|
-
knownProperties.set("view-transition-name", {
|
|
487
|
-
none: Infinity,
|
|
488
|
-
auto: Infinity,
|
|
489
|
-
"match-element": Infinity,
|
|
490
|
-
...GLOBAL_VALUES
|
|
491
|
-
});
|
|
492
|
-
knownProperties.set("view-transition-group", {
|
|
493
|
-
normal: Infinity,
|
|
494
|
-
contain: Infinity,
|
|
495
|
-
nearest: Infinity,
|
|
496
|
-
...GLOBAL_VALUES
|
|
497
|
-
});
|
|
498
|
-
knownProperties.set("view-transition-class", {
|
|
499
|
-
none: Infinity,
|
|
500
|
-
...GLOBAL_VALUES
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
if (options.grid) {
|
|
505
|
-
knownProperties.set("grid", GRID);
|
|
506
|
-
knownProperties.set("grid-area", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
507
|
-
knownProperties.set("grid-column", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
508
|
-
knownProperties.set("grid-column-end", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
509
|
-
knownProperties.set("grid-column-start", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
510
|
-
knownProperties.set("grid-row", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
511
|
-
knownProperties.set("grid-row-end", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
512
|
-
knownProperties.set("grid-row-start", GRID_AREA_OR_COLUMN_OR_ROW);
|
|
513
|
-
knownProperties.set("grid-template", GRID_TEMPLATE);
|
|
514
|
-
knownProperties.set("grid-template-areas", GRID_TEMPLATE_AREAS);
|
|
515
|
-
knownProperties.set("grid-template-columns", GRID_TEMPLATE_COLUMNS_OR_ROWS);
|
|
516
|
-
knownProperties.set("grid-template-rows", GRID_TEMPLATE_COLUMNS_OR_ROWS);
|
|
329
|
+
for (const [property, option] of CSS_MODULES_KEYWORD_OPTIONS) {
|
|
330
|
+
if (
|
|
331
|
+
options[
|
|
332
|
+
/** @type {"animation" | "container" | "customIdents" | "grid"} */
|
|
333
|
+
(option)
|
|
334
|
+
]
|
|
335
|
+
) {
|
|
336
|
+
knownProperties.set(
|
|
337
|
+
property,
|
|
338
|
+
/** @type {Map<string, number>} */
|
|
339
|
+
(CSS_MODULES_KEYWORDS.get(property))
|
|
340
|
+
);
|
|
341
|
+
}
|
|
517
342
|
}
|
|
518
|
-
|
|
519
343
|
return knownProperties;
|
|
520
344
|
};
|
|
521
345
|
|
|
522
|
-
/** @type {Map<number, Map<string,
|
|
346
|
+
/** @type {Map<number, Map<string, Map<string, number>>>} */
|
|
523
347
|
const KNOWN_PROPERTIES_CACHE = new Map();
|
|
524
348
|
|
|
525
349
|
/**
|
|
526
350
|
* Memoized {@link buildKnownProperties}: the table depends only on the four
|
|
527
|
-
* boolean options (≤16 combinations) and is read-only, while the same parser is
|
|
351
|
+
* boolean options (≤ 16 combinations) and is read-only, while the same parser is
|
|
528
352
|
* reused across modules — so build each combination once and share it instead
|
|
529
|
-
* of rebuilding the Map
|
|
353
|
+
* of rebuilding the Map per parsed module.
|
|
530
354
|
* @param {{ animation?: boolean, container?: boolean, customIdents?: boolean, grid?: boolean }=} options options
|
|
531
|
-
* @returns {Map<string,
|
|
355
|
+
* @returns {Map<string, Map<string, number>>} known properties table
|
|
532
356
|
*/
|
|
533
357
|
const getKnownProperties = (options = {}) => {
|
|
534
358
|
const key =
|
|
@@ -595,6 +419,74 @@ const isContainerKeyword = (input, start, end) => {
|
|
|
595
419
|
}
|
|
596
420
|
};
|
|
597
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Whether the byte range contains a CSS escape (`\`) — function names are short, so this scan replaces a per-name slice.
|
|
424
|
+
* @param {string} input source
|
|
425
|
+
* @param {number} start start offset
|
|
426
|
+
* @param {number} end end offset (exclusive)
|
|
427
|
+
* @returns {boolean} true when the range contains a backslash
|
|
428
|
+
*/
|
|
429
|
+
const rangeHasEscape = (input, start, end) => {
|
|
430
|
+
for (let i = start; i < end; i++) {
|
|
431
|
+
if (input.charCodeAt(i) === CC_REVERSE_SOLIDUS) return true;
|
|
432
|
+
}
|
|
433
|
+
return false;
|
|
434
|
+
};
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Whether a raw ident range names a custom property — `\2d\2d x` is `--x` too,
|
|
438
|
+
* so a name opening with a dash or a backslash pays the unescape.
|
|
439
|
+
* @param {string} input source
|
|
440
|
+
* @param {number} start ident start offset
|
|
441
|
+
* @param {number} end ident end offset (exclusive)
|
|
442
|
+
* @returns {boolean} true when the ident names a custom property
|
|
443
|
+
*/
|
|
444
|
+
const rangeIsDashedIdentifier = (input, start, end) => {
|
|
445
|
+
// `--x` is the shortest spelling; an escaped one is longer still.
|
|
446
|
+
if (end - start < 3) return false;
|
|
447
|
+
const first = input.charCodeAt(start);
|
|
448
|
+
if (first === CC_HYPHEN_MINUS) {
|
|
449
|
+
if (input.charCodeAt(start + 1) === CC_HYPHEN_MINUS) return true;
|
|
450
|
+
if (input.charCodeAt(start + 1) !== CC_REVERSE_SOLIDUS) return false;
|
|
451
|
+
} else if (first !== CC_REVERSE_SOLIDUS) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
return isDashedIdentifier(unescapeIdentifier(input.slice(start, end)));
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* The named cell tokens of a `grid-template-areas` string, in source offsets.
|
|
459
|
+
* A whitespace closing a hex escape does not separate; a `.` run names nothing.
|
|
460
|
+
* @param {string} input source
|
|
461
|
+
* @param {number} start content start offset (inside the quote)
|
|
462
|
+
* @param {number} end content end offset (exclusive)
|
|
463
|
+
* @returns {[number, number][]} one `[start, end]` per named cell
|
|
464
|
+
*/
|
|
465
|
+
const gridAreaNames = (input, start, end) => {
|
|
466
|
+
/** @type {[number, number][]} */
|
|
467
|
+
const names = [];
|
|
468
|
+
let i = start;
|
|
469
|
+
while (i < end) {
|
|
470
|
+
while (i < end && isWhitespace(input.charCodeAt(i))) i++;
|
|
471
|
+
if (i >= end) break;
|
|
472
|
+
const nameStart = i;
|
|
473
|
+
let nullCell = true;
|
|
474
|
+
while (i < end) {
|
|
475
|
+
const cc = input.charCodeAt(i);
|
|
476
|
+
if (isWhitespace(cc)) break;
|
|
477
|
+
if (cc === CC_REVERSE_SOLIDUS) {
|
|
478
|
+
i = Math.min(skipEscape(input, i), end);
|
|
479
|
+
nullCell = false;
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
if (cc !== CC_FULL_STOP) nullCell = false;
|
|
483
|
+
i++;
|
|
484
|
+
}
|
|
485
|
+
if (!nullCell) names.push([nameStart, i]);
|
|
486
|
+
}
|
|
487
|
+
return names;
|
|
488
|
+
};
|
|
489
|
+
|
|
598
490
|
/**
|
|
599
491
|
* @param {string} input source
|
|
600
492
|
* @param {number} pos position
|
|
@@ -888,10 +780,14 @@ class CssParser extends Parser {
|
|
|
888
780
|
const { line: el, column: ec } = locConverter.get(end);
|
|
889
781
|
|
|
890
782
|
state.current.addWarning(
|
|
891
|
-
new
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
783
|
+
new (getModuleDependencyWarning())(
|
|
784
|
+
state.module,
|
|
785
|
+
new WebpackError(message),
|
|
786
|
+
{
|
|
787
|
+
start: { line: sl, column: sc },
|
|
788
|
+
end: { line: el, column: ec }
|
|
789
|
+
}
|
|
790
|
+
)
|
|
895
791
|
);
|
|
896
792
|
}
|
|
897
793
|
|
|
@@ -916,6 +812,92 @@ class CssParser extends Parser {
|
|
|
916
812
|
state.module.addError(err);
|
|
917
813
|
}
|
|
918
814
|
|
|
815
|
+
/**
|
|
816
|
+
* Arbitrate cross-kind CSS-Modules export collisions collected during
|
|
817
|
+
* parsing. A class always wins the shared JS export key over the
|
|
818
|
+
* CSS-only kinds (`@keyframes`, `@counter-style`, `@container`, custom
|
|
819
|
+
* property, grid identifier) — matching css-loader / lightning css /
|
|
820
|
+
* postcss-modules; the loser's `EXPORT_MODE` is demoted to `NONE` so
|
|
821
|
+
* the CSS-side rewrite is preserved but the entry no longer contributes
|
|
822
|
+
* to `styles.<name>`. Other pairs (`class` ↔ `id`,
|
|
823
|
+
* `class` ↔ `:export`, `class` ↔ `@value`, kind-vs-kind without a
|
|
824
|
+
* class present, …) surface as a warning so the user resolves the name
|
|
825
|
+
* themselves. Same-kind redeclarations are silent.
|
|
826
|
+
* @param {ParserState} state parser state
|
|
827
|
+
* @param {Map<string, { kind: string, line: number, column: number, entries: number[] }[]>} declaredExports collected declarations grouped by (name, kind)
|
|
828
|
+
* @param {import("../dependencies/CssIcssExportDependency").CssExportEntry[]} cssExportEntries all export entries — losers are demoted in place
|
|
829
|
+
* @returns {void}
|
|
830
|
+
*/
|
|
831
|
+
_resolveAmbiguousExports(state, declaredExports, cssExportEntries) {
|
|
832
|
+
const NONE = CssIcssExportDependency.EXPORT_MODE.NONE;
|
|
833
|
+
for (const [name, decls] of declaredExports) {
|
|
834
|
+
if (decls.length <= 1) continue;
|
|
835
|
+
// Prefer `class` as the winner (matches css-loader / lightning css / postcss-modules); otherwise the first-declared kind wins de facto.
|
|
836
|
+
let winner;
|
|
837
|
+
for (const d of decls) {
|
|
838
|
+
if (d.kind === "class") {
|
|
839
|
+
winner = d;
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
const reference = winner !== undefined ? winner : decls[0];
|
|
844
|
+
for (const loser of decls) {
|
|
845
|
+
if (loser === reference) continue;
|
|
846
|
+
const anchor = cssExportEntries[loser.entries[0]];
|
|
847
|
+
if (
|
|
848
|
+
winner !== undefined &&
|
|
849
|
+
(loser.kind === "custom property" ||
|
|
850
|
+
loser.kind === "@keyframes" ||
|
|
851
|
+
loser.kind === "@counter-style" ||
|
|
852
|
+
loser.kind === "@container" ||
|
|
853
|
+
loser.kind === "grid identifier")
|
|
854
|
+
) {
|
|
855
|
+
for (const idx of loser.entries) {
|
|
856
|
+
cssExportEntries[idx].exportMode = NONE;
|
|
857
|
+
}
|
|
858
|
+
state.current.addWarning(
|
|
859
|
+
new (getModuleDependencyWarning())(
|
|
860
|
+
state.module,
|
|
861
|
+
new WebpackError(
|
|
862
|
+
`CSS module export "${name}" is shadowed by ${winner.kind} at line ${winner.line}:${winner.column}: the ${loser.kind} "${name}" is still scoped in the emitted CSS but is not accessible from the JavaScript export — rename one of them if both are needed`
|
|
863
|
+
),
|
|
864
|
+
{
|
|
865
|
+
start: {
|
|
866
|
+
line: anchor.locStartLine,
|
|
867
|
+
column: anchor.locStartColumn
|
|
868
|
+
},
|
|
869
|
+
end: {
|
|
870
|
+
line: anchor.locEndLine,
|
|
871
|
+
column: anchor.locEndColumn
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
)
|
|
875
|
+
);
|
|
876
|
+
} else {
|
|
877
|
+
// Other collision — warn without changing behavior.
|
|
878
|
+
state.current.addWarning(
|
|
879
|
+
new (getModuleDependencyWarning())(
|
|
880
|
+
state.module,
|
|
881
|
+
new WebpackError(
|
|
882
|
+
`Conflicting CSS module export "${name}": already declared as ${reference.kind} at line ${reference.line}:${reference.column}, redeclared as ${loser.kind}`
|
|
883
|
+
),
|
|
884
|
+
{
|
|
885
|
+
start: {
|
|
886
|
+
line: anchor.locStartLine,
|
|
887
|
+
column: anchor.locStartColumn
|
|
888
|
+
},
|
|
889
|
+
end: {
|
|
890
|
+
line: anchor.locEndLine,
|
|
891
|
+
column: anchor.locEndColumn
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
)
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
|
|
919
901
|
/**
|
|
920
902
|
* Parses the provided source and updates the parser state.
|
|
921
903
|
* @param {string | Buffer | PreparsedAst} source the source to parse
|
|
@@ -975,6 +957,43 @@ class CssParser extends Parser {
|
|
|
975
957
|
|
|
976
958
|
const module = state.module;
|
|
977
959
|
|
|
960
|
+
// Every CSS Modules export declaration is tracked here so `_resolveAmbiguousExports` can arbitrate cross-kind collisions in one pass at end-of-parse: a class silently wins over CSS-scoped kinds (`@keyframes`, `@counter-style`, `@container`, custom property, grid identifier) — matching css-loader / lightning css / postcss-modules — while other pairs (`class` ↔ `id`, `class` ↔ `:export`, `class` ↔ `@value`, …) surface as a warning so the user can resolve them.
|
|
961
|
+
/** @typedef {{ kind: string, line: number, column: number, entries: number[] }} DeclarationOfKind */
|
|
962
|
+
/** @type {Map<string, DeclarationOfKind[]>} */
|
|
963
|
+
const declaredExports = new Map();
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Track a declaration site for later ambiguity resolution. Pointer
|
|
967
|
+
* into `cssExportEntries` is captured now because the entry is
|
|
968
|
+
* pushed immediately after by the calling `addCssExport(…)`.
|
|
969
|
+
* Property-value references (`animation: foo`) are not declarations
|
|
970
|
+
* and skip this hook.
|
|
971
|
+
* @param {string} name export name
|
|
972
|
+
* @param {string} kind human-readable declaration kind
|
|
973
|
+
* @param {number} line start line (1-based) of the declaration
|
|
974
|
+
* @param {number} column start column (0-based) of the declaration
|
|
975
|
+
* @returns {void}
|
|
976
|
+
*/
|
|
977
|
+
const recordDeclaration = (name, kind, line, column) => {
|
|
978
|
+
let decls = declaredExports.get(name);
|
|
979
|
+
if (decls === undefined) {
|
|
980
|
+
decls = [];
|
|
981
|
+
declaredExports.set(name, decls);
|
|
982
|
+
}
|
|
983
|
+
let d;
|
|
984
|
+
for (const existing of decls) {
|
|
985
|
+
if (existing.kind === kind) {
|
|
986
|
+
d = existing;
|
|
987
|
+
break;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (d === undefined) {
|
|
991
|
+
d = { kind, line, column, entries: [] };
|
|
992
|
+
decls.push(d);
|
|
993
|
+
}
|
|
994
|
+
d.entries.push(cssExportEntries.length);
|
|
995
|
+
};
|
|
996
|
+
|
|
978
997
|
// All `:export`-style exports are collected into a single
|
|
979
998
|
// `CssIcssExportDependency` per module (emitted at parse end) instead of one
|
|
980
999
|
// `Dependency` per export — far fewer retained objects on CSS-heavy builds.
|
|
@@ -1141,7 +1160,7 @@ class CssParser extends Parser {
|
|
|
1141
1160
|
if (errors) {
|
|
1142
1161
|
for (const e of errors) {
|
|
1143
1162
|
state.module.addWarning(
|
|
1144
|
-
new
|
|
1163
|
+
new (getCommentCompilationWarning())(
|
|
1145
1164
|
`Compilation error while processing magic comment(-s): /*${e.comment.value}*/: ${e.message}`,
|
|
1146
1165
|
rangeLoc(e.comment.range[0], e.comment.range[1])
|
|
1147
1166
|
)
|
|
@@ -1154,7 +1173,7 @@ class CssParser extends Parser {
|
|
|
1154
1173
|
// Loc is computed lazily here — it's only needed for this rare
|
|
1155
1174
|
// warning, not on every checked `url()` / `@import`.
|
|
1156
1175
|
state.module.addWarning(
|
|
1157
|
-
new
|
|
1176
|
+
new (getUnsupportedFeatureWarning())(
|
|
1158
1177
|
`\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
|
|
1159
1178
|
rangeLoc(warnStart, warnEnd)
|
|
1160
1179
|
)
|
|
@@ -1183,10 +1202,12 @@ class CssParser extends Parser {
|
|
|
1183
1202
|
this.options.customMedia && input.includes("@custom-media");
|
|
1184
1203
|
const mayHaveCustomSelectors =
|
|
1185
1204
|
this.options.customSelectors && input.includes("@custom-selector");
|
|
1186
|
-
/** @type {Map<string,
|
|
1205
|
+
/** @type {Map<string, CustomMediaDefinition> | undefined} */
|
|
1187
1206
|
let customMediaDefs;
|
|
1188
|
-
/** @type {
|
|
1189
|
-
let
|
|
1207
|
+
/** @type {Map<string, CustomMediaValue> | undefined} */
|
|
1208
|
+
let customMediaValues;
|
|
1209
|
+
/** @type {{ queries: MediaNode[], start: number, end: number, uses: CustomMediaUse[] }[] | undefined} */
|
|
1210
|
+
let customMediaQueries;
|
|
1190
1211
|
/** @type {Map<string, string> | undefined} */
|
|
1191
1212
|
let customSelectorDefs;
|
|
1192
1213
|
/** @type {{ name: string, start: number, end: number }[] | undefined} */
|
|
@@ -1510,6 +1531,7 @@ class CssParser extends Parser {
|
|
|
1510
1531
|
} else if (type === 1) {
|
|
1511
1532
|
const { line: sl, column: sc } = locConverter.get(start);
|
|
1512
1533
|
const { line: el, column: ec } = locConverter.get(end);
|
|
1534
|
+
recordDeclaration(name, ":export", sl, sc);
|
|
1513
1535
|
addCssExport(sl, sc, el, ec, name, getReexport(value));
|
|
1514
1536
|
}
|
|
1515
1537
|
};
|
|
@@ -1562,8 +1584,9 @@ class CssParser extends Parser {
|
|
|
1562
1584
|
* Process a `local(...)` / `global(...)` pseudo-function: strip the call (and a leading legacy `:`) via a presentational dep, then emit `local()`'s inner top-level idents as ICSS exports.
|
|
1563
1585
|
* @param {FunctionNode} fn parsed local/global function node
|
|
1564
1586
|
* @param {1 | 2} type 1 = local, 2 = global
|
|
1587
|
+
* @param {string=} declarationKind human-readable export kind to use for conflict tracking when the caller is a declaration site (selector or at-rule prelude). Undefined for property-value references, which are not tracked.
|
|
1565
1588
|
*/
|
|
1566
|
-
const processLocalOrGlobalFunction = (fn, type) => {
|
|
1589
|
+
const processLocalOrGlobalFunction = (fn, type, declarationKind) => {
|
|
1567
1590
|
// Replace `local(` / `global(` (and a leading `:` for the `:local(`/`:global(` selector form) with empty.
|
|
1568
1591
|
const fnStart = A.start(fn);
|
|
1569
1592
|
const isColon = input.charCodeAt(fnStart - 1) === CC_COLON;
|
|
@@ -1581,6 +1604,14 @@ class CssParser extends Parser {
|
|
|
1581
1604
|
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1582
1605
|
const isDashedIdent = isDashedIdentifier(identifier);
|
|
1583
1606
|
if (isDashedIdent) identifier = identifier.slice(2);
|
|
1607
|
+
if (declarationKind !== undefined) {
|
|
1608
|
+
recordDeclaration(
|
|
1609
|
+
identifier,
|
|
1610
|
+
isDashedIdent ? "custom property" : declarationKind,
|
|
1611
|
+
sl,
|
|
1612
|
+
sc
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1584
1615
|
addCssExport(
|
|
1585
1616
|
sl,
|
|
1586
1617
|
sc,
|
|
@@ -1608,9 +1639,10 @@ class CssParser extends Parser {
|
|
|
1608
1639
|
* Localize the prelude name of `@keyframes` / `@counter-style` / `@container`: `options.string` takes the first string, `options.identifier` the first ident (a `RegExp` skips matching keywords), `:local()`/`:global()` count as found; top-level `var()`/`style()` dashed idents are always ICSS-processed.
|
|
1609
1640
|
* @param {AtRule} atRule parsed at-rule
|
|
1610
1641
|
* @param {{ string?: boolean, identifier?: boolean | RegExp }} options which prelude value kinds count as the local name
|
|
1642
|
+
* @param {string} kind human-readable export kind for the surrounding at-rule (`"@keyframes"`, `"@counter-style"`, `"@container"`)
|
|
1611
1643
|
* @returns {number} position after handling
|
|
1612
1644
|
*/
|
|
1613
|
-
const processLocalAtRule = (atRule, options) => {
|
|
1645
|
+
const processLocalAtRule = (atRule, options, kind) => {
|
|
1614
1646
|
let found = false;
|
|
1615
1647
|
for (const cv of A.prelude(atRule)) {
|
|
1616
1648
|
const cvType = A.type(cv);
|
|
@@ -1621,6 +1653,7 @@ class CssParser extends Parser {
|
|
|
1621
1653
|
const value = A.unescaped(cv);
|
|
1622
1654
|
const { line: sl, column: sc } = locConverter.get(A.start(cv));
|
|
1623
1655
|
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1656
|
+
recordDeclaration(value, kind, sl, sc);
|
|
1624
1657
|
addCssExport(
|
|
1625
1658
|
sl,
|
|
1626
1659
|
sc,
|
|
@@ -1649,6 +1682,7 @@ class CssParser extends Parser {
|
|
|
1649
1682
|
}
|
|
1650
1683
|
const { line: sl, column: sc } = locConverter.get(A.start(cv));
|
|
1651
1684
|
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1685
|
+
recordDeclaration(identifier, kind, sl, sc);
|
|
1652
1686
|
addCssExport(
|
|
1653
1687
|
sl,
|
|
1654
1688
|
sc,
|
|
@@ -1678,7 +1712,7 @@ class CssParser extends Parser {
|
|
|
1678
1712
|
if (!found && type) {
|
|
1679
1713
|
found = true;
|
|
1680
1714
|
if (type === 1) pure.markLocal();
|
|
1681
|
-
processLocalOrGlobalFunction(fn, type);
|
|
1715
|
+
processLocalOrGlobalFunction(fn, type, kind);
|
|
1682
1716
|
continue;
|
|
1683
1717
|
}
|
|
1684
1718
|
if (
|
|
@@ -1692,15 +1726,29 @@ class CssParser extends Parser {
|
|
|
1692
1726
|
}
|
|
1693
1727
|
return A.end(atRule);
|
|
1694
1728
|
};
|
|
1729
|
+
/**
|
|
1730
|
+
* The custom property's name, without its `--`. An escaped dash makes the
|
|
1731
|
+
* prefix longer than two bytes, so it comes off the unescaped value.
|
|
1732
|
+
* @param {number} identStart start of the `--<name>` ident
|
|
1733
|
+
* @param {number} identEnd end of the ident
|
|
1734
|
+
* @returns {string} the name after `--`
|
|
1735
|
+
*/
|
|
1736
|
+
const dashedIdentName = (identStart, identEnd) =>
|
|
1737
|
+
source.charCodeAt(identStart) === CC_HYPHEN_MINUS &&
|
|
1738
|
+
source.charCodeAt(identStart + 1) === CC_HYPHEN_MINUS
|
|
1739
|
+
? unescapeRange(identStart + 2, identEnd)
|
|
1740
|
+
: unescapeRange(identStart, identEnd).slice(2);
|
|
1741
|
+
|
|
1695
1742
|
/**
|
|
1696
1743
|
* Emit the ICSS export declaring this module exports the given custom property.
|
|
1697
1744
|
* @param {number} identStart start of the `--<name>` ident
|
|
1698
1745
|
* @param {number} identEnd end of the ident (exclusive)
|
|
1699
1746
|
*/
|
|
1700
1747
|
const emitDashedIdentExport = (identStart, identEnd) => {
|
|
1701
|
-
const identifier =
|
|
1748
|
+
const identifier = dashedIdentName(identStart, identEnd);
|
|
1702
1749
|
const { line: sl, column: sc } = locConverter.get(identStart);
|
|
1703
1750
|
const { line: el, column: ec } = locConverter.get(identEnd);
|
|
1751
|
+
recordDeclaration(identifier, "custom property", sl, sc);
|
|
1704
1752
|
addCssExport(
|
|
1705
1753
|
sl,
|
|
1706
1754
|
sc,
|
|
@@ -1730,7 +1778,7 @@ class CssParser extends Parser {
|
|
|
1730
1778
|
sourceEnd,
|
|
1731
1779
|
pathContent
|
|
1732
1780
|
) => {
|
|
1733
|
-
const identifier =
|
|
1781
|
+
const identifier = dashedIdentName(identStart, identEnd);
|
|
1734
1782
|
const { line: sl, column: sc } = locConverter.get(identStart);
|
|
1735
1783
|
const { line: el, column: ec } = locConverter.get(sourceEnd - 1);
|
|
1736
1784
|
const localName = nextIcssImportName();
|
|
@@ -1745,6 +1793,7 @@ class CssParser extends Parser {
|
|
|
1745
1793
|
importDep.setLoc(sl, sc, el, ec);
|
|
1746
1794
|
module.addDependency(importDep);
|
|
1747
1795
|
|
|
1796
|
+
recordDeclaration(identifier, "custom property", sl, sc);
|
|
1748
1797
|
addCssExport(
|
|
1749
1798
|
sl,
|
|
1750
1799
|
sc,
|
|
@@ -1797,16 +1846,7 @@ class CssParser extends Parser {
|
|
|
1797
1846
|
|
|
1798
1847
|
const identStart = A.start(identNode);
|
|
1799
1848
|
const identEnd = A.end(identNode);
|
|
1800
|
-
|
|
1801
|
-
// prefix of length >= 3 (escaped dashes don't match, same as the string
|
|
1802
|
-
// form, since the raw bytes aren't `--`).
|
|
1803
|
-
if (
|
|
1804
|
-
identEnd - identStart < 3 ||
|
|
1805
|
-
input.charCodeAt(identStart) !== CC_HYPHEN_MINUS ||
|
|
1806
|
-
input.charCodeAt(identStart + 1) !== CC_HYPHEN_MINUS
|
|
1807
|
-
) {
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1849
|
+
if (!rangeIsDashedIdentifier(input, identStart, identEnd)) return;
|
|
1810
1850
|
|
|
1811
1851
|
let j = identIdx + 1;
|
|
1812
1852
|
while (j < fv.length && A.type(fv[j]) === NodeType.Whitespace) {
|
|
@@ -1848,26 +1888,6 @@ class CssParser extends Parser {
|
|
|
1848
1888
|
}
|
|
1849
1889
|
};
|
|
1850
1890
|
|
|
1851
|
-
/**
|
|
1852
|
-
* The child list of an AST node (a function/block `value` or a rule `prelude`) for sibling lookahead.
|
|
1853
|
-
* @param {AstNode | null} parent parent node
|
|
1854
|
-
* @returns {AstNode[] | undefined} the child list, or undefined
|
|
1855
|
-
*/
|
|
1856
|
-
const childrenOf = (parent) => {
|
|
1857
|
-
if (!parent) return undefined;
|
|
1858
|
-
switch (A.type(parent)) {
|
|
1859
|
-
case NodeType.Function:
|
|
1860
|
-
case NodeType.SimpleBlock:
|
|
1861
|
-
case NodeType.Declaration:
|
|
1862
|
-
return A.children(parent);
|
|
1863
|
-
case NodeType.AtRule:
|
|
1864
|
-
case NodeType.QualifiedRule:
|
|
1865
|
-
return A.prelude(parent);
|
|
1866
|
-
default:
|
|
1867
|
-
return undefined;
|
|
1868
|
-
}
|
|
1869
|
-
};
|
|
1870
|
-
|
|
1871
1891
|
// `allowImport` mirrors `allowImportAtRule`: true until the first top-level block-bearing rule.
|
|
1872
1892
|
let allowImport = true;
|
|
1873
1893
|
// Persistent CSS-Modules mode for a top-level rule: set by bare `:local` / `:global`, leaks into sibling rules, reset at each top-level `}`.
|
|
@@ -1882,18 +1902,25 @@ class CssParser extends Parser {
|
|
|
1882
1902
|
active: false,
|
|
1883
1903
|
/** Should top-level dashed-ident exports be emitted at this nesting level? */
|
|
1884
1904
|
emit: false,
|
|
1885
|
-
/**
|
|
1905
|
+
/** Directly inside a `counter()`-family call whose arguments were already rewritten — suppresses the generic ICSS ident rewrite over the same ranges. */
|
|
1906
|
+
counterArgs: false,
|
|
1907
|
+
/** LIFO save/restore of `active` + `emit` + `counterArgs` across function nesting, bit-packed (bit 0 = active, bit 1 = emit, bit 2 = counterArgs) to avoid a per-function-token object allocation. */
|
|
1886
1908
|
/** @type {number[]} */
|
|
1887
1909
|
stack: [],
|
|
1888
1910
|
/** Push the current scope; call before descending into a `Function` body. */
|
|
1889
1911
|
push() {
|
|
1890
|
-
this.stack.push(
|
|
1912
|
+
this.stack.push(
|
|
1913
|
+
(this.active ? 1 : 0) |
|
|
1914
|
+
(this.emit ? 2 : 0) |
|
|
1915
|
+
(this.counterArgs ? 4 : 0)
|
|
1916
|
+
);
|
|
1891
1917
|
},
|
|
1892
1918
|
/** Pop the saved scope; call when leaving a `Function` body. */
|
|
1893
1919
|
pop() {
|
|
1894
1920
|
const s = /** @type {number} */ (this.stack.pop());
|
|
1895
1921
|
this.active = (s & 1) !== 0;
|
|
1896
1922
|
this.emit = (s & 2) !== 0;
|
|
1923
|
+
this.counterArgs = (s & 4) !== 0;
|
|
1897
1924
|
}
|
|
1898
1925
|
};
|
|
1899
1926
|
// Nearest enclosing declaration / at-rule / qualified-rule, set by each structural enter; the Url / Function / Ident / Comma visitors read it (via `urlActive` / `localGlobalActive` / `icssActive`) to decide value handling from the node hierarchy instead of carrying precomputed flags.
|
|
@@ -1907,10 +1934,12 @@ class CssParser extends Parser {
|
|
|
1907
1934
|
let currentDeclIsKnownProperty = false;
|
|
1908
1935
|
/** Whether the current `composes:` declaration owns the whole value (suppresses value rewrites). */
|
|
1909
1936
|
let currentDeclComposesSkip = false;
|
|
1937
|
+
/** Whether `counter()`-family arguments are scoped in the current declaration's value. */
|
|
1938
|
+
let currentDeclCounterActive = false;
|
|
1910
1939
|
|
|
1911
1940
|
/**
|
|
1912
1941
|
* Per-at-rule scope frames; `exit` reads `hasBlock` to pick the block-cleanup vs `suppressNextRulePrelude` branch.
|
|
1913
|
-
* @type {{ savedAnchor: boolean,
|
|
1942
|
+
* @type {{ savedAnchor: boolean, savedLocalIdentifierCount: number, name: string, hasBlock: boolean, endsWithSemicolon: boolean, fontPreloaded: boolean }[]}
|
|
1914
1943
|
*/
|
|
1915
1944
|
const atRuleStateStack = [];
|
|
1916
1945
|
|
|
@@ -2079,6 +2108,71 @@ class CssParser extends Parser {
|
|
|
2079
2108
|
}
|
|
2080
2109
|
};
|
|
2081
2110
|
|
|
2111
|
+
/**
|
|
2112
|
+
* Emit the ICSS export for one ident argument of a `counter()`-family call. Dashed names are left to the blanket dashed-ident scanner, and reserved names (UA counters, predefined counter styles, CSS-wide keywords) stay global.
|
|
2113
|
+
* @param {AstNode} node the ident node
|
|
2114
|
+
* @param {string} reservedFrom property whose keywords must not be localized here
|
|
2115
|
+
* @returns {void}
|
|
2116
|
+
*/
|
|
2117
|
+
const emitCounterIdent = (node, reservedFrom) => {
|
|
2118
|
+
const name = A.unescaped(node);
|
|
2119
|
+
if (isDashedIdentifier(name)) return;
|
|
2120
|
+
const reserved =
|
|
2121
|
+
/** @type {Map<string, number>} */
|
|
2122
|
+
(CSS_MODULES_KEYWORDS.get(reservedFrom));
|
|
2123
|
+
if (reserved.has(toLowerCaseIfNeeded(name))) return;
|
|
2124
|
+
const start = A.start(node);
|
|
2125
|
+
const end = A.end(node);
|
|
2126
|
+
const { line: sl, column: sc } = locConverter.get(start);
|
|
2127
|
+
const { line: el, column: ec } = locConverter.get(end);
|
|
2128
|
+
addCssExport(
|
|
2129
|
+
sl,
|
|
2130
|
+
sc,
|
|
2131
|
+
el,
|
|
2132
|
+
ec,
|
|
2133
|
+
name,
|
|
2134
|
+
getReexport(name),
|
|
2135
|
+
[start, end],
|
|
2136
|
+
true,
|
|
2137
|
+
CssIcssExportDependency.EXPORT_MODE.ONCE
|
|
2138
|
+
);
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
/**
|
|
2142
|
+
* Scope a `counter()` / `counters()` / `target-counter()` / `target-counters()` call: the counter-name argument localizes like a `counter-reset` value and a trailing `<counter-style>` ident like a `list-style-type` value, so both keep naming the scoped `counter-*` declaration / `@counter-style` rule.
|
|
2143
|
+
* @param {AstNode[]} cvs the call's argument component values
|
|
2144
|
+
* @param {number} nameIndex comma-separated index of the counter-name argument
|
|
2145
|
+
* @returns {void}
|
|
2146
|
+
*/
|
|
2147
|
+
const walkCounterFunction = (cvs, nameIndex) => {
|
|
2148
|
+
let group = 0;
|
|
2149
|
+
let groupNodes = 0;
|
|
2150
|
+
/** Sole ident of the current argument, or undefined when the argument isn't a lone ident. */
|
|
2151
|
+
let lastIdent;
|
|
2152
|
+
for (const cv of cvs) {
|
|
2153
|
+
const type = A.type(cv);
|
|
2154
|
+
if (type === NodeType.Whitespace) continue;
|
|
2155
|
+
if (type === NodeType.Comma) {
|
|
2156
|
+
group++;
|
|
2157
|
+
groupNodes = 0;
|
|
2158
|
+
lastIdent = undefined;
|
|
2159
|
+
continue;
|
|
2160
|
+
}
|
|
2161
|
+
groupNodes++;
|
|
2162
|
+
const loneIdent = groupNodes === 1 && type === NodeType.Ident;
|
|
2163
|
+
if (group === nameIndex) {
|
|
2164
|
+
if (loneIdent) emitCounterIdent(cv, "counter-reset");
|
|
2165
|
+
lastIdent = undefined;
|
|
2166
|
+
} else {
|
|
2167
|
+
lastIdent = loneIdent ? cv : undefined;
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
// The counter style is the last argument when it's a lone ident (`counter(n, style)` / `counters(n, sep, style)`).
|
|
2171
|
+
if (lastIdent !== undefined && group > nameIndex) {
|
|
2172
|
+
emitCounterIdent(lastIdent, "list-style-type");
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2082
2176
|
/**
|
|
2083
2177
|
* Walk component values as a selector list, emitting ID / attribute deps and recursing into `:not()`/`:is()`/`:local()`/`:global()` wrappers; `localMode` is the sub-tree mode and `topLevel` controls whether commas reset it (only outside parentheses).
|
|
2084
2178
|
* @param {AstNode[]} values component values to walk
|
|
@@ -2187,6 +2281,7 @@ class CssParser extends Parser {
|
|
|
2187
2281
|
const idName = A.unescaped(v);
|
|
2188
2282
|
const { line: idSl, column: idSc } = locConverter.get(A.start(v));
|
|
2189
2283
|
const { line: idEl, column: idEc } = locConverter.get(A.end(v));
|
|
2284
|
+
recordDeclaration(idName, "id", idSl, idSc);
|
|
2190
2285
|
addCssExport(
|
|
2191
2286
|
idSl,
|
|
2192
2287
|
idSc,
|
|
@@ -2229,6 +2324,7 @@ class CssParser extends Parser {
|
|
|
2229
2324
|
// Cursor reads instead of `A.loc` — this is the hottest export site.
|
|
2230
2325
|
const { line: sl, column: sc } = locConverter.get(A.start(next));
|
|
2231
2326
|
const { line: el, column: ec } = locConverter.get(A.end(next));
|
|
2327
|
+
recordDeclaration(name, "class", sl, sc);
|
|
2232
2328
|
addCssExport(
|
|
2233
2329
|
sl,
|
|
2234
2330
|
sc,
|
|
@@ -2272,18 +2368,20 @@ class CssParser extends Parser {
|
|
|
2272
2368
|
};
|
|
2273
2369
|
/**
|
|
2274
2370
|
* Per-qualified-rule scope frames; `{ bailed: true }` for inline-handled `:import` / `:export` pseudo-rules.
|
|
2275
|
-
* @type {({ bailed: true } | { bailed: false, savedAnchor: boolean,
|
|
2371
|
+
* @type {({ bailed: true } | { bailed: false, savedAnchor: boolean, savedLocalIdentifierCount: number, savedPrevComposesFile: string | undefined, savedComposesFiles: Set<string> | null })[]}
|
|
2276
2372
|
*/
|
|
2277
2373
|
const qualifiedRuleStateStack = [];
|
|
2278
2374
|
|
|
2279
2375
|
/**
|
|
2280
|
-
* Whether url() deps are emitted here (from `currentStructural`):
|
|
2376
|
+
* Whether url() deps are emitted here (from `currentStructural`): off in an `@import`
|
|
2377
|
+
* prelude (the import target, unless recovering) and in `@namespace` (an opaque identifier).
|
|
2281
2378
|
* @returns {boolean} true when url() deps should be emitted
|
|
2282
2379
|
*/
|
|
2283
2380
|
const urlActive = () => {
|
|
2284
2381
|
if (!this.options.url || !currentStructural) return false;
|
|
2285
2382
|
if (A.type(currentStructural) === NodeType.AtRule) {
|
|
2286
2383
|
// `currentAtRuleName` is cached on at-rule enter — no per-value slice.
|
|
2384
|
+
if (currentAtRuleName === "@namespace") return false;
|
|
2287
2385
|
return currentAtRuleName !== "@import" || currentUrlRecovery;
|
|
2288
2386
|
}
|
|
2289
2387
|
return true;
|
|
@@ -2639,10 +2737,39 @@ class CssParser extends Parser {
|
|
|
2639
2737
|
/**
|
|
2640
2738
|
* Emit url() deps for a `url(...)` / `src(...)` / `image-set(...)` value function.
|
|
2641
2739
|
* @param {FunctionNode} fn the function node
|
|
2642
|
-
* @param {string}
|
|
2740
|
+
* @param {string | undefined} escapedName the unescaped function name when it carries an escape, undefined for the raw byte-range path
|
|
2643
2741
|
*/
|
|
2644
|
-
const emitUrlFunction = (fn,
|
|
2645
|
-
|
|
2742
|
+
const emitUrlFunction = (fn, escapedName) => {
|
|
2743
|
+
const fnNameStart = A.nameStart(fn);
|
|
2744
|
+
const fnNameEnd = A.nameEnd(fn);
|
|
2745
|
+
let isUrlOrSrc;
|
|
2746
|
+
let isImageSet = false;
|
|
2747
|
+
if (escapedName !== undefined) {
|
|
2748
|
+
isUrlOrSrc =
|
|
2749
|
+
equalsLowerCase(escapedName, "url") ||
|
|
2750
|
+
equalsLowerCase(escapedName, "src");
|
|
2751
|
+
if (!isUrlOrSrc) isImageSet = IMAGE_SET_FUNCTION.test(escapedName);
|
|
2752
|
+
} else {
|
|
2753
|
+
const nameLength = fnNameEnd - fnNameStart;
|
|
2754
|
+
isUrlOrSrc =
|
|
2755
|
+
nameLength === 3 &&
|
|
2756
|
+
(rangeEqualsLowerCase(input, fnNameStart, fnNameEnd, "url") ||
|
|
2757
|
+
rangeEqualsLowerCase(input, fnNameStart, fnNameEnd, "src"));
|
|
2758
|
+
if (!isUrlOrSrc) {
|
|
2759
|
+
// Suffix probe first, so only a vendor-prefixed `…-image-set` pays the slice + regex.
|
|
2760
|
+
isImageSet =
|
|
2761
|
+
nameLength >= 9 &&
|
|
2762
|
+
rangeEqualsLowerCase(
|
|
2763
|
+
input,
|
|
2764
|
+
fnNameEnd - 9,
|
|
2765
|
+
fnNameEnd,
|
|
2766
|
+
"image-set"
|
|
2767
|
+
) &&
|
|
2768
|
+
(nameLength === 9 ||
|
|
2769
|
+
IMAGE_SET_FUNCTION.test(input.slice(fnNameStart, fnNameEnd)));
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
if (isUrlOrSrc) {
|
|
2646
2773
|
// Quoted `url("…")` / `src("…")`: first non-whitespace value must be the string token.
|
|
2647
2774
|
const first = A.children(fn)[nextNonWhitespace(A.children(fn), 0)];
|
|
2648
2775
|
if (!first || A.type(first) !== NodeType.String) return;
|
|
@@ -2673,9 +2800,9 @@ class CssParser extends Parser {
|
|
|
2673
2800
|
);
|
|
2674
2801
|
module.addDependency(dep);
|
|
2675
2802
|
module.addCodeGenerationDependency(dep);
|
|
2676
|
-
} else if (
|
|
2803
|
+
} else if (isImageSet) {
|
|
2677
2804
|
// `image-set(…)`: each comma segment's first string is the URL; advance the magic-comment fence per string.
|
|
2678
|
-
lastTokenEndForComments =
|
|
2805
|
+
lastTokenEndForComments = fnNameEnd + 1;
|
|
2679
2806
|
let prevStringEnd = A.start(fn);
|
|
2680
2807
|
let firstInSegment = true;
|
|
2681
2808
|
for (const cv of A.children(fn)) {
|
|
@@ -2983,6 +3110,7 @@ class CssParser extends Parser {
|
|
|
2983
3110
|
{
|
|
2984
3111
|
const { line: sl, column: sc } = locConverter.get(start);
|
|
2985
3112
|
const { line: el, column: ec } = locConverter.get(nameEnd);
|
|
3113
|
+
recordDeclaration(localName, "@value", sl, sc);
|
|
2986
3114
|
addCssExport(
|
|
2987
3115
|
sl,
|
|
2988
3116
|
sc,
|
|
@@ -3024,10 +3152,12 @@ class CssParser extends Parser {
|
|
|
3024
3152
|
|
|
3025
3153
|
icssDefinitions.set(localName, def);
|
|
3026
3154
|
|
|
3155
|
+
recordDeclaration(localName, "@value", sl, sc);
|
|
3027
3156
|
addCssExport(sl, sc, el, ec, localName, getReexport(value));
|
|
3028
3157
|
} else {
|
|
3029
3158
|
icssDefinitions.set(localName, { value });
|
|
3030
3159
|
|
|
3160
|
+
recordDeclaration(localName, "@value", sl, sc);
|
|
3031
3161
|
addCssExport(sl, sc, el, ec, localName, value);
|
|
3032
3162
|
}
|
|
3033
3163
|
}
|
|
@@ -3060,7 +3190,10 @@ class CssParser extends Parser {
|
|
|
3060
3190
|
};
|
|
3061
3191
|
|
|
3062
3192
|
/**
|
|
3063
|
-
* Collect one `@custom-media --name <value>` definition (last-wins) and drop
|
|
3193
|
+
* Collect one `@custom-media --name <value>` definition (last-wins) and drop
|
|
3194
|
+
* the rule. A value naming another custom media is kept as an `alias` — the
|
|
3195
|
+
* name it points at may be defined further down the file, and node ids are
|
|
3196
|
+
* recycled per top-level rule, so nothing AST-shaped can outlive the walk.
|
|
3064
3197
|
* @param {AtRule} at the `@custom-media` at-rule
|
|
3065
3198
|
*/
|
|
3066
3199
|
const collectCustomMedia = (at) => {
|
|
@@ -3081,27 +3214,27 @@ class CssParser extends Parser {
|
|
|
3081
3214
|
if (!isDashedIdentifier(name)) return;
|
|
3082
3215
|
i++;
|
|
3083
3216
|
|
|
3084
|
-
/**
|
|
3085
|
-
* @param {string} text resolved text
|
|
3086
|
-
* @param {"condition" | "type" | "unsupported"} kind value kind
|
|
3087
|
-
*/
|
|
3088
|
-
const store = (text, kind) => {
|
|
3089
|
-
(customMediaDefs || (customMediaDefs = new Map())).set(name, {
|
|
3090
|
-
text,
|
|
3091
|
-
kind
|
|
3092
|
-
});
|
|
3093
|
-
};
|
|
3094
|
-
const extra = { hasExtra: false };
|
|
3095
|
-
|
|
3096
3217
|
// Value span after the name, trimmed.
|
|
3097
3218
|
let vs = i;
|
|
3098
3219
|
let ve = prelude.length;
|
|
3099
3220
|
while (vs < ve && A.type(prelude[vs]) === NodeType.Whitespace) vs++;
|
|
3100
3221
|
while (ve > vs && A.type(prelude[ve - 1]) === NodeType.Whitespace) ve--;
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3222
|
+
(customMediaDefs || (customMediaDefs = new Map())).set(
|
|
3223
|
+
name,
|
|
3224
|
+
classifyCustomMedia(prelude, vs, ve)
|
|
3225
|
+
);
|
|
3226
|
+
};
|
|
3227
|
+
|
|
3228
|
+
/**
|
|
3229
|
+
* Classify one `@custom-media` value against the live AST.
|
|
3230
|
+
* @param {readonly AstNode[]} prelude the defining at-rule's prelude
|
|
3231
|
+
* @param {number} vs first value token
|
|
3232
|
+
* @param {number} ve one past the last value token
|
|
3233
|
+
* @returns {CustomMediaDefinition} what the value is, aliases unresolved
|
|
3234
|
+
*/
|
|
3235
|
+
const classifyCustomMedia = (prelude, vs, ve) => {
|
|
3236
|
+
if (vs >= ve) return CUSTOM_MEDIA_UNSUPPORTED;
|
|
3237
|
+
const extra = { hasExtra: false };
|
|
3105
3238
|
|
|
3106
3239
|
let hasComma = false;
|
|
3107
3240
|
for (let k = vs; k < ve; k++) {
|
|
@@ -3114,46 +3247,52 @@ class CssParser extends Parser {
|
|
|
3114
3247
|
if (!hasComma) {
|
|
3115
3248
|
const first = prelude[vs];
|
|
3116
3249
|
const valueText = input.slice(A.start(first), A.end(prelude[ve - 1]));
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
const nested =
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3250
|
+
// A `(--x)` standing alone is this value spelled as another name.
|
|
3251
|
+
if (ve - vs === 1 && A.type(first) === NodeType.SimpleBlock) {
|
|
3252
|
+
const nested = loneDashedIdentOfBlock(
|
|
3253
|
+
/** @type {SimpleBlock} */ (first),
|
|
3254
|
+
extra
|
|
3255
|
+
);
|
|
3256
|
+
if (nested !== undefined && !extra.hasExtra) {
|
|
3257
|
+
return { kind: "alias", name: nested };
|
|
3258
|
+
}
|
|
3126
3259
|
}
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3260
|
+
// A reference anywhere else in the value has no resolution step of its
|
|
3261
|
+
// own — only a `@media` prelude's uses are scanned — so writing this
|
|
3262
|
+
// value out would emit the reference unresolved.
|
|
3263
|
+
if (hasCustomMediaRef(prelude, vs, ve)) return CUSTOM_MEDIA_UNSUPPORTED;
|
|
3264
|
+
if (A.type(first) === NodeType.SimpleBlock) {
|
|
3265
|
+
return { kind: "condition", text: valueText };
|
|
3130
3266
|
}
|
|
3131
|
-
if (
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
) {
|
|
3135
|
-
|
|
3136
|
-
|
|
3267
|
+
if (A.type(first) !== NodeType.Ident) return CUSTOM_MEDIA_UNSUPPORTED;
|
|
3268
|
+
const s = A.start(first);
|
|
3269
|
+
const e = A.end(first);
|
|
3270
|
+
if (ve - vs === 1) {
|
|
3271
|
+
if (rangeEqualsLowerCase(input, s, e, "true")) {
|
|
3272
|
+
return CUSTOM_MEDIA_TRUE;
|
|
3273
|
+
}
|
|
3274
|
+
if (rangeEqualsLowerCase(input, s, e, "false")) {
|
|
3275
|
+
return CUSTOM_MEDIA_FALSE;
|
|
3276
|
+
}
|
|
3137
3277
|
}
|
|
3138
|
-
if (rangeEqualsLowerCase(input,
|
|
3139
|
-
// `not (…)` is a media condition (wrap so it stays a media-in-parens);
|
|
3278
|
+
if (rangeEqualsLowerCase(input, s, e, "not")) {
|
|
3279
|
+
// `not (…)` is a media condition (wrap so it stays a media-in-parens);
|
|
3280
|
+
// `not <type>` is a media type.
|
|
3140
3281
|
let j = vs + 1;
|
|
3141
3282
|
while (j < ve && A.type(prelude[j]) === NodeType.Whitespace) j++;
|
|
3142
3283
|
if (j < ve && A.type(prelude[j]) === NodeType.SimpleBlock) {
|
|
3143
|
-
|
|
3144
|
-
} else {
|
|
3145
|
-
store(valueText, "type");
|
|
3284
|
+
return { kind: "condition", text: `(${valueText})` };
|
|
3146
3285
|
}
|
|
3147
|
-
return;
|
|
3286
|
+
return { kind: "type", text: valueText };
|
|
3148
3287
|
}
|
|
3149
3288
|
// `screen`, `only screen`, `screen and (…)`, …
|
|
3150
|
-
|
|
3151
|
-
return;
|
|
3289
|
+
return { kind: "type", text: valueText };
|
|
3152
3290
|
}
|
|
3153
3291
|
|
|
3154
|
-
// Comma list → `(seg1 or seg2 …)`; supported only when every segment is a
|
|
3155
|
-
|
|
3156
|
-
|
|
3292
|
+
// Comma list → `(seg1 or seg2 …)`; supported only when every segment is a
|
|
3293
|
+
// media-in-parens (or a name standing for one).
|
|
3294
|
+
/** @type {({ text: string } | { alias: string })[]} */
|
|
3295
|
+
const parts = [];
|
|
3157
3296
|
let ok = true;
|
|
3158
3297
|
/** @type {AstNode[]} */
|
|
3159
3298
|
let seg = [];
|
|
@@ -3168,21 +3307,25 @@ class CssParser extends Parser {
|
|
|
3168
3307
|
}
|
|
3169
3308
|
const f = seg[a];
|
|
3170
3309
|
const text = input.slice(A.start(f), A.end(seg[b - 1]));
|
|
3310
|
+
if (b - a === 1 && A.type(f) === NodeType.SimpleBlock) {
|
|
3311
|
+
const nested = loneDashedIdentOfBlock(
|
|
3312
|
+
/** @type {SimpleBlock} */ (f),
|
|
3313
|
+
extra
|
|
3314
|
+
);
|
|
3315
|
+
if (extra.hasExtra) ok = false;
|
|
3316
|
+
else if (nested === undefined) parts.push({ text });
|
|
3317
|
+
else parts.push({ alias: nested });
|
|
3318
|
+
return;
|
|
3319
|
+
}
|
|
3171
3320
|
if (
|
|
3172
|
-
b - a === 1 &&
|
|
3173
|
-
A.type(f) === NodeType.SimpleBlock &&
|
|
3174
|
-
loneDashedIdentOfBlock(/** @type {SimpleBlock} */ (f), extra) ===
|
|
3175
|
-
undefined
|
|
3176
|
-
) {
|
|
3177
|
-
segments.push(text);
|
|
3178
|
-
} else if (
|
|
3179
3321
|
A.type(f) === NodeType.Ident &&
|
|
3180
|
-
rangeEqualsLowerCase(input, A.start(f), A.end(f), "not")
|
|
3322
|
+
rangeEqualsLowerCase(input, A.start(f), A.end(f), "not") &&
|
|
3323
|
+
!hasCustomMediaRef(seg, a, b)
|
|
3181
3324
|
) {
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
ok = false;
|
|
3325
|
+
parts.push({ text: `(${text})` });
|
|
3326
|
+
return;
|
|
3185
3327
|
}
|
|
3328
|
+
ok = false;
|
|
3186
3329
|
};
|
|
3187
3330
|
for (let k = vs; k < ve; k++) {
|
|
3188
3331
|
if (A.type(prelude[k]) === NodeType.Comma) {
|
|
@@ -3193,52 +3336,384 @@ class CssParser extends Parser {
|
|
|
3193
3336
|
}
|
|
3194
3337
|
}
|
|
3195
3338
|
flush();
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3339
|
+
return ok ? { kind: "or", parts } : CUSTOM_MEDIA_UNSUPPORTED;
|
|
3340
|
+
};
|
|
3341
|
+
|
|
3342
|
+
/**
|
|
3343
|
+
* What a `@custom-media` name resolves to, memoized. An undefined name and a
|
|
3344
|
+
* definition cycle both resolve to unsupported (the use site warns).
|
|
3345
|
+
* @param {string} name the dashed ident
|
|
3346
|
+
* @param {Set<string>} resolving names currently being resolved
|
|
3347
|
+
* @returns {CustomMediaValue} what the name resolves to
|
|
3348
|
+
*/
|
|
3349
|
+
const resolveCustomMediaValue = (name, resolving) => {
|
|
3350
|
+
const cached = customMediaValues && customMediaValues.get(name);
|
|
3351
|
+
if (cached !== undefined) return cached;
|
|
3352
|
+
const def = customMediaDefs && customMediaDefs.get(name);
|
|
3353
|
+
if (def === undefined || resolving.has(name)) {
|
|
3354
|
+
return CUSTOM_MEDIA_UNSUPPORTED;
|
|
3355
|
+
}
|
|
3356
|
+
resolving.add(name);
|
|
3357
|
+
/** @type {CustomMediaValue} */
|
|
3358
|
+
let value;
|
|
3359
|
+
if (def.kind === "alias") {
|
|
3360
|
+
const inner = resolveCustomMediaValue(def.name, resolving);
|
|
3361
|
+
// A media type cannot sit in parens, so a name standing for one is no value.
|
|
3362
|
+
value = inner.kind === "type" ? CUSTOM_MEDIA_UNSUPPORTED : inner;
|
|
3363
|
+
} else if (def.kind === "or") {
|
|
3364
|
+
/** @type {string[]} */
|
|
3365
|
+
const texts = [];
|
|
3366
|
+
let ok = true;
|
|
3367
|
+
let anyTrue = false;
|
|
3368
|
+
for (const part of def.parts) {
|
|
3369
|
+
if (!("alias" in part)) {
|
|
3370
|
+
texts.push(part.text);
|
|
3371
|
+
continue;
|
|
3372
|
+
}
|
|
3373
|
+
const inner = resolveCustomMediaValue(part.alias, resolving);
|
|
3374
|
+
// A media query list is an `or`, so a constant segment drops out of it.
|
|
3375
|
+
if (inner.kind === "boolean") anyTrue = anyTrue || inner.value;
|
|
3376
|
+
else if (inner.kind === "condition") texts.push(inner.text);
|
|
3377
|
+
else ok = false;
|
|
3378
|
+
}
|
|
3379
|
+
value = !ok
|
|
3380
|
+
? CUSTOM_MEDIA_UNSUPPORTED
|
|
3381
|
+
: anyTrue
|
|
3382
|
+
? CUSTOM_MEDIA_TRUE
|
|
3383
|
+
: texts.length === 0
|
|
3384
|
+
? CUSTOM_MEDIA_FALSE
|
|
3385
|
+
: {
|
|
3386
|
+
kind: "condition",
|
|
3387
|
+
text:
|
|
3388
|
+
texts.length === 1 ? texts[0] : `(${texts.join(" or ")})`
|
|
3389
|
+
};
|
|
3201
3390
|
} else {
|
|
3202
|
-
|
|
3391
|
+
value = def;
|
|
3203
3392
|
}
|
|
3393
|
+
resolving.delete(name);
|
|
3394
|
+
(customMediaValues || (customMediaValues = new Map())).set(name, value);
|
|
3395
|
+
return value;
|
|
3204
3396
|
};
|
|
3205
3397
|
|
|
3206
3398
|
/**
|
|
3207
|
-
*
|
|
3208
|
-
*
|
|
3209
|
-
* @param {
|
|
3399
|
+
* Whether a node is the media keyword `word` (media queries are ASCII
|
|
3400
|
+
* case-insensitive).
|
|
3401
|
+
* @param {AstNode} node candidate node
|
|
3402
|
+
* @param {string} word lower-case keyword
|
|
3403
|
+
* @returns {boolean} true on a match
|
|
3210
3404
|
*/
|
|
3211
|
-
const
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3405
|
+
const isMediaKeyword = (node, word) =>
|
|
3406
|
+
A.type(node) === NodeType.Ident &&
|
|
3407
|
+
rangeEqualsLowerCase(input, A.start(node), A.end(node), word);
|
|
3408
|
+
|
|
3409
|
+
/**
|
|
3410
|
+
* First significant index in `tokens[from…to)`.
|
|
3411
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3412
|
+
* @param {number} from first index
|
|
3413
|
+
* @param {number} to one past the last index
|
|
3414
|
+
* @returns {number} the trimmed start
|
|
3415
|
+
*/
|
|
3416
|
+
const mediaTrimStart = (tokens, from, to) => {
|
|
3417
|
+
let a = from;
|
|
3418
|
+
while (a < to && A.type(tokens[a]) === NodeType.Whitespace) a++;
|
|
3419
|
+
return a;
|
|
3420
|
+
};
|
|
3421
|
+
|
|
3422
|
+
/**
|
|
3423
|
+
* One past the last significant index in `tokens[from…to)`.
|
|
3424
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3425
|
+
* @param {number} from first index
|
|
3426
|
+
* @param {number} to one past the last index
|
|
3427
|
+
* @returns {number} the trimmed end
|
|
3428
|
+
*/
|
|
3429
|
+
const mediaTrimEnd = (tokens, from, to) => {
|
|
3430
|
+
let b = to;
|
|
3431
|
+
while (b > from && A.type(tokens[b - 1]) === NodeType.Whitespace) b--;
|
|
3432
|
+
return b;
|
|
3433
|
+
};
|
|
3434
|
+
|
|
3435
|
+
/**
|
|
3436
|
+
* The source text spanned by `tokens[from…to)`.
|
|
3437
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3438
|
+
* @param {number} from first index
|
|
3439
|
+
* @param {number} to one past the last index
|
|
3440
|
+
* @returns {string} the source slice
|
|
3441
|
+
*/
|
|
3442
|
+
const mediaText = (tokens, from, to) =>
|
|
3443
|
+
input.slice(A.start(tokens[from]), A.end(tokens[to - 1]));
|
|
3444
|
+
|
|
3445
|
+
// One flag object for the whole parse: `loneDashedIdentOfBlock` writes it and
|
|
3446
|
+
// every caller reads it back before the next call.
|
|
3447
|
+
const mediaExtra = { hasExtra: false };
|
|
3448
|
+
|
|
3449
|
+
/**
|
|
3450
|
+
* Whether any `(--name)` reference is reachable inside `node`. `childAt` walks
|
|
3451
|
+
* the children without materializing the list.
|
|
3452
|
+
* @param {AstNode} node a block or function node
|
|
3453
|
+
* @returns {boolean} true when a reference is present
|
|
3454
|
+
*/
|
|
3455
|
+
const hasCustomMediaRefIn = (node) => {
|
|
3456
|
+
const count = A.childCount(node);
|
|
3457
|
+
for (let k = 0; k < count; k++) {
|
|
3458
|
+
const child = A.childAt(node, k);
|
|
3459
|
+
const type = A.type(child);
|
|
3460
|
+
if (type !== NodeType.SimpleBlock && type !== NodeType.Function) {
|
|
3219
3461
|
continue;
|
|
3220
3462
|
}
|
|
3221
|
-
if (
|
|
3222
|
-
|
|
3223
|
-
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3463
|
+
if (
|
|
3464
|
+
type === NodeType.SimpleBlock &&
|
|
3465
|
+
loneDashedIdentOfBlock(
|
|
3466
|
+
/** @type {SimpleBlock} */ (child),
|
|
3467
|
+
mediaExtra
|
|
3468
|
+
) !== undefined
|
|
3469
|
+
) {
|
|
3470
|
+
return true;
|
|
3471
|
+
}
|
|
3472
|
+
if (hasCustomMediaRefIn(child)) return true;
|
|
3473
|
+
}
|
|
3474
|
+
return false;
|
|
3475
|
+
};
|
|
3476
|
+
|
|
3477
|
+
/**
|
|
3478
|
+
* Whether any `(--name)` reference is reachable in `tokens[from…to)`. Cheap
|
|
3479
|
+
* enough to run over every `@media` prelude so one without a reference builds
|
|
3480
|
+
* no tree at all.
|
|
3481
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3482
|
+
* @param {number} from first index
|
|
3483
|
+
* @param {number} to one past the last index
|
|
3484
|
+
* @returns {boolean} true when a reference is present
|
|
3485
|
+
*/
|
|
3486
|
+
const hasCustomMediaRef = (tokens, from, to) => {
|
|
3487
|
+
for (let i = from; i < to; i++) {
|
|
3488
|
+
const node = tokens[i];
|
|
3489
|
+
const type = A.type(node);
|
|
3490
|
+
if (type !== NodeType.SimpleBlock && type !== NodeType.Function) {
|
|
3491
|
+
continue;
|
|
3492
|
+
}
|
|
3493
|
+
if (
|
|
3494
|
+
type === NodeType.SimpleBlock &&
|
|
3495
|
+
loneDashedIdentOfBlock(
|
|
3496
|
+
/** @type {SimpleBlock} */ (node),
|
|
3497
|
+
mediaExtra
|
|
3498
|
+
) !== undefined
|
|
3499
|
+
) {
|
|
3500
|
+
return true;
|
|
3501
|
+
}
|
|
3502
|
+
if (hasCustomMediaRefIn(node)) return true;
|
|
3503
|
+
}
|
|
3504
|
+
return false;
|
|
3505
|
+
};
|
|
3506
|
+
|
|
3507
|
+
/**
|
|
3508
|
+
* Capture one `<media-in-parens>` — a reference to a custom media name, a
|
|
3509
|
+
* parenthesised sub-condition, or an opaque feature test.
|
|
3510
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3511
|
+
* @param {number} from first index
|
|
3512
|
+
* @param {number} to one past the last index
|
|
3513
|
+
* @param {boolean} leading whether the term starts a top-level query
|
|
3514
|
+
* @param {CustomMediaUse[]} uses the prelude's use list, appended to
|
|
3515
|
+
* @returns {MediaNode} the captured term
|
|
3516
|
+
*/
|
|
3517
|
+
const captureMediaInParens = (tokens, from, to, leading, uses) => {
|
|
3518
|
+
const a = mediaTrimStart(tokens, from, to);
|
|
3519
|
+
const b = mediaTrimEnd(tokens, a, to);
|
|
3520
|
+
if (a >= b) return { kind: "text", text: "" };
|
|
3521
|
+
const text = mediaText(tokens, a, b);
|
|
3522
|
+
if (b - a !== 1 || A.type(tokens[a]) !== NodeType.SimpleBlock) {
|
|
3523
|
+
return { kind: "text", text };
|
|
3524
|
+
}
|
|
3525
|
+
const block = /** @type {SimpleBlock} */ (tokens[a]);
|
|
3526
|
+
const name = loneDashedIdentOfBlock(block, mediaExtra);
|
|
3527
|
+
if (name !== undefined) {
|
|
3528
|
+
const use = {
|
|
3529
|
+
name,
|
|
3530
|
+
start: A.start(block),
|
|
3531
|
+
end: A.end(block),
|
|
3532
|
+
invalid: mediaExtra.hasExtra,
|
|
3533
|
+
leading
|
|
3534
|
+
};
|
|
3535
|
+
uses.push(use);
|
|
3536
|
+
return { kind: "ref", text, use };
|
|
3537
|
+
}
|
|
3538
|
+
const children = A.children(block);
|
|
3539
|
+
const inner = captureMediaCondition(children, 0, children.length, uses);
|
|
3540
|
+
return inner.kind === "text"
|
|
3541
|
+
? { kind: "text", text }
|
|
3542
|
+
: { kind: "group", operand: inner };
|
|
3543
|
+
};
|
|
3544
|
+
|
|
3545
|
+
/**
|
|
3546
|
+
* Capture a `<media-condition>` — `not <in-parens>`, or an `and` / `or` chain
|
|
3547
|
+
* of them (CSS never mixes the two at one level).
|
|
3548
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3549
|
+
* @param {number} from first index
|
|
3550
|
+
* @param {number} to one past the last index
|
|
3551
|
+
* @param {CustomMediaUse[]} uses the prelude's use list, appended to
|
|
3552
|
+
* @returns {MediaNode} the captured condition
|
|
3553
|
+
*/
|
|
3554
|
+
const captureMediaCondition = (tokens, from, to, uses) => {
|
|
3555
|
+
const a = mediaTrimStart(tokens, from, to);
|
|
3556
|
+
const b = mediaTrimEnd(tokens, a, to);
|
|
3557
|
+
if (a >= b) return { kind: "text", text: "" };
|
|
3558
|
+
if (isMediaKeyword(tokens[a], "not")) {
|
|
3559
|
+
return {
|
|
3560
|
+
kind: "not",
|
|
3561
|
+
operand: captureMediaInParens(tokens, a + 1, b, false, uses)
|
|
3562
|
+
};
|
|
3563
|
+
}
|
|
3564
|
+
/** @type {MediaNode[]} */
|
|
3565
|
+
const terms = [];
|
|
3566
|
+
let isOr = false;
|
|
3567
|
+
let start = a;
|
|
3568
|
+
for (let i = a; i <= b; i++) {
|
|
3569
|
+
const atEnd = i === b;
|
|
3570
|
+
if (
|
|
3571
|
+
!atEnd &&
|
|
3572
|
+
!isMediaKeyword(tokens[i], "and") &&
|
|
3573
|
+
!isMediaKeyword(tokens[i], "or")
|
|
3574
|
+
) {
|
|
3575
|
+
continue;
|
|
3576
|
+
}
|
|
3577
|
+
if (!atEnd && isMediaKeyword(tokens[i], "or")) isOr = true;
|
|
3578
|
+
terms.push(captureMediaInParens(tokens, start, i, start === a, uses));
|
|
3579
|
+
start = i + 1;
|
|
3580
|
+
}
|
|
3581
|
+
if (terms.length === 1) return terms[0];
|
|
3582
|
+
return { kind: "chain", isOr, terms };
|
|
3583
|
+
};
|
|
3584
|
+
|
|
3585
|
+
/**
|
|
3586
|
+
* Capture one `<media-query>` — a bare condition, or a media type with an
|
|
3587
|
+
* optional `and` chain after it.
|
|
3588
|
+
* @param {readonly AstNode[]} tokens token list
|
|
3589
|
+
* @param {number} from first index
|
|
3590
|
+
* @param {number} to one past the last index
|
|
3591
|
+
* @param {CustomMediaUse[]} uses the prelude's use list, appended to
|
|
3592
|
+
* @returns {MediaNode} the captured query
|
|
3593
|
+
*/
|
|
3594
|
+
const captureMediaQuery = (tokens, from, to, uses) => {
|
|
3595
|
+
const a = mediaTrimStart(tokens, from, to);
|
|
3596
|
+
const b = mediaTrimEnd(tokens, a, to);
|
|
3597
|
+
if (a >= b) return { kind: "text", text: "" };
|
|
3598
|
+
const rest = mediaTrimStart(tokens, a + 1, b);
|
|
3599
|
+
const startsWithType =
|
|
3600
|
+
A.type(tokens[a]) === NodeType.Ident &&
|
|
3601
|
+
(!isMediaKeyword(tokens[a], "not") ||
|
|
3602
|
+
rest >= b ||
|
|
3603
|
+
A.type(tokens[rest]) !== NodeType.SimpleBlock);
|
|
3604
|
+
if (!startsWithType) return captureMediaCondition(tokens, a, b, uses);
|
|
3605
|
+
// `[not | only]? <type> [and <condition-without-or>]?` — the type itself is
|
|
3606
|
+
// never constant, so only the `and` chain after it can fold.
|
|
3607
|
+
let split = b;
|
|
3608
|
+
for (let i = a; i < b; i++) {
|
|
3609
|
+
if (isMediaKeyword(tokens[i], "and")) {
|
|
3610
|
+
split = i;
|
|
3611
|
+
break;
|
|
3612
|
+
}
|
|
3613
|
+
}
|
|
3614
|
+
return {
|
|
3615
|
+
kind: "typed",
|
|
3616
|
+
text: mediaText(tokens, a, mediaTrimEnd(tokens, a, split)),
|
|
3617
|
+
rest:
|
|
3618
|
+
split === b ? null : captureMediaCondition(tokens, split + 1, b, uses)
|
|
3619
|
+
};
|
|
3620
|
+
};
|
|
3621
|
+
|
|
3622
|
+
/**
|
|
3623
|
+
* Record one `@media` prelude, the custom-media references inside it, and the
|
|
3624
|
+
* boolean shape needed to fold it once the references resolve.
|
|
3625
|
+
* @param {AtRule} at the `@media` at-rule
|
|
3626
|
+
*/
|
|
3627
|
+
const collectMediaQuery = (at) => {
|
|
3628
|
+
const prelude = A.prelude(at);
|
|
3629
|
+
const start = mediaTrimStart(prelude, 0, prelude.length);
|
|
3630
|
+
const end = mediaTrimEnd(prelude, start, prelude.length);
|
|
3631
|
+
if (start >= end || !hasCustomMediaRef(prelude, start, end)) return;
|
|
3632
|
+
/** @type {CustomMediaUse[]} */
|
|
3633
|
+
const uses = [];
|
|
3634
|
+
/** @type {MediaNode[]} */
|
|
3635
|
+
const queries = [];
|
|
3636
|
+
let queryStart = start;
|
|
3637
|
+
for (let i = start; i <= end; i++) {
|
|
3638
|
+
if (i !== end && A.type(prelude[i]) !== NodeType.Comma) continue;
|
|
3639
|
+
queries.push(captureMediaQuery(prelude, queryStart, i, uses));
|
|
3640
|
+
queryStart = i + 1;
|
|
3641
|
+
}
|
|
3642
|
+
if (uses.length === 0) return;
|
|
3643
|
+
(customMediaQueries || (customMediaQueries = [])).push({
|
|
3644
|
+
queries,
|
|
3645
|
+
start: A.start(prelude[start]),
|
|
3646
|
+
end: A.end(prelude[end - 1]),
|
|
3647
|
+
uses
|
|
3648
|
+
});
|
|
3649
|
+
};
|
|
3650
|
+
|
|
3651
|
+
/**
|
|
3652
|
+
* Fold a captured media node against the resolved definitions. A reference the
|
|
3653
|
+
* resolver could not classify keeps its source text, so it prints as authored.
|
|
3654
|
+
* @param {MediaNode} node the captured node
|
|
3655
|
+
* @param {Set<string>} resolving names currently being resolved
|
|
3656
|
+
* @returns {boolean | string} the constant, or the node's text
|
|
3657
|
+
*/
|
|
3658
|
+
const foldMediaNode = (node, resolving) => {
|
|
3659
|
+
switch (node.kind) {
|
|
3660
|
+
case "text":
|
|
3661
|
+
return node.text;
|
|
3662
|
+
case "ref": {
|
|
3663
|
+
const value = resolveCustomMediaValue(node.use.name, resolving);
|
|
3664
|
+
if (node.use.invalid) return node.text;
|
|
3665
|
+
if (value.kind === "boolean") return value.value;
|
|
3666
|
+
if (value.kind === "condition") return value.text;
|
|
3667
|
+
if (value.kind === "type" && node.use.leading) return value.text;
|
|
3668
|
+
return node.text;
|
|
3669
|
+
}
|
|
3670
|
+
case "group": {
|
|
3671
|
+
const inner = foldMediaNode(node.operand, resolving);
|
|
3672
|
+
return typeof inner === "boolean" ? inner : `(${inner})`;
|
|
3673
|
+
}
|
|
3674
|
+
case "not": {
|
|
3675
|
+
const operand = foldMediaNode(node.operand, resolving);
|
|
3676
|
+
return typeof operand === "boolean" ? !operand : `not ${operand}`;
|
|
3677
|
+
}
|
|
3678
|
+
case "chain": {
|
|
3679
|
+
/** @type {string[]} */
|
|
3680
|
+
const kept = [];
|
|
3681
|
+
for (const term of node.terms) {
|
|
3682
|
+
const folded = foldMediaNode(term, resolving);
|
|
3683
|
+
if (folded === node.isOr) return node.isOr;
|
|
3684
|
+
if (typeof folded !== "boolean") kept.push(folded);
|
|
3236
3685
|
}
|
|
3237
|
-
|
|
3238
|
-
|
|
3686
|
+
if (kept.length === 0) return !node.isOr;
|
|
3687
|
+
if (kept.length === 1) return kept[0];
|
|
3688
|
+
return kept.join(node.isOr ? " or " : " and ");
|
|
3239
3689
|
}
|
|
3240
|
-
|
|
3690
|
+
default: {
|
|
3691
|
+
if (node.rest === null) return node.text;
|
|
3692
|
+
const rest = foldMediaNode(node.rest, resolving);
|
|
3693
|
+
if (rest === false) return false;
|
|
3694
|
+
if (rest === true) return node.text;
|
|
3695
|
+
return `${node.text} and ${rest}`;
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
};
|
|
3699
|
+
|
|
3700
|
+
/**
|
|
3701
|
+
* Fold a whole `@media` prelude. A query that is always false leaves the list;
|
|
3702
|
+
* one that is always true makes the list match everywhere (`all`), and a list
|
|
3703
|
+
* with nothing left matches nowhere (`not all`).
|
|
3704
|
+
* @param {MediaNode[]} queries the prelude's captured queries
|
|
3705
|
+
* @param {Set<string>} resolving names currently being resolved
|
|
3706
|
+
* @returns {string} the folded prelude
|
|
3707
|
+
*/
|
|
3708
|
+
const foldMediaPrelude = (queries, resolving) => {
|
|
3709
|
+
/** @type {string[]} */
|
|
3710
|
+
const kept = [];
|
|
3711
|
+
for (const query of queries) {
|
|
3712
|
+
const folded = foldMediaNode(query, resolving);
|
|
3713
|
+
if (folded === true) return "all";
|
|
3714
|
+
if (folded !== false && folded !== "") kept.push(folded);
|
|
3241
3715
|
}
|
|
3716
|
+
return kept.length === 0 ? "not all" : kept.join(", ");
|
|
3242
3717
|
};
|
|
3243
3718
|
|
|
3244
3719
|
/**
|
|
@@ -3304,55 +3779,71 @@ class CssParser extends Parser {
|
|
|
3304
3779
|
};
|
|
3305
3780
|
|
|
3306
3781
|
/**
|
|
3307
|
-
* Rewrite the collected `@custom-media` / `@custom-selector` uses now that all (possibly later-defined) definitions are known; warns on invalid, unknown, or
|
|
3782
|
+
* Rewrite the collected `@custom-media` / `@custom-selector` uses now that all (possibly later-defined) definitions are known; warns on invalid, unknown, or media-type-in-a-non-leading-position custom-media uses.
|
|
3308
3783
|
*/
|
|
3309
3784
|
const resolveCustomMediaAndSelectors = () => {
|
|
3310
|
-
if (
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3785
|
+
if (customMediaQueries) {
|
|
3786
|
+
/** @type {Set<string>} */
|
|
3787
|
+
const resolving = new Set();
|
|
3788
|
+
for (const query of customMediaQueries) {
|
|
3789
|
+
let hasBoolean = false;
|
|
3790
|
+
for (const use of query.uses) {
|
|
3791
|
+
if (use.invalid) {
|
|
3792
|
+
this._emitWarning(
|
|
3793
|
+
state,
|
|
3794
|
+
`Custom media query '${use.name}' must be used in a boolean context`,
|
|
3795
|
+
locConverter,
|
|
3796
|
+
use.start,
|
|
3797
|
+
use.end
|
|
3798
|
+
);
|
|
3799
|
+
continue;
|
|
3800
|
+
}
|
|
3801
|
+
const value = resolveCustomMediaValue(use.name, resolving);
|
|
3802
|
+
if (value.kind === "unsupported") {
|
|
3803
|
+
this._emitWarning(
|
|
3804
|
+
state,
|
|
3805
|
+
customMediaDefs && customMediaDefs.has(use.name)
|
|
3806
|
+
? `Custom media query '${use.name}' has a value that cannot be resolved and was left as written`
|
|
3807
|
+
: `Unknown custom media query '${use.name}'`,
|
|
3808
|
+
locConverter,
|
|
3809
|
+
use.start,
|
|
3810
|
+
use.end
|
|
3811
|
+
);
|
|
3812
|
+
} else if (value.kind === "boolean") {
|
|
3813
|
+
hasBoolean = true;
|
|
3814
|
+
} else if (value.kind === "type" && !use.leading) {
|
|
3815
|
+
this._emitWarning(
|
|
3816
|
+
state,
|
|
3817
|
+
`Custom media query '${use.name}' resolves to a media type and can only be used at the start of a media query`,
|
|
3818
|
+
locConverter,
|
|
3819
|
+
use.start,
|
|
3820
|
+
use.end
|
|
3821
|
+
);
|
|
3822
|
+
}
|
|
3332
3823
|
}
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3824
|
+
// `true` / `false` have no `<media-in-parens>` spelling, so a prelude
|
|
3825
|
+
// holding one is rewritten whole — every other use in it folds with it.
|
|
3826
|
+
if (hasBoolean) {
|
|
3827
|
+
module.addPresentationalDependency(
|
|
3828
|
+
new ConstDependency(foldMediaPrelude(query.queries, resolving), [
|
|
3829
|
+
query.start,
|
|
3830
|
+
query.end
|
|
3831
|
+
])
|
|
3340
3832
|
);
|
|
3341
3833
|
continue;
|
|
3342
3834
|
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
use.
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3835
|
+
for (const use of query.uses) {
|
|
3836
|
+
if (use.invalid) continue;
|
|
3837
|
+
const value = resolveCustomMediaValue(use.name, resolving);
|
|
3838
|
+
if (
|
|
3839
|
+
value.kind === "condition" ||
|
|
3840
|
+
(value.kind === "type" && use.leading)
|
|
3841
|
+
) {
|
|
3842
|
+
module.addPresentationalDependency(
|
|
3843
|
+
new ConstDependency(value.text, [use.start, use.end])
|
|
3844
|
+
);
|
|
3845
|
+
}
|
|
3352
3846
|
}
|
|
3353
|
-
module.addPresentationalDependency(
|
|
3354
|
-
new ConstDependency(def.text, [use.start, use.end])
|
|
3355
|
-
);
|
|
3356
3847
|
}
|
|
3357
3848
|
}
|
|
3358
3849
|
if (customSelectorUses) {
|
|
@@ -3376,10 +3867,13 @@ class CssParser extends Parser {
|
|
|
3376
3867
|
/** @type {Record<string, number>} */
|
|
3377
3868
|
let parsedKeywords = Object.create(null);
|
|
3378
3869
|
const isGridProperty = Boolean(declPropertyName.startsWith("grid"));
|
|
3379
|
-
// Only `view-transition-*` legitimately
|
|
3870
|
+
// Only `view-transition-*` and `counter-*` legitimately take a dashed-ident value; other known properties keep the historical plain-ident handling.
|
|
3380
3871
|
const isViewTransitionProperty = Boolean(
|
|
3381
3872
|
declPropertyName.startsWith("view-transition")
|
|
3382
3873
|
);
|
|
3874
|
+
const isCounterProperty = Boolean(
|
|
3875
|
+
declPropertyName.startsWith("counter-")
|
|
3876
|
+
);
|
|
3383
3877
|
const isGridTemplate = isGridProperty
|
|
3384
3878
|
? Boolean(
|
|
3385
3879
|
declPropertyName === "grid" ||
|
|
@@ -3389,7 +3883,7 @@ class CssParser extends Parser {
|
|
|
3389
3883
|
)
|
|
3390
3884
|
: false;
|
|
3391
3885
|
const keywords =
|
|
3392
|
-
/** @type {
|
|
3886
|
+
/** @type {Map<string, number>} */
|
|
3393
3887
|
(knownProperties.get(declPropertyName));
|
|
3394
3888
|
let afterExclamation = false;
|
|
3395
3889
|
/**
|
|
@@ -3406,6 +3900,8 @@ class CssParser extends Parser {
|
|
|
3406
3900
|
isString ? start + 1 : start,
|
|
3407
3901
|
isString ? end - 1 : end
|
|
3408
3902
|
);
|
|
3903
|
+
// Only grid-line names are declaration sites here; property-value references (`animation: foo`) are usages.
|
|
3904
|
+
if (isGridProperty) recordDeclaration(name, "grid identifier", sl, sc);
|
|
3409
3905
|
addCssExport(
|
|
3410
3906
|
sl,
|
|
3411
3907
|
sc,
|
|
@@ -3439,8 +3935,11 @@ class CssParser extends Parser {
|
|
|
3439
3935
|
break;
|
|
3440
3936
|
}
|
|
3441
3937
|
const identifier = A.value(cv);
|
|
3442
|
-
// `view-transition-name: --foo` — a dashed name scopes as a custom property under `dashedIdents`, not as a plain ident export.
|
|
3443
|
-
if (
|
|
3938
|
+
// `view-transition-name: --foo` / `counter-reset: --foo` — a dashed name scopes as a custom property under `dashedIdents`, not as a plain ident export.
|
|
3939
|
+
if (
|
|
3940
|
+
(isViewTransitionProperty || isCounterProperty) &&
|
|
3941
|
+
isDashedIdentifier(identifier)
|
|
3942
|
+
) {
|
|
3444
3943
|
if (this.options.dashedIdents) {
|
|
3445
3944
|
emitDashedIdentExport(A.start(cv), A.end(cv));
|
|
3446
3945
|
}
|
|
@@ -3452,10 +3951,8 @@ class CssParser extends Parser {
|
|
|
3452
3951
|
typeof parsedKeywords[keyword] !== "undefined"
|
|
3453
3952
|
? parsedKeywords[keyword] + 1
|
|
3454
3953
|
: 0;
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
parsedKeywords[keyword] < keywords[keyword]
|
|
3458
|
-
) {
|
|
3954
|
+
const limit = keywords.get(keyword);
|
|
3955
|
+
if (limit !== undefined && parsedKeywords[keyword] < limit) {
|
|
3459
3956
|
break;
|
|
3460
3957
|
}
|
|
3461
3958
|
emit(A.start(cv), A.end(cv));
|
|
@@ -3473,11 +3970,15 @@ class CssParser extends Parser {
|
|
|
3473
3970
|
declPropertyName === "grid-template" ||
|
|
3474
3971
|
declPropertyName === "grid-template-areas"
|
|
3475
3972
|
) {
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3973
|
+
// Raw offsets: a match index into the unescaped text would
|
|
3974
|
+
// slide the replaced range past every escape before it.
|
|
3975
|
+
const names = gridAreaNames(
|
|
3976
|
+
source,
|
|
3977
|
+
A.start(cv) + 1,
|
|
3978
|
+
A.end(cv) - 1
|
|
3979
|
+
);
|
|
3980
|
+
for (const [nameStart, nameEnd] of names) {
|
|
3981
|
+
emit(nameStart, nameEnd, false);
|
|
3481
3982
|
}
|
|
3482
3983
|
}
|
|
3483
3984
|
break;
|
|
@@ -3497,7 +3998,12 @@ class CssParser extends Parser {
|
|
|
3497
3998
|
break;
|
|
3498
3999
|
}
|
|
3499
4000
|
case NodeType.Function:
|
|
3500
|
-
|
|
4001
|
+
// `repeat(…)` line names, and the `counter-reset: reversed(name)` wrapper — but not `local()`/`global()`, whose idents the value visitors own.
|
|
4002
|
+
if (
|
|
4003
|
+
isGridTemplate ||
|
|
4004
|
+
(isCounterProperty &&
|
|
4005
|
+
equalsLowerCase(A.unescapedName(cv), "reversed"))
|
|
4006
|
+
) {
|
|
3501
4007
|
walkExports(A.children(cv));
|
|
3502
4008
|
}
|
|
3503
4009
|
break;
|
|
@@ -3564,13 +4070,10 @@ class CssParser extends Parser {
|
|
|
3564
4070
|
currentUrlRecovery = false;
|
|
3565
4071
|
advanceCommentCursor(A.start(at));
|
|
3566
4072
|
const savedAnchor = currentRule.hasLocalAnchor;
|
|
3567
|
-
|
|
3568
|
-
//
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
? [...savedLocalIdentifiers]
|
|
3572
|
-
: savedLocalIdentifiers;
|
|
3573
|
-
const name = `@${toLowerCaseIfNeeded(A.name(at))}`;
|
|
4073
|
+
// Rollback point: nested walks append to the shared list; the exit
|
|
4074
|
+
// truncates back to this length (no per-rule copy).
|
|
4075
|
+
const savedLocalIdentifierCount = currentRule.localIdentifiers.length;
|
|
4076
|
+
const name = `@${toLowerCaseIfNeeded(A.unescapedName(at))}`;
|
|
3574
4077
|
switch (name) {
|
|
3575
4078
|
case "@namespace": {
|
|
3576
4079
|
this._emitWarning(
|
|
@@ -3614,7 +4117,7 @@ class CssParser extends Parser {
|
|
|
3614
4117
|
break;
|
|
3615
4118
|
}
|
|
3616
4119
|
case "@media": {
|
|
3617
|
-
if (mayHaveCustomMedia)
|
|
4120
|
+
if (mayHaveCustomMedia) collectMediaQuery(at);
|
|
3618
4121
|
break;
|
|
3619
4122
|
}
|
|
3620
4123
|
default: {
|
|
@@ -3626,21 +4129,33 @@ class CssParser extends Parser {
|
|
|
3626
4129
|
this.options.animation &&
|
|
3627
4130
|
OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
|
|
3628
4131
|
) {
|
|
3629
|
-
processLocalAtRule(
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
4132
|
+
processLocalAtRule(
|
|
4133
|
+
at,
|
|
4134
|
+
{
|
|
4135
|
+
string: mode === "local",
|
|
4136
|
+
identifier: mode === "local"
|
|
4137
|
+
},
|
|
4138
|
+
"@keyframes"
|
|
4139
|
+
);
|
|
3633
4140
|
} else if (
|
|
3634
4141
|
this.options.customIdents &&
|
|
3635
4142
|
name === "@counter-style"
|
|
3636
4143
|
) {
|
|
3637
|
-
processLocalAtRule(
|
|
3638
|
-
|
|
3639
|
-
|
|
4144
|
+
processLocalAtRule(
|
|
4145
|
+
at,
|
|
4146
|
+
{
|
|
4147
|
+
identifier: mode === "local"
|
|
4148
|
+
},
|
|
4149
|
+
"@counter-style"
|
|
4150
|
+
);
|
|
3640
4151
|
} else if (this.options.container && name === "@container") {
|
|
3641
|
-
processLocalAtRule(
|
|
3642
|
-
|
|
3643
|
-
|
|
4152
|
+
processLocalAtRule(
|
|
4153
|
+
at,
|
|
4154
|
+
{
|
|
4155
|
+
identifier: mode === "local" ? /^(none|and|or|not)$/ : false
|
|
4156
|
+
},
|
|
4157
|
+
"@container"
|
|
4158
|
+
);
|
|
3644
4159
|
}
|
|
3645
4160
|
}
|
|
3646
4161
|
}
|
|
@@ -3648,7 +4163,7 @@ class CssParser extends Parser {
|
|
|
3648
4163
|
// `@scope (.x) to (.y)` — walk the prelude as a selector list.
|
|
3649
4164
|
if (
|
|
3650
4165
|
isModules &&
|
|
3651
|
-
equalsLowerCase(A.
|
|
4166
|
+
equalsLowerCase(A.unescapedName(at), "scope") &&
|
|
3652
4167
|
A.prelude(at).length > 0
|
|
3653
4168
|
) {
|
|
3654
4169
|
walkSelectorList(
|
|
@@ -3664,6 +4179,7 @@ class CssParser extends Parser {
|
|
|
3664
4179
|
const isProcessedByLocalAtRule = isLocalHandledAtRule(name);
|
|
3665
4180
|
currentStructural = at;
|
|
3666
4181
|
currentAtRuleName = name;
|
|
4182
|
+
currentDeclCounterActive = false;
|
|
3667
4183
|
dashed.active = false;
|
|
3668
4184
|
// `@import` url() is the import target — only walk its prelude for url deps on malformed-import recovery.
|
|
3669
4185
|
if (this.options.url && (name !== "@import" || currentUrlRecovery)) {
|
|
@@ -3704,12 +4220,13 @@ class CssParser extends Parser {
|
|
|
3704
4220
|
);
|
|
3705
4221
|
}
|
|
3706
4222
|
|
|
3707
|
-
// pure.stack push for block-bearing at-rules
|
|
4223
|
+
// pure.stack push for block-bearing at-rules (pure-off builds skip
|
|
4224
|
+
// the frame object — every consumer inside is a no-op then).
|
|
3708
4225
|
const atDecls = A.declarations(at);
|
|
3709
4226
|
const atChildRules = A.childRules(at);
|
|
3710
4227
|
const atHasBlock = Boolean(atDecls || atChildRules);
|
|
3711
4228
|
const atBlockStart = A.blockStart(at);
|
|
3712
|
-
if (atHasBlock && atBlockStart !== -1) {
|
|
4229
|
+
if (pure.enabled && atHasBlock && atBlockStart !== -1) {
|
|
3713
4230
|
const isAtRulePrelude = isPureBodyAtRule(name);
|
|
3714
4231
|
if (isAtRulePrelude) pure.finalizeSelector();
|
|
3715
4232
|
pure.enterBlock({
|
|
@@ -3725,7 +4242,7 @@ class CssParser extends Parser {
|
|
|
3725
4242
|
|
|
3726
4243
|
atRuleStateStack.push({
|
|
3727
4244
|
savedAnchor,
|
|
3728
|
-
|
|
4245
|
+
savedLocalIdentifierCount,
|
|
3729
4246
|
name,
|
|
3730
4247
|
hasBlock: atHasBlock,
|
|
3731
4248
|
endsWithSemicolon: source.charCodeAt(A.end(at)) === CC_SEMICOLON,
|
|
@@ -3748,7 +4265,7 @@ class CssParser extends Parser {
|
|
|
3748
4265
|
suppressNextRulePrelude = true;
|
|
3749
4266
|
}
|
|
3750
4267
|
currentRule.hasLocalAnchor = state.savedAnchor;
|
|
3751
|
-
currentRule.localIdentifiers = state.
|
|
4268
|
+
currentRule.localIdentifiers.length = state.savedLocalIdentifierCount;
|
|
3752
4269
|
if (path.parent === null) finishTopLevelRule(node, true);
|
|
3753
4270
|
}
|
|
3754
4271
|
},
|
|
@@ -3759,11 +4276,16 @@ class CssParser extends Parser {
|
|
|
3759
4276
|
const rule = /** @type {QualifiedRule} */ (node);
|
|
3760
4277
|
const topLevel = path.parent === null;
|
|
3761
4278
|
advanceCommentCursor(A.start(rule));
|
|
4279
|
+
// One prelude materialization per rule, shared by the scans below
|
|
4280
|
+
// (null in plain mode, which never reads the array).
|
|
4281
|
+
const rulePrelude =
|
|
4282
|
+
isModules || mayHaveCustomSelectors ? A.prelude(rule) : null;
|
|
3762
4283
|
// `:--name` custom-selector references (dashed idents never collide with the `:import`/`:export` ICSS preludes below).
|
|
3763
|
-
if (mayHaveCustomSelectors)
|
|
4284
|
+
if (mayHaveCustomSelectors && rulePrelude !== null) {
|
|
4285
|
+
scanCustomSelectorUses(rulePrelude);
|
|
4286
|
+
}
|
|
3764
4287
|
// `:import(…) { … }` / `:export { … }` ICSS pseudo-rules are processed inline at top level; nested ones bail out.
|
|
3765
|
-
if (isModules) {
|
|
3766
|
-
const rulePrelude = A.prelude(rule);
|
|
4288
|
+
if (isModules && rulePrelude !== null) {
|
|
3767
4289
|
const firstIdx = nextNonWhitespace(rulePrelude, 0);
|
|
3768
4290
|
if (
|
|
3769
4291
|
firstIdx + 1 < rulePrelude.length &&
|
|
@@ -3804,14 +4326,12 @@ class CssParser extends Parser {
|
|
|
3804
4326
|
}
|
|
3805
4327
|
}
|
|
3806
4328
|
}
|
|
3807
|
-
// Reset the anchor flag for this rule's body
|
|
4329
|
+
// Reset the anchor flag for this rule's body; nested `composes:` sees
|
|
4330
|
+
// parent + own class names in the shared identifier list, rolled back
|
|
4331
|
+
// by length on exit (no per-rule copy).
|
|
3808
4332
|
const savedAnchor = currentRule.hasLocalAnchor;
|
|
3809
|
-
const
|
|
4333
|
+
const savedLocalIdentifierCount = currentRule.localIdentifiers.length;
|
|
3810
4334
|
currentRule.hasLocalAnchor = false;
|
|
3811
|
-
// Only modules-mode walks mutate `localIdentifiers`; otherwise share the (empty) parent list instead of copying it per rule.
|
|
3812
|
-
currentRule.localIdentifiers = isModules
|
|
3813
|
-
? [...savedLocalIdentifiers]
|
|
3814
|
-
: savedLocalIdentifiers;
|
|
3815
4335
|
// Composes-state reset between rules (saved / restored around this rule); composesFiles is swapped out and re-created lazily only if this rule composes.
|
|
3816
4336
|
const savedPrevComposesFile = currentRule.composesPrevFile;
|
|
3817
4337
|
const savedComposesFiles = currentRule.composesFiles;
|
|
@@ -3820,13 +4340,12 @@ class CssParser extends Parser {
|
|
|
3820
4340
|
qualifiedRuleStateStack.push({
|
|
3821
4341
|
bailed: false,
|
|
3822
4342
|
savedAnchor,
|
|
3823
|
-
|
|
4343
|
+
savedLocalIdentifierCount,
|
|
3824
4344
|
savedPrevComposesFile,
|
|
3825
4345
|
savedComposesFiles
|
|
3826
4346
|
});
|
|
3827
4347
|
// Selectors are only CSS-Modules-relevant when `isModules` holds.
|
|
3828
|
-
|
|
3829
|
-
if (isModules) {
|
|
4348
|
+
if (isModules && rulePrelude !== null) {
|
|
3830
4349
|
walkSelectorList(
|
|
3831
4350
|
rulePrelude,
|
|
3832
4351
|
/** @type {"local" | "global"} */ (
|
|
@@ -3836,22 +4355,24 @@ class CssParser extends Parser {
|
|
|
3836
4355
|
}
|
|
3837
4356
|
// A malformed declaration can leave orphan `url(...)` in the prelude — let the url visitor pick those up.
|
|
3838
4357
|
currentStructural = rule;
|
|
4358
|
+
currentDeclCounterActive = false;
|
|
3839
4359
|
dashed.active = false;
|
|
3840
4360
|
dashed.emit = false;
|
|
3841
|
-
if (this.options.url &&
|
|
3842
|
-
lastTokenEndForComments = A.start(
|
|
4361
|
+
if (this.options.url && A.childCount(rule) > 0) {
|
|
4362
|
+
lastTokenEndForComments = A.start(A.childAt(rule, 0));
|
|
3843
4363
|
}
|
|
3844
4364
|
// Dashed-ident scoping for the deprecated `--foo: { … }` custom-property-set syntax (prelude starts with a dashed-ident).
|
|
3845
4365
|
if (
|
|
3846
4366
|
this.options.dashedIdents &&
|
|
3847
4367
|
isModules &&
|
|
4368
|
+
rulePrelude !== null &&
|
|
3848
4369
|
rulePrelude.length > 0
|
|
3849
4370
|
) {
|
|
3850
4371
|
const first = rulePrelude[nextNonWhitespace(rulePrelude, 0)];
|
|
3851
4372
|
if (
|
|
3852
4373
|
first &&
|
|
3853
4374
|
A.type(first) === NodeType.Ident &&
|
|
3854
|
-
|
|
4375
|
+
rangeIsDashedIdentifier(source, A.start(first), A.end(first))
|
|
3855
4376
|
) {
|
|
3856
4377
|
const effectiveLocalMode = isEffectivelyLocal();
|
|
3857
4378
|
if (effectiveLocalMode) {
|
|
@@ -3861,6 +4382,7 @@ class CssParser extends Parser {
|
|
|
3861
4382
|
}
|
|
3862
4383
|
}
|
|
3863
4384
|
// Pure-mode: report an impure prelude (if leaf-ish) and push the inherited-context frame before walking the body.
|
|
4385
|
+
if (!pure.enabled) return;
|
|
3864
4386
|
const ruleBlockStart = A.blockStart(rule);
|
|
3865
4387
|
pure.enterBlock({
|
|
3866
4388
|
isRulePrelude: true,
|
|
@@ -3879,7 +4401,7 @@ class CssParser extends Parser {
|
|
|
3879
4401
|
if (!state || state.bailed) return;
|
|
3880
4402
|
pure.exitBlock();
|
|
3881
4403
|
currentRule.hasLocalAnchor = state.savedAnchor;
|
|
3882
|
-
currentRule.localIdentifiers = state.
|
|
4404
|
+
currentRule.localIdentifiers.length = state.savedLocalIdentifierCount;
|
|
3883
4405
|
currentRule.composesPrevFile = state.savedPrevComposesFile;
|
|
3884
4406
|
currentRule.composesFiles = state.savedComposesFiles;
|
|
3885
4407
|
if (path.parent === null) finishTopLevelRule(node, false);
|
|
@@ -3904,6 +4426,8 @@ class CssParser extends Parser {
|
|
|
3904
4426
|
lastTokenEndForComments = colonPos + 1;
|
|
3905
4427
|
currentDeclIsKnownProperty = false;
|
|
3906
4428
|
currentDeclComposesSkip = false;
|
|
4429
|
+
currentDeclCounterActive = false;
|
|
4430
|
+
dashed.counterArgs = false;
|
|
3907
4431
|
// Property-name analysis and value exports are CSS-Modules-only; a plain
|
|
3908
4432
|
// stylesheet's declarations need no per-decl name slice / known-property lookup.
|
|
3909
4433
|
if (!isModules) return;
|
|
@@ -3915,13 +4439,23 @@ class CssParser extends Parser {
|
|
|
3915
4439
|
let declName;
|
|
3916
4440
|
/** @type {string | undefined} */
|
|
3917
4441
|
let declPropertyName;
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
)
|
|
3924
|
-
|
|
4442
|
+
let declIsDashed = false;
|
|
4443
|
+
if (
|
|
4444
|
+
source.charCodeAt(nameStart) === CC_HYPHEN_MINUS ||
|
|
4445
|
+
source.charCodeAt(nameStart) === CC_REVERSE_SOLIDUS
|
|
4446
|
+
) {
|
|
4447
|
+
if (rangeIsDashedIdentifier(source, nameStart, nameEnd)) {
|
|
4448
|
+
// Custom property: never vendor-prefixed / known / composes.
|
|
4449
|
+
declIsDashed = true;
|
|
4450
|
+
} else {
|
|
4451
|
+
// Vendor-prefixed, degenerate short, or an escaped name that is
|
|
4452
|
+
// not dashed after all — rare, string path.
|
|
4453
|
+
declName = A.unescapedName(decl);
|
|
4454
|
+
declPropertyName = toLowerCaseIfNeeded(
|
|
4455
|
+
declName.replace(VENDOR_PREFIX, "")
|
|
4456
|
+
);
|
|
4457
|
+
currentDeclIsKnownProperty = knownProperties.has(declPropertyName);
|
|
4458
|
+
}
|
|
3925
4459
|
} else {
|
|
3926
4460
|
declPropertyName = knownPropertyForRange(
|
|
3927
4461
|
knownPropertyIndex,
|
|
@@ -3942,6 +4476,11 @@ class CssParser extends Parser {
|
|
|
3942
4476
|
rangeEqualsLowerCase(source, nameStart, nameEnd, "compose-with"));
|
|
3943
4477
|
if (currentDeclComposesSkip) emitComposesWithAnchor(decl);
|
|
3944
4478
|
const skipForComposes = currentDeclComposesSkip;
|
|
4479
|
+
// `content: counter(name, style)` can name a scoped counter / `@counter-style` from any property, so this isn't driven by the known-property table.
|
|
4480
|
+
currentDeclCounterActive =
|
|
4481
|
+
Boolean(this.options.customIdents) &&
|
|
4482
|
+
effectiveLocalMode &&
|
|
4483
|
+
!skipForComposes;
|
|
3945
4484
|
// Known-property value localization (`animation-name: foo` exports `foo`).
|
|
3946
4485
|
if (effectiveLocalMode && currentDeclIsKnownProperty) {
|
|
3947
4486
|
emitKnownPropertyExports(
|
|
@@ -3955,8 +4494,8 @@ class CssParser extends Parser {
|
|
|
3955
4494
|
effectiveLocalMode &&
|
|
3956
4495
|
!skipForComposes
|
|
3957
4496
|
) {
|
|
3958
|
-
// Only the
|
|
3959
|
-
if (
|
|
4497
|
+
// Only the `--`-prefixed path can carry a dashed ident.
|
|
4498
|
+
if (declIsDashed) {
|
|
3960
4499
|
emitDashedIdentExport(nameStart, nameEnd);
|
|
3961
4500
|
}
|
|
3962
4501
|
dashed.active = true;
|
|
@@ -3972,7 +4511,7 @@ class CssParser extends Parser {
|
|
|
3972
4511
|
declName = source.slice(nameStart, nameEnd);
|
|
3973
4512
|
}
|
|
3974
4513
|
if (
|
|
3975
|
-
!(dashed.active &&
|
|
4514
|
+
!(dashed.active && declIsDashed) &&
|
|
3976
4515
|
icssDefinitions.has(declName)
|
|
3977
4516
|
) {
|
|
3978
4517
|
emitICSSSymbol(declName, nameStart, nameEnd);
|
|
@@ -4052,12 +4591,34 @@ class CssParser extends Parser {
|
|
|
4052
4591
|
enter: (path) => {
|
|
4053
4592
|
const node = path.node;
|
|
4054
4593
|
const fn = /** @type {FunctionNode} */ (node);
|
|
4055
|
-
const
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4594
|
+
const fnNameStart = A.nameStart(fn);
|
|
4595
|
+
const fnNameEnd = A.nameEnd(fn);
|
|
4596
|
+
const fnNameLength = fnNameEnd - fnNameStart;
|
|
4597
|
+
// Functions are the densest value nodes, so the name is matched by raw byte range; only a name carrying an escape (rare) pays the unescaped slice.
|
|
4598
|
+
/** @type {string | undefined} */
|
|
4599
|
+
let escapedName;
|
|
4600
|
+
let isLocalFn = false;
|
|
4601
|
+
let isGlobalFn = false;
|
|
4602
|
+
if (rangeHasEscape(input, fnNameStart, fnNameEnd)) {
|
|
4603
|
+
escapedName = A.unescapedName(fn);
|
|
4604
|
+
isLocalFn = equalsLowerCase(escapedName, "local");
|
|
4605
|
+
isGlobalFn = !isLocalFn && equalsLowerCase(escapedName, "global");
|
|
4606
|
+
} else if (fnNameLength === 5) {
|
|
4607
|
+
isLocalFn = rangeEqualsLowerCase(
|
|
4608
|
+
input,
|
|
4609
|
+
fnNameStart,
|
|
4610
|
+
fnNameEnd,
|
|
4611
|
+
"local"
|
|
4612
|
+
);
|
|
4613
|
+
} else if (fnNameLength === 6) {
|
|
4614
|
+
isGlobalFn = rangeEqualsLowerCase(
|
|
4615
|
+
input,
|
|
4616
|
+
fnNameStart,
|
|
4617
|
+
fnNameEnd,
|
|
4618
|
+
"global"
|
|
4619
|
+
);
|
|
4620
|
+
}
|
|
4621
|
+
if (urlActive()) emitUrlFunction(fn, escapedName);
|
|
4061
4622
|
if (localGlobalActive() && (isLocalFn || isGlobalFn)) {
|
|
4062
4623
|
processLocalOrGlobalFunction(fn, isLocalFn ? 1 : 2);
|
|
4063
4624
|
}
|
|
@@ -4065,27 +4626,67 @@ class CssParser extends Parser {
|
|
|
4065
4626
|
icssActive() &&
|
|
4066
4627
|
!isLocalFn &&
|
|
4067
4628
|
!isGlobalFn &&
|
|
4068
|
-
|
|
4069
|
-
icssDefinitions.has(fnameRaw)
|
|
4629
|
+
icssDefinitions.size !== 0
|
|
4070
4630
|
) {
|
|
4071
|
-
|
|
4631
|
+
// Without an escape the raw name equals the unescaped one — only the `@value`-lookup path needs the string at all.
|
|
4632
|
+
const fname = escapedName === undefined ? A.name(fn) : escapedName;
|
|
4633
|
+
if (
|
|
4634
|
+
!(dashed.active && isDashedIdentifier(fname)) &&
|
|
4635
|
+
icssDefinitions.has(fname)
|
|
4636
|
+
) {
|
|
4637
|
+
emitICSSSymbol(fname, fnNameStart, fnNameEnd);
|
|
4638
|
+
}
|
|
4639
|
+
}
|
|
4640
|
+
// `counter()` / `counters()` / `target-counter()` / `target-counters()`: rewrite the counter name and any trailing counter-style ident.
|
|
4641
|
+
let counterNameIndex = -1;
|
|
4642
|
+
if (currentDeclCounterActive && !isLocalFn && !isGlobalFn) {
|
|
4643
|
+
counterNameIndex = counterFunctionNameIndex(
|
|
4644
|
+
input,
|
|
4645
|
+
fnNameStart,
|
|
4646
|
+
fnNameEnd,
|
|
4647
|
+
escapedName
|
|
4648
|
+
);
|
|
4649
|
+
if (counterNameIndex !== -1) {
|
|
4650
|
+
walkCounterFunction(A.children(fn), counterNameIndex);
|
|
4651
|
+
}
|
|
4072
4652
|
}
|
|
4073
4653
|
// Dashed-ident scoping: handle this function, then set the child nesting level's state for the walk.
|
|
4074
4654
|
dashed.push();
|
|
4655
|
+
dashed.counterArgs = counterNameIndex !== -1;
|
|
4075
4656
|
if (dashed.active) {
|
|
4076
4657
|
if (isLocalFn || isGlobalFn) {
|
|
4077
4658
|
// `local()` / `global()` dashed args go through the ICSS path above, not here.
|
|
4078
4659
|
dashed.active = false;
|
|
4079
4660
|
} else if (
|
|
4080
|
-
|
|
4081
|
-
|
|
4661
|
+
escapedName === undefined
|
|
4662
|
+
? (fnNameLength === 3 &&
|
|
4663
|
+
rangeEqualsLowerCase(
|
|
4664
|
+
input,
|
|
4665
|
+
fnNameStart,
|
|
4666
|
+
fnNameEnd,
|
|
4667
|
+
"var"
|
|
4668
|
+
)) ||
|
|
4669
|
+
(fnNameLength === 5 &&
|
|
4670
|
+
rangeEqualsLowerCase(
|
|
4671
|
+
input,
|
|
4672
|
+
fnNameStart,
|
|
4673
|
+
fnNameEnd,
|
|
4674
|
+
"style"
|
|
4675
|
+
))
|
|
4676
|
+
: equalsLowerCase(escapedName, "var") ||
|
|
4677
|
+
equalsLowerCase(escapedName, "style")
|
|
4082
4678
|
) {
|
|
4083
4679
|
// `var(--foo, …)` / `style(--foo, …)`: emit the first ident; the fallback doesn't self-emit.
|
|
4084
4680
|
processDashedIdentInVarFunction(fn);
|
|
4085
4681
|
dashed.emit = false;
|
|
4086
|
-
} else if (
|
|
4087
|
-
|
|
4088
|
-
|
|
4682
|
+
} else if (
|
|
4683
|
+
dashed.emit &&
|
|
4684
|
+
fnNameLength >= 3 &&
|
|
4685
|
+
input.charCodeAt(fnNameStart) === CC_HYPHEN_MINUS &&
|
|
4686
|
+
input.charCodeAt(fnNameStart + 1) === CC_HYPHEN_MINUS
|
|
4687
|
+
) {
|
|
4688
|
+
// Custom-function call `--my-func(args)` — the name is the exported dashed-ident (a literal `--` prefix, like the `A.name` string check it replaces).
|
|
4689
|
+
emitDashedIdentExport(fnNameStart, fnNameEnd);
|
|
4089
4690
|
}
|
|
4090
4691
|
}
|
|
4091
4692
|
},
|
|
@@ -4099,31 +4700,50 @@ class CssParser extends Parser {
|
|
|
4099
4700
|
// and ICSS context (any non-CSS-Modules stylesheet) a bare ident carries
|
|
4100
4701
|
// no work, and idents are the most common node, so skipping the per-ident
|
|
4101
4702
|
// `value` slice matters. With no `@value`/`:import` definitions the ICSS
|
|
4102
|
-
// probe can never hit, so it doesn't warrant the slice either.
|
|
4703
|
+
// probe can never hit, so it doesn't warrant the slice either. The dashed
|
|
4704
|
+
// probe reads two char codes instead of slicing (escaped dashes don't
|
|
4705
|
+
// match, same as the string form — cf. `processDashedIdentInVarFunction`).
|
|
4103
4706
|
const dashedActive = dashed.active;
|
|
4104
4707
|
const icss = icssActive() && icssDefinitions.size !== 0;
|
|
4105
4708
|
if (!dashedActive && !icss) return;
|
|
4106
|
-
const
|
|
4107
|
-
|
|
4709
|
+
const identStart = A.start(node);
|
|
4710
|
+
const identEnd = A.end(node);
|
|
4711
|
+
if (
|
|
4712
|
+
dashedActive &&
|
|
4713
|
+
rangeIsDashedIdentifier(input, identStart, identEnd)
|
|
4714
|
+
) {
|
|
4108
4715
|
// Dashed idents are scoped here, never `@value` ICSS-rewritten.
|
|
4109
4716
|
if (!dashed.emit) return;
|
|
4110
|
-
// Resolve the `--foo from "./x.css"` / `--foo from global` import suffix via sibling lookahead.
|
|
4111
|
-
const
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4717
|
+
// Resolve the `--foo from "./x.css"` / `--foo from global` import suffix via sibling lookahead over the parent's child span (`path.index` avoids materializing the sibling list per dashed ident).
|
|
4718
|
+
const parent = path.parent;
|
|
4719
|
+
if (parent) {
|
|
4720
|
+
const count = A.childCount(parent);
|
|
4721
|
+
let j = path.index + 1;
|
|
4722
|
+
while (
|
|
4723
|
+
j < count &&
|
|
4724
|
+
A.type(A.childAt(parent, j)) === NodeType.Whitespace
|
|
4725
|
+
) {
|
|
4726
|
+
j++;
|
|
4727
|
+
}
|
|
4728
|
+
const fromIdent = j < count ? A.childAt(parent, j) : undefined;
|
|
4115
4729
|
if (
|
|
4116
|
-
|
|
4117
|
-
A.type(
|
|
4730
|
+
fromIdent &&
|
|
4731
|
+
A.type(fromIdent) === NodeType.Ident &&
|
|
4118
4732
|
rangeEqualsLowerCase(
|
|
4119
4733
|
input,
|
|
4120
|
-
A.start(
|
|
4121
|
-
A.end(
|
|
4734
|
+
A.start(fromIdent),
|
|
4735
|
+
A.end(fromIdent),
|
|
4122
4736
|
"from"
|
|
4123
4737
|
)
|
|
4124
4738
|
) {
|
|
4125
|
-
|
|
4126
|
-
|
|
4739
|
+
j++;
|
|
4740
|
+
while (
|
|
4741
|
+
j < count &&
|
|
4742
|
+
A.type(A.childAt(parent, j)) === NodeType.Whitespace
|
|
4743
|
+
) {
|
|
4744
|
+
j++;
|
|
4745
|
+
}
|
|
4746
|
+
const sourceNode = j < count ? A.childAt(parent, j) : undefined;
|
|
4127
4747
|
if (
|
|
4128
4748
|
sourceNode &&
|
|
4129
4749
|
A.type(sourceNode) === NodeType.Ident &&
|
|
@@ -4134,13 +4754,13 @@ class CssParser extends Parser {
|
|
|
4134
4754
|
"global"
|
|
4135
4755
|
)
|
|
4136
4756
|
) {
|
|
4137
|
-
emitDashedIdentFromGlobal(
|
|
4757
|
+
emitDashedIdentFromGlobal(identEnd, A.end(sourceNode));
|
|
4138
4758
|
return;
|
|
4139
4759
|
}
|
|
4140
4760
|
if (sourceNode && A.type(sourceNode) === NodeType.String) {
|
|
4141
4761
|
emitDashedIdentImport(
|
|
4142
|
-
|
|
4143
|
-
|
|
4762
|
+
identStart,
|
|
4763
|
+
identEnd,
|
|
4144
4764
|
A.start(fromIdent),
|
|
4145
4765
|
A.end(sourceNode),
|
|
4146
4766
|
input.slice(A.start(sourceNode) + 1, A.end(sourceNode) - 1)
|
|
@@ -4149,12 +4769,16 @@ class CssParser extends Parser {
|
|
|
4149
4769
|
}
|
|
4150
4770
|
}
|
|
4151
4771
|
}
|
|
4152
|
-
emitDashedIdentExport(
|
|
4772
|
+
emitDashedIdentExport(identStart, identEnd);
|
|
4153
4773
|
return;
|
|
4154
4774
|
}
|
|
4155
4775
|
if (!icss) return;
|
|
4776
|
+
// Already rewritten as a counter / counter-style name — a second dep would overlap the same range.
|
|
4777
|
+
if (dashed.counterArgs) return;
|
|
4778
|
+
// Deferred: only the ICSS probe needs the ident's string value.
|
|
4779
|
+
const identValue = A.value(node);
|
|
4156
4780
|
if (icssDefinitions.has(identValue)) {
|
|
4157
|
-
emitICSSSymbol(identValue,
|
|
4781
|
+
emitICSSSymbol(identValue, identStart, identEnd);
|
|
4158
4782
|
}
|
|
4159
4783
|
}
|
|
4160
4784
|
};
|
|
@@ -4164,19 +4788,22 @@ class CssParser extends Parser {
|
|
|
4164
4788
|
// (per-source) is passed to `process`. One skip set: selector prelude +
|
|
4165
4789
|
// unread value leaves (non-modules only; CSS Modules needs its selectors
|
|
4166
4790
|
// and ICSS-captured values).
|
|
4167
|
-
new SourceProcessor(
|
|
4168
|
-
as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as),
|
|
4169
|
-
// Non-modules parses skip selector preludes, but `@custom-selector` expansion needs them, so keep them when the file may use one.
|
|
4170
|
-
skip: isModules
|
|
4171
|
-
? undefined
|
|
4172
|
-
: mayHaveCustomSelectors
|
|
4173
|
-
? SKIP_NON_MODULES_KEEP_SELECTORS
|
|
4174
|
-
: SKIP_NON_MODULES
|
|
4175
|
-
})
|
|
4791
|
+
new SourceProcessor()
|
|
4176
4792
|
.use(/** @type {VisitorMap} */ (visitors))
|
|
4177
|
-
.process(source, {
|
|
4793
|
+
.process(source, {
|
|
4794
|
+
as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as),
|
|
4795
|
+
// Non-modules parses skip selector preludes, but `@custom-selector` expansion needs them, so keep them when the file may use one.
|
|
4796
|
+
skip: isModules
|
|
4797
|
+
? undefined
|
|
4798
|
+
: mayHaveCustomSelectors
|
|
4799
|
+
? SKIP_NON_MODULES_KEEP_SELECTORS
|
|
4800
|
+
: SKIP_NON_MODULES,
|
|
4801
|
+
locConverter
|
|
4802
|
+
});
|
|
4178
4803
|
|
|
4179
|
-
if (
|
|
4804
|
+
if (customMediaQueries || customSelectorUses) {
|
|
4805
|
+
resolveCustomMediaAndSelectors();
|
|
4806
|
+
}
|
|
4180
4807
|
|
|
4181
4808
|
/** @type {BuildInfo} */
|
|
4182
4809
|
(module.buildInfo).strict = true;
|
|
@@ -4201,6 +4828,9 @@ class CssParser extends Parser {
|
|
|
4201
4828
|
: "redirect-warn";
|
|
4202
4829
|
|
|
4203
4830
|
if (cssExportEntries.length > 0) {
|
|
4831
|
+
if (isModules && declaredExports.size > 0) {
|
|
4832
|
+
this._resolveAmbiguousExports(state, declaredExports, cssExportEntries);
|
|
4833
|
+
}
|
|
4204
4834
|
module.addDependency(new CssIcssExportDependency(cssExportEntries));
|
|
4205
4835
|
}
|
|
4206
4836
|
|