@edynamix/mf-isolation 0.0.34 → 0.0.36
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 +3 -1
- package/dist/document-root-selectors.d.ts.map +1 -1
- package/dist/document-root-selectors.js +9 -1
- package/dist/document-root-selectors.js.map +1 -1
- package/dist/postcss.d.ts.map +1 -1
- package/dist/postcss.js +35 -1
- package/dist/postcss.js.map +1 -1
- package/dist/vite-development.d.ts.map +1 -1
- package/dist/vite-development.js +53 -4
- package/dist/vite-development.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,6 +39,8 @@ export default {
|
|
|
39
39
|
|
|
40
40
|
The host and remote must use the same `scopeId`. Both PostCSS plugins keep ordinary global and vendor selectors under the zero-specificity `:where([data-edyn-mf="<scope-id>"])` boundary. Document-root descendants such as `html body#app button` or `html body button` keep the weight of the root they start from: it becomes `:where([data-edyn-mf="<scope-id>"]):not(<carrier>)`, where `:where()` weighs nothing and the carrier (for example `edyn-mf-root edyn-mf-root#edyn-mf-root` for `html body#app`) has the same id, class and type counts as the replaced root and never matches the scope element. Module overrides therefore win or lose against Angular Material exactly as on the standalone page.
|
|
41
41
|
|
|
42
|
+
A module page had one `<html>` and one `<body>`, so a selector that needs a second one never matched there: `html body html body .x` (what a global partial compiles to when it is loaded inside `html body {}`), `body .a body .b`, or a document root after a combinator (`.x html`, `.x :root`). Scoping would turn those roots into the boundary and make the rule match hosted, so both PostCSS plugins drop such a selector, and the rule when no selector is left (0.0.36 or later). The runtime rescope below leaves it as written, where it matches nothing either.
|
|
43
|
+
|
|
42
44
|
### Root font size and rem
|
|
43
45
|
|
|
44
46
|
`rem` always resolves against the page's `<html>`, even inside a shadow root. A module page that sized its own root (`html, body { font-size: 12px }`) drew every rem length from that size; hosted, the same lengths would use the host page's root. Both PostCSS plugins therefore record a resolvable `font-size` or `font` size on `html` or `:root` (px, %, em, rem, absolute units and size keywords, against the initial 16px) as `--edyn-mf-rem` on the module boundary, in a rule right after the one that sets it, so `@media` conditions and `!important` carry over. Sizing only `body` (or `html body`) leaves rem alone, as it did on the module's own page. A size that cannot be resolved at build time (`var()`, `calc()` with `var()`, viewport units, system fonts) is reported as a PostCSS warning; rem then keeps the host root size. CSS that never sizes the root is emitted exactly as before.
|
|
@@ -154,7 +156,7 @@ const localHostNavigationUrl = new URL(
|
|
|
154
156
|
).href;
|
|
155
157
|
```
|
|
156
158
|
|
|
157
|
-
`hostNavigationUrl` selects the host environment. Load the browser entry from `localHostNavigationUrl`; the BFF serves the selected bundle and its host-owned logo assets through the secure local origin, avoiding mixed-content failures when the selected host is an HTTP localhost instance. Host API calls go to the selected host origin, while module API calls go to the explicit `moduleApiOrigin`. The BFF performs OIDC authorization code with PKCE, retains tokens and module API cookies in the development process, and forwards authenticated API requests without exposing either to module JavaScript. The refresh token is also kept in an HttpOnly `__Host-edyn_dev_refresh` cookie for the local origin, so one sign-in survives dev server restarts and switching between modules until the token expires. The sign-in service accepts each refresh token once, so requests the browser sent before a restart's rotated cookie reached it share that restore instead of spending the token again and clearing the new cookie. Host API requests keep the browser's navigation selection headers, which the host validates. Module API requests instead carry the selection the host last confirmed, read from `/api/navigation` responses and navigation stream events, through `X-Edyn-Navigation-Group-Id`, `X-Edyn-Navigation-Dealer-Ids` and, for a single dealer, `X-Edyn-Navigation-Dealer-Id`; module backends must still authorize those values before constructing module-specific session state. Request bodies are forwarded with a fixed length (up to 100 MB), because deployed module front ends reject chunked bodies. Before a module's first API call the BFF asks the host for the current selection, because the local shell starts the module beside the navigation rather than after it. A module's redirect to its legacy `/login` page leads to the development sign-in while signed out; signed in, it shows that the module API refused the session instead of reloading the module in a loop.
|
|
159
|
+
`hostNavigationUrl` selects the host environment. Load the browser entry from `localHostNavigationUrl`; the BFF serves the selected bundle and its host-owned logo assets through the secure local origin, avoiding mixed-content failures when the selected host is an HTTP localhost instance. Host API calls go to the selected host origin, while module API calls go to the explicit `moduleApiOrigin`. The BFF performs OIDC authorization code with PKCE, retains tokens and module API cookies in the development process, and forwards authenticated API requests without exposing either to module JavaScript. The refresh token is also kept in an HttpOnly `__Host-edyn_dev_refresh` cookie for the local origin, so one sign-in survives dev server restarts and switching between modules until the token expires. The sign-in service accepts each refresh token once, so requests the browser sent before a restart's rotated cookie reached it share that restore instead of spending the token again and clearing the new cookie. Host API requests keep the browser's navigation selection headers, which the host validates. Module API requests instead carry the selection the host last confirmed, read from `/api/navigation` responses and navigation stream events, through `X-Edyn-Navigation-Group-Id`, `X-Edyn-Navigation-Dealer-Ids` and, for a single dealer, `X-Edyn-Navigation-Dealer-Id`; module backends must still authorize those values before constructing module-specific session state. The standalone navigation's portal menus (`/api/navigation/portal/...`) go to the selected host's own portal API (`/portal/api/...`) the same way, so they also load from a deployed host, which relays nothing under `/api/navigation/portal`. Request bodies are forwarded with a fixed length (up to 100 MB), because deployed module front ends reject chunked bodies. Before a module's first API call the BFF asks the host for the current selection, because the local shell starts the module beside the navigation rather than after it. A module's redirect to its legacy `/login` page leads to the development sign-in while signed out; signed in, it shows that the module API refused the session instead of reloading the module in a loop. When nothing answers at `moduleApiOrigin`, module API calls answer 502 `module_api_unreachable` with that origin and the reason, and the terminal says so once until the module server answers again.
|
|
158
160
|
|
|
159
161
|
## Angular base path in any letter case
|
|
160
162
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-root-selectors.d.ts","sourceRoot":"","sources":["../src/document-root-selectors.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,kHAAkH;IAClH,YAAY,EAAE,MAAM,CAAC;IACrB,uHAAuH;IACvH,cAAc,EAAE,MAAM,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"document-root-selectors.d.ts","sourceRoot":"","sources":["../src/document-root-selectors.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,oBAAoB;IACnC,kHAAkH;IAClH,YAAY,EAAE,MAAM,CAAC;IACrB,uHAAuH;IACvH,cAAc,EAAE,MAAM,CAAC;CACxB;AAsHD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,GAAI,cAAc,MAAM,KAAG,oBAgBnE,CAAC","sourcesContent":["// Inside a shadow root no element is the document's <html> or <body>, so a rule aimed at the document root never\n// matches. The build-time PostCSS plugins move such rules onto the module boundary; CSS a library injects at runtime\n// skips that step. Angular Material's `html { --mat-focus-indicator-display: block; }` is one: hosted, the variable never\n// reached Material's components and keyboard focus rings stayed off. This is the runtime counterpart for those rules.\n\nexport interface IDocumentRootRescope {\n /** The selector list with exact document-root compounds moved onto `:host`; unchanged when nothing could move. */\n selectorText: string;\n /** Selectors led by a document root with conditions of its own (`html.dark`, `body#app`, `:root[dir]`), left alone. */\n qualifiedRoots: number;\n}\n\nconst ROOT_COMPOUND_PATTERN = /^(?:html|body|:root)$/i;\nconst ROOT_LED_COMPOUND_PATTERN = /^(?:html|body)(?![\\w-])|^:root(?![\\w-])/i;\n// A cheap first look: a document root at the start of a selector or after a combinator or comma.\nconst ROOT_SELECTOR_HINT_PATTERN = /(?:^|[\\s,>+~])(?:html|body|:root)(?![\\w-])/i;\n// Rules that already name the boundary were scoped at build time or by the host, and stay as they are.\nconst SCOPED_SELECTOR_PATTERN = /data-edyn-mf|:host/i;\nconst COMBINATOR_PATTERN = /^[\\s>+~]$/;\nconst DOCUMENT_ROOT_LED_PATTERN = /^(?:html(?![\\w-])|:root(?![\\w-]))/i;\nconst BODY_LED_PATTERN = /^body(?![\\w-])/i;\n\ninterface IComplexSelector {\n combinators: string[];\n compounds: string[];\n}\n\n// Splits at top level only: commas, combinators and spaces inside (), [] and strings belong to their compound.\nconst splitTopLevel = (text: string, visit: (character: string, depth: number) => boolean): string[] => {\n const parts: string[] = [];\n let current = '';\n let depth = 0;\n let quote: string | undefined;\n for (let index = 0; index < text.length; index += 1) {\n const character = text[index] ?? '';\n if (character === '\\\\') {\n current += character + (text[index + 1] ?? '');\n index += 1;\n continue;\n }\n if (quote) {\n quote = character === quote ? undefined : quote;\n current += character;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '(' || character === '[') {\n depth += 1;\n } else if (character === ')' || character === ']') {\n depth -= 1;\n }\n if (visit(character, depth)) {\n parts.push(current);\n current = character;\n continue;\n }\n current += character;\n }\n parts.push(current);\n return parts;\n};\n\nconst splitSelectorList = (selectorText: string): string[] => {\n return splitTopLevel(selectorText, (character, depth) => depth === 0 && character === ',').map((part) => part.replace(/^,/, '').trim());\n};\n\nconst parseComplexSelector = (selector: string): IComplexSelector | undefined => {\n const tokens = splitTopLevel(selector, (character, depth) => depth === 0 && COMBINATOR_PATTERN.test(character));\n const compounds: string[] = [];\n const combinators: string[] = [];\n let combinator: string | undefined;\n for (const token of tokens) {\n const separator = token[0] ?? '';\n const compound = COMBINATOR_PATTERN.test(separator) ? token.slice(1) : token;\n if (COMBINATOR_PATTERN.test(separator) && separator.trim()) {\n combinator = separator;\n } else if (COMBINATOR_PATTERN.test(separator)) {\n combinator ??= ' ';\n }\n if (!compound) {\n continue;\n }\n if (compounds.length > 0) {\n combinators.push(combinator ?? ' ');\n } else if (combinator?.trim()) {\n // A relative selector (`> .x` in nested CSS) has no document root to move.\n return undefined;\n }\n compounds.push(compound);\n combinator = undefined;\n }\n return compounds.length > 0 ? { combinators, compounds } : undefined;\n};\n\n// The module's own page had one <html> and one <body>, so a selector that needs a second one (`html body html body .x`)\n// never matched there; left as it is, it matches nothing in the shadow root either.\nconst needsSecondDocumentRoot = (compounds: string[]): boolean => {\n return (\n compounds.slice(1).some((compound) => DOCUMENT_ROOT_LED_PATTERN.test(compound)) ||\n compounds.filter((compound) => BODY_LED_PATTERN.test(compound)).length > 1\n );\n};\n\nconst rescopeComplexSelector = (selector: string): { qualified: boolean; selector: string } => {\n const parsed = parseComplexSelector(selector);\n const first = parsed?.compounds[0];\n if (!parsed || !first || !ROOT_LED_COMPOUND_PATTERN.test(first) || needsSecondDocumentRoot(parsed.compounds)) {\n return { qualified: false, selector };\n }\n\n let rootCompounds = 0;\n while (ROOT_COMPOUND_PATTERN.test(parsed.compounds[rootCompounds] ?? '')) {\n rootCompounds += 1;\n }\n const next = parsed.compounds[rootCompounds];\n if (rootCompounds === 0 || (next !== undefined && ROOT_LED_COMPOUND_PATTERN.test(next))) {\n return { qualified: true, selector };\n }\n\n let rescoped = ':host';\n for (let index = rootCompounds; index < parsed.compounds.length; index += 1) {\n const combinator = parsed.combinators[index - 1] ?? ' ';\n rescoped += `${combinator === ' ' ? ' ' : ` ${combinator} `}${parsed.compounds[index]}`;\n }\n return { qualified: false, selector: rescoped };\n};\n\n/**\n * Moves the selectors of a runtime rule that start at the document root onto the shadow host, as the PostCSS plugins\n * do at build time for root-only selectors: `html`, `body`, `:root` and `html body` become `:host`, and `html .x`,\n * `body > .x` or `:root .x` become `:host .x` and `:host > .x`. A root with conditions of its own is left alone and\n * counted, and a list that already names `:host` or the module boundary is returned as it is.\n */\nexport const rescopeDocumentRootSelectors = (selectorText: string): IDocumentRootRescope => {\n if (!ROOT_SELECTOR_HINT_PATTERN.test(selectorText) || SCOPED_SELECTOR_PATTERN.test(selectorText) || selectorText.includes('&')) {\n return { qualifiedRoots: 0, selectorText };\n }\n\n let qualifiedRoots = 0;\n const selectors: string[] = [];\n for (const part of splitSelectorList(selectorText)) {\n const { qualified, selector } = rescopeComplexSelector(part);\n qualifiedRoots += qualified ? 1 : 0;\n if (!selectors.includes(selector)) {\n selectors.push(selector);\n }\n }\n const rescoped = selectors.join(', ');\n return { qualifiedRoots, selectorText: rescoped === splitSelectorList(selectorText).join(', ') ? selectorText : rescoped };\n};\n"]}
|
|
@@ -9,6 +9,8 @@ const ROOT_SELECTOR_HINT_PATTERN = /(?:^|[\s,>+~])(?:html|body|:root)(?![\w-])/i
|
|
|
9
9
|
// Rules that already name the boundary were scoped at build time or by the host, and stay as they are.
|
|
10
10
|
const SCOPED_SELECTOR_PATTERN = /data-edyn-mf|:host/i;
|
|
11
11
|
const COMBINATOR_PATTERN = /^[\s>+~]$/;
|
|
12
|
+
const DOCUMENT_ROOT_LED_PATTERN = /^(?:html(?![\w-])|:root(?![\w-]))/i;
|
|
13
|
+
const BODY_LED_PATTERN = /^body(?![\w-])/i;
|
|
12
14
|
// Splits at top level only: commas, combinators and spaces inside (), [] and strings belong to their compound.
|
|
13
15
|
const splitTopLevel = (text, visit) => {
|
|
14
16
|
const parts = [];
|
|
@@ -78,10 +80,16 @@ const parseComplexSelector = (selector) => {
|
|
|
78
80
|
}
|
|
79
81
|
return compounds.length > 0 ? { combinators, compounds } : undefined;
|
|
80
82
|
};
|
|
83
|
+
// The module's own page had one <html> and one <body>, so a selector that needs a second one (`html body html body .x`)
|
|
84
|
+
// never matched there; left as it is, it matches nothing in the shadow root either.
|
|
85
|
+
const needsSecondDocumentRoot = (compounds) => {
|
|
86
|
+
return (compounds.slice(1).some((compound) => DOCUMENT_ROOT_LED_PATTERN.test(compound)) ||
|
|
87
|
+
compounds.filter((compound) => BODY_LED_PATTERN.test(compound)).length > 1);
|
|
88
|
+
};
|
|
81
89
|
const rescopeComplexSelector = (selector) => {
|
|
82
90
|
const parsed = parseComplexSelector(selector);
|
|
83
91
|
const first = parsed?.compounds[0];
|
|
84
|
-
if (!parsed || !first || !ROOT_LED_COMPOUND_PATTERN.test(first)) {
|
|
92
|
+
if (!parsed || !first || !ROOT_LED_COMPOUND_PATTERN.test(first) || needsSecondDocumentRoot(parsed.compounds)) {
|
|
85
93
|
return { qualified: false, selector };
|
|
86
94
|
}
|
|
87
95
|
let rootCompounds = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document-root-selectors.js","sourceRoot":"","sources":["../src/document-root-selectors.ts"],"names":[],"mappings":"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","sourcesContent":["// Inside a shadow root no element is the document's <html> or <body>, so a rule aimed at the document root never\n// matches. The build-time PostCSS plugins move such rules onto the module boundary; CSS a library injects at runtime\n// skips that step. Angular Material's `html { --mat-focus-indicator-display: block; }` is one: hosted, the variable never\n// reached Material's components and keyboard focus rings stayed off. This is the runtime counterpart for those rules.\n\nexport interface IDocumentRootRescope {\n /** The selector list with exact document-root compounds moved onto `:host`; unchanged when nothing could move. */\n selectorText: string;\n /** Selectors led by a document root with conditions of its own (`html.dark`, `body#app`, `:root[dir]`), left alone. */\n qualifiedRoots: number;\n}\n\nconst ROOT_COMPOUND_PATTERN = /^(?:html|body|:root)$/i;\nconst ROOT_LED_COMPOUND_PATTERN = /^(?:html|body)(?![\\w-])|^:root(?![\\w-])/i;\n// A cheap first look: a document root at the start of a selector or after a combinator or comma.\nconst ROOT_SELECTOR_HINT_PATTERN = /(?:^|[\\s,>+~])(?:html|body|:root)(?![\\w-])/i;\n// Rules that already name the boundary were scoped at build time or by the host, and stay as they are.\nconst SCOPED_SELECTOR_PATTERN = /data-edyn-mf|:host/i;\nconst COMBINATOR_PATTERN = /^[\\s>+~]$/;\n\ninterface IComplexSelector {\n combinators: string[];\n compounds: string[];\n}\n\n// Splits at top level only: commas, combinators and spaces inside (), [] and strings belong to their compound.\nconst splitTopLevel = (text: string, visit: (character: string, depth: number) => boolean): string[] => {\n const parts: string[] = [];\n let current = '';\n let depth = 0;\n let quote: string | undefined;\n for (let index = 0; index < text.length; index += 1) {\n const character = text[index] ?? '';\n if (character === '\\\\') {\n current += character + (text[index + 1] ?? '');\n index += 1;\n continue;\n }\n if (quote) {\n quote = character === quote ? undefined : quote;\n current += character;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '(' || character === '[') {\n depth += 1;\n } else if (character === ')' || character === ']') {\n depth -= 1;\n }\n if (visit(character, depth)) {\n parts.push(current);\n current = character;\n continue;\n }\n current += character;\n }\n parts.push(current);\n return parts;\n};\n\nconst splitSelectorList = (selectorText: string): string[] => {\n return splitTopLevel(selectorText, (character, depth) => depth === 0 && character === ',').map((part) => part.replace(/^,/, '').trim());\n};\n\nconst parseComplexSelector = (selector: string): IComplexSelector | undefined => {\n const tokens = splitTopLevel(selector, (character, depth) => depth === 0 && COMBINATOR_PATTERN.test(character));\n const compounds: string[] = [];\n const combinators: string[] = [];\n let combinator: string | undefined;\n for (const token of tokens) {\n const separator = token[0] ?? '';\n const compound = COMBINATOR_PATTERN.test(separator) ? token.slice(1) : token;\n if (COMBINATOR_PATTERN.test(separator) && separator.trim()) {\n combinator = separator;\n } else if (COMBINATOR_PATTERN.test(separator)) {\n combinator ??= ' ';\n }\n if (!compound) {\n continue;\n }\n if (compounds.length > 0) {\n combinators.push(combinator ?? ' ');\n } else if (combinator?.trim()) {\n // A relative selector (`> .x` in nested CSS) has no document root to move.\n return undefined;\n }\n compounds.push(compound);\n combinator = undefined;\n }\n return compounds.length > 0 ? { combinators, compounds } : undefined;\n};\n\nconst rescopeComplexSelector = (selector: string): { qualified: boolean; selector: string } => {\n const parsed = parseComplexSelector(selector);\n const first = parsed?.compounds[0];\n if (!parsed || !first || !ROOT_LED_COMPOUND_PATTERN.test(first)) {\n return { qualified: false, selector };\n }\n\n let rootCompounds = 0;\n while (ROOT_COMPOUND_PATTERN.test(parsed.compounds[rootCompounds] ?? '')) {\n rootCompounds += 1;\n }\n const next = parsed.compounds[rootCompounds];\n if (rootCompounds === 0 || (next !== undefined && ROOT_LED_COMPOUND_PATTERN.test(next))) {\n return { qualified: true, selector };\n }\n\n let rescoped = ':host';\n for (let index = rootCompounds; index < parsed.compounds.length; index += 1) {\n const combinator = parsed.combinators[index - 1] ?? ' ';\n rescoped += `${combinator === ' ' ? ' ' : ` ${combinator} `}${parsed.compounds[index]}`;\n }\n return { qualified: false, selector: rescoped };\n};\n\n/**\n * Moves the selectors of a runtime rule that start at the document root onto the shadow host, as the PostCSS plugins\n * do at build time for root-only selectors: `html`, `body`, `:root` and `html body` become `:host`, and `html .x`,\n * `body > .x` or `:root .x` become `:host .x` and `:host > .x`. A root with conditions of its own is left alone and\n * counted, and a list that already names `:host` or the module boundary is returned as it is.\n */\nexport const rescopeDocumentRootSelectors = (selectorText: string): IDocumentRootRescope => {\n if (!ROOT_SELECTOR_HINT_PATTERN.test(selectorText) || SCOPED_SELECTOR_PATTERN.test(selectorText) || selectorText.includes('&')) {\n return { qualifiedRoots: 0, selectorText };\n }\n\n let qualifiedRoots = 0;\n const selectors: string[] = [];\n for (const part of splitSelectorList(selectorText)) {\n const { qualified, selector } = rescopeComplexSelector(part);\n qualifiedRoots += qualified ? 1 : 0;\n if (!selectors.includes(selector)) {\n selectors.push(selector);\n }\n }\n const rescoped = selectors.join(', ');\n return { qualifiedRoots, selectorText: rescoped === splitSelectorList(selectorText).join(', ') ? selectorText : rescoped };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"document-root-selectors.js","sourceRoot":"","sources":["../src/document-root-selectors.ts"],"names":[],"mappings":"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","sourcesContent":["// Inside a shadow root no element is the document's <html> or <body>, so a rule aimed at the document root never\n// matches. The build-time PostCSS plugins move such rules onto the module boundary; CSS a library injects at runtime\n// skips that step. Angular Material's `html { --mat-focus-indicator-display: block; }` is one: hosted, the variable never\n// reached Material's components and keyboard focus rings stayed off. This is the runtime counterpart for those rules.\n\nexport interface IDocumentRootRescope {\n /** The selector list with exact document-root compounds moved onto `:host`; unchanged when nothing could move. */\n selectorText: string;\n /** Selectors led by a document root with conditions of its own (`html.dark`, `body#app`, `:root[dir]`), left alone. */\n qualifiedRoots: number;\n}\n\nconst ROOT_COMPOUND_PATTERN = /^(?:html|body|:root)$/i;\nconst ROOT_LED_COMPOUND_PATTERN = /^(?:html|body)(?![\\w-])|^:root(?![\\w-])/i;\n// A cheap first look: a document root at the start of a selector or after a combinator or comma.\nconst ROOT_SELECTOR_HINT_PATTERN = /(?:^|[\\s,>+~])(?:html|body|:root)(?![\\w-])/i;\n// Rules that already name the boundary were scoped at build time or by the host, and stay as they are.\nconst SCOPED_SELECTOR_PATTERN = /data-edyn-mf|:host/i;\nconst COMBINATOR_PATTERN = /^[\\s>+~]$/;\nconst DOCUMENT_ROOT_LED_PATTERN = /^(?:html(?![\\w-])|:root(?![\\w-]))/i;\nconst BODY_LED_PATTERN = /^body(?![\\w-])/i;\n\ninterface IComplexSelector {\n combinators: string[];\n compounds: string[];\n}\n\n// Splits at top level only: commas, combinators and spaces inside (), [] and strings belong to their compound.\nconst splitTopLevel = (text: string, visit: (character: string, depth: number) => boolean): string[] => {\n const parts: string[] = [];\n let current = '';\n let depth = 0;\n let quote: string | undefined;\n for (let index = 0; index < text.length; index += 1) {\n const character = text[index] ?? '';\n if (character === '\\\\') {\n current += character + (text[index + 1] ?? '');\n index += 1;\n continue;\n }\n if (quote) {\n quote = character === quote ? undefined : quote;\n current += character;\n continue;\n }\n if (character === '\"' || character === \"'\") {\n quote = character;\n } else if (character === '(' || character === '[') {\n depth += 1;\n } else if (character === ')' || character === ']') {\n depth -= 1;\n }\n if (visit(character, depth)) {\n parts.push(current);\n current = character;\n continue;\n }\n current += character;\n }\n parts.push(current);\n return parts;\n};\n\nconst splitSelectorList = (selectorText: string): string[] => {\n return splitTopLevel(selectorText, (character, depth) => depth === 0 && character === ',').map((part) => part.replace(/^,/, '').trim());\n};\n\nconst parseComplexSelector = (selector: string): IComplexSelector | undefined => {\n const tokens = splitTopLevel(selector, (character, depth) => depth === 0 && COMBINATOR_PATTERN.test(character));\n const compounds: string[] = [];\n const combinators: string[] = [];\n let combinator: string | undefined;\n for (const token of tokens) {\n const separator = token[0] ?? '';\n const compound = COMBINATOR_PATTERN.test(separator) ? token.slice(1) : token;\n if (COMBINATOR_PATTERN.test(separator) && separator.trim()) {\n combinator = separator;\n } else if (COMBINATOR_PATTERN.test(separator)) {\n combinator ??= ' ';\n }\n if (!compound) {\n continue;\n }\n if (compounds.length > 0) {\n combinators.push(combinator ?? ' ');\n } else if (combinator?.trim()) {\n // A relative selector (`> .x` in nested CSS) has no document root to move.\n return undefined;\n }\n compounds.push(compound);\n combinator = undefined;\n }\n return compounds.length > 0 ? { combinators, compounds } : undefined;\n};\n\n// The module's own page had one <html> and one <body>, so a selector that needs a second one (`html body html body .x`)\n// never matched there; left as it is, it matches nothing in the shadow root either.\nconst needsSecondDocumentRoot = (compounds: string[]): boolean => {\n return (\n compounds.slice(1).some((compound) => DOCUMENT_ROOT_LED_PATTERN.test(compound)) ||\n compounds.filter((compound) => BODY_LED_PATTERN.test(compound)).length > 1\n );\n};\n\nconst rescopeComplexSelector = (selector: string): { qualified: boolean; selector: string } => {\n const parsed = parseComplexSelector(selector);\n const first = parsed?.compounds[0];\n if (!parsed || !first || !ROOT_LED_COMPOUND_PATTERN.test(first) || needsSecondDocumentRoot(parsed.compounds)) {\n return { qualified: false, selector };\n }\n\n let rootCompounds = 0;\n while (ROOT_COMPOUND_PATTERN.test(parsed.compounds[rootCompounds] ?? '')) {\n rootCompounds += 1;\n }\n const next = parsed.compounds[rootCompounds];\n if (rootCompounds === 0 || (next !== undefined && ROOT_LED_COMPOUND_PATTERN.test(next))) {\n return { qualified: true, selector };\n }\n\n let rescoped = ':host';\n for (let index = rootCompounds; index < parsed.compounds.length; index += 1) {\n const combinator = parsed.combinators[index - 1] ?? ' ';\n rescoped += `${combinator === ' ' ? ' ' : ` ${combinator} `}${parsed.compounds[index]}`;\n }\n return { qualified: false, selector: rescoped };\n};\n\n/**\n * Moves the selectors of a runtime rule that start at the document root onto the shadow host, as the PostCSS plugins\n * do at build time for root-only selectors: `html`, `body`, `:root` and `html body` become `:host`, and `html .x`,\n * `body > .x` or `:root .x` become `:host .x` and `:host > .x`. A root with conditions of its own is left alone and\n * counted, and a list that already names `:host` or the module boundary is returned as it is.\n */\nexport const rescopeDocumentRootSelectors = (selectorText: string): IDocumentRootRescope => {\n if (!ROOT_SELECTOR_HINT_PATTERN.test(selectorText) || SCOPED_SELECTOR_PATTERN.test(selectorText) || selectorText.includes('&')) {\n return { qualifiedRoots: 0, selectorText };\n }\n\n let qualifiedRoots = 0;\n const selectors: string[] = [];\n for (const part of splitSelectorList(selectorText)) {\n const { qualified, selector } = rescopeComplexSelector(part);\n qualifiedRoots += qualified ? 1 : 0;\n if (!selectors.includes(selector)) {\n selectors.push(selector);\n }\n }\n const rescoped = selectors.join(', ');\n return { qualifiedRoots, selectorText: rescoped === splitSelectorList(selectorText).join(', ') ? selectorText : rescoped };\n};\n"]}
|
package/dist/postcss.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postcss.d.ts","sourceRoot":"","sources":["../src/postcss.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,MAAM,EAAc,MAAM,SAAS,CAAC;AAM/D,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AA2OD,eAAO,MAAM,gCAAgC,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,OAEhF,CAAC;AA0TF,eAAO,MAAM,cAAc,GAAI,aAAa,sBAAsB,KAAG,MAWpE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,aAAa,sBAAsB,KAAG,MAgB3E,CAAC","sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport type { Declaration, Plugin, Root, Rule } from 'postcss';\nimport selectorParser from 'postcss-selector-parser';\nimport valueParser from 'postcss-value-parser';\nimport { getMfScopeSelector, MF_ROOT_SELECTOR, MF_SCOPE_ATTRIBUTE, validateMfScopeId } from './index.js';\nimport { MF_ROOT_FONT_SIZE_PROPERTY } from './root-font-size.js';\n\nexport interface IScopeRemoteCssOptions {\n scopeId: string;\n}\n\nconst ANGULAR_COMPONENT_STYLE_PATTERN = /\\.component\\.(?:css|less|sass|scss)$/i;\nconst VIEW_ENCAPSULATION_NONE_PATTERN = /(?:^|[,{])\\s*encapsulation\\s*:\\s*(?:[A-Za-z_$][\\w$]*\\s*\\.\\s*)+None\\b/m;\nconst MF_OVERLAY_ATTRIBUTE = 'data-edyn-mf-overlay';\n\ntype TTypeScriptMaskState = 'block-comment' | 'code' | 'double-quote' | 'line-comment' | 'single-quote' | 'template';\n\nconst maskTypeScriptCommentsAndStrings = (source: string): string => {\n let maskedSource = '';\n let state: TTypeScriptMaskState = 'code';\n let escaped = false;\n\n const maskCharacter = (character: string): string => {\n return character === '\\n' || character === '\\r' ? character : ' ';\n };\n\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index] ?? '';\n const nextCharacter = source[index + 1];\n\n if (state === 'code') {\n if (character === '/' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'line-comment';\n } else if (character === '/' && nextCharacter === '*') {\n maskedSource += ' ';\n index += 1;\n state = 'block-comment';\n } else if (character === \"'\") {\n maskedSource += ' ';\n state = 'single-quote';\n } else if (character === '\"') {\n maskedSource += ' ';\n state = 'double-quote';\n } else if (character === '`') {\n maskedSource += ' ';\n state = 'template';\n } else {\n maskedSource += character;\n }\n continue;\n }\n\n if (state === 'line-comment') {\n maskedSource += maskCharacter(character);\n if (character === '\\n' || character === '\\r') {\n state = 'code';\n }\n continue;\n }\n\n if (state === 'block-comment') {\n if (character === '*' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'code';\n } else {\n maskedSource += maskCharacter(character);\n }\n continue;\n }\n\n maskedSource += maskCharacter(character);\n if (escaped) {\n escaped = false;\n } else if (character === '\\\\') {\n escaped = true;\n } else if (\n (state === 'single-quote' && character === \"'\") ||\n (state === 'double-quote' && character === '\"') ||\n (state === 'template' && character === '`')\n ) {\n state = 'code';\n }\n }\n\n return maskedSource;\n};\n\nconst isKeyframesRule = (rule: Rule): boolean => {\n const parent = rule.parent;\n return parent?.type === 'atrule' && /keyframes$/i.test(parent.name);\n};\n\nconst isRootNode = (node: selectorParser.Node): boolean => {\n return (\n (node.type === 'tag' && (node.value.toLowerCase() === 'html' || node.value.toLowerCase() === 'body')) ||\n (node.type === 'pseudo' && (node.value === ':root' || node.value === MF_ROOT_SELECTOR))\n );\n};\n\nconst isScopeNode = (node: selectorParser.Node | undefined, scopeId: string): boolean => {\n if (node?.type === 'attribute' && node.attribute === MF_SCOPE_ATTRIBUTE && node.operator === '=' && node.value === scopeId) {\n return true;\n }\n\n const normalized = node?.toString().replaceAll('\"', '').replaceAll(\"'\", '');\n return (\n node?.type === 'pseudo' &&\n (normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}])` ||\n normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}]:not([${MF_OVERLAY_ATTRIBUTE}]))`)\n );\n};\n\nconst startsWithHostPseudo = (selector: selectorParser.Selector): boolean => {\n return selector.first?.type === 'pseudo' && selector.first.value === ':host';\n};\n\nconst removeRootIdentityIds = (selector: selectorParser.Selector): void => {\n let compound: selectorParser.Node[] = [];\n const removeIdsFromRootCompound = (): void => {\n if (compound.some(isRootNode)) {\n for (const node of compound) {\n if (node.type === 'id') {\n node.remove();\n }\n }\n }\n };\n\n for (const node of [...selector.nodes]) {\n if (node.type === 'combinator') {\n removeIdsFromRootCompound();\n compound = [];\n } else {\n compound.push(node);\n }\n }\n removeIdsFromRootCompound();\n};\n\nconst SPECIFICITY_CARRIER = 'edyn-mf-root';\n\n// Legacy rules such as `html body button` or `html body#app .mdc-checkbox__background` are weighed against Angular\n// Material's own rules by the html, body and #app they start from, so the scope that replaces that root must weigh\n// exactly the same. A plain scope attribute (0,1,0) drops the id of `body#app`, letting Material's checked colour win,\n// and outweighs the two types of `html body`, letting an override that lost to `.mat-mdc-button` on the old site win\n// hosted. The root becomes :where(<scope>):not(<carrier>): :where() weighs nothing, and the carrier has the same id,\n// class and type counts as the root part it replaces and never matches the scope element, so :not() always matches and\n// weighs exactly that. Neutral names keep `html`, `body` and `#app` out of the emitted CSS.\nconst rootSpecificityCarrier = (selector: selectorParser.Selector): string => {\n const compounds: selectorParser.Node[][] = [[]];\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const carrier: string[] = [];\n for (const compound of compounds) {\n if (!compound.some(isRootNode)) {\n continue;\n }\n const types = compound.filter((node) => node.type === 'tag' && isRootNode(node)).length;\n const pseudoRoots = compound.filter((node) => node.type === 'pseudo' && isRootNode(node)).length;\n const ids = compound.filter((node) => node.type === 'id').length;\n carrier.push(\n `${SPECIFICITY_CARRIER.repeat(Math.min(types, 1))}${`.${SPECIFICITY_CARRIER}`.repeat(pseudoRoots)}${`#${SPECIFICITY_CARRIER}`.repeat(ids)}`,\n );\n }\n\n return carrier.filter(Boolean).join(' ');\n};\n\nconst rootedDescendantScope = (selector: selectorParser.Selector, scopeId: string): string => {\n return `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]):not(${rootSpecificityCarrier(selector)})`;\n};\n\nconst isRootOnlySelector = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n return compounds.every((compound) => compound.some(isRootNode));\n};\n\nconst hasRootOnlySelector = (selectorList: string): boolean => {\n let result = false;\n selectorParser((root) => {\n result = root.nodes.some(isRootOnlySelector);\n }).processSync(selectorList);\n return result;\n};\n\nconst escapeRegExp = (text: string): string => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n// A component stylesheet need not be named *.component.scss (CampaignManagement's create-campaign.ts uses\n// `styleUrl: './create-campaign.scss'`); treated as global CSS, Angular would then encapsulate the boundary itself and\n// the rules could never match. Such a file is a component's when a sibling component source references it.\nconst referencingComponentSourceOf = (stylePath: string): string | undefined => {\n const directory = dirname(stylePath);\n if (!existsSync(directory)) {\n return undefined;\n }\n const reference = new RegExp(`styleUrls?\\\\s*:\\\\s*(?:\\\\[[^\\\\]]*?)?['\"\\`]\\\\./${escapeRegExp(basename(stylePath))}['\"\\`]`);\n for (const fileName of readdirSync(directory)) {\n if (!fileName.endsWith('.ts') || /\\.(?:spec|test|d)\\.ts$/.test(fileName)) {\n continue;\n }\n const sourcePath = join(directory, fileName);\n if (reference.test(readFileSync(sourcePath, 'utf8'))) {\n return sourcePath;\n }\n }\n return undefined;\n};\n\nconst getAngularComponentSourcePath = (stylePath: string): string | undefined => {\n const cleanStylePath = stylePath.replace(/[?#].*$/, '');\n if (ANGULAR_COMPONENT_STYLE_PATTERN.test(cleanStylePath)) {\n return cleanStylePath.replace(/\\.(?:css|less|sass|scss)$/i, '.ts');\n }\n return /\\.(?:css|less|sass|scss)$/i.test(cleanStylePath) ? referencingComponentSourceOf(cleanStylePath) : undefined;\n};\n\nconst usesViewEncapsulationNone = (stylePath: string): boolean => {\n const componentSourcePath = getAngularComponentSourcePath(stylePath);\n if (!componentSourcePath || !existsSync(componentSourcePath)) {\n return false;\n }\n\n const componentSource = readFileSync(componentSourcePath, 'utf8');\n return VIEW_ENCAPSULATION_NONE_PATTERN.test(maskTypeScriptCommentsAndStrings(componentSource));\n};\n\nexport const shouldUseAngularComponentScoping = (stylePath: string | undefined): boolean => {\n return !!stylePath && !!getAngularComponentSourcePath(stylePath) && !usesViewEncapsulationNone(stylePath);\n};\n\nconst scopeSelectorList = (selectorList: string, scopeId: string, scopeSelector: string, rootScopeSelectors: string[]): string => {\n return selectorParser((root) => {\n const sourceSelectors = [...root.nodes];\n\n for (const selector of sourceSelectors) {\n const rootNodes = selector.nodes.filter(isRootNode);\n\n if (rootNodes.length > 0) {\n const replacementSelectors = isRootOnlySelector(selector) ? rootScopeSelectors : [rootedDescendantScope(selector, scopeId)];\n\n for (const replacementSelector of replacementSelectors) {\n const variant = selector.clone();\n removeRootIdentityIds(variant);\n const [firstRoot, ...duplicateRoots] = variant.nodes.filter(isRootNode);\n // The replacement can be a compound of several nodes, e.g. :where(<scope>):not(<carrier>).\n const scopeNodes = selectorParser()\n .astSync(replacementSelector)\n .first.nodes.map((node) => node.clone());\n const [scopeNode, ...followingScopeNodes] = scopeNodes;\n if (firstRoot && scopeNode) {\n firstRoot.replaceWith(scopeNode);\n let previous = scopeNode;\n for (const node of followingScopeNodes) {\n variant.insertAfter(previous, node);\n previous = node;\n }\n }\n\n for (const duplicateRoot of duplicateRoots) {\n const previous = duplicateRoot.prev();\n if (previous?.type === 'combinator') {\n previous.remove();\n }\n duplicateRoot.remove();\n }\n\n root.insertBefore(selector, variant);\n }\n selector.remove();\n continue;\n }\n\n if (startsWithHostPseudo(selector) || isScopeNode(selector.first, scopeId)) {\n continue;\n }\n\n const first = selector.first;\n const needsBoundaryVariant = first?.type === 'universal' || (first?.type === 'pseudo' && first.value.startsWith('::'));\n\n if (needsBoundaryVariant) {\n const hasSiblingCombinator = selector.nodes.some((node) => node.type === 'combinator' && (node.value === '+' || node.value === '~'));\n\n if (!hasSiblingCombinator) {\n const boundaryVariant = selector.clone();\n const boundaryScope = selectorParser().astSync(scopeSelector).first.first.clone();\n boundaryVariant.first.rawSpaceBefore = '';\n if (boundaryVariant.first.type === 'universal') {\n boundaryVariant.first.replaceWith(boundaryScope);\n } else {\n boundaryVariant.prepend(boundaryScope);\n }\n root.insertBefore(selector, boundaryVariant);\n }\n }\n\n const descendantScope = selectorParser().astSync(`${scopeSelector} *`).first;\n const prefixNodes = descendantScope.nodes.slice(0, -1).map((node) => node.clone());\n selector.first.rawSpaceBefore = '';\n for (const prefixNode of prefixNodes.reverse()) {\n selector.prepend(prefixNode);\n }\n }\n\n const seenSelectors = new Set<string>();\n for (const selector of [...root.nodes]) {\n const normalizedSelector = selector.toString().trim();\n if (seenSelectors.has(normalizedSelector)) {\n selector.remove();\n } else {\n seenSelectors.add(normalizedSelector);\n }\n }\n }).processSync(selectorList);\n};\n\nconst namespaceKeyframes = (root: Root, keyframePrefix: string): void => {\n const keyframes = new Map<string, string>();\n\n root.walkAtRules((atRule) => {\n if (!/keyframes$/i.test(atRule.name) || atRule.params.startsWith(keyframePrefix)) {\n return;\n }\n\n const originalName = atRule.params.trim();\n const scopedName = `${keyframePrefix}${originalName}`;\n keyframes.set(originalName, scopedName);\n atRule.params = scopedName;\n });\n\n root.walkDecls((declaration) => {\n if (!/^(?:-webkit-)?animation(?:-name)?$/i.test(declaration.prop) && !declaration.prop.startsWith('--animate-')) {\n return;\n }\n\n const parsed = valueParser(declaration.value);\n parsed.walk((node) => {\n if (node.type === 'word') {\n node.value = keyframes.get(node.value) ?? node.value;\n }\n });\n declaration.value = parsed.toString();\n });\n};\n\nconst INITIAL_FONT_SIZE_PX = 16;\n// Absolute-size keywords as browsers compute them, and the relative ones as they resolve on the root, whose parent size\n// is the initial 16px.\nconst FONT_SIZE_KEYWORDS_PX: Readonly<Record<string, number>> = {\n 'xx-small': 9,\n 'x-small': 10,\n small: 13,\n medium: 16,\n large: 18,\n 'x-large': 24,\n 'xx-large': 32,\n 'xxx-large': 48,\n smaller: INITIAL_FONT_SIZE_PX / 1.2,\n larger: INITIAL_FONT_SIZE_PX * 1.2,\n};\n// On the root, every global keyword gives the initial size.\nconst GLOBAL_KEYWORDS = new Set(['inherit', 'initial', 'revert', 'revert-layer', 'unset']);\n// em, rem and % on the root are relative to the initial size.\nconst FONT_SIZE_UNITS_PX: Readonly<Record<string, number>> = {\n '%': INITIAL_FONT_SIZE_PX / 100,\n cm: 96 / 2.54,\n em: INITIAL_FONT_SIZE_PX,\n in: 96,\n mm: 96 / 25.4,\n pc: 16,\n pt: 96 / 72,\n px: 1,\n q: 96 / 101.6,\n rem: INITIAL_FONT_SIZE_PX,\n};\n\nconst fontSizeOfWord = (word: string): number | undefined => {\n const keyword = FONT_SIZE_KEYWORDS_PX[word.toLowerCase()];\n if (keyword !== undefined) {\n return keyword;\n }\n const dimension = valueParser.unit(word);\n const unitPx = dimension ? FONT_SIZE_UNITS_PX[dimension.unit.toLowerCase()] : undefined;\n const amount = Number(dimension ? dimension.number : Number.NaN);\n return unitPx !== undefined && Number.isFinite(amount) && amount >= 0 ? amount * unitPx : undefined;\n};\n\nconst significantValueNodes = (value: string): valueParser.Node[] => {\n return valueParser(value).nodes.filter((node) => node.type !== 'space' && node.type !== 'comment');\n};\n\nconst globalKeywordFontSize = (nodes: valueParser.Node[]): number | undefined => {\n const [only] = nodes;\n return nodes.length === 1 && only?.type === 'word' && GLOBAL_KEYWORDS.has(only.value.toLowerCase()) ? INITIAL_FONT_SIZE_PX : undefined;\n};\n\nconst resolveFontSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const [only] = nodes;\n return globalKeywordFontSize(nodes) ?? (nodes.length === 1 && only?.type === 'word' ? fontSizeOfWord(only.value) : undefined);\n};\n\n// `font: [style] [variant] [weight] [stretch] <size>[/<line-height>] <family>`: the size is the word before `/`, or else\n// the first word that is a size. A function (var(), calc()) or a family name reached first means it cannot be read.\nconst resolveFontShorthandSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const globalSize = globalKeywordFontSize(nodes);\n if (globalSize !== undefined) {\n return globalSize;\n }\n\n const slashIndex = nodes.findIndex((node) => node.type === 'div' && node.value === '/');\n if (slashIndex > 0) {\n const size = nodes[slashIndex - 1];\n return size?.type === 'word' ? fontSizeOfWord(size.value) : undefined;\n }\n\n for (const node of nodes) {\n if (node.type !== 'word') {\n return undefined;\n }\n const size = fontSizeOfWord(node.value);\n if (size !== undefined) {\n return size;\n }\n }\n return undefined;\n};\n\n// `html` and `:root` size the document root, so rem; `body` and `html body` size only the body.\nconst targetsDocumentRoot = (selector: selectorParser.Selector): boolean => {\n let subject: selectorParser.Node[] = [];\n for (const node of selector.nodes) {\n subject = node.type === 'combinator' ? [] : [...subject, node];\n }\n return subject.some((node) => (node.type === 'tag' && node.value.toLowerCase() === 'html') || (node.type === 'pseudo' && node.value === ':root'));\n};\n\nconst documentRootSelectorsOf = (selectorList: string): string[] => {\n const selectors: string[] = [];\n selectorParser((root) => {\n for (const selector of root.nodes) {\n if (targetsDocumentRoot(selector)) {\n selectors.push(selector.toString().trim());\n }\n }\n }).processSync(selectorList);\n return selectors;\n};\n\ntype TWarn = (node: Declaration, text: string) => void;\n\n// Hosted, rem resolves against the host page's root, not the root size the module's own page set. Each rule that sizes\n// the document root gets a sibling rule right after it that records that size as MF_ROOT_FONT_SIZE_PROPERTY, under the\n// same conditions (@media, importance) and in the same cascade order; scoping then moves it onto the module boundary,\n// where followModuleRootFontSize() makes rem lengths read it. CSS that never sizes the root is left byte-identical.\nconst recordRootFontSize = (root: Root, warn: TWarn): void => {\n root.walkRules((rule) => {\n if (isKeyframesRule(rule)) {\n return;\n }\n\n let sizing: Declaration | undefined;\n for (const node of rule.nodes) {\n if (node.type === 'decl' && /^font(?:-size)?$/i.test(node.prop) && (node.important || !sizing?.important)) {\n sizing = node;\n }\n }\n if (!sizing) {\n return;\n }\n\n const rootSelectors = documentRootSelectorsOf(rule.selector);\n if (rootSelectors.length === 0) {\n return;\n }\n\n const sizePx = sizing.prop.toLowerCase() === 'font' ? resolveFontShorthandSize(sizing.value) : resolveFontSize(sizing.value);\n if (sizePx === undefined) {\n warn(\n sizing,\n `Cannot resolve the document root font size \"${sizing.value}\" at build time; rem lengths in the hosted module will use the host page's root size.`,\n );\n return;\n }\n\n const recorded = rule.clone({ selector: rootSelectors.join(', ') });\n recorded.raws.before = rule.raws.before || '\\n';\n recorded.removeAll();\n // The recorded size points back at the declaration it came from, so source maps keep a source for it.\n recorded.append({\n important: sizing.important,\n prop: MF_ROOT_FONT_SIZE_PROPERTY,\n source: sizing.source,\n value: `${Number(sizePx.toFixed(4))}px`,\n });\n rule.after(recorded);\n });\n};\n\nconst scopeGlobalRoot = (root: Root, scopeId: string, scopeSelector: string, keyframePrefix: string, warn: TWarn): void => {\n recordRootFontSize(root, warn);\n namespaceKeyframes(root, keyframePrefix);\n const contentRootSelector = `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]:not([${MF_OVERLAY_ATTRIBUTE}]))`;\n root.walkRules((rule) => {\n if (!isKeyframesRule(rule)) {\n const declarations = rule.nodes.filter((node) => node.type === 'decl');\n const customProperties = declarations.filter((declaration) => declaration.prop.startsWith('--'));\n const standardDeclarations = declarations.filter((declaration) => !declaration.prop.startsWith('--'));\n\n if (customProperties.length > 0 && standardDeclarations.length > 0 && hasRootOnlySelector(rule.selector)) {\n const customPropertyRule = rule.cloneBefore();\n customPropertyRule.walkDecls((declaration) => {\n if (!declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n customPropertyRule.selector = scopeSelectorList(customPropertyRule.selector, scopeId, scopeSelector, [':host', scopeSelector]);\n rule.walkDecls((declaration) => {\n if (declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n }\n\n const containsOnlyCustomProperties = declarations.length > 0 && declarations.every((declaration) => declaration.prop.startsWith('--'));\n const rootScopeSelectors = containsOnlyCustomProperties ? [':host', scopeSelector] : [':host', contentRootSelector];\n rule.selector = scopeSelectorList(rule.selector, scopeId, scopeSelector, rootScopeSelectors);\n }\n });\n};\n\n// Emulated component CSS keeps its selectors exactly as written, so Angular compiles what it compiled on the module's\n// own page and every rule keeps its weight and reach: `mat-form-field[_ngcontent-x]` (0,1,1) still loses to a global\n// `.mat-sidenav-content .mat-mdc-form-field` (0,2,0), template content rendered in an overlay (outside the component's\n// host) keeps its component styles, and a top-level `::ng-deep` rule stays global to the module. Wrapping every rule in\n// :host-context(<boundary>) added (0,2,0) to each, and limited all of them to the component's host. Isolation needs no\n// boundary here: Angular's _ngcontent and _nghost attributes are unique to each component, and a hosted module's\n// component styles live in its own shadow root.\nconst scopeAngularComponentRoot = (root: Root, keyframePrefix: string): void => {\n namespaceKeyframes(root, keyframePrefix);\n};\n\nexport const scopeRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-isolation-${validScopeId}`,\n Once(root, { result }) {\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n\nexport const scopeAngularRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-angular-isolation-${validScopeId}`,\n Once(root, { result }) {\n if (shouldUseAngularComponentScoping(root.source?.input.file)) {\n scopeAngularComponentRoot(root, keyframePrefix);\n return;\n }\n\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"postcss.d.ts","sourceRoot":"","sources":["../src/postcss.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,MAAM,EAAc,MAAM,SAAS,CAAC;AAM/D,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAqQD,eAAO,MAAM,gCAAgC,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,OAEhF,CAAC;AAsUF,eAAO,MAAM,cAAc,GAAI,aAAa,sBAAsB,KAAG,MAWpE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,aAAa,sBAAsB,KAAG,MAgB3E,CAAC","sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport type { Declaration, Plugin, Root, Rule } from 'postcss';\nimport selectorParser from 'postcss-selector-parser';\nimport valueParser from 'postcss-value-parser';\nimport { getMfScopeSelector, MF_ROOT_SELECTOR, MF_SCOPE_ATTRIBUTE, validateMfScopeId } from './index.js';\nimport { MF_ROOT_FONT_SIZE_PROPERTY } from './root-font-size.js';\n\nexport interface IScopeRemoteCssOptions {\n scopeId: string;\n}\n\nconst ANGULAR_COMPONENT_STYLE_PATTERN = /\\.component\\.(?:css|less|sass|scss)$/i;\nconst VIEW_ENCAPSULATION_NONE_PATTERN = /(?:^|[,{])\\s*encapsulation\\s*:\\s*(?:[A-Za-z_$][\\w$]*\\s*\\.\\s*)+None\\b/m;\nconst MF_OVERLAY_ATTRIBUTE = 'data-edyn-mf-overlay';\n\ntype TTypeScriptMaskState = 'block-comment' | 'code' | 'double-quote' | 'line-comment' | 'single-quote' | 'template';\n\nconst maskTypeScriptCommentsAndStrings = (source: string): string => {\n let maskedSource = '';\n let state: TTypeScriptMaskState = 'code';\n let escaped = false;\n\n const maskCharacter = (character: string): string => {\n return character === '\\n' || character === '\\r' ? character : ' ';\n };\n\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index] ?? '';\n const nextCharacter = source[index + 1];\n\n if (state === 'code') {\n if (character === '/' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'line-comment';\n } else if (character === '/' && nextCharacter === '*') {\n maskedSource += ' ';\n index += 1;\n state = 'block-comment';\n } else if (character === \"'\") {\n maskedSource += ' ';\n state = 'single-quote';\n } else if (character === '\"') {\n maskedSource += ' ';\n state = 'double-quote';\n } else if (character === '`') {\n maskedSource += ' ';\n state = 'template';\n } else {\n maskedSource += character;\n }\n continue;\n }\n\n if (state === 'line-comment') {\n maskedSource += maskCharacter(character);\n if (character === '\\n' || character === '\\r') {\n state = 'code';\n }\n continue;\n }\n\n if (state === 'block-comment') {\n if (character === '*' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'code';\n } else {\n maskedSource += maskCharacter(character);\n }\n continue;\n }\n\n maskedSource += maskCharacter(character);\n if (escaped) {\n escaped = false;\n } else if (character === '\\\\') {\n escaped = true;\n } else if (\n (state === 'single-quote' && character === \"'\") ||\n (state === 'double-quote' && character === '\"') ||\n (state === 'template' && character === '`')\n ) {\n state = 'code';\n }\n }\n\n return maskedSource;\n};\n\nconst isKeyframesRule = (rule: Rule): boolean => {\n const parent = rule.parent;\n return parent?.type === 'atrule' && /keyframes$/i.test(parent.name);\n};\n\nconst isRootNode = (node: selectorParser.Node): boolean => {\n return (\n (node.type === 'tag' && (node.value.toLowerCase() === 'html' || node.value.toLowerCase() === 'body')) ||\n (node.type === 'pseudo' && (node.value === ':root' || node.value === MF_ROOT_SELECTOR))\n );\n};\n\nconst isScopeNode = (node: selectorParser.Node | undefined, scopeId: string): boolean => {\n if (node?.type === 'attribute' && node.attribute === MF_SCOPE_ATTRIBUTE && node.operator === '=' && node.value === scopeId) {\n return true;\n }\n\n const normalized = node?.toString().replaceAll('\"', '').replaceAll(\"'\", '');\n return (\n node?.type === 'pseudo' &&\n (normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}])` ||\n normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}]:not([${MF_OVERLAY_ATTRIBUTE}]))`)\n );\n};\n\nconst startsWithHostPseudo = (selector: selectorParser.Selector): boolean => {\n return selector.first?.type === 'pseudo' && selector.first.value === ':host';\n};\n\nconst removeRootIdentityIds = (selector: selectorParser.Selector): void => {\n let compound: selectorParser.Node[] = [];\n const removeIdsFromRootCompound = (): void => {\n if (compound.some(isRootNode)) {\n for (const node of compound) {\n if (node.type === 'id') {\n node.remove();\n }\n }\n }\n };\n\n for (const node of [...selector.nodes]) {\n if (node.type === 'combinator') {\n removeIdsFromRootCompound();\n compound = [];\n } else {\n compound.push(node);\n }\n }\n removeIdsFromRootCompound();\n};\n\nconst SPECIFICITY_CARRIER = 'edyn-mf-root';\n\n// Legacy rules such as `html body button` or `html body#app .mdc-checkbox__background` are weighed against Angular\n// Material's own rules by the html, body and #app they start from, so the scope that replaces that root must weigh\n// exactly the same. A plain scope attribute (0,1,0) drops the id of `body#app`, letting Material's checked colour win,\n// and outweighs the two types of `html body`, letting an override that lost to `.mat-mdc-button` on the old site win\n// hosted. The root becomes :where(<scope>):not(<carrier>): :where() weighs nothing, and the carrier has the same id,\n// class and type counts as the root part it replaces and never matches the scope element, so :not() always matches and\n// weighs exactly that. Neutral names keep `html`, `body` and `#app` out of the emitted CSS.\nconst rootSpecificityCarrier = (selector: selectorParser.Selector): string => {\n const compounds: selectorParser.Node[][] = [[]];\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const carrier: string[] = [];\n for (const compound of compounds) {\n if (!compound.some(isRootNode)) {\n continue;\n }\n const types = compound.filter((node) => node.type === 'tag' && isRootNode(node)).length;\n const pseudoRoots = compound.filter((node) => node.type === 'pseudo' && isRootNode(node)).length;\n const ids = compound.filter((node) => node.type === 'id').length;\n carrier.push(\n `${SPECIFICITY_CARRIER.repeat(Math.min(types, 1))}${`.${SPECIFICITY_CARRIER}`.repeat(pseudoRoots)}${`#${SPECIFICITY_CARRIER}`.repeat(ids)}`,\n );\n }\n\n return carrier.filter(Boolean).join(' ');\n};\n\nconst rootedDescendantScope = (selector: selectorParser.Selector, scopeId: string): string => {\n return `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]):not(${rootSpecificityCarrier(selector)})`;\n};\n\nconst isRootOnlySelector = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n return compounds.every((compound) => compound.some(isRootNode));\n};\n\nconst isTagNamed = (node: selectorParser.Node, name: string): boolean => {\n return node.type === 'tag' && node.value.toLowerCase() === name;\n};\n\n// The module's own page had one <html> and one <body>, so a selector that needs a second one never matched there:\n// `html body html body .x`, which a global partial compiles to when it is loaded inside `html body {}`, or `.x html`.\n// Scoping replaces the first root with the module boundary and drops the others, which made such a rule match hosted\n// (AutoCleanse's datepicker cells turned blue), so the selector is dropped instead.\nconst needsSecondDocumentRoot = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const documentRootAfterFirst = compounds\n .slice(1)\n .some((compound) => compound.some((node) => isTagNamed(node, 'html') || (node.type === 'pseudo' && node.value === ':root')));\n const bodyCompounds = compounds.filter((compound) => compound.some((node) => isTagNamed(node, 'body'))).length;\n return documentRootAfterFirst || bodyCompounds > 1;\n};\n\nconst hasRootOnlySelector = (selectorList: string): boolean => {\n let result = false;\n selectorParser((root) => {\n result = root.nodes.some(isRootOnlySelector);\n }).processSync(selectorList);\n return result;\n};\n\nconst escapeRegExp = (text: string): string => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n// A component stylesheet need not be named *.component.scss (CampaignManagement's create-campaign.ts uses\n// `styleUrl: './create-campaign.scss'`); treated as global CSS, Angular would then encapsulate the boundary itself and\n// the rules could never match. Such a file is a component's when a sibling component source references it.\nconst referencingComponentSourceOf = (stylePath: string): string | undefined => {\n const directory = dirname(stylePath);\n if (!existsSync(directory)) {\n return undefined;\n }\n const reference = new RegExp(`styleUrls?\\\\s*:\\\\s*(?:\\\\[[^\\\\]]*?)?['\"\\`]\\\\./${escapeRegExp(basename(stylePath))}['\"\\`]`);\n for (const fileName of readdirSync(directory)) {\n if (!fileName.endsWith('.ts') || /\\.(?:spec|test|d)\\.ts$/.test(fileName)) {\n continue;\n }\n const sourcePath = join(directory, fileName);\n if (reference.test(readFileSync(sourcePath, 'utf8'))) {\n return sourcePath;\n }\n }\n return undefined;\n};\n\nconst getAngularComponentSourcePath = (stylePath: string): string | undefined => {\n const cleanStylePath = stylePath.replace(/[?#].*$/, '');\n if (ANGULAR_COMPONENT_STYLE_PATTERN.test(cleanStylePath)) {\n return cleanStylePath.replace(/\\.(?:css|less|sass|scss)$/i, '.ts');\n }\n return /\\.(?:css|less|sass|scss)$/i.test(cleanStylePath) ? referencingComponentSourceOf(cleanStylePath) : undefined;\n};\n\nconst usesViewEncapsulationNone = (stylePath: string): boolean => {\n const componentSourcePath = getAngularComponentSourcePath(stylePath);\n if (!componentSourcePath || !existsSync(componentSourcePath)) {\n return false;\n }\n\n const componentSource = readFileSync(componentSourcePath, 'utf8');\n return VIEW_ENCAPSULATION_NONE_PATTERN.test(maskTypeScriptCommentsAndStrings(componentSource));\n};\n\nexport const shouldUseAngularComponentScoping = (stylePath: string | undefined): boolean => {\n return !!stylePath && !!getAngularComponentSourcePath(stylePath) && !usesViewEncapsulationNone(stylePath);\n};\n\nconst scopeSelectorList = (selectorList: string, scopeId: string, scopeSelector: string, rootScopeSelectors: string[]): string => {\n return selectorParser((root) => {\n const sourceSelectors = [...root.nodes];\n\n for (const selector of sourceSelectors) {\n if (needsSecondDocumentRoot(selector)) {\n selector.remove();\n continue;\n }\n\n const rootNodes = selector.nodes.filter(isRootNode);\n\n if (rootNodes.length > 0) {\n const replacementSelectors = isRootOnlySelector(selector) ? rootScopeSelectors : [rootedDescendantScope(selector, scopeId)];\n\n for (const replacementSelector of replacementSelectors) {\n const variant = selector.clone();\n removeRootIdentityIds(variant);\n const [firstRoot, ...duplicateRoots] = variant.nodes.filter(isRootNode);\n // The replacement can be a compound of several nodes, e.g. :where(<scope>):not(<carrier>).\n const scopeNodes = selectorParser()\n .astSync(replacementSelector)\n .first.nodes.map((node) => node.clone());\n const [scopeNode, ...followingScopeNodes] = scopeNodes;\n if (firstRoot && scopeNode) {\n firstRoot.replaceWith(scopeNode);\n let previous = scopeNode;\n for (const node of followingScopeNodes) {\n variant.insertAfter(previous, node);\n previous = node;\n }\n }\n\n for (const duplicateRoot of duplicateRoots) {\n const previous = duplicateRoot.prev();\n if (previous?.type === 'combinator') {\n previous.remove();\n }\n duplicateRoot.remove();\n }\n\n root.insertBefore(selector, variant);\n }\n selector.remove();\n continue;\n }\n\n if (startsWithHostPseudo(selector) || isScopeNode(selector.first, scopeId)) {\n continue;\n }\n\n const first = selector.first;\n const needsBoundaryVariant = first?.type === 'universal' || (first?.type === 'pseudo' && first.value.startsWith('::'));\n\n if (needsBoundaryVariant) {\n const hasSiblingCombinator = selector.nodes.some((node) => node.type === 'combinator' && (node.value === '+' || node.value === '~'));\n\n if (!hasSiblingCombinator) {\n const boundaryVariant = selector.clone();\n const boundaryScope = selectorParser().astSync(scopeSelector).first.first.clone();\n boundaryVariant.first.rawSpaceBefore = '';\n if (boundaryVariant.first.type === 'universal') {\n boundaryVariant.first.replaceWith(boundaryScope);\n } else {\n boundaryVariant.prepend(boundaryScope);\n }\n root.insertBefore(selector, boundaryVariant);\n }\n }\n\n const descendantScope = selectorParser().astSync(`${scopeSelector} *`).first;\n const prefixNodes = descendantScope.nodes.slice(0, -1).map((node) => node.clone());\n selector.first.rawSpaceBefore = '';\n for (const prefixNode of prefixNodes.reverse()) {\n selector.prepend(prefixNode);\n }\n }\n\n const seenSelectors = new Set<string>();\n for (const selector of [...root.nodes]) {\n const normalizedSelector = selector.toString().trim();\n if (seenSelectors.has(normalizedSelector)) {\n selector.remove();\n } else {\n seenSelectors.add(normalizedSelector);\n }\n }\n }).processSync(selectorList);\n};\n\nconst namespaceKeyframes = (root: Root, keyframePrefix: string): void => {\n const keyframes = new Map<string, string>();\n\n root.walkAtRules((atRule) => {\n if (!/keyframes$/i.test(atRule.name) || atRule.params.startsWith(keyframePrefix)) {\n return;\n }\n\n const originalName = atRule.params.trim();\n const scopedName = `${keyframePrefix}${originalName}`;\n keyframes.set(originalName, scopedName);\n atRule.params = scopedName;\n });\n\n root.walkDecls((declaration) => {\n if (!/^(?:-webkit-)?animation(?:-name)?$/i.test(declaration.prop) && !declaration.prop.startsWith('--animate-')) {\n return;\n }\n\n const parsed = valueParser(declaration.value);\n parsed.walk((node) => {\n if (node.type === 'word') {\n node.value = keyframes.get(node.value) ?? node.value;\n }\n });\n declaration.value = parsed.toString();\n });\n};\n\nconst INITIAL_FONT_SIZE_PX = 16;\n// Absolute-size keywords as browsers compute them, and the relative ones as they resolve on the root, whose parent size\n// is the initial 16px.\nconst FONT_SIZE_KEYWORDS_PX: Readonly<Record<string, number>> = {\n 'xx-small': 9,\n 'x-small': 10,\n small: 13,\n medium: 16,\n large: 18,\n 'x-large': 24,\n 'xx-large': 32,\n 'xxx-large': 48,\n smaller: INITIAL_FONT_SIZE_PX / 1.2,\n larger: INITIAL_FONT_SIZE_PX * 1.2,\n};\n// On the root, every global keyword gives the initial size.\nconst GLOBAL_KEYWORDS = new Set(['inherit', 'initial', 'revert', 'revert-layer', 'unset']);\n// em, rem and % on the root are relative to the initial size.\nconst FONT_SIZE_UNITS_PX: Readonly<Record<string, number>> = {\n '%': INITIAL_FONT_SIZE_PX / 100,\n cm: 96 / 2.54,\n em: INITIAL_FONT_SIZE_PX,\n in: 96,\n mm: 96 / 25.4,\n pc: 16,\n pt: 96 / 72,\n px: 1,\n q: 96 / 101.6,\n rem: INITIAL_FONT_SIZE_PX,\n};\n\nconst fontSizeOfWord = (word: string): number | undefined => {\n const keyword = FONT_SIZE_KEYWORDS_PX[word.toLowerCase()];\n if (keyword !== undefined) {\n return keyword;\n }\n const dimension = valueParser.unit(word);\n const unitPx = dimension ? FONT_SIZE_UNITS_PX[dimension.unit.toLowerCase()] : undefined;\n const amount = Number(dimension ? dimension.number : Number.NaN);\n return unitPx !== undefined && Number.isFinite(amount) && amount >= 0 ? amount * unitPx : undefined;\n};\n\nconst significantValueNodes = (value: string): valueParser.Node[] => {\n return valueParser(value).nodes.filter((node) => node.type !== 'space' && node.type !== 'comment');\n};\n\nconst globalKeywordFontSize = (nodes: valueParser.Node[]): number | undefined => {\n const [only] = nodes;\n return nodes.length === 1 && only?.type === 'word' && GLOBAL_KEYWORDS.has(only.value.toLowerCase()) ? INITIAL_FONT_SIZE_PX : undefined;\n};\n\nconst resolveFontSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const [only] = nodes;\n return globalKeywordFontSize(nodes) ?? (nodes.length === 1 && only?.type === 'word' ? fontSizeOfWord(only.value) : undefined);\n};\n\n// `font: [style] [variant] [weight] [stretch] <size>[/<line-height>] <family>`: the size is the word before `/`, or else\n// the first word that is a size. A function (var(), calc()) or a family name reached first means it cannot be read.\nconst resolveFontShorthandSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const globalSize = globalKeywordFontSize(nodes);\n if (globalSize !== undefined) {\n return globalSize;\n }\n\n const slashIndex = nodes.findIndex((node) => node.type === 'div' && node.value === '/');\n if (slashIndex > 0) {\n const size = nodes[slashIndex - 1];\n return size?.type === 'word' ? fontSizeOfWord(size.value) : undefined;\n }\n\n for (const node of nodes) {\n if (node.type !== 'word') {\n return undefined;\n }\n const size = fontSizeOfWord(node.value);\n if (size !== undefined) {\n return size;\n }\n }\n return undefined;\n};\n\n// `html` and `:root` size the document root, so rem; `body` and `html body` size only the body.\nconst targetsDocumentRoot = (selector: selectorParser.Selector): boolean => {\n let subject: selectorParser.Node[] = [];\n for (const node of selector.nodes) {\n subject = node.type === 'combinator' ? [] : [...subject, node];\n }\n return subject.some((node) => (node.type === 'tag' && node.value.toLowerCase() === 'html') || (node.type === 'pseudo' && node.value === ':root'));\n};\n\nconst documentRootSelectorsOf = (selectorList: string): string[] => {\n const selectors: string[] = [];\n selectorParser((root) => {\n for (const selector of root.nodes) {\n if (targetsDocumentRoot(selector) && !needsSecondDocumentRoot(selector)) {\n selectors.push(selector.toString().trim());\n }\n }\n }).processSync(selectorList);\n return selectors;\n};\n\ntype TWarn = (node: Declaration, text: string) => void;\n\n// Hosted, rem resolves against the host page's root, not the root size the module's own page set. Each rule that sizes\n// the document root gets a sibling rule right after it that records that size as MF_ROOT_FONT_SIZE_PROPERTY, under the\n// same conditions (@media, importance) and in the same cascade order; scoping then moves it onto the module boundary,\n// where followModuleRootFontSize() makes rem lengths read it. CSS that never sizes the root is left byte-identical.\nconst recordRootFontSize = (root: Root, warn: TWarn): void => {\n root.walkRules((rule) => {\n if (isKeyframesRule(rule)) {\n return;\n }\n\n let sizing: Declaration | undefined;\n for (const node of rule.nodes) {\n if (node.type === 'decl' && /^font(?:-size)?$/i.test(node.prop) && (node.important || !sizing?.important)) {\n sizing = node;\n }\n }\n if (!sizing) {\n return;\n }\n\n const rootSelectors = documentRootSelectorsOf(rule.selector);\n if (rootSelectors.length === 0) {\n return;\n }\n\n const sizePx = sizing.prop.toLowerCase() === 'font' ? resolveFontShorthandSize(sizing.value) : resolveFontSize(sizing.value);\n if (sizePx === undefined) {\n warn(\n sizing,\n `Cannot resolve the document root font size \"${sizing.value}\" at build time; rem lengths in the hosted module will use the host page's root size.`,\n );\n return;\n }\n\n const recorded = rule.clone({ selector: rootSelectors.join(', ') });\n recorded.raws.before = rule.raws.before || '\\n';\n recorded.removeAll();\n // The recorded size points back at the declaration it came from, so source maps keep a source for it.\n recorded.append({\n important: sizing.important,\n prop: MF_ROOT_FONT_SIZE_PROPERTY,\n source: sizing.source,\n value: `${Number(sizePx.toFixed(4))}px`,\n });\n rule.after(recorded);\n });\n};\n\nconst scopeGlobalRoot = (root: Root, scopeId: string, scopeSelector: string, keyframePrefix: string, warn: TWarn): void => {\n recordRootFontSize(root, warn);\n namespaceKeyframes(root, keyframePrefix);\n const contentRootSelector = `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]:not([${MF_OVERLAY_ATTRIBUTE}]))`;\n root.walkRules((rule) => {\n if (!isKeyframesRule(rule)) {\n const declarations = rule.nodes.filter((node) => node.type === 'decl');\n const customProperties = declarations.filter((declaration) => declaration.prop.startsWith('--'));\n const standardDeclarations = declarations.filter((declaration) => !declaration.prop.startsWith('--'));\n\n if (customProperties.length > 0 && standardDeclarations.length > 0 && hasRootOnlySelector(rule.selector)) {\n const customPropertyRule = rule.cloneBefore();\n customPropertyRule.walkDecls((declaration) => {\n if (!declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n customPropertyRule.selector = scopeSelectorList(customPropertyRule.selector, scopeId, scopeSelector, [':host', scopeSelector]);\n if (!customPropertyRule.selector.trim()) {\n customPropertyRule.remove();\n }\n rule.walkDecls((declaration) => {\n if (declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n }\n\n const containsOnlyCustomProperties = declarations.length > 0 && declarations.every((declaration) => declaration.prop.startsWith('--'));\n const rootScopeSelectors = containsOnlyCustomProperties ? [':host', scopeSelector] : [':host', contentRootSelector];\n rule.selector = scopeSelectorList(rule.selector, scopeId, scopeSelector, rootScopeSelectors);\n // Every selector of the rule needed a second document root.\n if (!rule.selector.trim()) {\n rule.remove();\n }\n }\n });\n};\n\n// Emulated component CSS keeps its selectors exactly as written, so Angular compiles what it compiled on the module's\n// own page and every rule keeps its weight and reach: `mat-form-field[_ngcontent-x]` (0,1,1) still loses to a global\n// `.mat-sidenav-content .mat-mdc-form-field` (0,2,0), template content rendered in an overlay (outside the component's\n// host) keeps its component styles, and a top-level `::ng-deep` rule stays global to the module. Wrapping every rule in\n// :host-context(<boundary>) added (0,2,0) to each, and limited all of them to the component's host. Isolation needs no\n// boundary here: Angular's _ngcontent and _nghost attributes are unique to each component, and a hosted module's\n// component styles live in its own shadow root.\nconst scopeAngularComponentRoot = (root: Root, keyframePrefix: string): void => {\n namespaceKeyframes(root, keyframePrefix);\n};\n\nexport const scopeRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-isolation-${validScopeId}`,\n Once(root, { result }) {\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n\nexport const scopeAngularRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-angular-isolation-${validScopeId}`,\n Once(root, { result }) {\n if (shouldUseAngularComponentScoping(root.source?.input.file)) {\n scopeAngularComponentRoot(root, keyframePrefix);\n return;\n }\n\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n"]}
|
package/dist/postcss.js
CHANGED
|
@@ -165,6 +165,29 @@ const isRootOnlySelector = (selector) => {
|
|
|
165
165
|
}
|
|
166
166
|
return compounds.every((compound) => compound.some(isRootNode));
|
|
167
167
|
};
|
|
168
|
+
const isTagNamed = (node, name) => {
|
|
169
|
+
return node.type === 'tag' && node.value.toLowerCase() === name;
|
|
170
|
+
};
|
|
171
|
+
// The module's own page had one <html> and one <body>, so a selector that needs a second one never matched there:
|
|
172
|
+
// `html body html body .x`, which a global partial compiles to when it is loaded inside `html body {}`, or `.x html`.
|
|
173
|
+
// Scoping replaces the first root with the module boundary and drops the others, which made such a rule match hosted
|
|
174
|
+
// (AutoCleanse's datepicker cells turned blue), so the selector is dropped instead.
|
|
175
|
+
const needsSecondDocumentRoot = (selector) => {
|
|
176
|
+
const compounds = [[]];
|
|
177
|
+
for (const node of selector.nodes) {
|
|
178
|
+
if (node.type === 'combinator') {
|
|
179
|
+
compounds.push([]);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
compounds.at(-1)?.push(node);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const documentRootAfterFirst = compounds
|
|
186
|
+
.slice(1)
|
|
187
|
+
.some((compound) => compound.some((node) => isTagNamed(node, 'html') || (node.type === 'pseudo' && node.value === ':root')));
|
|
188
|
+
const bodyCompounds = compounds.filter((compound) => compound.some((node) => isTagNamed(node, 'body'))).length;
|
|
189
|
+
return documentRootAfterFirst || bodyCompounds > 1;
|
|
190
|
+
};
|
|
168
191
|
const hasRootOnlySelector = (selectorList) => {
|
|
169
192
|
let result = false;
|
|
170
193
|
selectorParser((root) => {
|
|
@@ -215,6 +238,10 @@ const scopeSelectorList = (selectorList, scopeId, scopeSelector, rootScopeSelect
|
|
|
215
238
|
return selectorParser((root) => {
|
|
216
239
|
const sourceSelectors = [...root.nodes];
|
|
217
240
|
for (const selector of sourceSelectors) {
|
|
241
|
+
if (needsSecondDocumentRoot(selector)) {
|
|
242
|
+
selector.remove();
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
218
245
|
const rootNodes = selector.nodes.filter(isRootNode);
|
|
219
246
|
if (rootNodes.length > 0) {
|
|
220
247
|
const replacementSelectors = isRootOnlySelector(selector) ? rootScopeSelectors : [rootedDescendantScope(selector, scopeId)];
|
|
@@ -398,7 +425,7 @@ const documentRootSelectorsOf = (selectorList) => {
|
|
|
398
425
|
const selectors = [];
|
|
399
426
|
selectorParser((root) => {
|
|
400
427
|
for (const selector of root.nodes) {
|
|
401
|
-
if (targetsDocumentRoot(selector)) {
|
|
428
|
+
if (targetsDocumentRoot(selector) && !needsSecondDocumentRoot(selector)) {
|
|
402
429
|
selectors.push(selector.toString().trim());
|
|
403
430
|
}
|
|
404
431
|
}
|
|
@@ -462,6 +489,9 @@ const scopeGlobalRoot = (root, scopeId, scopeSelector, keyframePrefix, warn) =>
|
|
|
462
489
|
}
|
|
463
490
|
});
|
|
464
491
|
customPropertyRule.selector = scopeSelectorList(customPropertyRule.selector, scopeId, scopeSelector, [':host', scopeSelector]);
|
|
492
|
+
if (!customPropertyRule.selector.trim()) {
|
|
493
|
+
customPropertyRule.remove();
|
|
494
|
+
}
|
|
465
495
|
rule.walkDecls((declaration) => {
|
|
466
496
|
if (declaration.prop.startsWith('--')) {
|
|
467
497
|
declaration.remove();
|
|
@@ -471,6 +501,10 @@ const scopeGlobalRoot = (root, scopeId, scopeSelector, keyframePrefix, warn) =>
|
|
|
471
501
|
const containsOnlyCustomProperties = declarations.length > 0 && declarations.every((declaration) => declaration.prop.startsWith('--'));
|
|
472
502
|
const rootScopeSelectors = containsOnlyCustomProperties ? [':host', scopeSelector] : [':host', contentRootSelector];
|
|
473
503
|
rule.selector = scopeSelectorList(rule.selector, scopeId, scopeSelector, rootScopeSelectors);
|
|
504
|
+
// Every selector of the rule needed a second document root.
|
|
505
|
+
if (!rule.selector.trim()) {
|
|
506
|
+
rule.remove();
|
|
507
|
+
}
|
|
474
508
|
}
|
|
475
509
|
});
|
|
476
510
|
};
|
package/dist/postcss.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postcss.js","sourceRoot":"","sources":["../src/postcss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,cAAc,MAAM,yBAAyB,CAAC;AACrD,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAMjE,MAAM,+BAA+B,GAAG,uCAAuC,CAAC;AAChF,MAAM,+BAA+B,GAAG,uEAAuE,CAAC;AAChH,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAIpD,MAAM,gCAAgC,GAAG,CAAC,MAAc,EAAU,EAAE;IAClE,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,KAAK,GAAyB,MAAM,CAAC;IACzC,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAU,EAAE;QAClD,OAAO,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;IACpE,CAAC,CAAC;IAEF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAExC,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACrB,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC/C,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBACtD,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,eAAe,CAAC;YAC1B,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,UAAU,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,YAAY,IAAI,SAAS,CAAC;YAC5B,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC7B,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBAC7C,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;YAC9B,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC/C,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;YAC3C,CAAC;YACD,SAAS;QACX,CAAC;QAED,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;aAAM,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YAC9B,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IACL,CAAC,KAAK,KAAK,cAAc,IAAI,SAAS,KAAK,GAAG,CAAC;YAC/C,CAAC,KAAK,KAAK,cAAc,IAAI,SAAS,KAAK,GAAG,CAAC;YAC/C,CAAC,KAAK,KAAK,UAAU,IAAI,SAAS,KAAK,GAAG,CAAC,EAC3C,CAAC;YACD,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAW,EAAE;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,IAAyB,EAAW,EAAE;IACxD,OAAO,CACL,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;QACrG,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,gBAAgB,CAAC,CAAC,CACxF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,IAAqC,EAAE,OAAe,EAAW,EAAE;IACtF,IAAI,IAAI,EAAE,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,SAAS,KAAK,kBAAkB,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC3H,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5E,OAAO,CACL,IAAI,EAAE,IAAI,KAAK,QAAQ;QACvB,CAAC,UAAU,KAAK,WAAW,kBAAkB,IAAI,OAAO,IAAI;YAC1D,UAAU,KAAK,WAAW,kBAAkB,IAAI,OAAO,UAAU,oBAAoB,KAAK,CAAC,CAC9F,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,QAAiC,EAAW,EAAE;IAC1E,OAAO,QAAQ,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC;AAC/E,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,QAAiC,EAAQ,EAAE;IACxE,IAAI,QAAQ,GAA0B,EAAE,CAAC;IACzC,MAAM,yBAAyB,GAAG,GAAS,EAAE;QAC3C,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;oBACvB,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,yBAAyB,EAAE,CAAC;YAC5B,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,yBAAyB,EAAE,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAE3C,mHAAmH;AACnH,mHAAmH;AACnH,uHAAuH;AACvH,qHAAqH;AACrH,qHAAqH;AACrH,uHAAuH;AACvH,4FAA4F;AAC5F,MAAM,sBAAsB,GAAG,CAAC,QAAiC,EAAU,EAAE;IAC3E,MAAM,SAAS,GAA4B,CAAC,EAAE,CAAC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACxF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACjG,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;QACjE,OAAO,CAAC,IAAI,CACV,GAAG,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,mBAAmB,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,mBAAmB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5I,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,QAAiC,EAAE,OAAe,EAAU,EAAE;IAC3F,OAAO,WAAW,kBAAkB,KAAK,OAAO,WAAW,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,QAAiC,EAAW,EAAE;IACxE,MAAM,SAAS,GAA4B,CAAC,EAAE,CAAC,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,YAAoB,EAAW,EAAE;IAC5D,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE3F,0GAA0G;AAC1G,uHAAuH;AACvH,2GAA2G;AAC3G,MAAM,4BAA4B,GAAG,CAAC,SAAiB,EAAsB,EAAE;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,gDAAgD,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxH,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzE,SAAS;QACX,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACrD,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAAsB,EAAE;IAC9E,MAAM,cAAc,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACxD,IAAI,+BAA+B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACzD,OAAO,cAAc,CAAC,OAAO,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,4BAA4B,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtH,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAAC,SAAiB,EAAW,EAAE;IAC/D,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,mBAAmB,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,eAAe,GAAG,YAAY,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IAClE,OAAO,+BAA+B,CAAC,IAAI,CAAC,gCAAgC,CAAC,eAAe,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,SAA6B,EAAW,EAAE;IACzF,OAAO,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,6BAA6B,CAAC,SAAS,CAAC,IAAI,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAC5G,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,YAAoB,EAAE,OAAe,EAAE,aAAqB,EAAE,kBAA4B,EAAU,EAAE;IAC/H,OAAO,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7B,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAExC,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;YACvC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;gBAE5H,KAAK,MAAM,mBAAmB,IAAI,oBAAoB,EAAE,CAAC;oBACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACjC,qBAAqB,CAAC,OAAO,CAAC,CAAC;oBAC/B,MAAM,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBACxE,2FAA2F;oBAC3F,MAAM,UAAU,GAAG,cAAc,EAAE;yBAChC,OAAO,CAAC,mBAAmB,CAAC;yBAC5B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;oBAC3C,MAAM,CAAC,SAAS,EAAE,GAAG,mBAAmB,CAAC,GAAG,UAAU,CAAC;oBACvD,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;wBAC3B,SAAS,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;wBACjC,IAAI,QAAQ,GAAG,SAAS,CAAC;wBACzB,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;4BACvC,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;4BACpC,QAAQ,GAAG,IAAI,CAAC;wBAClB,CAAC;oBACH,CAAC;oBAED,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;wBAC3C,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;wBACtC,IAAI,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;4BACpC,QAAQ,CAAC,MAAM,EAAE,CAAC;wBACpB,CAAC;wBACD,aAAa,CAAC,MAAM,EAAE,CAAC;oBACzB,CAAC;oBAED,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACvC,CAAC;gBACD,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YAED,IAAI,oBAAoB,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC3E,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;YAC7B,MAAM,oBAAoB,GAAG,KAAK,EAAE,IAAI,KAAK,WAAW,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAEvH,IAAI,oBAAoB,EAAE,CAAC;gBACzB,MAAM,oBAAoB,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAErI,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBAC1B,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACzC,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBAClF,eAAe,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;oBAC1C,IAAI,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;wBAC/C,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;oBACnD,CAAC;yBAAM,CAAC;wBACN,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;oBACzC,CAAC;oBACD,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAED,MAAM,eAAe,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,GAAG,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC;YAC7E,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACnF,QAAQ,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;YACnC,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC/C,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACtD,IAAI,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC1C,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,IAAU,EAAE,cAAsB,EAAQ,EAAE;IACtE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,EAAE;QAC1B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACjF,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,GAAG,cAAc,GAAG,YAAY,EAAE,CAAC;QACtD,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;QAC7B,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChH,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC;YACvD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,wHAAwH;AACxH,uBAAuB;AACvB,MAAM,qBAAqB,GAAqC;IAC9D,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,EAAE;IACb,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,SAAS,EAAE,EAAE;IACb,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,oBAAoB,GAAG,GAAG;IACnC,MAAM,EAAE,oBAAoB,GAAG,GAAG;CACnC,CAAC;AACF,4DAA4D;AAC5D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3F,8DAA8D;AAC9D,MAAM,kBAAkB,GAAqC;IAC3D,GAAG,EAAE,oBAAoB,GAAG,GAAG;IAC/B,EAAE,EAAE,EAAE,GAAG,IAAI;IACb,EAAE,EAAE,oBAAoB;IACxB,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE,GAAG,IAAI;IACb,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE,GAAG,EAAE;IACX,EAAE,EAAE,CAAC;IACL,CAAC,EAAE,EAAE,GAAG,KAAK;IACb,GAAG,EAAE,oBAAoB;CAC1B,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,IAAY,EAAsB,EAAE;IAC1D,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtG,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAa,EAAsB,EAAE;IAClE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACrG,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAyB,EAAsB,EAAE;IAC9E,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrB,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC;AACzI,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,KAAa,EAAsB,EAAE;IAC5D,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrB,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChI,CAAC,CAAC;AAEF,yHAAyH;AACzH,oHAAoH;AACpH,MAAM,wBAAwB,GAAG,CAAC,KAAa,EAAsB,EAAE;IACrE,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;IACxF,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;QACnC,OAAO,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,mBAAmB,GAAG,CAAC,QAAiC,EAAW,EAAE;IACzE,IAAI,OAAO,GAA0B,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC;AACpJ,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,YAAoB,EAAY,EAAE;IACjE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAClC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IAC7B,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAIF,uHAAuH;AACvH,uHAAuH;AACvH,sHAAsH;AACtH,oHAAoH;AACpH,MAAM,kBAAkB,GAAG,CAAC,IAAU,EAAE,IAAW,EAAQ,EAAE;IAC3D,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,MAA+B,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC1G,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7H,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CACF,MAAM,EACN,+CAA+C,MAAM,CAAC,KAAK,uFAAuF,CACnJ,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpE,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QAChD,QAAQ,CAAC,SAAS,EAAE,CAAC;QACrB,sGAAsG;QACtG,QAAQ,CAAC,MAAM,CAAC;YACd,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,IAAI,EAAE,0BAA0B;YAChC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAE,OAAe,EAAE,aAAqB,EAAE,cAAsB,EAAE,IAAW,EAAQ,EAAE;IACxH,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,kBAAkB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACzC,MAAM,mBAAmB,GAAG,WAAW,kBAAkB,KAAK,OAAO,WAAW,oBAAoB,KAAK,CAAC;IAC1G,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;YACvE,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACjG,MAAM,oBAAoB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAEtG,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzG,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9C,kBAAkB,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;oBAC3C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvC,WAAW,CAAC,MAAM,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,kBAAkB,CAAC,QAAQ,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;gBAC/H,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;oBAC7B,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;wBACtC,WAAW,CAAC,MAAM,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,MAAM,4BAA4B,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACvI,MAAM,kBAAkB,GAAG,4BAA4B,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACpH,IAAI,CAAC,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,sHAAsH;AACtH,qHAAqH;AACrH,uHAAuH;AACvH,wHAAwH;AACxH,uHAAuH;AACvH,iHAAiH;AACjH,gDAAgD;AAChD,MAAM,yBAAyB,GAAG,CAAC,IAAU,EAAE,cAAsB,EAAQ,EAAE;IAC7E,kBAAkB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAA0B,EAAU,EAAE;IAC5E,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,WAAW,YAAY,IAAI,CAAC;IAEnD,OAAO;QACL,aAAa,EAAE,qBAAqB,YAAY,EAAE;QAClD,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE;YACnB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9G,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EAAE,OAAO,EAA0B,EAAU,EAAE;IACnF,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,WAAW,YAAY,IAAI,CAAC;IAEnD,OAAO;QACL,aAAa,EAAE,6BAA6B,YAAY,EAAE;QAC1D,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE;YACnB,IAAI,gCAAgC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,yBAAyB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YAED,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9G,CAAC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport type { Declaration, Plugin, Root, Rule } from 'postcss';\nimport selectorParser from 'postcss-selector-parser';\nimport valueParser from 'postcss-value-parser';\nimport { getMfScopeSelector, MF_ROOT_SELECTOR, MF_SCOPE_ATTRIBUTE, validateMfScopeId } from './index.js';\nimport { MF_ROOT_FONT_SIZE_PROPERTY } from './root-font-size.js';\n\nexport interface IScopeRemoteCssOptions {\n scopeId: string;\n}\n\nconst ANGULAR_COMPONENT_STYLE_PATTERN = /\\.component\\.(?:css|less|sass|scss)$/i;\nconst VIEW_ENCAPSULATION_NONE_PATTERN = /(?:^|[,{])\\s*encapsulation\\s*:\\s*(?:[A-Za-z_$][\\w$]*\\s*\\.\\s*)+None\\b/m;\nconst MF_OVERLAY_ATTRIBUTE = 'data-edyn-mf-overlay';\n\ntype TTypeScriptMaskState = 'block-comment' | 'code' | 'double-quote' | 'line-comment' | 'single-quote' | 'template';\n\nconst maskTypeScriptCommentsAndStrings = (source: string): string => {\n let maskedSource = '';\n let state: TTypeScriptMaskState = 'code';\n let escaped = false;\n\n const maskCharacter = (character: string): string => {\n return character === '\\n' || character === '\\r' ? character : ' ';\n };\n\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index] ?? '';\n const nextCharacter = source[index + 1];\n\n if (state === 'code') {\n if (character === '/' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'line-comment';\n } else if (character === '/' && nextCharacter === '*') {\n maskedSource += ' ';\n index += 1;\n state = 'block-comment';\n } else if (character === \"'\") {\n maskedSource += ' ';\n state = 'single-quote';\n } else if (character === '\"') {\n maskedSource += ' ';\n state = 'double-quote';\n } else if (character === '`') {\n maskedSource += ' ';\n state = 'template';\n } else {\n maskedSource += character;\n }\n continue;\n }\n\n if (state === 'line-comment') {\n maskedSource += maskCharacter(character);\n if (character === '\\n' || character === '\\r') {\n state = 'code';\n }\n continue;\n }\n\n if (state === 'block-comment') {\n if (character === '*' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'code';\n } else {\n maskedSource += maskCharacter(character);\n }\n continue;\n }\n\n maskedSource += maskCharacter(character);\n if (escaped) {\n escaped = false;\n } else if (character === '\\\\') {\n escaped = true;\n } else if (\n (state === 'single-quote' && character === \"'\") ||\n (state === 'double-quote' && character === '\"') ||\n (state === 'template' && character === '`')\n ) {\n state = 'code';\n }\n }\n\n return maskedSource;\n};\n\nconst isKeyframesRule = (rule: Rule): boolean => {\n const parent = rule.parent;\n return parent?.type === 'atrule' && /keyframes$/i.test(parent.name);\n};\n\nconst isRootNode = (node: selectorParser.Node): boolean => {\n return (\n (node.type === 'tag' && (node.value.toLowerCase() === 'html' || node.value.toLowerCase() === 'body')) ||\n (node.type === 'pseudo' && (node.value === ':root' || node.value === MF_ROOT_SELECTOR))\n );\n};\n\nconst isScopeNode = (node: selectorParser.Node | undefined, scopeId: string): boolean => {\n if (node?.type === 'attribute' && node.attribute === MF_SCOPE_ATTRIBUTE && node.operator === '=' && node.value === scopeId) {\n return true;\n }\n\n const normalized = node?.toString().replaceAll('\"', '').replaceAll(\"'\", '');\n return (\n node?.type === 'pseudo' &&\n (normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}])` ||\n normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}]:not([${MF_OVERLAY_ATTRIBUTE}]))`)\n );\n};\n\nconst startsWithHostPseudo = (selector: selectorParser.Selector): boolean => {\n return selector.first?.type === 'pseudo' && selector.first.value === ':host';\n};\n\nconst removeRootIdentityIds = (selector: selectorParser.Selector): void => {\n let compound: selectorParser.Node[] = [];\n const removeIdsFromRootCompound = (): void => {\n if (compound.some(isRootNode)) {\n for (const node of compound) {\n if (node.type === 'id') {\n node.remove();\n }\n }\n }\n };\n\n for (const node of [...selector.nodes]) {\n if (node.type === 'combinator') {\n removeIdsFromRootCompound();\n compound = [];\n } else {\n compound.push(node);\n }\n }\n removeIdsFromRootCompound();\n};\n\nconst SPECIFICITY_CARRIER = 'edyn-mf-root';\n\n// Legacy rules such as `html body button` or `html body#app .mdc-checkbox__background` are weighed against Angular\n// Material's own rules by the html, body and #app they start from, so the scope that replaces that root must weigh\n// exactly the same. A plain scope attribute (0,1,0) drops the id of `body#app`, letting Material's checked colour win,\n// and outweighs the two types of `html body`, letting an override that lost to `.mat-mdc-button` on the old site win\n// hosted. The root becomes :where(<scope>):not(<carrier>): :where() weighs nothing, and the carrier has the same id,\n// class and type counts as the root part it replaces and never matches the scope element, so :not() always matches and\n// weighs exactly that. Neutral names keep `html`, `body` and `#app` out of the emitted CSS.\nconst rootSpecificityCarrier = (selector: selectorParser.Selector): string => {\n const compounds: selectorParser.Node[][] = [[]];\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const carrier: string[] = [];\n for (const compound of compounds) {\n if (!compound.some(isRootNode)) {\n continue;\n }\n const types = compound.filter((node) => node.type === 'tag' && isRootNode(node)).length;\n const pseudoRoots = compound.filter((node) => node.type === 'pseudo' && isRootNode(node)).length;\n const ids = compound.filter((node) => node.type === 'id').length;\n carrier.push(\n `${SPECIFICITY_CARRIER.repeat(Math.min(types, 1))}${`.${SPECIFICITY_CARRIER}`.repeat(pseudoRoots)}${`#${SPECIFICITY_CARRIER}`.repeat(ids)}`,\n );\n }\n\n return carrier.filter(Boolean).join(' ');\n};\n\nconst rootedDescendantScope = (selector: selectorParser.Selector, scopeId: string): string => {\n return `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]):not(${rootSpecificityCarrier(selector)})`;\n};\n\nconst isRootOnlySelector = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n return compounds.every((compound) => compound.some(isRootNode));\n};\n\nconst hasRootOnlySelector = (selectorList: string): boolean => {\n let result = false;\n selectorParser((root) => {\n result = root.nodes.some(isRootOnlySelector);\n }).processSync(selectorList);\n return result;\n};\n\nconst escapeRegExp = (text: string): string => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n// A component stylesheet need not be named *.component.scss (CampaignManagement's create-campaign.ts uses\n// `styleUrl: './create-campaign.scss'`); treated as global CSS, Angular would then encapsulate the boundary itself and\n// the rules could never match. Such a file is a component's when a sibling component source references it.\nconst referencingComponentSourceOf = (stylePath: string): string | undefined => {\n const directory = dirname(stylePath);\n if (!existsSync(directory)) {\n return undefined;\n }\n const reference = new RegExp(`styleUrls?\\\\s*:\\\\s*(?:\\\\[[^\\\\]]*?)?['\"\\`]\\\\./${escapeRegExp(basename(stylePath))}['\"\\`]`);\n for (const fileName of readdirSync(directory)) {\n if (!fileName.endsWith('.ts') || /\\.(?:spec|test|d)\\.ts$/.test(fileName)) {\n continue;\n }\n const sourcePath = join(directory, fileName);\n if (reference.test(readFileSync(sourcePath, 'utf8'))) {\n return sourcePath;\n }\n }\n return undefined;\n};\n\nconst getAngularComponentSourcePath = (stylePath: string): string | undefined => {\n const cleanStylePath = stylePath.replace(/[?#].*$/, '');\n if (ANGULAR_COMPONENT_STYLE_PATTERN.test(cleanStylePath)) {\n return cleanStylePath.replace(/\\.(?:css|less|sass|scss)$/i, '.ts');\n }\n return /\\.(?:css|less|sass|scss)$/i.test(cleanStylePath) ? referencingComponentSourceOf(cleanStylePath) : undefined;\n};\n\nconst usesViewEncapsulationNone = (stylePath: string): boolean => {\n const componentSourcePath = getAngularComponentSourcePath(stylePath);\n if (!componentSourcePath || !existsSync(componentSourcePath)) {\n return false;\n }\n\n const componentSource = readFileSync(componentSourcePath, 'utf8');\n return VIEW_ENCAPSULATION_NONE_PATTERN.test(maskTypeScriptCommentsAndStrings(componentSource));\n};\n\nexport const shouldUseAngularComponentScoping = (stylePath: string | undefined): boolean => {\n return !!stylePath && !!getAngularComponentSourcePath(stylePath) && !usesViewEncapsulationNone(stylePath);\n};\n\nconst scopeSelectorList = (selectorList: string, scopeId: string, scopeSelector: string, rootScopeSelectors: string[]): string => {\n return selectorParser((root) => {\n const sourceSelectors = [...root.nodes];\n\n for (const selector of sourceSelectors) {\n const rootNodes = selector.nodes.filter(isRootNode);\n\n if (rootNodes.length > 0) {\n const replacementSelectors = isRootOnlySelector(selector) ? rootScopeSelectors : [rootedDescendantScope(selector, scopeId)];\n\n for (const replacementSelector of replacementSelectors) {\n const variant = selector.clone();\n removeRootIdentityIds(variant);\n const [firstRoot, ...duplicateRoots] = variant.nodes.filter(isRootNode);\n // The replacement can be a compound of several nodes, e.g. :where(<scope>):not(<carrier>).\n const scopeNodes = selectorParser()\n .astSync(replacementSelector)\n .first.nodes.map((node) => node.clone());\n const [scopeNode, ...followingScopeNodes] = scopeNodes;\n if (firstRoot && scopeNode) {\n firstRoot.replaceWith(scopeNode);\n let previous = scopeNode;\n for (const node of followingScopeNodes) {\n variant.insertAfter(previous, node);\n previous = node;\n }\n }\n\n for (const duplicateRoot of duplicateRoots) {\n const previous = duplicateRoot.prev();\n if (previous?.type === 'combinator') {\n previous.remove();\n }\n duplicateRoot.remove();\n }\n\n root.insertBefore(selector, variant);\n }\n selector.remove();\n continue;\n }\n\n if (startsWithHostPseudo(selector) || isScopeNode(selector.first, scopeId)) {\n continue;\n }\n\n const first = selector.first;\n const needsBoundaryVariant = first?.type === 'universal' || (first?.type === 'pseudo' && first.value.startsWith('::'));\n\n if (needsBoundaryVariant) {\n const hasSiblingCombinator = selector.nodes.some((node) => node.type === 'combinator' && (node.value === '+' || node.value === '~'));\n\n if (!hasSiblingCombinator) {\n const boundaryVariant = selector.clone();\n const boundaryScope = selectorParser().astSync(scopeSelector).first.first.clone();\n boundaryVariant.first.rawSpaceBefore = '';\n if (boundaryVariant.first.type === 'universal') {\n boundaryVariant.first.replaceWith(boundaryScope);\n } else {\n boundaryVariant.prepend(boundaryScope);\n }\n root.insertBefore(selector, boundaryVariant);\n }\n }\n\n const descendantScope = selectorParser().astSync(`${scopeSelector} *`).first;\n const prefixNodes = descendantScope.nodes.slice(0, -1).map((node) => node.clone());\n selector.first.rawSpaceBefore = '';\n for (const prefixNode of prefixNodes.reverse()) {\n selector.prepend(prefixNode);\n }\n }\n\n const seenSelectors = new Set<string>();\n for (const selector of [...root.nodes]) {\n const normalizedSelector = selector.toString().trim();\n if (seenSelectors.has(normalizedSelector)) {\n selector.remove();\n } else {\n seenSelectors.add(normalizedSelector);\n }\n }\n }).processSync(selectorList);\n};\n\nconst namespaceKeyframes = (root: Root, keyframePrefix: string): void => {\n const keyframes = new Map<string, string>();\n\n root.walkAtRules((atRule) => {\n if (!/keyframes$/i.test(atRule.name) || atRule.params.startsWith(keyframePrefix)) {\n return;\n }\n\n const originalName = atRule.params.trim();\n const scopedName = `${keyframePrefix}${originalName}`;\n keyframes.set(originalName, scopedName);\n atRule.params = scopedName;\n });\n\n root.walkDecls((declaration) => {\n if (!/^(?:-webkit-)?animation(?:-name)?$/i.test(declaration.prop) && !declaration.prop.startsWith('--animate-')) {\n return;\n }\n\n const parsed = valueParser(declaration.value);\n parsed.walk((node) => {\n if (node.type === 'word') {\n node.value = keyframes.get(node.value) ?? node.value;\n }\n });\n declaration.value = parsed.toString();\n });\n};\n\nconst INITIAL_FONT_SIZE_PX = 16;\n// Absolute-size keywords as browsers compute them, and the relative ones as they resolve on the root, whose parent size\n// is the initial 16px.\nconst FONT_SIZE_KEYWORDS_PX: Readonly<Record<string, number>> = {\n 'xx-small': 9,\n 'x-small': 10,\n small: 13,\n medium: 16,\n large: 18,\n 'x-large': 24,\n 'xx-large': 32,\n 'xxx-large': 48,\n smaller: INITIAL_FONT_SIZE_PX / 1.2,\n larger: INITIAL_FONT_SIZE_PX * 1.2,\n};\n// On the root, every global keyword gives the initial size.\nconst GLOBAL_KEYWORDS = new Set(['inherit', 'initial', 'revert', 'revert-layer', 'unset']);\n// em, rem and % on the root are relative to the initial size.\nconst FONT_SIZE_UNITS_PX: Readonly<Record<string, number>> = {\n '%': INITIAL_FONT_SIZE_PX / 100,\n cm: 96 / 2.54,\n em: INITIAL_FONT_SIZE_PX,\n in: 96,\n mm: 96 / 25.4,\n pc: 16,\n pt: 96 / 72,\n px: 1,\n q: 96 / 101.6,\n rem: INITIAL_FONT_SIZE_PX,\n};\n\nconst fontSizeOfWord = (word: string): number | undefined => {\n const keyword = FONT_SIZE_KEYWORDS_PX[word.toLowerCase()];\n if (keyword !== undefined) {\n return keyword;\n }\n const dimension = valueParser.unit(word);\n const unitPx = dimension ? FONT_SIZE_UNITS_PX[dimension.unit.toLowerCase()] : undefined;\n const amount = Number(dimension ? dimension.number : Number.NaN);\n return unitPx !== undefined && Number.isFinite(amount) && amount >= 0 ? amount * unitPx : undefined;\n};\n\nconst significantValueNodes = (value: string): valueParser.Node[] => {\n return valueParser(value).nodes.filter((node) => node.type !== 'space' && node.type !== 'comment');\n};\n\nconst globalKeywordFontSize = (nodes: valueParser.Node[]): number | undefined => {\n const [only] = nodes;\n return nodes.length === 1 && only?.type === 'word' && GLOBAL_KEYWORDS.has(only.value.toLowerCase()) ? INITIAL_FONT_SIZE_PX : undefined;\n};\n\nconst resolveFontSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const [only] = nodes;\n return globalKeywordFontSize(nodes) ?? (nodes.length === 1 && only?.type === 'word' ? fontSizeOfWord(only.value) : undefined);\n};\n\n// `font: [style] [variant] [weight] [stretch] <size>[/<line-height>] <family>`: the size is the word before `/`, or else\n// the first word that is a size. A function (var(), calc()) or a family name reached first means it cannot be read.\nconst resolveFontShorthandSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const globalSize = globalKeywordFontSize(nodes);\n if (globalSize !== undefined) {\n return globalSize;\n }\n\n const slashIndex = nodes.findIndex((node) => node.type === 'div' && node.value === '/');\n if (slashIndex > 0) {\n const size = nodes[slashIndex - 1];\n return size?.type === 'word' ? fontSizeOfWord(size.value) : undefined;\n }\n\n for (const node of nodes) {\n if (node.type !== 'word') {\n return undefined;\n }\n const size = fontSizeOfWord(node.value);\n if (size !== undefined) {\n return size;\n }\n }\n return undefined;\n};\n\n// `html` and `:root` size the document root, so rem; `body` and `html body` size only the body.\nconst targetsDocumentRoot = (selector: selectorParser.Selector): boolean => {\n let subject: selectorParser.Node[] = [];\n for (const node of selector.nodes) {\n subject = node.type === 'combinator' ? [] : [...subject, node];\n }\n return subject.some((node) => (node.type === 'tag' && node.value.toLowerCase() === 'html') || (node.type === 'pseudo' && node.value === ':root'));\n};\n\nconst documentRootSelectorsOf = (selectorList: string): string[] => {\n const selectors: string[] = [];\n selectorParser((root) => {\n for (const selector of root.nodes) {\n if (targetsDocumentRoot(selector)) {\n selectors.push(selector.toString().trim());\n }\n }\n }).processSync(selectorList);\n return selectors;\n};\n\ntype TWarn = (node: Declaration, text: string) => void;\n\n// Hosted, rem resolves against the host page's root, not the root size the module's own page set. Each rule that sizes\n// the document root gets a sibling rule right after it that records that size as MF_ROOT_FONT_SIZE_PROPERTY, under the\n// same conditions (@media, importance) and in the same cascade order; scoping then moves it onto the module boundary,\n// where followModuleRootFontSize() makes rem lengths read it. CSS that never sizes the root is left byte-identical.\nconst recordRootFontSize = (root: Root, warn: TWarn): void => {\n root.walkRules((rule) => {\n if (isKeyframesRule(rule)) {\n return;\n }\n\n let sizing: Declaration | undefined;\n for (const node of rule.nodes) {\n if (node.type === 'decl' && /^font(?:-size)?$/i.test(node.prop) && (node.important || !sizing?.important)) {\n sizing = node;\n }\n }\n if (!sizing) {\n return;\n }\n\n const rootSelectors = documentRootSelectorsOf(rule.selector);\n if (rootSelectors.length === 0) {\n return;\n }\n\n const sizePx = sizing.prop.toLowerCase() === 'font' ? resolveFontShorthandSize(sizing.value) : resolveFontSize(sizing.value);\n if (sizePx === undefined) {\n warn(\n sizing,\n `Cannot resolve the document root font size \"${sizing.value}\" at build time; rem lengths in the hosted module will use the host page's root size.`,\n );\n return;\n }\n\n const recorded = rule.clone({ selector: rootSelectors.join(', ') });\n recorded.raws.before = rule.raws.before || '\\n';\n recorded.removeAll();\n // The recorded size points back at the declaration it came from, so source maps keep a source for it.\n recorded.append({\n important: sizing.important,\n prop: MF_ROOT_FONT_SIZE_PROPERTY,\n source: sizing.source,\n value: `${Number(sizePx.toFixed(4))}px`,\n });\n rule.after(recorded);\n });\n};\n\nconst scopeGlobalRoot = (root: Root, scopeId: string, scopeSelector: string, keyframePrefix: string, warn: TWarn): void => {\n recordRootFontSize(root, warn);\n namespaceKeyframes(root, keyframePrefix);\n const contentRootSelector = `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]:not([${MF_OVERLAY_ATTRIBUTE}]))`;\n root.walkRules((rule) => {\n if (!isKeyframesRule(rule)) {\n const declarations = rule.nodes.filter((node) => node.type === 'decl');\n const customProperties = declarations.filter((declaration) => declaration.prop.startsWith('--'));\n const standardDeclarations = declarations.filter((declaration) => !declaration.prop.startsWith('--'));\n\n if (customProperties.length > 0 && standardDeclarations.length > 0 && hasRootOnlySelector(rule.selector)) {\n const customPropertyRule = rule.cloneBefore();\n customPropertyRule.walkDecls((declaration) => {\n if (!declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n customPropertyRule.selector = scopeSelectorList(customPropertyRule.selector, scopeId, scopeSelector, [':host', scopeSelector]);\n rule.walkDecls((declaration) => {\n if (declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n }\n\n const containsOnlyCustomProperties = declarations.length > 0 && declarations.every((declaration) => declaration.prop.startsWith('--'));\n const rootScopeSelectors = containsOnlyCustomProperties ? [':host', scopeSelector] : [':host', contentRootSelector];\n rule.selector = scopeSelectorList(rule.selector, scopeId, scopeSelector, rootScopeSelectors);\n }\n });\n};\n\n// Emulated component CSS keeps its selectors exactly as written, so Angular compiles what it compiled on the module's\n// own page and every rule keeps its weight and reach: `mat-form-field[_ngcontent-x]` (0,1,1) still loses to a global\n// `.mat-sidenav-content .mat-mdc-form-field` (0,2,0), template content rendered in an overlay (outside the component's\n// host) keeps its component styles, and a top-level `::ng-deep` rule stays global to the module. Wrapping every rule in\n// :host-context(<boundary>) added (0,2,0) to each, and limited all of them to the component's host. Isolation needs no\n// boundary here: Angular's _ngcontent and _nghost attributes are unique to each component, and a hosted module's\n// component styles live in its own shadow root.\nconst scopeAngularComponentRoot = (root: Root, keyframePrefix: string): void => {\n namespaceKeyframes(root, keyframePrefix);\n};\n\nexport const scopeRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-isolation-${validScopeId}`,\n Once(root, { result }) {\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n\nexport const scopeAngularRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-angular-isolation-${validScopeId}`,\n Once(root, { result }) {\n if (shouldUseAngularComponentScoping(root.source?.input.file)) {\n scopeAngularComponentRoot(root, keyframePrefix);\n return;\n }\n\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n"]}
|
|
1
|
+
{"version":3,"file":"postcss.js","sourceRoot":"","sources":["../src/postcss.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,cAAc,MAAM,yBAAyB,CAAC;AACrD,OAAO,WAAW,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAMjE,MAAM,+BAA+B,GAAG,uCAAuC,CAAC;AAChF,MAAM,+BAA+B,GAAG,uEAAuE,CAAC;AAChH,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAIpD,MAAM,gCAAgC,GAAG,CAAC,MAAc,EAAU,EAAE;IAClE,IAAI,YAAY,GAAG,EAAE,CAAC;IACtB,IAAI,KAAK,GAAyB,MAAM,CAAC;IACzC,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,aAAa,GAAG,CAAC,SAAiB,EAAU,EAAE;QAClD,OAAO,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC;IACpE,CAAC,CAAC;IAEF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACtC,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAExC,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YACrB,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC/C,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBACtD,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,eAAe,CAAC;YAC1B,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,cAAc,CAAC;YACzB,CAAC;iBAAM,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBAC7B,YAAY,IAAI,GAAG,CAAC;gBACpB,KAAK,GAAG,UAAU,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,YAAY,IAAI,SAAS,CAAC;YAC5B,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,cAAc,EAAE,CAAC;YAC7B,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;YACzC,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBAC7C,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,KAAK,KAAK,eAAe,EAAE,CAAC;YAC9B,IAAI,SAAS,KAAK,GAAG,IAAI,aAAa,KAAK,GAAG,EAAE,CAAC;gBAC/C,YAAY,IAAI,IAAI,CAAC;gBACrB,KAAK,IAAI,CAAC,CAAC;gBACX,KAAK,GAAG,MAAM,CAAC;YACjB,CAAC;iBAAM,CAAC;gBACN,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;YAC3C,CAAC;YACD,SAAS;QACX,CAAC;QAED,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;aAAM,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YAC9B,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IACL,CAAC,KAAK,KAAK,cAAc,IAAI,SAAS,KAAK,GAAG,CAAC;YAC/C,CAAC,KAAK,KAAK,cAAc,IAAI,SAAS,KAAK,GAAG,CAAC;YAC/C,CAAC,KAAK,KAAK,UAAU,IAAI,SAAS,KAAK,GAAG,CAAC,EAC3C,CAAC;YACD,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAW,EAAE;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,OAAO,MAAM,EAAE,IAAI,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,IAAyB,EAAW,EAAE;IACxD,OAAO,CACL,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;QACrG,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,gBAAgB,CAAC,CAAC,CACxF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,IAAqC,EAAE,OAAe,EAAW,EAAE;IACtF,IAAI,IAAI,EAAE,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,SAAS,KAAK,kBAAkB,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;QAC3H,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5E,OAAO,CACL,IAAI,EAAE,IAAI,KAAK,QAAQ;QACvB,CAAC,UAAU,KAAK,WAAW,kBAAkB,IAAI,OAAO,IAAI;YAC1D,UAAU,KAAK,WAAW,kBAAkB,IAAI,OAAO,UAAU,oBAAoB,KAAK,CAAC,CAC9F,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAAC,QAAiC,EAAW,EAAE;IAC1E,OAAO,QAAQ,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,OAAO,CAAC;AAC/E,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,QAAiC,EAAQ,EAAE;IACxE,IAAI,QAAQ,GAA0B,EAAE,CAAC;IACzC,MAAM,yBAAyB,GAAG,GAAS,EAAE;QAC3C,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;oBACvB,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,yBAAyB,EAAE,CAAC;YAC5B,QAAQ,GAAG,EAAE,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,yBAAyB,EAAE,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,cAAc,CAAC;AAE3C,mHAAmH;AACnH,mHAAmH;AACnH,uHAAuH;AACvH,qHAAqH;AACrH,qHAAqH;AACrH,uHAAuH;AACvH,4FAA4F;AAC5F,MAAM,sBAAsB,GAAG,CAAC,QAAiC,EAAU,EAAE;IAC3E,MAAM,SAAS,GAA4B,CAAC,EAAE,CAAC,CAAC;IAChD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/B,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACxF,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACjG,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;QACjE,OAAO,CAAC,IAAI,CACV,GAAG,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,mBAAmB,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,IAAI,mBAAmB,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC5I,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,QAAiC,EAAE,OAAe,EAAU,EAAE;IAC3F,OAAO,WAAW,kBAAkB,KAAK,OAAO,WAAW,sBAAsB,CAAC,QAAQ,CAAC,GAAG,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,QAAiC,EAAW,EAAE;IACxE,MAAM,SAAS,GAA4B,CAAC,EAAE,CAAC,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AAClE,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,IAAyB,EAAE,IAAY,EAAW,EAAE;IACtE,OAAO,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC;AAClE,CAAC,CAAC;AAEF,kHAAkH;AAClH,sHAAsH;AACtH,qHAAqH;AACrH,oFAAoF;AACpF,MAAM,uBAAuB,GAAG,CAAC,QAAiC,EAAW,EAAE;IAC7E,MAAM,SAAS,GAA4B,CAAC,EAAE,CAAC,CAAC;IAEhD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAC/B,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;aAAM,CAAC;YACN,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,sBAAsB,GAAG,SAAS;SACrC,KAAK,CAAC,CAAC,CAAC;SACR,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/H,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/G,OAAO,sBAAsB,IAAI,aAAa,GAAG,CAAC,CAAC;AACrD,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,YAAoB,EAAW,EAAE;IAC5D,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAE3F,0GAA0G;AAC1G,uHAAuH;AACvH,2GAA2G;AAC3G,MAAM,4BAA4B,GAAG,CAAC,SAAiB,EAAsB,EAAE;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,MAAM,CAAC,gDAAgD,YAAY,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC;IACxH,KAAK,MAAM,QAAQ,IAAI,WAAW,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzE,SAAS;QACX,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC;YACrD,OAAO,UAAU,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAAsB,EAAE;IAC9E,MAAM,cAAc,GAAG,SAAS,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACxD,IAAI,+BAA+B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QACzD,OAAO,cAAc,CAAC,OAAO,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,4BAA4B,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,4BAA4B,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACtH,CAAC,CAAC;AAEF,MAAM,yBAAyB,GAAG,CAAC,SAAiB,EAAW,EAAE;IAC/D,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,SAAS,CAAC,CAAC;IACrE,IAAI,CAAC,mBAAmB,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC7D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,eAAe,GAAG,YAAY,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;IAClE,OAAO,+BAA+B,CAAC,IAAI,CAAC,gCAAgC,CAAC,eAAe,CAAC,CAAC,CAAC;AACjG,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,SAA6B,EAAW,EAAE;IACzF,OAAO,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,6BAA6B,CAAC,SAAS,CAAC,IAAI,CAAC,yBAAyB,CAAC,SAAS,CAAC,CAAC;AAC5G,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,YAAoB,EAAE,OAAe,EAAE,aAAqB,EAAE,kBAA4B,EAAU,EAAE;IAC/H,OAAO,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7B,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAExC,KAAK,MAAM,QAAQ,IAAI,eAAe,EAAE,CAAC;YACvC,IAAI,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACtC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAEpD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;gBAE5H,KAAK,MAAM,mBAAmB,IAAI,oBAAoB,EAAE,CAAC;oBACvD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACjC,qBAAqB,CAAC,OAAO,CAAC,CAAC;oBAC/B,MAAM,CAAC,SAAS,EAAE,GAAG,cAAc,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;oBACxE,2FAA2F;oBAC3F,MAAM,UAAU,GAAG,cAAc,EAAE;yBAChC,OAAO,CAAC,mBAAmB,CAAC;yBAC5B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;oBAC3C,MAAM,CAAC,SAAS,EAAE,GAAG,mBAAmB,CAAC,GAAG,UAAU,CAAC;oBACvD,IAAI,SAAS,IAAI,SAAS,EAAE,CAAC;wBAC3B,SAAS,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;wBACjC,IAAI,QAAQ,GAAG,SAAS,CAAC;wBACzB,KAAK,MAAM,IAAI,IAAI,mBAAmB,EAAE,CAAC;4BACvC,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;4BACpC,QAAQ,GAAG,IAAI,CAAC;wBAClB,CAAC;oBACH,CAAC;oBAED,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;wBAC3C,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;wBACtC,IAAI,QAAQ,EAAE,IAAI,KAAK,YAAY,EAAE,CAAC;4BACpC,QAAQ,CAAC,MAAM,EAAE,CAAC;wBACpB,CAAC;wBACD,aAAa,CAAC,MAAM,EAAE,CAAC;oBACzB,CAAC;oBAED,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBACvC,CAAC;gBACD,QAAQ,CAAC,MAAM,EAAE,CAAC;gBAClB,SAAS;YACX,CAAC;YAED,IAAI,oBAAoB,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC3E,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;YAC7B,MAAM,oBAAoB,GAAG,KAAK,EAAE,IAAI,KAAK,WAAW,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAEvH,IAAI,oBAAoB,EAAE,CAAC;gBACzB,MAAM,oBAAoB,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC;gBAErI,IAAI,CAAC,oBAAoB,EAAE,CAAC;oBAC1B,MAAM,eAAe,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC;oBACzC,MAAM,aAAa,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;oBAClF,eAAe,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;oBAC1C,IAAI,eAAe,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;wBAC/C,eAAe,CAAC,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;oBACnD,CAAC;yBAAM,CAAC;wBACN,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;oBACzC,CAAC;oBACD,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;gBAC/C,CAAC;YACH,CAAC;YAED,MAAM,eAAe,GAAG,cAAc,EAAE,CAAC,OAAO,CAAC,GAAG,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC;YAC7E,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACnF,QAAQ,CAAC,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;YACnC,KAAK,MAAM,UAAU,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC/C,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;QACxC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,MAAM,kBAAkB,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACtD,IAAI,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC1C,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YACxC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,IAAU,EAAE,cAAsB,EAAQ,EAAE;IACtE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE5C,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,EAAE;QAC1B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;YACjF,OAAO;QACT,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,GAAG,cAAc,GAAG,YAAY,EAAE,CAAC;QACtD,SAAS,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;QAC7B,IAAI,CAAC,qCAAqC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChH,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACzB,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC;YACvD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,WAAW,CAAC,KAAK,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAChC,wHAAwH;AACxH,uBAAuB;AACvB,MAAM,qBAAqB,GAAqC;IAC9D,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,EAAE;IACb,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,EAAE;IACV,KAAK,EAAE,EAAE;IACT,SAAS,EAAE,EAAE;IACb,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,EAAE;IACf,OAAO,EAAE,oBAAoB,GAAG,GAAG;IACnC,MAAM,EAAE,oBAAoB,GAAG,GAAG;CACnC,CAAC;AACF,4DAA4D;AAC5D,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC,CAAC;AAC3F,8DAA8D;AAC9D,MAAM,kBAAkB,GAAqC;IAC3D,GAAG,EAAE,oBAAoB,GAAG,GAAG;IAC/B,EAAE,EAAE,EAAE,GAAG,IAAI;IACb,EAAE,EAAE,oBAAoB;IACxB,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE,GAAG,IAAI;IACb,EAAE,EAAE,EAAE;IACN,EAAE,EAAE,EAAE,GAAG,EAAE;IACX,EAAE,EAAE,CAAC;IACL,CAAC,EAAE,EAAE,GAAG,KAAK;IACb,GAAG,EAAE,oBAAoB;CAC1B,CAAC;AAEF,MAAM,cAAc,GAAG,CAAC,IAAY,EAAsB,EAAE;IAC1D,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AACtG,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAa,EAAsB,EAAE;IAClE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;AACrG,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAyB,EAAsB,EAAE;IAC9E,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrB,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,SAAS,CAAC;AACzI,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,KAAa,EAAsB,EAAE;IAC5D,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IACrB,OAAO,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAChI,CAAC,CAAC;AAEF,yHAAyH;AACzH,oHAAoH;AACpH,MAAM,wBAAwB,GAAG,CAAC,KAAa,EAAsB,EAAE;IACrE,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAChD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC;IACxF,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;QACnC,OAAO,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,gGAAgG;AAChG,MAAM,mBAAmB,GAAG,CAAC,QAAiC,EAAW,EAAE;IACzE,IAAI,OAAO,GAA0B,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;QAClC,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC;AACpJ,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,YAAoB,EAAY,EAAE;IACjE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAClC,IAAI,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IAC7B,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAIF,uHAAuH;AACvH,uHAAuH;AACvH,sHAAsH;AACtH,oHAAoH;AACpH,MAAM,kBAAkB,GAAG,CAAC,IAAU,EAAE,IAAW,EAAQ,EAAE;IAC3D,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,MAA+B,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;gBAC1G,MAAM,GAAG,IAAI,CAAC;YAChB,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,uBAAuB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/B,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,wBAAwB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7H,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,IAAI,CACF,MAAM,EACN,+CAA+C,MAAM,CAAC,KAAK,uFAAuF,CACnJ,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpE,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QAChD,QAAQ,CAAC,SAAS,EAAE,CAAC;QACrB,sGAAsG;QACtG,QAAQ,CAAC,MAAM,CAAC;YACd,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,IAAI,EAAE,0BAA0B;YAChC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,IAAU,EAAE,OAAe,EAAE,aAAqB,EAAE,cAAsB,EAAE,IAAW,EAAQ,EAAE;IACxH,kBAAkB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,kBAAkB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;IACzC,MAAM,mBAAmB,GAAG,WAAW,kBAAkB,KAAK,OAAO,WAAW,oBAAoB,KAAK,CAAC;IAC1G,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACtB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;YACvE,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACjG,MAAM,oBAAoB,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YAEtG,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,oBAAoB,CAAC,MAAM,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACzG,MAAM,kBAAkB,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9C,kBAAkB,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;oBAC3C,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;wBACvC,WAAW,CAAC,MAAM,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;gBACH,kBAAkB,CAAC,QAAQ,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;gBAC/H,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;oBACxC,kBAAkB,CAAC,MAAM,EAAE,CAAC;gBAC9B,CAAC;gBACD,IAAI,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;oBAC7B,IAAI,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;wBACtC,WAAW,CAAC,MAAM,EAAE,CAAC;oBACvB,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;YAED,MAAM,4BAA4B,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;YACvI,MAAM,kBAAkB,GAAG,4BAA4B,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACpH,IAAI,CAAC,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC;YAC7F,4DAA4D;YAC5D,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC1B,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,sHAAsH;AACtH,qHAAqH;AACrH,uHAAuH;AACvH,wHAAwH;AACxH,uHAAuH;AACvH,iHAAiH;AACjH,gDAAgD;AAChD,MAAM,yBAAyB,GAAG,CAAC,IAAU,EAAE,cAAsB,EAAQ,EAAE;IAC7E,kBAAkB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAAE,OAAO,EAA0B,EAAU,EAAE;IAC5E,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,WAAW,YAAY,IAAI,CAAC;IAEnD,OAAO;QACL,aAAa,EAAE,qBAAqB,YAAY,EAAE;QAClD,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE;YACnB,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9G,CAAC;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,EAAE,OAAO,EAA0B,EAAU,EAAE;IACnF,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,kBAAkB,CAAC,YAAY,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,WAAW,YAAY,IAAI,CAAC;IAEnD,OAAO;QACL,aAAa,EAAE,6BAA6B,YAAY,EAAE;QAC1D,IAAI,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE;YACnB,IAAI,gCAAgC,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,yBAAyB,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YAED,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9G,CAAC;KACF,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { basename, dirname, join } from 'node:path';\nimport type { Declaration, Plugin, Root, Rule } from 'postcss';\nimport selectorParser from 'postcss-selector-parser';\nimport valueParser from 'postcss-value-parser';\nimport { getMfScopeSelector, MF_ROOT_SELECTOR, MF_SCOPE_ATTRIBUTE, validateMfScopeId } from './index.js';\nimport { MF_ROOT_FONT_SIZE_PROPERTY } from './root-font-size.js';\n\nexport interface IScopeRemoteCssOptions {\n scopeId: string;\n}\n\nconst ANGULAR_COMPONENT_STYLE_PATTERN = /\\.component\\.(?:css|less|sass|scss)$/i;\nconst VIEW_ENCAPSULATION_NONE_PATTERN = /(?:^|[,{])\\s*encapsulation\\s*:\\s*(?:[A-Za-z_$][\\w$]*\\s*\\.\\s*)+None\\b/m;\nconst MF_OVERLAY_ATTRIBUTE = 'data-edyn-mf-overlay';\n\ntype TTypeScriptMaskState = 'block-comment' | 'code' | 'double-quote' | 'line-comment' | 'single-quote' | 'template';\n\nconst maskTypeScriptCommentsAndStrings = (source: string): string => {\n let maskedSource = '';\n let state: TTypeScriptMaskState = 'code';\n let escaped = false;\n\n const maskCharacter = (character: string): string => {\n return character === '\\n' || character === '\\r' ? character : ' ';\n };\n\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index] ?? '';\n const nextCharacter = source[index + 1];\n\n if (state === 'code') {\n if (character === '/' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'line-comment';\n } else if (character === '/' && nextCharacter === '*') {\n maskedSource += ' ';\n index += 1;\n state = 'block-comment';\n } else if (character === \"'\") {\n maskedSource += ' ';\n state = 'single-quote';\n } else if (character === '\"') {\n maskedSource += ' ';\n state = 'double-quote';\n } else if (character === '`') {\n maskedSource += ' ';\n state = 'template';\n } else {\n maskedSource += character;\n }\n continue;\n }\n\n if (state === 'line-comment') {\n maskedSource += maskCharacter(character);\n if (character === '\\n' || character === '\\r') {\n state = 'code';\n }\n continue;\n }\n\n if (state === 'block-comment') {\n if (character === '*' && nextCharacter === '/') {\n maskedSource += ' ';\n index += 1;\n state = 'code';\n } else {\n maskedSource += maskCharacter(character);\n }\n continue;\n }\n\n maskedSource += maskCharacter(character);\n if (escaped) {\n escaped = false;\n } else if (character === '\\\\') {\n escaped = true;\n } else if (\n (state === 'single-quote' && character === \"'\") ||\n (state === 'double-quote' && character === '\"') ||\n (state === 'template' && character === '`')\n ) {\n state = 'code';\n }\n }\n\n return maskedSource;\n};\n\nconst isKeyframesRule = (rule: Rule): boolean => {\n const parent = rule.parent;\n return parent?.type === 'atrule' && /keyframes$/i.test(parent.name);\n};\n\nconst isRootNode = (node: selectorParser.Node): boolean => {\n return (\n (node.type === 'tag' && (node.value.toLowerCase() === 'html' || node.value.toLowerCase() === 'body')) ||\n (node.type === 'pseudo' && (node.value === ':root' || node.value === MF_ROOT_SELECTOR))\n );\n};\n\nconst isScopeNode = (node: selectorParser.Node | undefined, scopeId: string): boolean => {\n if (node?.type === 'attribute' && node.attribute === MF_SCOPE_ATTRIBUTE && node.operator === '=' && node.value === scopeId) {\n return true;\n }\n\n const normalized = node?.toString().replaceAll('\"', '').replaceAll(\"'\", '');\n return (\n node?.type === 'pseudo' &&\n (normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}])` ||\n normalized === `:where([${MF_SCOPE_ATTRIBUTE}=${scopeId}]:not([${MF_OVERLAY_ATTRIBUTE}]))`)\n );\n};\n\nconst startsWithHostPseudo = (selector: selectorParser.Selector): boolean => {\n return selector.first?.type === 'pseudo' && selector.first.value === ':host';\n};\n\nconst removeRootIdentityIds = (selector: selectorParser.Selector): void => {\n let compound: selectorParser.Node[] = [];\n const removeIdsFromRootCompound = (): void => {\n if (compound.some(isRootNode)) {\n for (const node of compound) {\n if (node.type === 'id') {\n node.remove();\n }\n }\n }\n };\n\n for (const node of [...selector.nodes]) {\n if (node.type === 'combinator') {\n removeIdsFromRootCompound();\n compound = [];\n } else {\n compound.push(node);\n }\n }\n removeIdsFromRootCompound();\n};\n\nconst SPECIFICITY_CARRIER = 'edyn-mf-root';\n\n// Legacy rules such as `html body button` or `html body#app .mdc-checkbox__background` are weighed against Angular\n// Material's own rules by the html, body and #app they start from, so the scope that replaces that root must weigh\n// exactly the same. A plain scope attribute (0,1,0) drops the id of `body#app`, letting Material's checked colour win,\n// and outweighs the two types of `html body`, letting an override that lost to `.mat-mdc-button` on the old site win\n// hosted. The root becomes :where(<scope>):not(<carrier>): :where() weighs nothing, and the carrier has the same id,\n// class and type counts as the root part it replaces and never matches the scope element, so :not() always matches and\n// weighs exactly that. Neutral names keep `html`, `body` and `#app` out of the emitted CSS.\nconst rootSpecificityCarrier = (selector: selectorParser.Selector): string => {\n const compounds: selectorParser.Node[][] = [[]];\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const carrier: string[] = [];\n for (const compound of compounds) {\n if (!compound.some(isRootNode)) {\n continue;\n }\n const types = compound.filter((node) => node.type === 'tag' && isRootNode(node)).length;\n const pseudoRoots = compound.filter((node) => node.type === 'pseudo' && isRootNode(node)).length;\n const ids = compound.filter((node) => node.type === 'id').length;\n carrier.push(\n `${SPECIFICITY_CARRIER.repeat(Math.min(types, 1))}${`.${SPECIFICITY_CARRIER}`.repeat(pseudoRoots)}${`#${SPECIFICITY_CARRIER}`.repeat(ids)}`,\n );\n }\n\n return carrier.filter(Boolean).join(' ');\n};\n\nconst rootedDescendantScope = (selector: selectorParser.Selector, scopeId: string): string => {\n return `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]):not(${rootSpecificityCarrier(selector)})`;\n};\n\nconst isRootOnlySelector = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n return compounds.every((compound) => compound.some(isRootNode));\n};\n\nconst isTagNamed = (node: selectorParser.Node, name: string): boolean => {\n return node.type === 'tag' && node.value.toLowerCase() === name;\n};\n\n// The module's own page had one <html> and one <body>, so a selector that needs a second one never matched there:\n// `html body html body .x`, which a global partial compiles to when it is loaded inside `html body {}`, or `.x html`.\n// Scoping replaces the first root with the module boundary and drops the others, which made such a rule match hosted\n// (AutoCleanse's datepicker cells turned blue), so the selector is dropped instead.\nconst needsSecondDocumentRoot = (selector: selectorParser.Selector): boolean => {\n const compounds: selectorParser.Node[][] = [[]];\n\n for (const node of selector.nodes) {\n if (node.type === 'combinator') {\n compounds.push([]);\n } else {\n compounds.at(-1)?.push(node);\n }\n }\n\n const documentRootAfterFirst = compounds\n .slice(1)\n .some((compound) => compound.some((node) => isTagNamed(node, 'html') || (node.type === 'pseudo' && node.value === ':root')));\n const bodyCompounds = compounds.filter((compound) => compound.some((node) => isTagNamed(node, 'body'))).length;\n return documentRootAfterFirst || bodyCompounds > 1;\n};\n\nconst hasRootOnlySelector = (selectorList: string): boolean => {\n let result = false;\n selectorParser((root) => {\n result = root.nodes.some(isRootOnlySelector);\n }).processSync(selectorList);\n return result;\n};\n\nconst escapeRegExp = (text: string): string => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n// A component stylesheet need not be named *.component.scss (CampaignManagement's create-campaign.ts uses\n// `styleUrl: './create-campaign.scss'`); treated as global CSS, Angular would then encapsulate the boundary itself and\n// the rules could never match. Such a file is a component's when a sibling component source references it.\nconst referencingComponentSourceOf = (stylePath: string): string | undefined => {\n const directory = dirname(stylePath);\n if (!existsSync(directory)) {\n return undefined;\n }\n const reference = new RegExp(`styleUrls?\\\\s*:\\\\s*(?:\\\\[[^\\\\]]*?)?['\"\\`]\\\\./${escapeRegExp(basename(stylePath))}['\"\\`]`);\n for (const fileName of readdirSync(directory)) {\n if (!fileName.endsWith('.ts') || /\\.(?:spec|test|d)\\.ts$/.test(fileName)) {\n continue;\n }\n const sourcePath = join(directory, fileName);\n if (reference.test(readFileSync(sourcePath, 'utf8'))) {\n return sourcePath;\n }\n }\n return undefined;\n};\n\nconst getAngularComponentSourcePath = (stylePath: string): string | undefined => {\n const cleanStylePath = stylePath.replace(/[?#].*$/, '');\n if (ANGULAR_COMPONENT_STYLE_PATTERN.test(cleanStylePath)) {\n return cleanStylePath.replace(/\\.(?:css|less|sass|scss)$/i, '.ts');\n }\n return /\\.(?:css|less|sass|scss)$/i.test(cleanStylePath) ? referencingComponentSourceOf(cleanStylePath) : undefined;\n};\n\nconst usesViewEncapsulationNone = (stylePath: string): boolean => {\n const componentSourcePath = getAngularComponentSourcePath(stylePath);\n if (!componentSourcePath || !existsSync(componentSourcePath)) {\n return false;\n }\n\n const componentSource = readFileSync(componentSourcePath, 'utf8');\n return VIEW_ENCAPSULATION_NONE_PATTERN.test(maskTypeScriptCommentsAndStrings(componentSource));\n};\n\nexport const shouldUseAngularComponentScoping = (stylePath: string | undefined): boolean => {\n return !!stylePath && !!getAngularComponentSourcePath(stylePath) && !usesViewEncapsulationNone(stylePath);\n};\n\nconst scopeSelectorList = (selectorList: string, scopeId: string, scopeSelector: string, rootScopeSelectors: string[]): string => {\n return selectorParser((root) => {\n const sourceSelectors = [...root.nodes];\n\n for (const selector of sourceSelectors) {\n if (needsSecondDocumentRoot(selector)) {\n selector.remove();\n continue;\n }\n\n const rootNodes = selector.nodes.filter(isRootNode);\n\n if (rootNodes.length > 0) {\n const replacementSelectors = isRootOnlySelector(selector) ? rootScopeSelectors : [rootedDescendantScope(selector, scopeId)];\n\n for (const replacementSelector of replacementSelectors) {\n const variant = selector.clone();\n removeRootIdentityIds(variant);\n const [firstRoot, ...duplicateRoots] = variant.nodes.filter(isRootNode);\n // The replacement can be a compound of several nodes, e.g. :where(<scope>):not(<carrier>).\n const scopeNodes = selectorParser()\n .astSync(replacementSelector)\n .first.nodes.map((node) => node.clone());\n const [scopeNode, ...followingScopeNodes] = scopeNodes;\n if (firstRoot && scopeNode) {\n firstRoot.replaceWith(scopeNode);\n let previous = scopeNode;\n for (const node of followingScopeNodes) {\n variant.insertAfter(previous, node);\n previous = node;\n }\n }\n\n for (const duplicateRoot of duplicateRoots) {\n const previous = duplicateRoot.prev();\n if (previous?.type === 'combinator') {\n previous.remove();\n }\n duplicateRoot.remove();\n }\n\n root.insertBefore(selector, variant);\n }\n selector.remove();\n continue;\n }\n\n if (startsWithHostPseudo(selector) || isScopeNode(selector.first, scopeId)) {\n continue;\n }\n\n const first = selector.first;\n const needsBoundaryVariant = first?.type === 'universal' || (first?.type === 'pseudo' && first.value.startsWith('::'));\n\n if (needsBoundaryVariant) {\n const hasSiblingCombinator = selector.nodes.some((node) => node.type === 'combinator' && (node.value === '+' || node.value === '~'));\n\n if (!hasSiblingCombinator) {\n const boundaryVariant = selector.clone();\n const boundaryScope = selectorParser().astSync(scopeSelector).first.first.clone();\n boundaryVariant.first.rawSpaceBefore = '';\n if (boundaryVariant.first.type === 'universal') {\n boundaryVariant.first.replaceWith(boundaryScope);\n } else {\n boundaryVariant.prepend(boundaryScope);\n }\n root.insertBefore(selector, boundaryVariant);\n }\n }\n\n const descendantScope = selectorParser().astSync(`${scopeSelector} *`).first;\n const prefixNodes = descendantScope.nodes.slice(0, -1).map((node) => node.clone());\n selector.first.rawSpaceBefore = '';\n for (const prefixNode of prefixNodes.reverse()) {\n selector.prepend(prefixNode);\n }\n }\n\n const seenSelectors = new Set<string>();\n for (const selector of [...root.nodes]) {\n const normalizedSelector = selector.toString().trim();\n if (seenSelectors.has(normalizedSelector)) {\n selector.remove();\n } else {\n seenSelectors.add(normalizedSelector);\n }\n }\n }).processSync(selectorList);\n};\n\nconst namespaceKeyframes = (root: Root, keyframePrefix: string): void => {\n const keyframes = new Map<string, string>();\n\n root.walkAtRules((atRule) => {\n if (!/keyframes$/i.test(atRule.name) || atRule.params.startsWith(keyframePrefix)) {\n return;\n }\n\n const originalName = atRule.params.trim();\n const scopedName = `${keyframePrefix}${originalName}`;\n keyframes.set(originalName, scopedName);\n atRule.params = scopedName;\n });\n\n root.walkDecls((declaration) => {\n if (!/^(?:-webkit-)?animation(?:-name)?$/i.test(declaration.prop) && !declaration.prop.startsWith('--animate-')) {\n return;\n }\n\n const parsed = valueParser(declaration.value);\n parsed.walk((node) => {\n if (node.type === 'word') {\n node.value = keyframes.get(node.value) ?? node.value;\n }\n });\n declaration.value = parsed.toString();\n });\n};\n\nconst INITIAL_FONT_SIZE_PX = 16;\n// Absolute-size keywords as browsers compute them, and the relative ones as they resolve on the root, whose parent size\n// is the initial 16px.\nconst FONT_SIZE_KEYWORDS_PX: Readonly<Record<string, number>> = {\n 'xx-small': 9,\n 'x-small': 10,\n small: 13,\n medium: 16,\n large: 18,\n 'x-large': 24,\n 'xx-large': 32,\n 'xxx-large': 48,\n smaller: INITIAL_FONT_SIZE_PX / 1.2,\n larger: INITIAL_FONT_SIZE_PX * 1.2,\n};\n// On the root, every global keyword gives the initial size.\nconst GLOBAL_KEYWORDS = new Set(['inherit', 'initial', 'revert', 'revert-layer', 'unset']);\n// em, rem and % on the root are relative to the initial size.\nconst FONT_SIZE_UNITS_PX: Readonly<Record<string, number>> = {\n '%': INITIAL_FONT_SIZE_PX / 100,\n cm: 96 / 2.54,\n em: INITIAL_FONT_SIZE_PX,\n in: 96,\n mm: 96 / 25.4,\n pc: 16,\n pt: 96 / 72,\n px: 1,\n q: 96 / 101.6,\n rem: INITIAL_FONT_SIZE_PX,\n};\n\nconst fontSizeOfWord = (word: string): number | undefined => {\n const keyword = FONT_SIZE_KEYWORDS_PX[word.toLowerCase()];\n if (keyword !== undefined) {\n return keyword;\n }\n const dimension = valueParser.unit(word);\n const unitPx = dimension ? FONT_SIZE_UNITS_PX[dimension.unit.toLowerCase()] : undefined;\n const amount = Number(dimension ? dimension.number : Number.NaN);\n return unitPx !== undefined && Number.isFinite(amount) && amount >= 0 ? amount * unitPx : undefined;\n};\n\nconst significantValueNodes = (value: string): valueParser.Node[] => {\n return valueParser(value).nodes.filter((node) => node.type !== 'space' && node.type !== 'comment');\n};\n\nconst globalKeywordFontSize = (nodes: valueParser.Node[]): number | undefined => {\n const [only] = nodes;\n return nodes.length === 1 && only?.type === 'word' && GLOBAL_KEYWORDS.has(only.value.toLowerCase()) ? INITIAL_FONT_SIZE_PX : undefined;\n};\n\nconst resolveFontSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const [only] = nodes;\n return globalKeywordFontSize(nodes) ?? (nodes.length === 1 && only?.type === 'word' ? fontSizeOfWord(only.value) : undefined);\n};\n\n// `font: [style] [variant] [weight] [stretch] <size>[/<line-height>] <family>`: the size is the word before `/`, or else\n// the first word that is a size. A function (var(), calc()) or a family name reached first means it cannot be read.\nconst resolveFontShorthandSize = (value: string): number | undefined => {\n const nodes = significantValueNodes(value);\n const globalSize = globalKeywordFontSize(nodes);\n if (globalSize !== undefined) {\n return globalSize;\n }\n\n const slashIndex = nodes.findIndex((node) => node.type === 'div' && node.value === '/');\n if (slashIndex > 0) {\n const size = nodes[slashIndex - 1];\n return size?.type === 'word' ? fontSizeOfWord(size.value) : undefined;\n }\n\n for (const node of nodes) {\n if (node.type !== 'word') {\n return undefined;\n }\n const size = fontSizeOfWord(node.value);\n if (size !== undefined) {\n return size;\n }\n }\n return undefined;\n};\n\n// `html` and `:root` size the document root, so rem; `body` and `html body` size only the body.\nconst targetsDocumentRoot = (selector: selectorParser.Selector): boolean => {\n let subject: selectorParser.Node[] = [];\n for (const node of selector.nodes) {\n subject = node.type === 'combinator' ? [] : [...subject, node];\n }\n return subject.some((node) => (node.type === 'tag' && node.value.toLowerCase() === 'html') || (node.type === 'pseudo' && node.value === ':root'));\n};\n\nconst documentRootSelectorsOf = (selectorList: string): string[] => {\n const selectors: string[] = [];\n selectorParser((root) => {\n for (const selector of root.nodes) {\n if (targetsDocumentRoot(selector) && !needsSecondDocumentRoot(selector)) {\n selectors.push(selector.toString().trim());\n }\n }\n }).processSync(selectorList);\n return selectors;\n};\n\ntype TWarn = (node: Declaration, text: string) => void;\n\n// Hosted, rem resolves against the host page's root, not the root size the module's own page set. Each rule that sizes\n// the document root gets a sibling rule right after it that records that size as MF_ROOT_FONT_SIZE_PROPERTY, under the\n// same conditions (@media, importance) and in the same cascade order; scoping then moves it onto the module boundary,\n// where followModuleRootFontSize() makes rem lengths read it. CSS that never sizes the root is left byte-identical.\nconst recordRootFontSize = (root: Root, warn: TWarn): void => {\n root.walkRules((rule) => {\n if (isKeyframesRule(rule)) {\n return;\n }\n\n let sizing: Declaration | undefined;\n for (const node of rule.nodes) {\n if (node.type === 'decl' && /^font(?:-size)?$/i.test(node.prop) && (node.important || !sizing?.important)) {\n sizing = node;\n }\n }\n if (!sizing) {\n return;\n }\n\n const rootSelectors = documentRootSelectorsOf(rule.selector);\n if (rootSelectors.length === 0) {\n return;\n }\n\n const sizePx = sizing.prop.toLowerCase() === 'font' ? resolveFontShorthandSize(sizing.value) : resolveFontSize(sizing.value);\n if (sizePx === undefined) {\n warn(\n sizing,\n `Cannot resolve the document root font size \"${sizing.value}\" at build time; rem lengths in the hosted module will use the host page's root size.`,\n );\n return;\n }\n\n const recorded = rule.clone({ selector: rootSelectors.join(', ') });\n recorded.raws.before = rule.raws.before || '\\n';\n recorded.removeAll();\n // The recorded size points back at the declaration it came from, so source maps keep a source for it.\n recorded.append({\n important: sizing.important,\n prop: MF_ROOT_FONT_SIZE_PROPERTY,\n source: sizing.source,\n value: `${Number(sizePx.toFixed(4))}px`,\n });\n rule.after(recorded);\n });\n};\n\nconst scopeGlobalRoot = (root: Root, scopeId: string, scopeSelector: string, keyframePrefix: string, warn: TWarn): void => {\n recordRootFontSize(root, warn);\n namespaceKeyframes(root, keyframePrefix);\n const contentRootSelector = `:where([${MF_SCOPE_ATTRIBUTE}=\"${scopeId}\"]:not([${MF_OVERLAY_ATTRIBUTE}]))`;\n root.walkRules((rule) => {\n if (!isKeyframesRule(rule)) {\n const declarations = rule.nodes.filter((node) => node.type === 'decl');\n const customProperties = declarations.filter((declaration) => declaration.prop.startsWith('--'));\n const standardDeclarations = declarations.filter((declaration) => !declaration.prop.startsWith('--'));\n\n if (customProperties.length > 0 && standardDeclarations.length > 0 && hasRootOnlySelector(rule.selector)) {\n const customPropertyRule = rule.cloneBefore();\n customPropertyRule.walkDecls((declaration) => {\n if (!declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n customPropertyRule.selector = scopeSelectorList(customPropertyRule.selector, scopeId, scopeSelector, [':host', scopeSelector]);\n if (!customPropertyRule.selector.trim()) {\n customPropertyRule.remove();\n }\n rule.walkDecls((declaration) => {\n if (declaration.prop.startsWith('--')) {\n declaration.remove();\n }\n });\n }\n\n const containsOnlyCustomProperties = declarations.length > 0 && declarations.every((declaration) => declaration.prop.startsWith('--'));\n const rootScopeSelectors = containsOnlyCustomProperties ? [':host', scopeSelector] : [':host', contentRootSelector];\n rule.selector = scopeSelectorList(rule.selector, scopeId, scopeSelector, rootScopeSelectors);\n // Every selector of the rule needed a second document root.\n if (!rule.selector.trim()) {\n rule.remove();\n }\n }\n });\n};\n\n// Emulated component CSS keeps its selectors exactly as written, so Angular compiles what it compiled on the module's\n// own page and every rule keeps its weight and reach: `mat-form-field[_ngcontent-x]` (0,1,1) still loses to a global\n// `.mat-sidenav-content .mat-mdc-form-field` (0,2,0), template content rendered in an overlay (outside the component's\n// host) keeps its component styles, and a top-level `::ng-deep` rule stays global to the module. Wrapping every rule in\n// :host-context(<boundary>) added (0,2,0) to each, and limited all of them to the component's host. Isolation needs no\n// boundary here: Angular's _ngcontent and _nghost attributes are unique to each component, and a hosted module's\n// component styles live in its own shadow root.\nconst scopeAngularComponentRoot = (root: Root, keyframePrefix: string): void => {\n namespaceKeyframes(root, keyframePrefix);\n};\n\nexport const scopeRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-isolation-${validScopeId}`,\n Once(root, { result }) {\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n\nexport const scopeAngularRemoteCss = ({ scopeId }: IScopeRemoteCssOptions): Plugin => {\n const validScopeId = validateMfScopeId(scopeId);\n const scopeSelector = getMfScopeSelector(validScopeId);\n const keyframePrefix = `edyn-mf-${validScopeId}--`;\n\n return {\n postcssPlugin: `edyn-mf-angular-isolation-${validScopeId}`,\n Once(root, { result }) {\n if (shouldUseAngularComponentScoping(root.source?.input.file)) {\n scopeAngularComponentRoot(root, keyframePrefix);\n return;\n }\n\n scopeGlobalRoot(root, validScopeId, scopeSelector, keyframePrefix, (node, text) => node.warn(result, text));\n },\n };\n};\n"]}
|