{"_id":"@ace-code/shast","name":"@ace-code/shast","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@ace-code/shast","version":"0.1.0","publishConfig":{"access":"public"},"description":"Semantic HTML abstract syntax tree with structurally coupled, scoped CSS — validated at compile time and runtime","main":"index.ts","type":"module","keywords":["html","css","ast","semantic","typescript","type-safe","scoped-css","components","validation"],"author":{"name":"Sagi Carmel","url":"https://github.com/AceCodePt"},"license":"ISC","devDependencies":{"@total-typescript/ts-reset":"^0.6.1","@types/node":"^25.9.1","tsx":"^4.22.4"},"dependencies":{"typescript":"^6.0.3"},"scripts":{"test":"tsc --noEmit && node --import=tsx/esm --test","test:watch":"node --import=tsx/esm --test --watch"},"_id":"@ace-code/shast@0.1.0","_integrity":"sha512-wnc35qdWKiqJ9vHOybFeSoHgfOh5ftSCOHSoX1czuv7h/7qPB1XsVbARoywa2e/xtrAGSzdIeaszQ5djLGOi4g==","_resolved":"/tmp/602492b48f4ff776d93bffcfb2e21446/ace-code-shast-0.1.0.tgz","_from":"file:ace-code-shast-0.1.0.tgz","_nodeVersion":"25.2.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-wnc35qdWKiqJ9vHOybFeSoHgfOh5ftSCOHSoX1czuv7h/7qPB1XsVbARoywa2e/xtrAGSzdIeaszQ5djLGOi4g==","shasum":"dba94c618cfbbf4858203d2d728d8a79fc2ed963","tarball":"https://registry.npmjs.org/@ace-code/shast/-/shast-0.1.0.tgz","fileCount":52,"unpackedSize":414725,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDsN2CCOMjLFuszOMvnks/dHQR01ItVD8VWxFZaaNm1GgIgBMlBW1lUMXNDTxexDNvDVwJJcpDhrt8id9qHeS80xFM="}]},"_npmUser":{"name":"ace-code","email":"sagica5273@gmail.com"},"directories":{},"maintainers":[{"name":"ace-code","email":"sagica5273@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/shast_0.1.0_1784185596674_0.6812449857718021"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-16T07:06:36.423Z","0.1.0":"2026-07-16T07:06:36.821Z","modified":"2026-07-16T07:06:37.083Z"},"maintainers":[{"name":"ace-code","email":"sagica5273@gmail.com"}],"description":"Semantic HTML abstract syntax tree with structurally coupled, scoped CSS — validated at compile time and runtime","keywords":["html","css","ast","semantic","typescript","type-safe","scoped-css","components","validation"],"author":{"name":"Sagi Carmel","url":"https://github.com/AceCodePt"},"license":"ISC","readme":"# shast\n\n**shast** — the **s**emantic **H**TML **a**bstract **s**yntax **t**ree whose\nCSS can't go stale.\n\n> Not affiliated with (or node-compatible with) [hast](https://github.com/syntax-tree/hast)\n> from the unified ecosystem — the name is a nod, not an implementation.\n\nThe bug this library kills is not *writing* CSS — it's *refactoring* HTML.\nYou rename a wrapper, move a child, delete a node… and somewhere a selector\nsilently stops matching. Nothing fails. The dead CSS just stays there.\n\nHere, a component's CSS is typed *against its own structure*. Change the\nstructure and every style rule that targeted the old structure becomes a\n**compile error at that exact spot** — and, as a second wall, a **runtime\nerror** if the type layer was bypassed.\n\n```ts\nconst { createComponent, renderComponent } = engine({\n  supportedKeywords: SUPPORTED_KEYWORDS,\n  htmlAttributesConfig: HTML_GLOBAL_ATTRIBUTES_CONFIG,\n  htmlTagConfig: HTML_TAGS_CONFIG,\n  cssSyntaxConfig: CSS_SYNTAX_CONFIG,\n  cssAttributesConfig: CSS_ATTRIBUTES_CONFIG,\n  cssPseudoClassConfig: CSS_GLOBAL_PSEUDO_CLASSES_CONFIG,\n  cssPropertiesConfig: CSS_GLOBAL_PROPERTIES,\n});\n\nconst card = createComponent({\n  tag: \"div\",\n  innerHTML: {\n    title: { tag: \"h1\", innerHTML: \"hello\" },\n  },\n  css: {\n    width: \"100%\",\n    \"> title\": { color: \"inherit\" }, // typed as a key of innerHTML\n  },\n});\n\nconst { html, css } = renderComponent(card);\n// html: <div cid-x1y2z3><h1 cid-title>hello</h1></div>\n// css:  scoped rules for [cid-x1y2z3] and its > [cid-title]\n```\n\nNow rename `title` to `heading` and forget the CSS:\n\n```ts\ninnerHTML: { heading: { tag: \"h1\", innerHTML: \"hello\" } },\ncss: { \"> title\": { ... } }\n//     ^^^^^^^^^ error: '\"> title\"' does not exist in type\n//     '{ readonly \"> heading\"?: ... }'\n```\n\nThe stale style is not a visual bug you discover next month. It's a red\nsquiggle right now.\n\n## What gets validated\n\nEverything is defined in **closed-world config registries** — tags, allowed\nchildren, attributes (as DSL strings), CSS properties, syntax tokens,\n`@property` custom properties, pseudo-classes/elements — and every component\nis checked against them **twice**:\n\n| Rule | Compile time | Runtime |\n|---|---|---|\n| Tag exists in the registry | ✓ | ✓ |\n| Child tag allowed by parent (`ul` → only `li`) | ✓ | ✓ |\n| Ancestral inheritance (`a > h1 > b` rejected because `a ∩ h1` forbids `b`) | ✓ | ✓ |\n| Attribute exists and value matches its DSL type | ✓ | ✓ |\n| CSS property value matches the syntax config | ✓ | see [Limitations](#limitations) |\n| `> child` selector targets a real named child (at any nesting depth) | ✓ | ✓ |\n| `&.class` selector references a class declared on the context element | ✓ | ✓ |\n| Custom property (`--x`) registered and value matches its `syntax` | ✓ | ✓ |\n| Pseudo-class/element declared for that tag | ✓ | see [Limitations](#limitations) |\n\nComposition does not weaken any of this: components built in separate files\nand embedded into parents are **re-validated under the parent's context**, at\nboth levels. Widened types fail closed — they can't be embedded at all. See\n[docs/structural-coupling.md](docs/structural-coupling.md) for the verified\nguarantees and their test methodology.\n\n## For AI agents and humans alike\n\nThe same design serves both audiences, deliberately:\n\n- **Humans** get autocomplete driven by the registries (valid tags, valid\n  children, valid CSS values for *this* property on *this* element) and\n  refactoring that fails loudly instead of silently.\n- **AI agents** get anti-hallucination walls. A model cannot invent a tag,\n  attribute, design token, or custom property that isn't in the registry —\n  `tsc` rejects it with a pointed message (`'colr' is not supported`,\n  `'<p>' is not a permitted child of <ul>`), and the runtime backstop catches\n  anything that slips past the types (`as any`, generated code). The\n  component format is JSON-shaped, which models emit far more reliably than\n  JSX, and a config-derived schema can constrain generation outright.\n\nThe wall is only as good as its error messages, so diagnostic quality is\ntreated as an interface, not an accident — error strings carry the path and\nthe expectation, and regressions in message clarity are considered bugs.\n\n## Own your registry\n\nThe registries are meant to live **inside your codebase** and be tailored to\nit — the same philosophy as shadcn: you don't install a black box, you own the\nconfig and grow it as your project grows.\n\n- **Start from `common` (or `minimal`)**, not `full`. Add a tag, an attribute,\n  a syntax token *when you need it*, next to the code that needs it.\n- **`full` is a reference, not a starting point.** It covers essentially the\n  entire HTML/CSS surface, and it's extremely unlikely your project wants the\n  entire web platform as its vocabulary. A registry that permits everything\n  protects against nothing.\n- **Smaller registries are strictly better** on every axis this library cares\n  about: tighter anti-hallucination walls for AI (a model can't reach for a\n  tag your design system doesn't use), sharper autocomplete for humans, and a\n  smaller type-checking constant (registry breadth — not component count — is\n  what drives editor latency).\n\nYour registry *is* your design system's vocabulary. If `<table>` isn't in it,\nnobody — human or model — ships a table.\n\n## Performance (measured, not promised)\n\n- `tsc` cost is **linear**: ~4.8K instantiations / ~5ms per component\n  (400 components: 2.4s full check).\n- Editor: warm completions inside a `css` block 8–18ms; ~43ms full-file\n  recheck for a typical component file.\n\nKeep files to a handful of components each and the type machinery is\nimperceptible. Details in\n[docs/structural-coupling.md](docs/structural-coupling.md).\n\n## Limitations\n\nSome limitations are **deliberate trade-offs** to keep the type system snappy;\nothers are **known gaps** with the fix tracked in `TASK.md`. They are listed\nhere rather than hidden in either category's fine print.\n\n### Deliberate (kept for type-system performance)\n\nAttribute and CSS value types are written as DSL strings\n(`\"'ltr' | 'rtl' | undefined\"`, `` \"`${number}px`\" ``) that are parsed at the\ntype level *and* validated at runtime. Two parsing edge cases are intentionally\nunsupported because handling them would slow every DSL string down for a\nvanishingly rare case:\n\n- **Pipe inside quoted strings.** The `|` character is a **union separator**.\n  A literal pipe inside a single/double-quoted string (`\"'|'\"`) is not\n  supported: the type-level parser splits on `|` before checking quote\n  boundaries, and quote-aware splitting at the type level adds significant\n  complexity. Template literals are the exception: `` `${\"a\" | \"b\"}` ``\n  handles `|` inside `${...}` correctly, because backtick strings are parsed\n  by `DSLTemplateDelimiter` before the pipe split.\n- **Nested template literals.** `` `\\`${number | string}\\`` `` (a\n  backtick-literal backtick containing an interpolation) is not supported —\n  tracking escape depth across quote contexts at the type level costs far more\n  than the edge case is worth.\n\n### Known gaps (runtime wall only — the type wall covers these today)\n\n- **CSS property *values* are not validated at runtime.** Selector structure\n  in `css` blocks *is* runtime-validated (`> child` keys against `innerHTML`,\n  `&.class` keys against the context element's `class` attribute, at any\n  nesting depth), but an invalid property value (`color: \"magenta\"` when the\n  syntax config says `'red' | 'blue'`) passes runtime validation if the type\n  layer is bypassed (`as any`, generated code).\n- **Pseudo-class/element usage** in css blocks and pseudo-element declarations\n  in the tag config are type-checked but not runtime-checked.\n\nUntil these close, the runtime backstop covers *structure, attributes, and\nselector shape* but not yet *style values* — worth knowing if you rely on the\nruntime wall alone (e.g. validating untyped AI output without running `tsc`).\n","readmeFilename":"README.md","_rev":"1-44be3cf3ddcaf823e7079daff0d797e6"}