Skip to content

Releases: MatAtBread/AI-UI

v0.17.3. Fix leak & regression

03 Dec 16:31
Compare
Choose a tag to compare

Fixes

  • Minor leak in debugging output
  • Regression in the expression this.when('@ready') when no child selectors were ever specified (the async iterator would terminate immediately without yielding an intermediate {})

Full Changelog: Release-v0.17.2...Release-v0.17.3

v0.17.2: Fixes + ErrorTag option

28 Nov 15:13
88da790
Compare
Choose a tag to compare

Fixes + ErrorTag option

  • Fix leaks in async attributes
  • Correct implementations of AsyncIterator.throw()
  • Add debug info to deferred & ExtraAsyncs

What's Changed

Full Changelog: Release-v0.17.1...Release-v0.17.2

Release-v0.17.1: Performance optimizations & leak fixes

26 Nov 21:37
Compare
Choose a tag to compare

Breaking change

In this release tag.nodes(...) returns in Iterator<Node>, not a Node[]. In most cases, the iterator will substitute just fine, with no modification. The exception is that the iterator can only be spread once. For example (not that this is very useful)

const n = tag.nodes("ABC");
// Works as expected, spreads the nodes in `n` and appends them to the document
document.body.append(...n); 
// Oops! A second attempt to spread `n` returns an empty list - we have already exhausted the `Iterator<Node>`
document.body.append(...n);
/* (as it happens, in this case, this generates the same DOM as using arrays, since inserting the same nodes twice into a DOM moves them, it doesn't clone them) */

If you really want to re-use the nodes, spread them into an array, which will store them, thus: const n = [...tag.nodes("ABC")];

Why has this change taken place?

AI-UI could leak "detached" nodes when it used arrays. Any return from tag.nodes(...) that went unused would leak, which includes some internal races when the tags are dynamic and co-dependent (for example if a child nodes depended on an event generated by an ancestor, which itself depended on the same event or one directly from it). Using an Iterator<Node> avoids a great many of these cases by not actually creating the nodes until they are consumed.

Although it didn't leak, this also address another issue, which is if the returned nodes or their attributes were dynamic (via an async iterator or promise) and NOT inserted into a document, there were cases where the update could fail (with a warning). This might be happen if you made nodes which tried to update themselves, awaited some other async operation and finally inserted them into the DOM. In practice this doesn't happen often as the natural way to do this is to insert the promise of the nodes, not the nodes themselves.

