Skip to content

Releases

v0.7.10

Choose a tag to compare

@github-actions github-actions released this 08 Nov 08:09
74b0961

Summary

0.7.10 makes constructor-host-change read field initializers that a formatter wraps onto the next line, and keeps the README and llms.txt on ts-dom check.

Changes

  • constructor-host-change reads a field initializer wrapped onto the next line (readonly mark = then this.classList.add("x")) and one inside an object literal: a class member ends where its statement ends, not at every line break.
  • README (English and Traditional Chinese): the Quick Start and the short version use ts-dom check, with the tsconfig.json it needs; the counter example, which repeated the first example, is removed.
  • llms.txt sets up with ts-dom check.
  • ts-dom rules --explain=prop-forwarding no longer describes one application's plugin interface.

Breaking Changes

None.

v0.7.9

Choose a tag to compare

@github-actions github-actions released this 08 Nov 07:41
6ef5fe5

Summary

0.7.9 fixes lifecycle and Light DOM slot defects found in a real 0.7.3 to 0.7.8 migration, adds a lint rule for Custom Elements callbacks overridden without super, and widens two existing checks.

Changes

  • Breaking: on every connection, the components inside a component run connected() before it, in Light DOM and Shadow DOM. A component moved out and back in used to run connected() before the ones inside it, the reverse of its first start, and a Shadow DOM component ran it before its shadow tree's components even the first time, so a parent that changed a child's elements in connected() was undone by the child's own connected().
  • A list or data-if of a parent template written directly inside a Light DOM component with slots puts its elements straight into their slot. Before, each update inserted them at the top level of the element and the slot moved them in afterwards: without moveBefore they were disconnected and connected again (losing focus, running connected() twice), also when the slot sat in a container the component keeps out of the document.
  • A component class's type declares attributeChangedCallback and the static observedAttributes, so a subclass can extend them with super.
  • New lint rule callback-without-super (data-flow, warning): connectedCallback, disconnectedCallback or attributeChangedCallback overridden without super, or observedAttributes replaced without super.observedAttributes, which silently stops the component from starting or from reading props from attributes.
  • constructor-host-change also reports this.insertBefore(...) and instance field initializers that change the element.
  • dom-node-in-state no longer reports a prop typed as a function that returns nodes.
  • ts-dom doctor follows a Vite or Vitest config's relative imports to a helper that returns tsDom() before reporting vite-plugin-missing.
  • Docs: a parent gives a child data through its props, also in its first render; rules --explain=prop-forwarding says where the rule does not fit.

Breaking Changes

  • The order of connected() on reconnection and in Shadow DOM components: the components inside now always run it first. Code that relied on a parent's connected() running before its children's on reconnection should set the children through their props instead.

v0.7.8

Choose a tag to compare

@github-actions github-actions released this 08 Nov 06:27
86287be

Summary

0.7.8 adds two lint rules that catch component code drifting from Nativele's design, and states the design principles in docs/design.md. Both rules are data-flow warnings whose Fix: links the principle they rest on.

Changes

  • Lint rule static-markup-in-code (data-flow, warning): a component class that creates an element with document.createElement and gives it a fixed text or attribute in the same block (b.textContent = "Remove", b.type = "button", setAttribute with a literal), structure the template can hold. A value that adds data, a write to another element, comments and strings are not reported, nor is an element whose content comes from data.
  • Lint rule dom-node-in-state (data-flow, warning): a state or props value that holds several DOM nodes ([] as HTMLElement[], new Set<HTMLElement>(), a DocumentFragment), a copy of what the DOM holds. A single element such as an anchor a parent passes in is not reported.
  • docs/design.md states the design principles in five parts: HTML describes, TypeScript decides; the browser is the runtime; data flows one way; small surface, checked by tools; integrations stay at the edge.
  • npx ts-dom rules --explain=<id> explains both rules with an example.

Breaking Changes

None. New lint rules are warnings.

v0.7.7

Choose a tag to compare

