@tsrx/mcp 0.0.90 → 0.0.92

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 CHANGED
@@ -90,7 +90,9 @@ Add the generic config above to your Codex MCP configuration.
90
90
  before browser-based Axe validation, including missing button names, unlabeled
91
91
  form controls, and visible text accidentally wrapped in quote characters.
92
92
  - `review-tsrx-styles` - review function-local style usage for malformed style
93
- blocks, broad selectors, root styling, and contrast risks.
93
+ blocks, broad selectors, root styling, and contrast risks; recognises
94
+ self-closed `<style apply={theme} />` blocks and notes exported or applied theme
95
+ blocks (which expose `$class`).
94
96
  - `review-tsrx-components` - review component structure and suggest extraction
95
97
  points when control flow, repeated templates, or styles become dense.
96
98
  - `validate-tsrx-file` - read a `.tsrx` file and run formatting, compilation, and
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "MCP server for TSRX documentation and project context",
4
4
  "license": "MIT",
5
5
  "author": "Dominic Gannaway",
6
- "version": "0.0.90",
6
+ "version": "0.0.92",
7
7
  "type": "module",
8
8
  "repository": {
9
9
  "type": "git",
@@ -37,8 +37,8 @@
37
37
  "@modelcontextprotocol/sdk": "^1.29.0",
38
38
  "prettier": "^3.9.6",
39
39
  "zod": "^4.3.6",
40
- "@tsrx/core": "0.1.65",
41
- "@tsrx/prettier-plugin": "0.3.130"
40
+ "@tsrx/prettier-plugin": "0.3.132",
41
+ "@tsrx/core": "0.1.66"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^24.3.0",
package/src/authoring.js CHANGED
@@ -287,6 +287,52 @@ function contrast_ratio(foreground, background) {
287
287
  return (lighter + 0.05) / (darker + 0.05);
288
288
  }
289
289
 
290
+ /**
291
+ * Matches one `<style>` block. Group 1 is the attribute text; group 2 is the CSS
292
+ * body, or `undefined` for a self-closed `<style apply={theme} />` block, which
293
+ * has no body. The attribute pattern lets a `>` sit inside a quoted value or an
294
+ * `{...}` expression container (one level of nesting), so
295
+ * `apply={cond ? a : b}` and `apply={(x) => y}` do not end the tag early, and a
296
+ * self-closed block can never swallow a later bodied block.
297
+ */
298
+ const STYLE_BLOCK_PATTERN =
299
+ /<style\b((?:[^>"'{}/]|"[^"]*"|'[^']*'|\{(?:[^{}]|\{[^{}]*\})*\})*)(?:\/>|>([\s\S]*?)<\/style>)/g;
300
+
301
+ /**
302
+ * @typedef {{
303
+ * raw: string,
304
+ * index: number,
305
+ * attrs: string,
306
+ * css: string | undefined,
307
+ * apply: string | null,
308
+ * exported: boolean,
309
+ * }} StyleBlock
310
+ */
311
+
312
+ /**
313
+ * Scans TSRX source for every `<style>` block: bodied blocks, self-closed
314
+ * `<style apply={…} />` blocks (recognised as style usage even though they carry
315
+ * no CSS), and assigned blocks (`export const theme = <style>…</style>`).
316
+ *
317
+ * @param {string} code
318
+ * @returns {StyleBlock[]}
319
+ */
320
+ function scan_style_blocks(code) {
321
+ return [...code.matchAll(STYLE_BLOCK_PATTERN)].map((match) => {
322
+ const attrs = match[1] ?? '';
323
+ const apply = attrs.match(/\bapply\s*=\s*\{((?:[^{}]|\{[^{}]*\})*)\}/)?.[1]?.trim() ?? null;
324
+ const preceding = code.slice(Math.max(0, match.index - 120), match.index);
325
+ return {
326
+ raw: match[0],
327
+ index: match.index,
328
+ attrs,
329
+ css: match[2],
330
+ apply,
331
+ exported: /\bexport\s+(?:const|let|var)\s+[\w$]+\s*=\s*$/.test(preceding),
332
+ };
333
+ });
334
+ }
335
+
290
336
  /**
291
337
  * Reviews TSRX scoped style authoring for patterns that commonly produce invalid
292
338
  * CSS, missing root styling, or preventable contrast failures.
@@ -298,7 +344,7 @@ export function review_tsrx_styles(input) {
298
344
  const target = normalize_target(input.target);
299
345
  /** @type {AuthoringIssue[]} */
300
346
  const issues = [];
301
- const style_blocks = [...input.code.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style>/g)];
347
+ const style_blocks = scan_style_blocks(input.code);
302
348
 
303
349
  if (style_blocks.length === 0) {
304
350
  issues.push({
@@ -314,17 +360,39 @@ export function review_tsrx_styles(input) {
314
360
  });
315
361
  }
316
362
 
317
- for (const style_match of style_blocks) {
318
- const css = style_match[1] ?? '';
363
+ for (const block of style_blocks) {
364
+ if (block.exported || block.apply !== null) {
365
+ issues.push({
366
+ kind: 'style-theme',
367
+ severity: 'info',
368
+ title: block.exported ? 'Exported style block is a theme' : 'Style block applies a theme',
369
+ message: block.exported
370
+ ? 'An exported <style> block compiles as a theme: it exposes $class plus one property per class name, and other scopes compose it with <style apply={theme} /> or <style apply={theme}>...</style>.'
371
+ : `This block applies ${block.apply}. An applied binding must be a theme declared before use; its rules join this scope, and its own $class and class names stay reachable through the binding.`,
372
+ snippet: line_snippet(block.raw),
373
+ recommendation: block.exported
374
+ ? 'Keep shared, reusable rules in the theme and apply it where needed instead of duplicating CSS across components.'
375
+ : 'Reference theme classes through the theme binding rather than restating them, and keep scope-specific overrides in this block.',
376
+ documentation: ['tsrx://docs/style-and-server.md'],
377
+ });
378
+ }
379
+
380
+ // A self-closed `<style apply={…} />` block has no CSS body to review.
381
+ if (block.css === undefined) continue;
382
+
383
+ const css = block.css;
319
384
  if (/^\s*\{/.test(css)) {
385
+ // `<style>{expr}</style>` is the ordinary TSX element: the compiler
386
+ // neither scopes nor extracts it, so it contributes no scoped styles.
320
387
  issues.push({
321
388
  kind: 'style-expression-body',
322
- severity: 'error',
323
- title: 'Write CSS directly inside <style>',
389
+ severity: 'warning',
390
+ title: 'This <style> is a plain element, not a scoped block',
324
391
  message:
325
- 'A TSRX <style> block should contain CSS text, not a JavaScript template literal expression.',
326
- snippet: line_snippet(style_match[0]),
327
- recommendation: 'Replace <style>{`...`}</style> with <style> ...CSS... </style>.',
392
+ 'A <style> whose first child is an expression container is an ordinary TSX element: its content is not scoped, extracted, or hashed. Scoped TSRX blocks hold raw CSS text and sit inside a @{ ... } or control-flow body.',
393
+ snippet: line_snippet(block.raw),
394
+ recommendation:
395
+ 'To scope the rules, write CSS text directly inside <style> beside the elements it styles; keep <style>{css}</style> only for global CSS you inject yourself.',
328
396
  documentation: ['tsrx://docs/style-and-server.md'],
329
397
  });
330
398
  }
@@ -422,8 +490,8 @@ export function review_tsrx_components(input) {
422
490
  const body_lines = get_component_body_line_count(input.code);
423
491
  const control_flow_count = (input.code.match(/\b(if|for|switch)\s*\(/g) ?? []).length;
424
492
  const element_count = (input.code.match(/<[a-z][\w.-]*(\s|>|\/)/g) ?? []).length;
425
- const style_line_count = [...input.code.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style>/g)].reduce(
426
- (total, match) => total + (match[1] ?? '').split('\n').length,
493
+ const style_line_count = scan_style_blocks(input.code).reduce(
494
+ (total, block) => total + (block.css ?? '').split('\n').length,
427
495
  0,
428
496
  );
429
497
 
@@ -27,7 +27,7 @@ export const documentation_sections = [
27
27
  use_cases:
28
28
  'text children, jsx text, comments, string literals, expression containers',
29
29
  content:
30
- '# Text and Template Expressions\n\nStatic text is JSXText and can be written directly between tags. Dynamic values use normal JSX expression containers.\n\n```tsx\nfunction Greeting({ name }: { name: string }) @{\n <>\n <h1>Hello</h1>\n <p>{name}</p>\n </>\n}\n```\n\nJavaScript comments are also allowed between template children and are not rendered. Use braces for JavaScript expressions, including string literals that should be evaluated as JavaScript.\n\nSpecification grammar:\n\n```text\nJSXTextChild :\n JSXTextCharacters\n\nJSXExpressionContainer :\n { AssignmentExpression }\n\nJSXCodeBlock :\n @{ StatementListItemListopt TemplateOutput }\n\nTemplateBlock :\n { TemplateChildrenopt }\n { StatementListItemList TemplateOutput }\n\nJSXIfExpression :\n @if ( Expression ) TemplateBlock\n @if ( Expression ) TemplateBlock @else TemplateBlock\n @if ( Expression ) TemplateBlock @else JSXIfExpression\n\nJSXForExpression :\n @for ( ForHeader TemplateForOptionsopt ) TemplateBlock\n @for ( ForHeader TemplateForOptionsopt ) TemplateBlock @empty TemplateBlock\n\nJSXSwitchExpression :\n @switch ( Expression ) { JSXSwitchCaseListopt }\n\nJSXSwitchCase :\n @case Expression : TemplateBlock\n @default : TemplateBlock\n\nJSXTryExpression :\n @try TemplateBlock @pending TemplateBlock\n @try TemplateBlock @catch ( CatchParameteropt ) TemplateBlock\n```\n\nSource: website-tsrx/src/pages/specification.tsrx#templates',
30
+ '# Text and Template Expressions\n\nStatic text is JSXText and can be written directly between tags. Dynamic values use normal JSX expression containers.\n\n```tsx\nfunction Greeting({ name }: { name: string }) @{\n <>\n <h1>Hello</h1>\n <p>{name}</p>\n </>\n}\n```\n\nJavaScript comments are also allowed between template children and are not rendered. Use braces for JavaScript expressions, including string literals that should be evaluated as JavaScript.\n\nSpecification grammar:\n\n```text\nJSXTextChild :\n JSXTextCharacters\n\nJSXExpressionContainer :\n { AssignmentExpression }\n\nJSXCodeBlock :\n @{ TemplateSetupListopt TemplateOutput JSXStyleElementListopt }\n\nTemplateSetupList :\n TemplateSetupItem\n TemplateSetupList TemplateSetupItem\n\nTemplateSetupItem :\n StatementListItem\n JSXStyleElement\n\nJSXStyleElementList :\n JSXStyleElement\n JSXStyleElementList JSXStyleElement\n\nTemplateBlock :\n { TemplateChildrenopt }\n { TemplateSetupList TemplateOutput JSXStyleElementListopt }\n\nJSXIfExpression :\n @if ( Expression ) TemplateBlock\n @if ( Expression ) TemplateBlock @else TemplateBlock\n @if ( Expression ) TemplateBlock @else JSXIfExpression\n\nJSXForExpression :\n @for ( ForHeader TemplateForOptionsopt ) TemplateBlock\n @for ( ForHeader TemplateForOptionsopt ) TemplateBlock @empty TemplateBlock\n\nJSXSwitchExpression :\n @switch ( Expression ) { JSXSwitchCaseListopt }\n\nJSXSwitchCase :\n @case Expression : TemplateBlock\n @default : TemplateBlock\n\nJSXTryExpression :\n @try TemplateBlock @pending TemplateBlock\n @try TemplateBlock @catch ( CatchParameteropt ) TemplateBlock\n```\n\nSource: website-tsrx/src/pages/specification.tsrx#templates',
31
31
  },
32
32
  {
33
33
  slug: 'expression-values',
@@ -56,9 +56,9 @@ export const documentation_sections = [
56
56
  slug: 'style-and-server',
57
57
  title: 'Style and Server Extensions',
58
58
  use_cases:
59
- 'style expressions, scoped css, module server, submodule imports, compile-time identifiers, ripple server modules, octane rpc, server functions',
59
+ 'style expressions, scoped css, scoped style blocks, sibling scope, sibling-scoped styles, $class, apply, themes, class maps, :global, global selectors, unscoped selectors, escape scoping, third-party component styles, page-level styles, style diagnostics, module server, submodule imports, compile-time identifiers, ripple server modules, octane rpc, server functions',
60
60
  content:
61
- "# Style and Server Extensions\n\nAssign a `<style>` expression to expose scoped CSS class names declared in the current module.\n\n```tsx\nconst styles = <style>\n .card { padding: 1rem; }\n</style>;\n\nexport function ChildCard() @{\n <>\n <Child class={styles.card} />\n </>\n}\n```\n\n`module server { ... }` declares an explicit server-oriented submodule in the Ripple and Octane host profiles. Ripple exposes proposal-aligned imports such as `import { load } from server`; Octane uses the file-local module specifier `import { load } from 'server'` for RPC imports. Transport, serialization, and runtime behavior remain target-defined.\n\nFor Octane compiler, runtime, and validation guidance, use the Octane target documentation at https://octanejs.dev/llms.txt. The MCP `compile-tsrx` tool does not expose an Octane target.\n\nThe nested module scope gives host compilers and tooling a structural boundary for isolation and static analysis, including rejecting implicit cross-boundary captures and keeping server-only dependencies out of client output. It is not interchangeable with a target-specific `\"use server\"` directive.\n\nSpecification grammar:\n\n```text\nJSXStyleElement :\n <style JSXAttributesopt> CSSSource </style>\n\nSubmoduleDeclaration :\n module Identifier { ModuleItemListopt }\n\nSubmoduleImportDeclaration :\n import ImportClause from Identifier ;\n\n```\n\nThe identifier-source import production describes Ripple's proposal-aligned form. Octane's quoted `'server'` specifier uses the ordinary TypeScript import grammar.\n\nSource: website-tsrx/src/pages/specification.tsrx#server-profile",
61
+ '# Style and Server Extensions\n\nA `<style>` block written as template content is a standalone block. It is a child of an element or fragment, and that children list is its sibling scope: the block styles its siblings and everything below them, and it never styles the element that contains it. The compiler rewrites every selector in the block to require a hash class: a class it adds to each element the block reaches, so the selectors match only there. Sibling blocks share one hash class; a nested children list with blocks of its own gets a hash class of its own. Every element gets the hash class of each scope around it, outer first. A `<style>` block is an output node, so in a `@{ ... }` or control-flow body wrap it with its output in a fragment (`<><style>...</style><div /></>`); a lone block there is an error. A block inside an `@if` or `@for` branch styles only the elements that branch renders. Its CSS is still always part of the file\'s stylesheet, whether or not the branch ever renders, because CSS is static. Raw CSS in `<style>` is TSRX template syntax: a block with CSS in it outside every `@{ ... }` and control-flow body is an error; in plain TSX write `<style>{css}</style>`, an ordinary element. A standalone block at module scope is an error: assign it instead.\n\n```tsx\nexport function Panel() @{\n <>\n <style>\n /* sibling scope A: the children list of this fragment */\n div { color: black; }\n </style>\n <div>Black</div>\n\n <style>\n /* still scope A: shares the hash of the first block */\n p { margin: 0; }\n </style>\n <p>No margin</p>\n\n <section>\n <style>\n /* sibling scope B: the children list of <section>, nested in A. It\n styles its siblings and everything below them, never <section>. */\n div { font-weight: bold; }\n </style>\n <div>Black and bold: A and B both reach here</div>\n </section>\n </>\n}\n\n// Stamped classes: the outer div, p, and section carry "<A>"; the nested div carries "<A> <B>".\n// Emitted CSS order: div.<A>, p.<A>, div.<B>.\n```\n\nAssign a `<style>` block to get an object: `$class` (the block\'s hash class, preceded by the `$class` of every block it applies) plus one property per class name (`styles.card`). An assigned block that is exported, applied, or whose `$class` is read is a theme and keeps every selector; otherwise it is a class map and keeps only its class selectors. `<style apply={theme} />` adds `theme.$class` to every element of a scope, `<style apply={theme}>...</style>` also declares local rules that come after the theme\'s and so win at equal specificity, and `class={theme.$class}` adds it to one element. `apply` takes an identifier, a member expression, or an array of those, and every target must be an assigned block that is imported or declared before the applying block.\n\n```tsx\n// theme.tsrx\nexport const base = <style>\n div { font-family: system-ui; }\n .muted { color: gray; }\n</style>;\n// base is { $class: "<base>", muted: "<base> muted" }\n\nexport const theme = <style apply={base}>\n div { color: green; }\n .dark { color: purple; }\n</style>;\n// theme.$class is "<base> <theme>"; theme.dark is "<theme> dark"\n\n// panel.tsrx\nimport { theme } from "./theme.tsrx";\n\nexport function Panel() @{\n <>\n <style apply={theme}>\n /* scope A; every element of A also carries theme.$class */\n div { color: black; }\n </style>\n <span class={theme.dark}>Purple</span>\n <div>Black: the local rule follows the sheet of theme</div>\n @{\n <>\n <style>div { font-weight: bold; }</style>\n <div>Carries "<A> <B> " + theme.$class</div>\n </>\n }\n </>\n}\n// Emitted CSS order: base, theme (theme.tsrx); then scope A, scope B (panel.tsrx).\n\n// card.tsrx: opting elements in with $class\nfunction Card({ parentClass }: { parentClass: string }) @{\n <>\n <style>.local { padding: 0; }</style>\n <article class={`local ${parentClass}`}>\n <h2 class={parentClass}>Title</h2>\n </article>\n </>\n}\n\nexport function App() @{\n const palette = <style>\n div { color: blue; }\n .card { color: red; }\n </style>;\n <>\n <Card parentClass={palette.$class} />\n <div class={palette.$class}>Blue: carries palette.$class</div>\n <div class={palette.card}>Red: carries palette.card</div>\n <p>Untouched: carries nothing from palette</p>\n </>\n}\n// palette.$class is read, so palette is a theme and div { color: blue } is kept.\n// <article> and <h2> carry palette.$class, then the hash of the scope of Card.\n```\n\nLater rules win: CSS is output in source order, outer first. Outer before inner: a scope\'s sheets come before the sheets of the scopes nested in it. Applied theme before the block that applies it: an applied block\'s CSS always comes before the CSS of the block that applies it. Source order within a scope: the later block wins.\n\n`:global(...)` marks the wrapped part of a selector as unscoped: it gets no hash class, everything outside the parentheses is still scoped, and it may only start or end a selector (`tsrx-css-global-placement` otherwise). Bare `:global(.toast)` outputs `.toast`, a page-wide rule that matches anywhere on the page. Prefixed `.card :global(.note)` outputs `.card.<hash> .note`: only elements below the scoped `.card`, a child component\'s internals included, never upward. Leading `:global(.theme-dark) .card` outputs `.theme-dark .card.<hash>`, and compound `.card:global(.is-open)` outputs `.card.<hash>.is-open`. The block form `:global { .toast { ... } body { ... } }` drops its wrapper (left behind as a comment) and outputs `.toast { ... } body { ... }`, several page-wide rules at once. Both forms work with CSS nesting: `.card { :global { .note { ... } } }` and `.card { :global(.note) { ... } }` both output `.card.<hash> { .note { ... } }`, the same reach as the prefixed form with the scoped prefix written once, while plain nesting `.card { .note { ... } }` outputs `.card.<hash> { .note.<hash> { ... } }`, both parts scoped. A scoped rule adds one hash class to its first compound only; later compounds get `:where(.<hash>)`, which adds no specificity. So a scoped `.note.<hash>` (0,2,0) beats a bare `:global(.note)` (0,1,0) from anywhere, a `theme.$class` or class-map rule carries its hash and beats a bare global too, and a prefixed `.card.<hash> .note` (0,3,0) beats a child\'s own `.note.<hash>`.\n\nPrefer passing `theme.$class` (or a class-map entry) as a prop over `:global` for a child you own: the dependency is a visible prop, the child decides which elements receive it, renaming a class inside the child cannot silently break the parent, and the hash keeps the rule on the elements that carry it. With `:global` the child has no say and cannot see who styles it. To style several of a child\'s classes, nest one `:global { ... }` block under your scoped selector. Never write a bare `:global` selector or a top-level `:global { ... }` block for anything but page-level elements.\n\n| I want to ... | Use ... |\n| --- | --- |\n| Style my own elements | A `<style>` block beside them; nothing global |\n| Let a child component pick up my styles | Pass `theme.$class` or `theme.card` as a prop |\n| Style a child I cannot change (third-party, rendered HTML) | `.wrapper :global(.their-class)`, or `.wrapper { :global { ... } }` for several classes; scoped prefix first, keep it narrow |\n| React to page-level state | `:global(.theme-dark) .card` or `:global([data-theme=\'dark\']) .card` |\n| Style my element with a class another library toggles | `.card:global(.is-open)` |\n| Page-wide rules (`body`, resets, fonts) | A `.css` file; a bare `:global(body)` works but hides a global sheet in a component |\n\n`module server { ... }` declares an explicit server-oriented submodule in the Ripple and Octane host profiles. Ripple exposes proposal-aligned imports such as `import { load } from server`; Octane uses the file-local module specifier `import { load } from \'server\'` for RPC imports. Transport, serialization, and runtime behavior remain target-defined.\n\nFor Octane compiler, runtime, and validation guidance, use the Octane target documentation at https://octanejs.dev/llms.txt. The MCP `compile-tsrx` tool does not expose an Octane target.\n\nThe nested module scope gives host compilers and tooling a structural boundary for isolation and static analysis, including rejecting implicit cross-boundary captures and keeping server-only dependencies out of client output. It is not interchangeable with a target-specific `"use server"` directive.\n\nSpecification grammar:\n\n```text\nJSXStyleElement :\n <style JSXAttributesopt> CSSSource </style>\n <style JSXAttributesopt />\n\nStyleApplyValue :\n { StyleApplyTarget }\n { [ StyleApplyTargetListopt ] }\n\nStyleApplyTargetList :\n StyleApplyTarget\n StyleApplyTargetList , StyleApplyTarget\n\nStyleApplyTarget :\n IdentifierReference\n StyleApplyTarget . IdentifierName\n\nSubmoduleDeclaration :\n module Identifier { ModuleItemListopt }\n\nSubmoduleImportDeclaration :\n import ImportClause from Identifier ;\n\n```\n\nStatic constraints on style blocks, with their diagnostic codes:\n\n```text\ntsrx-style-standalone-at-module-scope\n A standalone <style> block must sit inside a template scope. At module scope\n assign it: const theme = <style>...</style>.\ntsrx-style-standalone-needs-fragment\n A standalone <style> block must be a child of an element or a fragment. As the\n lone output of a @{ ... } body or a control-flow body, or as a statement, it\n styles nothing: wrap it with the output it styles in a fragment. Beside another\n output node it is the ordinary multiple-outputs error.\ntsrx-style-standalone-outside-template\n Raw CSS in <style> is TSRX template syntax. A standalone block with CSS text\n must sit lexically inside a @{ ... } body or an @if/@for/@switch/@try body, at\n any depth. In plain TSX give <style> an expression child (<style>{css}</style>)\n or assign the block. Head styles and resource styles are exempt.\ntsrx-style-unknown-attribute\n A scoped <style> block admits only the attributes ref and apply. Head styles\n and resource styles (href) admit any attribute.\ntsrx-style-apply-value\n apply requires an expression container: apply={theme} or apply={[a, b]}.\n A bare attribute, a string value, or an empty container is an error.\ntsrx-style-apply-duplicate\n A <style> block carries at most one apply attribute; pass several targets\n as an array.\ntsrx-style-apply-unsupported-host\n apply is not admitted on a <head> style or on a resource style.\ntsrx-style-apply-target\n Every apply entry is an identifier or non-computed member chain that resolves\n by lexical scoping to an assigned <style> block: a binding initialized with a\n block, an import, or a member of an import or of a module-local object literal\n whose property holds a block. Calls, conditionals, spreads, and holes are errors.\ntsrx-style-apply-before-declaration\n A same-module target must be declared before the block that applies it, by\n source position; stricter than the temporal dead zone because same-module CSS\n is emitted in lexical order.\ntsrx-style-reserved-class-key\n An assigned block must not declare a class selector named $class.\ntsrx-css-global-placement\n :global(...) may begin or end a selector sequence but not sit in its middle,\n and a bare :global must not be nested inside another pseudo-class.\n\nEmission order (normative): outer scope before inner scope; applied block\nbefore the block that applies it; source order within one scope, later wins.\n```\n\nThe identifier-source import production describes Ripple\'s proposal-aligned form. Octane\'s quoted `\'server\'` specifier uses the ordinary TypeScript import grammar.\n\nSource: website-tsrx/src/pages/specification.tsrx#server-profile',
62
62
  },
63
63
  {
64
64
  slug: 'dynamic-elements-and-components',