@ethisyscore/vite-plugin 1.59.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +349 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +157 -2
- package/dist/index.d.ts +157 -2
- package/dist/index.js +340 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -312,8 +312,29 @@ interface PlatformReactPluginOptions {
|
|
|
312
312
|
* (see `PlatformReactSurfaceMount.tsx` in `coreconnect-web`). This pass only
|
|
313
313
|
* blocks remote/absolute paths at the manifest layer so a malformed manifest
|
|
314
314
|
* fails fast.
|
|
315
|
+
*
|
|
316
|
+
* Returns an ARRAY: this pass plus the plugin-CSS scoping pass it must always be
|
|
317
|
+
* paired with. Vite flattens nested plugin arrays (`PluginOption` is recursively
|
|
318
|
+
* `PluginOption[]`), so existing call sites
|
|
319
|
+
* (`plugins: [react(), tailwindcss(), ethisysPlatformReactPlugin()]`) are unaffected.
|
|
320
|
+
*
|
|
321
|
+
* The pairing CANNOT be done by returning `{ plugins: [...] }` from this pass's own
|
|
322
|
+
* `config()` hook: Vite resolves the plugin container before running config hooks, so
|
|
323
|
+
* a plugin injected there is dropped SILENTLY (no warning, build still green) and the
|
|
324
|
+
* scoping pass would never run. Anything needing the page pass on its own as a single
|
|
325
|
+
* `Plugin` should call `ethisysPlatformReactPagesPlugin` and compose the scoping pass
|
|
326
|
+
* itself.
|
|
327
|
+
*/
|
|
328
|
+
declare function ethisysPlatformReactPlugin(options?: PlatformReactPluginOptions): Plugin[];
|
|
329
|
+
/**
|
|
330
|
+
* The PlatformReact page-bundle pass ALONE, as a single `Plugin`.
|
|
331
|
+
*
|
|
332
|
+
* Prefer {@link ethisysPlatformReactPlugin}, which pairs this with the plugin-CSS
|
|
333
|
+
* scoping pass. Reach for this only when composing the passes by hand (a plugin with
|
|
334
|
+
* its own scoping step, or a test that drives one pass's hooks directly) — used on its
|
|
335
|
+
* own it emits UNSCOPED CSS, which leaks into the host document.
|
|
315
336
|
*/
|
|
316
|
-
declare function
|
|
337
|
+
declare function ethisysPlatformReactPagesPlugin(options?: PlatformReactPluginOptions): Plugin;
|
|
317
338
|
|
|
318
339
|
/**
|
|
319
340
|
* A fully-validated PlatformReact page declaration. All fields are guaranteed
|
|
@@ -534,6 +555,140 @@ declare function virtualPageEntry(page: PlatformReactPageInput, config: {
|
|
|
534
555
|
*/
|
|
535
556
|
declare function buildPlatformReactPages(options?: BuildPlatformReactPagesOptions): Promise<PlatformReactBuildSummary>;
|
|
536
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Scope selector prefixed onto plugin-global CSS layers.
|
|
560
|
+
*
|
|
561
|
+
* `:where()` NOT `:is()` on purpose: `:where()` contributes ZERO specificity, so a
|
|
562
|
+
* scoped utility keeps exactly the specificity it had unscoped. Inside a plugin
|
|
563
|
+
* surface the cascade therefore behaves identically to before this transform; the
|
|
564
|
+
* only change is that the rule no longer matches host chrome. `:is()` would have
|
|
565
|
+
* raised every utility by one class and could flip a plugin's own conflicts.
|
|
566
|
+
*
|
|
567
|
+
* Two scope roots: the plugin root applied by `definePlatformReactPluginPage`, and
|
|
568
|
+
* the portal container marker, because MUI overlays render into a portal. Phase 1
|
|
569
|
+
* (`PluginPortalScope`) puts that container INSIDE the plugin root, so the second
|
|
570
|
+
* arm is redundant for SDK-managed overlays and exists for a plugin that supplies
|
|
571
|
+
* its own container element and marks it.
|
|
572
|
+
*/
|
|
573
|
+
declare const EHX_PLUGIN_CSS_SCOPE = ":where(.ehx-plugin-root, [data-ehx-plugin-portal])";
|
|
574
|
+
/**
|
|
575
|
+
* Replacement for a document-root selector (`:root`, `:host`) in a plugin sheet.
|
|
576
|
+
*
|
|
577
|
+
* Tailwind's `theme` layer declares its scale as custom properties on
|
|
578
|
+
* `:root, :host` — `--spacing`, `--text-sm--line-height`, `--ease-*`,
|
|
579
|
+
* `--animate-*`. Injected into the host document that lands on the HOST root and
|
|
580
|
+
* silently redefines the host's own Tailwind scale for every element on the page:
|
|
581
|
+
* the same defect as the leaking utilities, one level deeper and inherited.
|
|
582
|
+
*
|
|
583
|
+
* These declarations cannot simply be dropped — the plugin's utilities read them —
|
|
584
|
+
* and prefixing is meaningless (`:where(.ehx-plugin-root) :root` matches nothing).
|
|
585
|
+
* They are REPLACED with the plugin root, which the whole surface inherits from.
|
|
586
|
+
*
|
|
587
|
+
* `:is()` here, not `:where()`: this is a substitution for a 0,1,0 selector, so
|
|
588
|
+
* matching that specificity is the faithful choice (a prefix is what must stay
|
|
589
|
+
* specificity-neutral). Note this only works because portal containment landed
|
|
590
|
+
* first — before that, overlays rendered outside the plugin root and would have
|
|
591
|
+
* lost the whole theme scale.
|
|
592
|
+
*/
|
|
593
|
+
declare const EHX_PLUGIN_ROOT_SCOPE = ":is(.ehx-plugin-root, [data-ehx-plugin-portal])";
|
|
594
|
+
/**
|
|
595
|
+
* Cascade layers whose rules a plugin emits UNSCOPED and which therefore leak into
|
|
596
|
+
* the host document.
|
|
597
|
+
*
|
|
598
|
+
* utilities Tailwind's generated utility classes. The leak that motivated this:
|
|
599
|
+
* a plugin's bare `.text-sm` is a duplicate of the host's own rule,
|
|
600
|
+
* so it changes nothing until the host settles a specificity tie by
|
|
601
|
+
* source order — then the plugin's copy, injected later, wins and
|
|
602
|
+
* silently restyles host chrome.
|
|
603
|
+
* properties Tailwind's `@property` fallback block, which sets ~40 `--tw-*`
|
|
604
|
+
* custom properties on `*, :before, :after, ::backdrop` for the whole
|
|
605
|
+
* document.
|
|
606
|
+
*
|
|
607
|
+
* The other layers are already scoped: `theme` holds custom properties on the
|
|
608
|
+
* plugin's own root class, and `base`/`components`/`mui` come from the SDK's
|
|
609
|
+
* `plugin-base.css`, which scopes everything to `.ehx-plugin-root`.
|
|
610
|
+
*/
|
|
611
|
+
declare const EHX_SCOPED_CSS_LAYERS: readonly string[];
|
|
612
|
+
/**
|
|
613
|
+
* What counts as "scoped to a plugin" — the convention every plugin front-end
|
|
614
|
+
* adheres to, and the only thing the build guard needs to know.
|
|
615
|
+
*
|
|
616
|
+
* .ehx-plugin-root applied to every surface by the SDK page definer
|
|
617
|
+
* .ethisys-<name>-root the plugin's own root class (all plugins use this
|
|
618
|
+
* shape: ethisys-sales-root, ethisys-hr-root, …)
|
|
619
|
+
* [data-ehx-plugin-portal] the portal container overlays render into
|
|
620
|
+
* :where(…) of the above what {@link scopePluginCss} emits
|
|
621
|
+
*
|
|
622
|
+
* A selector that mentions NONE of these can match host chrome, which is the whole
|
|
623
|
+
* defect class. Matching anywhere in the selector (not just leftmost) is deliberate:
|
|
624
|
+
* `:where(.dark) .ethisys-sales-root` is scoped even though the root is not first.
|
|
625
|
+
*/
|
|
626
|
+
declare const EHX_PLUGIN_SCOPE_ROOTS: readonly RegExp[];
|
|
627
|
+
interface ScopePluginCssOptions {
|
|
628
|
+
/** Descendant scope prefix. Default {@link EHX_PLUGIN_CSS_SCOPE}. */
|
|
629
|
+
scope?: string;
|
|
630
|
+
/** Replacement for `:root`/`:host`. Default {@link EHX_PLUGIN_ROOT_SCOPE}. */
|
|
631
|
+
rootScope?: string;
|
|
632
|
+
/** Layer names to scope. Default {@link EHX_SCOPED_CSS_LAYERS}. */
|
|
633
|
+
layers?: readonly string[];
|
|
634
|
+
/** What counts as scoped for the guard. Default {@link EHX_PLUGIN_SCOPE_ROOTS}. */
|
|
635
|
+
scopeRoots?: readonly RegExp[];
|
|
636
|
+
/**
|
|
637
|
+
* Guard behaviour when a selector would leak into the host document:
|
|
638
|
+
* `"error"` (default) fails the build, `"warn"` logs, `"off"` skips the check.
|
|
639
|
+
* Only reach for anything but `"error"` as a deliberate, time-boxed exception.
|
|
640
|
+
*/
|
|
641
|
+
guard?: "error" | "warn" | "off";
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Prefix every selector inside a plugin's UNSCOPED cascade layers with the plugin
|
|
645
|
+
* scope, so injecting the sheet into the host document cannot restyle host chrome.
|
|
646
|
+
*
|
|
647
|
+
* Pure and idempotent — running it twice is a no-op, so a rebuild or a second pass
|
|
648
|
+
* over already-scoped CSS is safe. See {@link EHX_SCOPED_CSS_LAYERS} for which
|
|
649
|
+
* layers are rewritten and why the others need no treatment.
|
|
650
|
+
*/
|
|
651
|
+
declare function scopePluginCss(css: string, options?: ScopePluginCssOptions): string;
|
|
652
|
+
/**
|
|
653
|
+
* Every selector in `css` that mentions no plugin scope root, i.e. every selector
|
|
654
|
+
* that can reach host chrome once the sheet is injected into the host document.
|
|
655
|
+
*
|
|
656
|
+
* The invariant this checks is the whole convention: **a plugin never emits an
|
|
657
|
+
* unscoped selector.** {@link scopePluginCss} satisfies it automatically for the
|
|
658
|
+
* layers Tailwind generates; everything else is authored, and this is what catches
|
|
659
|
+
* an author (or a stray `@import "tailwindcss"` re-emitting global preflight) who
|
|
660
|
+
* did not. Pure, so a plugin's own build script or test can call it directly.
|
|
661
|
+
*/
|
|
662
|
+
declare function findUnscopedSelectors(css: string, options?: Pick<ScopePluginCssOptions, "scopeRoots">): string[];
|
|
663
|
+
/** The build-failure message: what leaked, why it matters, and the usual cause. */
|
|
664
|
+
declare function formatUnscopedSelectorError(id: string, leaks: readonly string[]): string;
|
|
665
|
+
/** True for ids whose transform payload is plain CSS text we may rewrite. */
|
|
666
|
+
declare function isScopableCssId(id: string): boolean;
|
|
667
|
+
/**
|
|
668
|
+
* Vite plugin form of {@link scopePluginCss} PLUS the guard that makes it a
|
|
669
|
+
* convention rather than a courtesy, injected into every PlatformReact page
|
|
670
|
+
* sub-build by `buildPlatformReactPages`.
|
|
671
|
+
*
|
|
672
|
+
* Scoping Tailwind's generated layers is automatic; the guard fails the build if
|
|
673
|
+
* anything ELSE in the sheet is still unscoped (see
|
|
674
|
+
* {@link findUnscopedSelectors}). Together they are the enforceable form of one
|
|
675
|
+
* rule: a plugin never emits an unscoped selector into the host document. Prose in
|
|
676
|
+
* a standards doc did not hold across seven repos — the leak that prompted this
|
|
677
|
+
* shipped seven times, and the documented no-preflight rule was violated once
|
|
678
|
+
* without anyone noticing.
|
|
679
|
+
*
|
|
680
|
+
* Deliberately declares NO `enforce`. Vite resolves plugins in the order
|
|
681
|
+
* `[…prePlugins, vite:css, …normalPlugins, vite:css-post, …postPlugins]`, so a
|
|
682
|
+
* plugin with no `enforce` is the only position that sees compiled CSS:
|
|
683
|
+
*
|
|
684
|
+
* - `@tailwindcss/vite` is `enforce: "pre"` and returns the generated sheet, so
|
|
685
|
+
* the utilities exist by the time this runs.
|
|
686
|
+
* - `vite:css-post` serialises a `*.css?inline` import into `export default "…"`.
|
|
687
|
+
* `enforce: "post"` runs AFTER that and would be handed JavaScript, where the
|
|
688
|
+
* CSS is an escaped string literal.
|
|
689
|
+
*/
|
|
690
|
+
declare function scopePluginCssPlugin(options?: ScopePluginCssOptions): Plugin;
|
|
691
|
+
|
|
537
692
|
/**
|
|
538
693
|
* Build-time codegen for a PlatformReact plugin's `feature.manifest.json` +
|
|
539
694
|
* project-root `extension.manifest.json` overlay, from the plugin's `routeMeta.json`
|
|
@@ -807,4 +962,4 @@ interface EthisysPluginOptions {
|
|
|
807
962
|
*/
|
|
808
963
|
declare function ethisysManifestPlugin(options?: EthisysPluginOptions): Plugin;
|
|
809
964
|
|
|
810
|
-
export { type BuildPlatformReactPagesOptions, CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, type ComputePlatformReactPagesInput, type ComputePlatformReactPagesResult, type ContractAManifest, type ContractAPluginOptions, type ContractBManifest, type ContractBPluginOptions, type EthisysPluginOptions, type GeneratePlatformReactManifestConfig, type GeneratePlatformReactManifestResult, type IframeBuildContext, type IframeBuildOutputItem, type IframeBuildResult, type IframeSandboxBuildSummary, type IframeSandboxPluginOptions, type IframeViteBuild, type ManifestReactiveRuleRef, type ManifestResourceRef, PLATFORM_REACT_DEDUPE, PLATFORM_REACT_EXTERNALS, type ParsePlatformReactPagesOptions, type PlatformReactAlias, type PlatformReactBuildContext, type PlatformReactBuildSummary, type PlatformReactManifest, type PlatformReactManifestMeta, type PlatformReactManifestPaths, type PlatformReactPageDeclaration, type PlatformReactPageEntry, type PlatformReactPageInput, type PlatformReactPageOverride, type PlatformReactPageSource, type PlatformReactPluginOptions, type PlatformReactViteBuild, type ResolvedPlatformReactPage, type RouteMetaEntry, type ValidationFailure, type ValidationResult, type ViteBuildFn, buildIframeSandboxPages, buildPlatformReactPages, computePlatformReactPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPlugin, generatePlatformReactManifest, parsePlatformReactPages, rewriteAliasedExternalImports, validateDeclarativeResource, validateReactiveRule, virtualPageEntry };
|
|
965
|
+
export { type BuildPlatformReactPagesOptions, CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, type ComputePlatformReactPagesInput, type ComputePlatformReactPagesResult, type ContractAManifest, type ContractAPluginOptions, type ContractBManifest, type ContractBPluginOptions, EHX_PLUGIN_CSS_SCOPE, EHX_PLUGIN_ROOT_SCOPE, EHX_PLUGIN_SCOPE_ROOTS, EHX_SCOPED_CSS_LAYERS, type EthisysPluginOptions, type GeneratePlatformReactManifestConfig, type GeneratePlatformReactManifestResult, type IframeBuildContext, type IframeBuildOutputItem, type IframeBuildResult, type IframeSandboxBuildSummary, type IframeSandboxPluginOptions, type IframeViteBuild, type ManifestReactiveRuleRef, type ManifestResourceRef, PLATFORM_REACT_DEDUPE, PLATFORM_REACT_EXTERNALS, type ParsePlatformReactPagesOptions, type PlatformReactAlias, type PlatformReactBuildContext, type PlatformReactBuildSummary, type PlatformReactManifest, type PlatformReactManifestMeta, type PlatformReactManifestPaths, type PlatformReactPageDeclaration, type PlatformReactPageEntry, type PlatformReactPageInput, type PlatformReactPageOverride, type PlatformReactPageSource, type PlatformReactPluginOptions, type PlatformReactViteBuild, type ResolvedPlatformReactPage, type RouteMetaEntry, type ScopePluginCssOptions, type ValidationFailure, type ValidationResult, type ViteBuildFn, buildIframeSandboxPages, buildPlatformReactPages, computePlatformReactPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPagesPlugin, ethisysPlatformReactPlugin, findUnscopedSelectors, formatUnscopedSelectorError, generatePlatformReactManifest, isScopableCssId, parsePlatformReactPages, rewriteAliasedExternalImports, scopePluginCss, scopePluginCssPlugin, validateDeclarativeResource, validateReactiveRule, virtualPageEntry };
|
package/dist/index.d.ts
CHANGED
|
@@ -312,8 +312,29 @@ interface PlatformReactPluginOptions {
|
|
|
312
312
|
* (see `PlatformReactSurfaceMount.tsx` in `coreconnect-web`). This pass only
|
|
313
313
|
* blocks remote/absolute paths at the manifest layer so a malformed manifest
|
|
314
314
|
* fails fast.
|
|
315
|
+
*
|
|
316
|
+
* Returns an ARRAY: this pass plus the plugin-CSS scoping pass it must always be
|
|
317
|
+
* paired with. Vite flattens nested plugin arrays (`PluginOption` is recursively
|
|
318
|
+
* `PluginOption[]`), so existing call sites
|
|
319
|
+
* (`plugins: [react(), tailwindcss(), ethisysPlatformReactPlugin()]`) are unaffected.
|
|
320
|
+
*
|
|
321
|
+
* The pairing CANNOT be done by returning `{ plugins: [...] }` from this pass's own
|
|
322
|
+
* `config()` hook: Vite resolves the plugin container before running config hooks, so
|
|
323
|
+
* a plugin injected there is dropped SILENTLY (no warning, build still green) and the
|
|
324
|
+
* scoping pass would never run. Anything needing the page pass on its own as a single
|
|
325
|
+
* `Plugin` should call `ethisysPlatformReactPagesPlugin` and compose the scoping pass
|
|
326
|
+
* itself.
|
|
327
|
+
*/
|
|
328
|
+
declare function ethisysPlatformReactPlugin(options?: PlatformReactPluginOptions): Plugin[];
|
|
329
|
+
/**
|
|
330
|
+
* The PlatformReact page-bundle pass ALONE, as a single `Plugin`.
|
|
331
|
+
*
|
|
332
|
+
* Prefer {@link ethisysPlatformReactPlugin}, which pairs this with the plugin-CSS
|
|
333
|
+
* scoping pass. Reach for this only when composing the passes by hand (a plugin with
|
|
334
|
+
* its own scoping step, or a test that drives one pass's hooks directly) — used on its
|
|
335
|
+
* own it emits UNSCOPED CSS, which leaks into the host document.
|
|
315
336
|
*/
|
|
316
|
-
declare function
|
|
337
|
+
declare function ethisysPlatformReactPagesPlugin(options?: PlatformReactPluginOptions): Plugin;
|
|
317
338
|
|
|
318
339
|
/**
|
|
319
340
|
* A fully-validated PlatformReact page declaration. All fields are guaranteed
|
|
@@ -534,6 +555,140 @@ declare function virtualPageEntry(page: PlatformReactPageInput, config: {
|
|
|
534
555
|
*/
|
|
535
556
|
declare function buildPlatformReactPages(options?: BuildPlatformReactPagesOptions): Promise<PlatformReactBuildSummary>;
|
|
536
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Scope selector prefixed onto plugin-global CSS layers.
|
|
560
|
+
*
|
|
561
|
+
* `:where()` NOT `:is()` on purpose: `:where()` contributes ZERO specificity, so a
|
|
562
|
+
* scoped utility keeps exactly the specificity it had unscoped. Inside a plugin
|
|
563
|
+
* surface the cascade therefore behaves identically to before this transform; the
|
|
564
|
+
* only change is that the rule no longer matches host chrome. `:is()` would have
|
|
565
|
+
* raised every utility by one class and could flip a plugin's own conflicts.
|
|
566
|
+
*
|
|
567
|
+
* Two scope roots: the plugin root applied by `definePlatformReactPluginPage`, and
|
|
568
|
+
* the portal container marker, because MUI overlays render into a portal. Phase 1
|
|
569
|
+
* (`PluginPortalScope`) puts that container INSIDE the plugin root, so the second
|
|
570
|
+
* arm is redundant for SDK-managed overlays and exists for a plugin that supplies
|
|
571
|
+
* its own container element and marks it.
|
|
572
|
+
*/
|
|
573
|
+
declare const EHX_PLUGIN_CSS_SCOPE = ":where(.ehx-plugin-root, [data-ehx-plugin-portal])";
|
|
574
|
+
/**
|
|
575
|
+
* Replacement for a document-root selector (`:root`, `:host`) in a plugin sheet.
|
|
576
|
+
*
|
|
577
|
+
* Tailwind's `theme` layer declares its scale as custom properties on
|
|
578
|
+
* `:root, :host` — `--spacing`, `--text-sm--line-height`, `--ease-*`,
|
|
579
|
+
* `--animate-*`. Injected into the host document that lands on the HOST root and
|
|
580
|
+
* silently redefines the host's own Tailwind scale for every element on the page:
|
|
581
|
+
* the same defect as the leaking utilities, one level deeper and inherited.
|
|
582
|
+
*
|
|
583
|
+
* These declarations cannot simply be dropped — the plugin's utilities read them —
|
|
584
|
+
* and prefixing is meaningless (`:where(.ehx-plugin-root) :root` matches nothing).
|
|
585
|
+
* They are REPLACED with the plugin root, which the whole surface inherits from.
|
|
586
|
+
*
|
|
587
|
+
* `:is()` here, not `:where()`: this is a substitution for a 0,1,0 selector, so
|
|
588
|
+
* matching that specificity is the faithful choice (a prefix is what must stay
|
|
589
|
+
* specificity-neutral). Note this only works because portal containment landed
|
|
590
|
+
* first — before that, overlays rendered outside the plugin root and would have
|
|
591
|
+
* lost the whole theme scale.
|
|
592
|
+
*/
|
|
593
|
+
declare const EHX_PLUGIN_ROOT_SCOPE = ":is(.ehx-plugin-root, [data-ehx-plugin-portal])";
|
|
594
|
+
/**
|
|
595
|
+
* Cascade layers whose rules a plugin emits UNSCOPED and which therefore leak into
|
|
596
|
+
* the host document.
|
|
597
|
+
*
|
|
598
|
+
* utilities Tailwind's generated utility classes. The leak that motivated this:
|
|
599
|
+
* a plugin's bare `.text-sm` is a duplicate of the host's own rule,
|
|
600
|
+
* so it changes nothing until the host settles a specificity tie by
|
|
601
|
+
* source order — then the plugin's copy, injected later, wins and
|
|
602
|
+
* silently restyles host chrome.
|
|
603
|
+
* properties Tailwind's `@property` fallback block, which sets ~40 `--tw-*`
|
|
604
|
+
* custom properties on `*, :before, :after, ::backdrop` for the whole
|
|
605
|
+
* document.
|
|
606
|
+
*
|
|
607
|
+
* The other layers are already scoped: `theme` holds custom properties on the
|
|
608
|
+
* plugin's own root class, and `base`/`components`/`mui` come from the SDK's
|
|
609
|
+
* `plugin-base.css`, which scopes everything to `.ehx-plugin-root`.
|
|
610
|
+
*/
|
|
611
|
+
declare const EHX_SCOPED_CSS_LAYERS: readonly string[];
|
|
612
|
+
/**
|
|
613
|
+
* What counts as "scoped to a plugin" — the convention every plugin front-end
|
|
614
|
+
* adheres to, and the only thing the build guard needs to know.
|
|
615
|
+
*
|
|
616
|
+
* .ehx-plugin-root applied to every surface by the SDK page definer
|
|
617
|
+
* .ethisys-<name>-root the plugin's own root class (all plugins use this
|
|
618
|
+
* shape: ethisys-sales-root, ethisys-hr-root, …)
|
|
619
|
+
* [data-ehx-plugin-portal] the portal container overlays render into
|
|
620
|
+
* :where(…) of the above what {@link scopePluginCss} emits
|
|
621
|
+
*
|
|
622
|
+
* A selector that mentions NONE of these can match host chrome, which is the whole
|
|
623
|
+
* defect class. Matching anywhere in the selector (not just leftmost) is deliberate:
|
|
624
|
+
* `:where(.dark) .ethisys-sales-root` is scoped even though the root is not first.
|
|
625
|
+
*/
|
|
626
|
+
declare const EHX_PLUGIN_SCOPE_ROOTS: readonly RegExp[];
|
|
627
|
+
interface ScopePluginCssOptions {
|
|
628
|
+
/** Descendant scope prefix. Default {@link EHX_PLUGIN_CSS_SCOPE}. */
|
|
629
|
+
scope?: string;
|
|
630
|
+
/** Replacement for `:root`/`:host`. Default {@link EHX_PLUGIN_ROOT_SCOPE}. */
|
|
631
|
+
rootScope?: string;
|
|
632
|
+
/** Layer names to scope. Default {@link EHX_SCOPED_CSS_LAYERS}. */
|
|
633
|
+
layers?: readonly string[];
|
|
634
|
+
/** What counts as scoped for the guard. Default {@link EHX_PLUGIN_SCOPE_ROOTS}. */
|
|
635
|
+
scopeRoots?: readonly RegExp[];
|
|
636
|
+
/**
|
|
637
|
+
* Guard behaviour when a selector would leak into the host document:
|
|
638
|
+
* `"error"` (default) fails the build, `"warn"` logs, `"off"` skips the check.
|
|
639
|
+
* Only reach for anything but `"error"` as a deliberate, time-boxed exception.
|
|
640
|
+
*/
|
|
641
|
+
guard?: "error" | "warn" | "off";
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Prefix every selector inside a plugin's UNSCOPED cascade layers with the plugin
|
|
645
|
+
* scope, so injecting the sheet into the host document cannot restyle host chrome.
|
|
646
|
+
*
|
|
647
|
+
* Pure and idempotent — running it twice is a no-op, so a rebuild or a second pass
|
|
648
|
+
* over already-scoped CSS is safe. See {@link EHX_SCOPED_CSS_LAYERS} for which
|
|
649
|
+
* layers are rewritten and why the others need no treatment.
|
|
650
|
+
*/
|
|
651
|
+
declare function scopePluginCss(css: string, options?: ScopePluginCssOptions): string;
|
|
652
|
+
/**
|
|
653
|
+
* Every selector in `css` that mentions no plugin scope root, i.e. every selector
|
|
654
|
+
* that can reach host chrome once the sheet is injected into the host document.
|
|
655
|
+
*
|
|
656
|
+
* The invariant this checks is the whole convention: **a plugin never emits an
|
|
657
|
+
* unscoped selector.** {@link scopePluginCss} satisfies it automatically for the
|
|
658
|
+
* layers Tailwind generates; everything else is authored, and this is what catches
|
|
659
|
+
* an author (or a stray `@import "tailwindcss"` re-emitting global preflight) who
|
|
660
|
+
* did not. Pure, so a plugin's own build script or test can call it directly.
|
|
661
|
+
*/
|
|
662
|
+
declare function findUnscopedSelectors(css: string, options?: Pick<ScopePluginCssOptions, "scopeRoots">): string[];
|
|
663
|
+
/** The build-failure message: what leaked, why it matters, and the usual cause. */
|
|
664
|
+
declare function formatUnscopedSelectorError(id: string, leaks: readonly string[]): string;
|
|
665
|
+
/** True for ids whose transform payload is plain CSS text we may rewrite. */
|
|
666
|
+
declare function isScopableCssId(id: string): boolean;
|
|
667
|
+
/**
|
|
668
|
+
* Vite plugin form of {@link scopePluginCss} PLUS the guard that makes it a
|
|
669
|
+
* convention rather than a courtesy, injected into every PlatformReact page
|
|
670
|
+
* sub-build by `buildPlatformReactPages`.
|
|
671
|
+
*
|
|
672
|
+
* Scoping Tailwind's generated layers is automatic; the guard fails the build if
|
|
673
|
+
* anything ELSE in the sheet is still unscoped (see
|
|
674
|
+
* {@link findUnscopedSelectors}). Together they are the enforceable form of one
|
|
675
|
+
* rule: a plugin never emits an unscoped selector into the host document. Prose in
|
|
676
|
+
* a standards doc did not hold across seven repos — the leak that prompted this
|
|
677
|
+
* shipped seven times, and the documented no-preflight rule was violated once
|
|
678
|
+
* without anyone noticing.
|
|
679
|
+
*
|
|
680
|
+
* Deliberately declares NO `enforce`. Vite resolves plugins in the order
|
|
681
|
+
* `[…prePlugins, vite:css, …normalPlugins, vite:css-post, …postPlugins]`, so a
|
|
682
|
+
* plugin with no `enforce` is the only position that sees compiled CSS:
|
|
683
|
+
*
|
|
684
|
+
* - `@tailwindcss/vite` is `enforce: "pre"` and returns the generated sheet, so
|
|
685
|
+
* the utilities exist by the time this runs.
|
|
686
|
+
* - `vite:css-post` serialises a `*.css?inline` import into `export default "…"`.
|
|
687
|
+
* `enforce: "post"` runs AFTER that and would be handed JavaScript, where the
|
|
688
|
+
* CSS is an escaped string literal.
|
|
689
|
+
*/
|
|
690
|
+
declare function scopePluginCssPlugin(options?: ScopePluginCssOptions): Plugin;
|
|
691
|
+
|
|
537
692
|
/**
|
|
538
693
|
* Build-time codegen for a PlatformReact plugin's `feature.manifest.json` +
|
|
539
694
|
* project-root `extension.manifest.json` overlay, from the plugin's `routeMeta.json`
|
|
@@ -807,4 +962,4 @@ interface EthisysPluginOptions {
|
|
|
807
962
|
*/
|
|
808
963
|
declare function ethisysManifestPlugin(options?: EthisysPluginOptions): Plugin;
|
|
809
964
|
|
|
810
|
-
export { type BuildPlatformReactPagesOptions, CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, type ComputePlatformReactPagesInput, type ComputePlatformReactPagesResult, type ContractAManifest, type ContractAPluginOptions, type ContractBManifest, type ContractBPluginOptions, type EthisysPluginOptions, type GeneratePlatformReactManifestConfig, type GeneratePlatformReactManifestResult, type IframeBuildContext, type IframeBuildOutputItem, type IframeBuildResult, type IframeSandboxBuildSummary, type IframeSandboxPluginOptions, type IframeViteBuild, type ManifestReactiveRuleRef, type ManifestResourceRef, PLATFORM_REACT_DEDUPE, PLATFORM_REACT_EXTERNALS, type ParsePlatformReactPagesOptions, type PlatformReactAlias, type PlatformReactBuildContext, type PlatformReactBuildSummary, type PlatformReactManifest, type PlatformReactManifestMeta, type PlatformReactManifestPaths, type PlatformReactPageDeclaration, type PlatformReactPageEntry, type PlatformReactPageInput, type PlatformReactPageOverride, type PlatformReactPageSource, type PlatformReactPluginOptions, type PlatformReactViteBuild, type ResolvedPlatformReactPage, type RouteMetaEntry, type ValidationFailure, type ValidationResult, type ViteBuildFn, buildIframeSandboxPages, buildPlatformReactPages, computePlatformReactPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPlugin, generatePlatformReactManifest, parsePlatformReactPages, rewriteAliasedExternalImports, validateDeclarativeResource, validateReactiveRule, virtualPageEntry };
|
|
965
|
+
export { type BuildPlatformReactPagesOptions, CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, type ComputePlatformReactPagesInput, type ComputePlatformReactPagesResult, type ContractAManifest, type ContractAPluginOptions, type ContractBManifest, type ContractBPluginOptions, EHX_PLUGIN_CSS_SCOPE, EHX_PLUGIN_ROOT_SCOPE, EHX_PLUGIN_SCOPE_ROOTS, EHX_SCOPED_CSS_LAYERS, type EthisysPluginOptions, type GeneratePlatformReactManifestConfig, type GeneratePlatformReactManifestResult, type IframeBuildContext, type IframeBuildOutputItem, type IframeBuildResult, type IframeSandboxBuildSummary, type IframeSandboxPluginOptions, type IframeViteBuild, type ManifestReactiveRuleRef, type ManifestResourceRef, PLATFORM_REACT_DEDUPE, PLATFORM_REACT_EXTERNALS, type ParsePlatformReactPagesOptions, type PlatformReactAlias, type PlatformReactBuildContext, type PlatformReactBuildSummary, type PlatformReactManifest, type PlatformReactManifestMeta, type PlatformReactManifestPaths, type PlatformReactPageDeclaration, type PlatformReactPageEntry, type PlatformReactPageInput, type PlatformReactPageOverride, type PlatformReactPageSource, type PlatformReactPluginOptions, type PlatformReactViteBuild, type ResolvedPlatformReactPage, type RouteMetaEntry, type ScopePluginCssOptions, type ValidationFailure, type ValidationResult, type ViteBuildFn, buildIframeSandboxPages, buildPlatformReactPages, computePlatformReactPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPagesPlugin, ethisysPlatformReactPlugin, findUnscopedSelectors, formatUnscopedSelectorError, generatePlatformReactManifest, isScopableCssId, parsePlatformReactPages, rewriteAliasedExternalImports, scopePluginCss, scopePluginCssPlugin, validateDeclarativeResource, validateReactiveRule, virtualPageEntry };
|