@github-actions github-actions released this 08 Nov 05:36
4549d97

Summary

0.7.7 fixes a browser-only failure in lists without data-prop: the custom elements in a new item were not upgraded when update ran, so calling a component's method there threw TypeError, and setting a prop created an own property that hid the component's setter.

Changes

  • A list without data-prop imports each new item into the document (document.importNode), so its custom elements are upgraded before update and before the list sets their props. Since 0.7.6 calls update before inserting the item, a clone from the template's inert document was never upgraded in a browser; happy-dom upgrades such clones, so only a browser showed it.
  • A Chrome test covers a plain list whose update calls a child's batch() and sets its props.
  • The testing Skill notes that happy-dom upgrades template clones and Chrome does not until they are imported.

Breaking Changes

None.

v0.7.6

Choose a tag to compare

@github-actions github-actions released this 08 Nov 04:28
e771371

Summary

Child components first render with the props their parent gives them, lists update a new item before inserting it, and Light DOM slots take only content written in HTML, so children a framework renders go to shadow: true components. Recorded in CHANGELOG under 0.7.6.

Changes

  • Start order: a component inside another component, in its Light DOM or its shadow tree at any depth, starts after the outer component's first render, as a browser orders a shadow host and its shadow tree. A child of a template first renders with the props that render gives it. Starts are isolated from each other's errors, still run when the outer first render throws, and run once.
  • Lists: replace() and upsert() call update for a new item before inserting it, as assigning items does; an upsert() whose update throws leaves no item behind.
  • Light DOM slots: they place the children an element has when it is built and nodes a list or data-if of a parent template puts in later. A node other code adds afterwards stays where it was put, with the console warning unplaced-child once per tag. Slots move a node to another slot with moveBefore where the browser has it.
  • Cleanups: every cleanup and disconnected() runs when one throws; the errors are rethrown together.
  • Docs and Skills: the slot boundary is a design decision; the framework Skills give framework children shadow: true only; render writes compare first; a prop the parent always gives is declared with null, typed DeepReadonly<T> | null in an interface. Seven Skills re-verified by agent trials on 0.7.6.

Verification

  • npm run check, npm test (764), npm run lint, npm run test:browser (124), npm run bench:check, npm run smoke, npm run smoke:no-bundler.
  • Chrome tests of the start order in both modes, of nested parsing, of moveBefore in slots and of the slot rules; the start-order test fails without the change.
  • Fresh Sonnet agent trials of core, testing, react, vue, svelte, angular and integration, each checked again independently.

Breaking Changes

  • Child components of a Light DOM template start after the parent's first render: in that render a child has not built its own content, so calling its methods there moves to a later render or an event handler.
  • replace() and upsert() run update on a new item before it is in the document: read layout after the list call.
  • Light DOM slots no longer place nodes that code or a framework adds after the element is built: give such a component shadow: true, or put TypeScript content into an element the component exposes through a ref.

🤖 Generated with Claude Code

v0.7.4

Choose a tag to compare

@github-actions github-actions released this 08 Nov 02:54
a410638

Summary

Lint reads the components of the Nativele component packages a project depends on, findings from migrating a real application are fixed, diagnostics use one severity scale and one path per check, and the docs, Skills and tests are cut down and rewritten for reading. Recorded in CHANGELOG under 0.7.4.

