A set of functional programming "inspired" helpers
This project is a set of small helpers which utilize mostly monad and monad like patterns to cut down on code for essential tasks.
For now, it is only a small set of Helpers consisting of following items:
mona-dish/messagingThe default mona-dish package entry now exposes the core API only and does not load the RxJS-backed messaging module.
Projects using messaging must import it from mona-dish/messaging:
import {Broker, BroadcastChannelBroker, Message} from "mona-dish/messaging";
rxjs remains a consumer-provided external dependency. Install/provide it in applications which use mona-dish/messaging.
Everything is implemented in typescript and can be used straight from the source directories "src/main/typescript".
However, also javascript transpilations for various packaging systems and ecmascript levels are in place as well hosted under "dist".
If you want a cleaner cut between your own typescript sources, and the mona-dish sources there is a d.ts file also, hosted under "dist".
For building the project you need following
once this is done you can build it by calling ./init.sh one time to install all the needed build dependencies, after that calling /build.sh rebuilds the entire project.
You also can run mocha based unit tests on the project by calling ./test.sh
(note this is for unixoid systems, windows command files will be added soon, in the meanwhile simply check the command sequences in the sh files for building and testing)
The enhanced documentation for optional can be found here:
For a non sideffect free implementation, you can use:
Optional is a purely readonly construct, now for sideffect free-ness, having only readonly operations is fine. However, in iterative systems we often deal with states. To get the conciseness of Optional also for writeable states there is a class available which is inherited from optional and hence shares the same functionality.
ValueEmbedder
Promise is just a lightweight shim of the Promise API including finally. Cancellable promise adds on top of that by allowing to cancel (aka never hit the then/cancel phase)
The idea is to have streams like java does for arrays. (forEach, filter etc...)
The streams are heavily influenced by the java streams. Currently, two type of streams are implemented
The default (working already) a simple implementation of early evaluating streams
beforeEach(function () {
this.probe = [1, 2, 3, 4, 5];
});
it("must have a correct first last lazy", function () {
let stream = LazyStream.of<number>(...this.probe);
let first = LazyStream.of<number>(...this.probe).filter((data) => data != 5).onElem((data) => {
data;
}).first().value;
let last = Stream.of<number>(...this.probe).filter((data) => data != 5).onElem((data) => {
data;
}).last().value;
expect(first).to.eq(1);
expect(last).to.eq(4);
});
Or in conjunction with DomQuery
let searchRoot = DomQuery.querySelectorAll("input[type='hidden']")
let formWindowId: Optional<string> = searchRoot
.stream
.map<string>(getValue)
.reduce(doubleCheck, INIT);
let otherStream = LazyStream.ofDataSource(searchRoot);
See StreamTest.spec.ts in the "test sources" directory for additional examples
A JQuery like interface for standard dom queries, also supports Streams and Shadow doms. Further Info can be found here
DomQuery ... a jquery like functional query and dom manipulation engine based on querySelectorAll, also support streams and shadow dom trees
similar to DomQuery but atm without a full query engine behind it, the reason for that is, that the browsers do not have a universal query engine, yet. Also, I tried to avoid third party dependencies. You, also, will get many other benefits similar to DomQuery by using XmlQuery
A messaging bus ... for documentation follow this link:
Messaging is not exported by the default mona-dish package entry anymore. Use:
import {Broker, BroadcastChannelBroker, Message} from "mona-dish/messaging";
I am going to provide extended documentation on the various aspects of mona-dish in following subpages
Various usage examples can be found in the tests:
(Starting with version 0.18)
...
Adding Extended Array, to provide shim like functionality without shims (adds several functions to the standard array older browsers do not support, but does not hook itself in like a shim)
Rxjs connectivity, rxjs is a more popular framework than mona-dish but both have a heavy functional overlap. It makes sense to open mona-dish for rjxs in both directions to be able to combine both frameworks easily
RXJS forward connectivity enabled via iterable implementation! you can basically now use streams as iterables
20.3 Adding basic rxjs support for streams
20.4-20.5 Adding rxjs connectivity apis for the messages, brokerchannels now can be exported as Subjects
0.20.7 Adding encryption extension points to the messaging api
0.20.8 extension refinements tests for the extensions documentation updates
This is from now on a development branch, to finally split between unstable and stable
Breaking change:
To get reduced coupling between modules (I want to make the usage of Config optional) DomQuery does not use Config anymore but relies on standard associative arrays:
Config now is not a dependency of DomQuery anymore!
A new module AssocArray provides helper functions to provide a similar functionality as Config
Another minor breaking change.
0.25.26 reorganizes the internal data structure of config to allow easier access and a direct mapping of associative arrays and arrays. (Allows for easier debugging internal data structures and a small speed bump) due to this change following construct is not possible anymore
let conf = new Config({}); conf.assign("[5]","[6]","key").value = "new value";
This goes hand in hand with the newly introduced low level associative array api you have to change the code accordingly let conf = new Config([]); conf.assign("[5]","[6]","key").value = "new value";
So always when an array is referenced from root, the root element must be an array otherwise an exception is thrown (the same goes for existing subelemements)
(the same goes implicity for associative arrays in the other direction, arrays cannot have key references anymore with assignments)
This is from now on a stable branch (and all even numbered ones will be, with every odd branch there will be a higher even numbered one release to avoid accidental downloads)
In order to reduce the possible include size, there now is a stronger decoupling between streams and DomQuery. You now can use DomQuery without linking the Streams. In order to do so, the API has slightly changed. DomQuery.streams now is gone To generate a Stream of a DomQuery object you can use Stream.ofDomQuery and LazyStream.ofDomQuery
The reason was that Streams have a significant code overhead and with ES2019 the native api has somewhat reached the status of good enough with the inclusion of map. (internally we provide a non, bleeding shim for that functionality)
If you include Streams the backwards compatibility is restored
Additional api change, in order do decouple DomQuery and Config encodeSubmittableFields now returns an associative array instead of a Config. You can convert it back to an associative array simply by using
new Config(dq.encodeSubmittableFields())
Es2019 Array as non-intrusive Es2019 array shim (providing filter and flapMap to browsers which do not support it)
New helper module providing functions similar to what config does to plain associative arrays
Internal Config data structure reorganisation on top of the new AssocArray helper module it now uses plain associative arrays as internal data structure to make debugging easier
added nonce ValueHolder to DomQuery (console.log(element.nonce.value) and element.nonce.value = "nonceValue"), or element.nonce.isPresent()
Fixing shallow copy in AssocArray
Update to typescript 6.0 in preparation for typescript 7
Breaking change:
Messaging moved out of the default mona-dish package entry and is now exposed via mona-dish/messaging.
This keeps the default package entry free of the RxJS-backed messaging layer. Applications using messaging must import from mona-dish/messaging and provide rxjs themselves.
Build and test changes:
Removed the runtime build/test dependency on ts-node; TypeScript config files and tests now run through tsx.
Webpack keeps using webpack.config.ts, but bundle builds now run with full ts-loader type checking.
npm run build runs verify first, then docs, declarations, bundles, dist copy, and dist smoke tests.
Added npm run smoke to verify generated dist module formats.
Added manual npm run package:test to pack the package isolatedly and verify core usage without RxJS plus messaging usage with explicitly provided RxJS.
Fixed Beta 2 - beta 3
- Beta 2 and older
- Webpack runtime: aliased mona-dish → src/main/typescript/index_core.ts (TS source, compiled by ts-loader) — same as now
- TypeScript type-checking: package had no useful native types entry, so modules.d.ts declared an ambient module "mona-dish" override and the tsconfig paths redirected to the shim, which re-exported from dist/typescript/index_core.ts (TS source alongside .d.ts files in the same dir)
- Beta 3 (new):
- Webpack runtime: same — src/main/typescript/index_core.ts via the alias, nothing changed
- TypeScript type-checking: beta 3 added a proper "types": "./dist/types/index_core.d.ts" condition to the package.json exports map, so TypeScript resolves it natively
Performance (deep selector lookups):
_querySelectorAll now pushes each NodeList straight into a single target array via
pushChunked instead of nodes = nodes.concat(objToArray(res)), eliminating the per-root
objToArray copy and the concat reallocation (two redundant full copies of large result
sets, e.g. the querySelectorAll("*") shadow scan in querySelectorAllDeep).querySelectorAllDeep collects shadow hosts in a single pass (new private helper
_collectShadowRoots) instead of querySelectorAll("*").shadowRoot, which materialized a
DomQuery wrapping every element and then re-walked it through the shadowRoot getter. The cost
stays O(number of elements) — there is no selector for "has a shadow root" — but the throwaway
all-elements DomQuery and the second traversal are gone. Behaviour is unchanged, covered by a
new nested-shadow-root regression test.childNodes now pushChunkeds each root's child list into one target array instead of
childNodeArr = childNodeArr.concat(objToArray(item.childNodes)) per root, removing the
per-root copy and the O(roots × children) accumulator reallocation.byTagName (includeRoot branch) appends the matching roots via pushChunked instead of
reduce((acc, item) => acc.concat([item])), which reallocated the accumulator on every match
(O(matches²)). Both are covered by new multi-root regression tests.Bug fix (caret restore on non-text inputs):
Uncaught InvalidStateError: Failed to execute 'setSelectionRange' on 'HTMLInputElement'
thrown by DomQuery.setCaretPosition when a checkbox or radio button is re-rendered (e.g. via
a JSF/Faces Ajax partial update that focuses the re-rendered control). setSelectionRange
exists on every HTMLInputElement but the DOM spec mandates it throw for input types without
text selection (checkbox, radio, button, file, …); the prior existence-only guard was
therefore insufficient. The call is now wrapped so the error is swallowed while the preceding
focus() still applies (silent fail as documented). Regression introduced together with the
caret-restore refocus logic.Bug fix (browser argument-stack limit on large arrays):
RangeError: Maximum call stack size exceeded when collections beyond the engine
argument-stack limit (~65k elements in Chromium, varies per engine) flow through the library.
All internal call-position spreads of unbounded arrays (fn(...data), new Cls(...data),
push(...data), Element.prepend(...data)) were replaced by chunk-safe copies
(chunk size 30000, see MAX_ARG_LENGTH).Es2019ArrayFrom(arrayLike),
pushChunked(target, source), Stream.ofArr(array), LazyStream.ofArr(array),
ArrayStreamDataSource.ofArray(array). The variadic forms (Stream.of(...arr) etc.) remain
unchanged but are inherently subject to the engine argument limit when the caller spreads —
use the ofArr-style factories for large arrays.DomQuery now accepts plain element arrays directly (new DomQuery(elementArray)) and
flattens them chunk-safely (the constructor signature always advertised this).DomQuery.prepend / prependTo prepend in reverse chunk order — same resulting element
order as before, still a single native prepend call below the chunk size.DomQuery.offsetTop returning NaN (long-standing missing spread in the reduction).LargeArrayChunkingTest.spec.ts: 200k-element runs over all
chunking primitives with full order/completeness verification, 70k-element DomQuery
construction, 35k chunk-boundary prepend order check.Cleanup:
DomQuery.getCaretPosition: removed the legacy IE document.selection / TextRange
fallback branch and rewrote the method as a clean-room selectionStart-only
implementation. Caret read-out works on IE9+ and all modern browsers; IE8 and older
(which never supported selectionStart) are no longer handled.Bug fix:
DomQuery.outerHTML / caret handling: fixed a regression where a partial update of an
unrelated component reset the caret of a different, still-focused input field to position 0.
The caret is now only saved/restored when the focused element is actually part of the
subtree being replaced.DomQuery.getCaretPosition: prefer the modern selectionStart property when available,
falling back to the legacy IE document.selection range only when it is not. This makes
caret read-out reliable across partial-update cycles (e.g. the Tobago <tc:in> typing scenario).Bug fixes and test coverage improvements:
Lang.objAssign fallback path: fixed spec non-compliance — now copies enumerable Symbol-keyed own properties via Object.getOwnPropertySymbols + propertyIsEnumerable, matching ES2015 Object.assign behaviourDomQuery.fromMarkup: fixed tfoot branch (was using wrong table index); unified thead/tbody/tfoot into a single branch; added th cell handling (previously fell through to default)DomQuery.setCaretPosition: fixed typo setSelectiongRange → setSelectionRange (caret positioning was silently doing nothing)DomQuery.firstElem / lastElem: fixed guard condition > 1 → > 0 (single-element DomQuery was skipped); fixed lastElem passing wrong index to callbackDomQuery.elements / deepElements: removed invalid checkbox CSS selector (dead weight — checkboxes are already matched by input)DomQuery legacy waitUntilDom fallback: moved timeout/interval declarations before assignment for clarityStyle.getClass() / Style.fromNullable(): fixed both returning/creating ElementAttribute instead of StyleElementAttribute.set value(): removed duplicate setAttribute call after loopobjAssign (12 tests), fromMarkup all branches (14 tests), setCaretPosition (3 tests), firstElem/lastElem (6 tests), Style.fromNullable/getClass (3 tests), waitUntilDom fast-path + tightened assertions