Other optimizations and leak fixes

  • Iterators.merge and Iterators.combine no longer rely on a forever Promise, avoiding cases where the promise chain leaks
  • Rather than waiting for a async iterator to yield before checking if a dynamic node is no longer in the DOM, it is also checked when it is removed, meaning resources are freed quicker (and possibly freed at all in the case of an async iterator that doesn't yield)

Full Changelog: Release-v0.15.5...Release-v0.17.1

Create by ID. Improve typings. Childless `when` selectors

22 Sep 01:53
Compare
Choose a tag to compare

Changes

Typing of iterable arrays has been improved

Please see the notes at https://github.com/MatAtBread/AI-UI/blob/v0.15.5/module/src/iterators.ts#L65-L72 about assigning an entire array in one statement.

Create children by id & related tag function

Within the scope of an extended tag, this.ids resolves not only as an object with live connections to contained elements by id (as previously), but also a function that can be used to create children by id, for example:

const MyDiv = div.extended({
  ids:{
   summary: span,
   details: table
  },
  constructed() {
    return [
      h1('Sales report'),
      // Create by ID, in this case a span
      this.ids({ id: 'summary' }, geSummary()),
      // Create by ID, in this case a table
      this.ids({ id: 'details' }, ...),
      div('Created on ', new Date().toString())
    ]
  }
});

This style removes the chance of the ids incorrectly referring to a different tag type.

"Childless" when selectors

When selectors, which fire when an identified child or any of its children generates the specified event, can have a ">" suffix with no grandchild specified to suppress grand-child elements fire. For example:

this.when('#form').consume(...); // Fires when the child id 'form' fires a change, or any of it's children do

this.when('#form>').consume(...); // Fires when the child id 'form' fires a change, bit ignores any fired by children of '#form'

Improvements

  • ValidWhenSelector and CSSIdentifier type improved
  • EventObservation now uses a WeakRef to improve GC performance if an Element is removed and no event fires that would cause it to be removed
  • Improvements in the typing of tags and tag functions
  • Some internal type names have been improved

Full Changelog: Release-v0.15.2...Release-v0.15.5

v0.15.2: Optimize `.ids`, better type checks,

15 Jul 16:35
6db7ff3
Compare
Choose a tag to compare

This release focuses on performance, removing legacy code, and ensuring document is correctly referenced.

The guide, examples and tests have been updated to reflect the changes, and the enhancements in v0.14.x for iterable objects, arrays and other fixes,

Breaking changes:

  • The legacy function getElementIDMap() has been removed
    • No longer used internally, and it was a slow function as it ended up enumerating a lot of nodes.
  • The legacy function enableOnRemovedFromDOM() has been removed
    • To enable this deprecated functionality, pass the flag enableOnRemovedFromDOM: true to the tag() options.
  • The legacy method for creating an element in a non-global document (by specifying it in the tag function attributes) has been removed. You can, if necessary, pass an alternative document to the tag() function options.
    • This is rarely necessary. The only real use cases are within a shadow DOM or an IFrame. In the latter case it is better if the frame calls tag() itself.

Optimization

  • The implementation of .ids has been completely re-written to lazily instantiate a proxy that caches elements keyed by their ID, and it is now a "live" implementation like an HTMLCollection. Assigning to .ids or any member of it now throws an exception.
  • Use common forever in Iterators.merge/combine to reduce memory footprint

Better types

  • Correctly define SpecialWhenEvents as having no members
  • Add excess keys test to extended definitions
  • add debugger non-persistent attribute specifier
  • attributes is now typed correctly for read (NamedNodeMap) and write (object). The write type doesn't yet enforce the attribute names/types.

Remove global references to document

The library no longer refers to the global document. You can specify a document in the TagFunctionOptions, eg: const { div } = tag({ document: frameDocument }). The default is to use the global document. All other document references are derived from the elements as they are managed. Removing this dependancy means you can create tag functions that work on a different document.

  • Add optional TagFunctionOptions['docuemnt'] & 'enableOnRemovedFromDOM' (replaces legacy export)
  • Make eventObservations weakly mapped from a document reference
  • reference elt.ownerDocument within elementIsInDOM
  • Move AI-UI style, resolvedNodes mutationTracker & Dom* functions within tag() call to use the specified document

What's Changed

  • v0.15.0 Deprecate legacy calls. Optimize .ids. Remove references to globalThis.document. by @matAtWork in #39
  • v0.15.1 Correctly escape CSS IDs. by @matAtWork in #41

Full Changelog: Release-v0.14.5...Release-v0.15.2

v0.14.5: Fixes & optimizations

02 Jul 14:31
Compare
Choose a tag to compare

Optimizations

  • Prefer isAsyncIterator over isAsyncIterable to reuse existing iterators (note: can be fooled by synchronous iterators)
  • Show stack in debug logging
  • export TagLoader type
  • assign initial iterable value in a single Object.assign() in preference to walking down the hierarchy and doing it field by field.

Fixes:

  • Correct test for a queue value in internalDebounceQueueIteratableIterator
  • Don't test path when an initial (top level) iterable value push occurs. This (incorrectly) supressed initial values
  • Assign in the (error) case of an iterable field being re-defined by an extended tag

Full Changelog: Realease-v0.14.4...Release-v0.14.5

v0.14.4: Type fixes

01 Jul 20:58
Compare
Choose a tag to compare

This release mainly fixes/corrects TypeScript issues with iterable properties & tag.attributes = {...} assigments. The worked as expected, but would generate TS errors in VSCode.

There's also one runtime fix: don't add to _inflight array when there are no pending consumers of a queue. This could result in a value getting eaten by the debouncing queue

Full Changelog: Release-v0.14.3...Realease-v0.14.4

PR: #36

v0.14.3: Improve iterable object implementation

29 Jun 16:04
d911fd0
Compare
Choose a tag to compare

Main release notes: https://github.com/MatAtBread/AI-UI/releases/tag/Release-v0.14.0

Updates:

  • export asyncExtras so they can be invoked directly if required
  • Add stack traces to verbose logs
  • Implement debouncing queue iterator
  • Pass path in object queue updates so minimal updates are applied to members. Specifically, changing a member will yield changes to all consumers of the parent paths, and any children if their value has changed
  • Don't create placeholder property in target until it is assigned by Proxy

Fixes

  • Apply initially valued async iterated properties in assignProps
  • Create DomPromiseContainer ai-ui.ts where an async iterable duck-types to a zero length array so subsequent updates work
  • Don't wrap members of a boxedObject if they are already iterable

The implementation permits consuming non-existent properties and nested objects, but does so by generating an undefined member on read, so:

iterable: {
  o: {}
 }
 ....
o.n.consume(...); // Works, even tho `n` was never declared. `"n" in o` is false
o.n = 123; // Creates `n` and yields to the consumer

What's Changed

Full Changelog: Release-v0.14.2...Release-v0.14.3

v0.14.2: Iterable Optimizations & Arrays

26 Jun 18:46
Compare
Choose a tag to compare

This release contains performance enhancements and implements iterable arrays:

  • Typings: define new explicit type for IterablePropertyValue which accepts arrays and objects
  • Accept function as supporting the JS in operator in isObjectLike
  • Refactor the implementation of queueIteratableIterator to permit derived versions such as debounceQueueIteratableIterator whilst hiding the internal implementation from the external interface.
  • debounceQueueIteratableIterator tracks in-flight async iterations to prevent duplicate (===) values being yielded in quick succession.
  • Fire iterables on a sub-property delete

Full Changelog: Release-v0.14.1...Release-v0.14.2

v0.14.1: Fix leak

18 Jun 11:59
cfac59f
Compare
Choose a tag to compare

See https://github.com/MatAtBread/AI-UI/releases/tag/Release-v0.14.0 for full release info

Fixes:

  • Fix leak when updated notes have been removed form the DOM and case falls through to call .next() erroneously

Other:

  • Update structure of Chrome Devtools extension
  • Change from unpkg.com to cdn.jsdelivr.net due to performance/reliability issues with unpkg.com

Full Changelog
1581146...Release-v0.14.1