Thanks to the amazing group of people and knowledge here, I have developed a couple of useful program objects that can be found at GitHub - Jphreak/Niagara_N4: Tridium N4 Useful Objects · GitHub . I hope you find them as useful as I do.
I read the three v3.0 programs and the two AX ports, not just the README. The part worth commenting on is the copy engine, not the feature list.
The Component Copier does not hand-roll the copy. It builds a Mark over the source and hands Mark.copyTo a throwaway BComponent carrying a single keepAllLinks boolean. That name is not arbitrary: it is the same parameter the framework’s own copy strategy reads, so your copies behave exactly like a Workbench paste. Inside that strategy every link in the copied set is rewritten from a handle map. A source inside the set is remapped to the new copy. A source outside it has two fates. Same space and keepAllLinks true, and the handle is unswizzled back to the original, so the copy stays wired to the source. Otherwise the link is deleted and the target property is reset to its type default, not left holding its last value. That is why copying a folder whole fixes sibling links, so your v3.0 note is right.
Two things I would change.
- Adding a link never fails loudly. Once add has parented the BLink, the framework activates it through a helper that catches Throwable and only logs. So a source ord that will not resolve, a misspelled source or target slot, a slot type the framework refuses to link, or crossing the station’s licensed link count all return normally from add, and your code writes LINKED. The refused-slot case also removes the slot it just added; the over-licence case leaves the link in the property sheet with a fault flag set, so it never propagates. For a CSV-driven bulk linker that is the one that will bite someone: a typo in a two hundred row CSV, a clean results CSV, and nothing works.
The fix is small and public API only: read the link back after add and treat missing, not active, or fault-flagged as a failure row. That also makes verify honest, since a slot-exists test reports a link as present even when it never resolved.
- Flatten mode can leave two live links into one input. With the trailing star each child is copied in its own call, so a sibling link’s source handle is not in that child’s map. It takes the keep branch, and the copy arrives still fed by the original folder’s child, under the original link slot name. Your internal-link pass then adds the correct link under the hashed name, and the already-exists guard cannot see the preserved one because the names differ. Niagara allows more than one active link into a slot, so both propagate and the order is undefined, and reverse only removes the hashed one. Either drop inbound links whose source still resolves under the source folder before recreating, or pass keepAllLinks false for the flatten-mode child copies and accept the property reset.
All of that is read off the 4.15 framework code, not run on a station, so treat it as a code reading.
Thanks again for taking the time to read through the code and offer your suggestions. I have implemented the changes as you laid them out. Your explanation was excellent and thanks for helping make these tools better!