Releases: MatAtBread/AI-UI
v0.17.3. Fix leak & regression
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
Fixes + ErrorTag option
- Fix leaks in async attributes
- Correct implementations of AsyncIterator.throw()
- Add debug info to deferred & ExtraAsyncs
What's Changed
- V0.17.1 by @MatAtBread in #45
- V0.17.2: Add
ErrorTag
option. More leak fixes by @matAtWork in #46
Full Changelog: Release-v0.17.1...Release-v0.17.2
Release-v0.17.1: Performance optimizations & leak fixes
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, await
ed 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
andIterators.combine
no longer rely on aforever
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
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,
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
has been removedgetElementIDMap()
- No longer used internally, and it was a slow function as it ended up enumerating a lot of nodes.
- The legacy function
has been removedenableOnRemovedFromDOM()
- To enable this deprecated functionality, pass the flag
enableOnRemovedFromDOM: true
to thetag()
options.
- To enable this deprecated functionality, pass the flag
- 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 thetag()
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.
- 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
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
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
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
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
- V0.14.2 by @MatAtBread in #34
- V0.14.3 by @MatAtBread in #35
Full Changelog: Release-v0.14.2...Release-v0.14.3
v0.14.2: Iterable Optimizations & Arrays
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 JSin
operator inisObjectLike
- Refactor the implementation of
queueIteratableIterator
to permit derived versions such asdebounceQueueIteratableIterator
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
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