Changes

  • Component packages: lint, ts-dom check and the oxlint plugin check the components of each dependency that lists @nativele/ts-dom, read from the modules its exports name; ts-dom gen still writes only from the scanned folders. A tag declared only in TypeScript is listed as such by unchecked-custom-elements.
  • New checks: constructor-host-change (a constructor that changes the element itself, which makes a browser create an HTMLUnknownElement), define-class-not-exported in ts-dom check, and the runtime warning unslotted-node when a Light DOM component removes a child with no matching slot. Lint follows extends to the Component(...) class a subclass extends.
  • doctor: only errors and warnings (skill-outdated is a warning; ts-dom skills shows which Skills cover the project's dependencies), no stale-generated and no --include/--exclude/--whitespace, --ignore added.
  • One path per check: duplicate-define within and across folders, one stale-generated message, one issue formatter, each id once in ts-dom rules, --ignore reaching unchecked-content.
  • Fixes: comments among a Light DOM host's children stay where they are; lifecycle callbacks are declared on the component type (no TS4113); several tsDom() share one watcher listener (no MaxListenersExceededWarning); the runtime data-prop error is item-prop-missing.
  • Docs and Skills: duplicated, stale and wrong passages removed; every passage restructured under writing rules now in docs/contributing.md; all 19 Skills re-verified by agent trials on 2026-11-08.
  • Tests: shared helpers, duplicate tests removed, browser tests on ephemeral ports, a real-browser test of the constructor behavior and the slot warning.
  • Versioning policy: any 0.x version, a patch included, may contain breaking changes, marked in its section.

Verification

  • npm run check, npm test (751), npm run lint, npm run test:browser (118), npm run bench:check.
  • Fresh Sonnet agent trials of all 19 Skills from packed builds, each checked again independently; the four Skills changed afterwards (core, linting, testing, formatting) trialled again.

Breaking Changes

  • ts-dom doctor no longer takes --include, --exclude and --whitespace, no longer reports stale-generated (use ts-dom gen --check or ts-dom check --no-write), and its --json has no info issues; skill-available is gone.

🤖 Generated with Claude Code

v0.7.3

Choose a tag to compare

@github-actions github-actions released this 07 Nov 19:23
aa0f3cf

Summary

Nativele 0.7.3: fixes found by migrating a real application to Nativele: list items at the top level of a Light DOM template are no longer removed, Light DOM slots place nodes from where they are, another template system's ./x.html imports are left alone, and several diagnostics point at the right fix.

Changes

  • Light DOM slots: a <template data-each> at a Light DOM template's top level keeps the items it inserts after the first render (adds, removes, reorders, inserts while disconnected); it used to lose them a microtask later, or have them moved into the default slot. Slot content is placed from the nodes' current positions, so a node moved within the same task, a node added while disconnected and a slot's fallback (with its data-if blocks and lists in their last state) all end up where they belong.
  • Template imports: lint, ts-dom check and the oxlint plugin treat only ./x.html.js as a Nativele template import; ./x.html (another template system's import) is no longer linted as one, and ts-dom doctor still reports a Nativele import without .js. docs/tooling.md describes how two template systems coexist.
  • unused-ref: refs destructured from any .refs expression, renamed, quoted, nested or followed by as/satisfies or no semicolon count as used; refs: { … } in a type or object literal no longer hides an unused ref.
  • Fix hints: the a11y name rules say to give an element a data-ref when TypeScript sets its name; TS2307 for a missing ./x.html.js says to run ts-dom gen and scan the template's folder.
  • Robustness: a folder that vanishes during a run, or a symbolic link to nothing, is skipped instead of crashing a long-running host; the bin path is written as npm normalizes it.
  • Skills: nativele-linting (coexisting template systems, data-ref and the a11y name rules), nativele-monorepo and nativele-vite (one tsDom() per workspace package, its dev server watches those folders), nativele-core (points at the store adapter), nativele-state-management (getSnapshot clients); each re-verified by a fresh agent trial on 2026-11-08.

Breaking Changes

None. A module importing a template as ./x.html (without .js) is no longer linted as a Nativele template; ts-dom doctor reports it (template-import-without-js).

v0.7.2

Choose a tag to compare

@github-actions github-actions released this 07 Nov 18:10
228456f

Summary

Nativele 0.7.2: library elements are checked against their custom elements manifests, misspelled events on native elements are reported, component trees of any depth type check, and Skill trials and performance budgets are scripted.

Changes

  • Custom elements manifests: lint reads the customElements manifest of the template's package and its dependencies (no node_modules scan), so unknown-prop, invalid-prop-value (literal unions with Did you mean, ="false" on a boolean attribute, NaN numbers), unknown-event, and the new unknown-slot and unknown-custom-element check library elements such as Web Awesome's; completeness is judged per element along its superclass chain; manifest-known tags leave unchecked-custom-elements; doctor reports a broken manifest (custom-elements-manifest).
  • unknown-native-event (new): a data-on-* name on a native element that is close to one of its native events, and that no component, dispatched event or manifest declares, with Did you mean; not reported when the element holds content whose events lint cannot know.
  • Types: component trees of any depth, recursive and mutually recursive components type check (no TS2589, no circularity).
  • Fixes: data-flow issues in --json carry only the documented keys; emit-forwarding and custom-event-on-native point at the reported attribute; unguarded-input-value treats value, valueAsNumber and valueAsDate as one and counts only a comparison that gates the write; the Vite plugin parses each template once; the release workflow builds before staging so npm sees the bin file.
  • Skills and tooling: scripted Skill trials (npm run trial, fixtures in trials/, replay of the last accepted agent output in CI, first accepted trial for nativele-vue); performance budgets in CI (npm run bench:check: parse/read/readdir counts, memo entries, tsc instantiations, a scaling ratio); nativele-vue, nativele-integration, nativele-web-awesome and nativele-linting updated from trials (object props change by a new object, <KeepAlive> caches components, manifest checks).
  • Node: engines.node is >=22 (CI tests 22 and 24).

Breaking Changes

None in the public API. --json issues of the data-flow rules no longer carry undocumented extra fields (tag, attrs, values, events, slotted).

v0.7.1

Choose a tag to compare

@github-actions github-actions released this 07 Nov 16:30
a34a718

Summary

Nativele 0.7.1 makes any unable to switch the HTML–TypeScript checks off, and makes lint and codegen faster.

Changes

  • any-in-contract (new check): any in a component's state, props, derive, emits details, its template (Template<any> or an untyped Template), a handler member or a handler's first parameter is a tsc contract error, which ts-dom check reports at the declaring key, the Component(...) call or the data-on-* attribute, with a Fix. Only the data the component declares is looked into (objects, arrays, tuples, index signatures, Map, Set); DOM and other library types stop the search, so null as HTMLElement | null or a CustomEvent in state is not reported. unknown never triggers it.
  • any from outside types: an any in lib.dom, a third-party element class, HTMLElementTagNameMap or a child's contract is treated as not declared everywhere the types look things up, instead of satisfying a check by accident or turning an event into unknown.
  • Library source: typescript/no-explicit-any is an error in the repository's own lint.
  • Performance: each scanned folder is read once per run; the declared props and emits of each component are kept between runs; each folder's package is found once per run (1000 components: single-file oxlint re-lint about 21 to 13 ms, Vite template save about 45 to 29 ms, lint --a11y about 330 to 295 ms); a DOM-typed state field no longer expands lib.dom in tsc.
  • Skills: nativele-linting explains where any is reported and in which order; re-verified by an agent trial.

Breaking Changes

  • Code with any in a component contract now fails tsc (anyInContract: "props.item" and the like): declare a specific type, or unknown and narrow it where it is read.
  • Component(template([...])) without type arguments (an untyped Template) is now anyInContract: "template": import the template from its ./x.html.js module.

v0.7.0

Choose a tag to compare

@github-actions github-actions released this 07 Nov 15:35
7b3247d

Summary

Nativele 0.7.0 checks more of the contract between HTML and TypeScript: a data-on-* handler's parameter is checked against the event it is bound to, a form's elements and a list item's el are typed from the template. Lint, ts-dom check, codegen and the oxlint plugin now read how templates, classes and define() calls relate from one index that follows imports, barrels and namespaces, so they agree with each other on any file layout and stay current in the editor and the Vite dev server. The accessibility rules judge an element by its composed content, including what child components render into it, and say so with unchecked-content when they cannot. This release has breaking changes; see below.

Changes

Types and checks

  • A data-on-* handler may declare its event as its first parameter (onPick(e: EmitEvent<Picker, "pick">), onKey(e: KeyboardEvent)); define() checks it against the event the element declares for that name (the child's emits, the element's on<event> property, then HTMLElementEventMap), and ts-dom check reports a mismatch as handler-event-type at the attribute. this.on() checks an annotated parameter the same way.
  • A data-ref on a <form> types elements with the controls inside it by name and id; a misspelled name is a tsc error.
  • A list item's el is typed by the item's root tag: the item component's class for a component list, the element type for plain items.
  • New errors and warnings: each-in-svg (data-each inside <svg> or <math>), unchecked-custom-elements (custom elements lint has no single definition of, listed once per run with the cause and fix of each), and the a11y warning unchecked-content.
  • ts-dom lint and ts-dom check take --ignore=<rule-id> (repeatable) to leave out warnings.

Lint and tooling

  • One component index follows templates and classes through re-exports, barrels and namespaces and finds a class whose define() is in another file, so such components are in ts-dom-tags.ts, have typed refs, and get their props, events and template checked.
  • ts-dom check points missing-binding, missing-handler and handler-event-type at the template of the class the error is about, for every missing name, and keeps independent errors inside a broken class.
  • role-tabindex and click-semantics no longer overlap; click-semantics, control-name and heading-empty read what child components render, slots filled, so <div data-on-click><button> and a button whose name comes from a child component pass.
  • custom-event-on-native uses lib.dom's event names and reports only an event a component emits without bubbles: true.
  • The oxlint language server and the Vite plugin follow file changes across files (a child template, a new define(), a package.json) instead of keeping what they read first; the Vite plugin's a11y gives the same results as ts-dom lint --a11y.
  • Faster on large projects: each template is parsed once per run, a define() save regenerates only the templates that use the changed tags, and ts-dom gen --watch parses only the saved template.

Fixes

  • A data-on-* inside a data-if block of a list item now fires.
  • ts-dom lint and ts-dom gen report a missing folder as dir-not-found instead of crashing.
  • Templates imported from any folder, imported without .js, or used by a generic component class are found and checked.

Documentation and Skills

  • New Official Skill nativele-web-awesome; nativele-svelte, nativele-angular, nativele-zod, nativele-tanstack-query and nativele-tailwind are Official.
  • Every library rule is stated once in docs/ and linked from llms.txt; new recipes for request cancellation, config-driven tables, form-associated components and switching the language; AGENTS.md is a guide for agents that use the library.

Breaking Changes

  • Schema["events"] maps each handler to the [tag, event] pairs it is bound to instead of being a union of handler names. Migration: only a schema written by hand for template<...>() changes; use events: Record<never, never> for a template without handlers.
  • A handler whose first parameter does not accept the bound event (KeyboardEvent on a click, InputEvent on a change) is a tsc error (wrongHandlerParameters). Migration: declare the event type the error names, or type the parameter Event and narrow it in the body.
  • A list item's el is no longer Element, so a cast such as ctx.el as HTMLInputElement on an <li> item fails. Migration: remove the cast, or cast to the element the template has at the root.
  • The lint rule missing-handler is removed from ts-dom lint and the oxlint plugin (ts-dom/missing-handler); tsc reports a missing handler at define(), and ts-dom check reports it at the template under the same id. Migration: drop ts-dom/missing-handler from the linter config, and run ts-dom check or tsc where only ts-dom lint ran.
  • emits named focusin, focusout, compositionstart, compositionupdate, compositionend, touchstart, touchmove, touchend or touchcancel throws [native-event-name] in every browser (tsc already reported it). Migration: rename the event, for example with a prefix.
  • A custom event emitted with bubbles: true is handled in the bubble phase, so a stopPropagation() between its target and the handler now stops it. Migration: where the handler must still receive it, do not stop its propagation below that handler.