marionette 5.0.0-alpha.2 → 5.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (188) hide show
  1. package/changelog.md +136 -1
  2. package/dist/agent-skill/SKILL.md +79 -0
  3. package/dist/agent-skill/scripts/docs.mjs +110 -0
  4. package/dist/docs/config/diagnostics/catalog.json +684 -0
  5. package/dist/docs/docs/agent-tools.md +114 -0
  6. package/dist/docs/docs/agents.md +130 -0
  7. package/dist/docs/docs/application-agent-template.md +58 -0
  8. package/dist/docs/docs/basics.md +275 -0
  9. package/dist/docs/docs/beta.md +106 -0
  10. package/dist/docs/docs/choosing-integrations.md +135 -0
  11. package/dist/docs/docs/classes.md +100 -0
  12. package/dist/docs/docs/common.md +315 -0
  13. package/dist/docs/docs/data.api.md +293 -0
  14. package/dist/docs/docs/diagnostic-catalog.md +153 -0
  15. package/dist/docs/docs/dom.api.md +253 -0
  16. package/dist/docs/docs/dom.interactions.md +315 -0
  17. package/dist/docs/docs/dom.prerendered.md +173 -0
  18. package/dist/docs/docs/events.class.md +498 -0
  19. package/dist/docs/docs/events.entity.md +163 -0
  20. package/dist/docs/docs/events.md +651 -0
  21. package/dist/docs/docs/forms-and-accessibility.md +154 -0
  22. package/dist/docs/docs/installation.md +273 -0
  23. package/dist/docs/docs/marionette.application.md +502 -0
  24. package/dist/docs/docs/marionette.behavior.md +608 -0
  25. package/dist/docs/docs/marionette.collectionview.md +1434 -0
  26. package/dist/docs/docs/marionette.mnobject.md +179 -0
  27. package/dist/docs/docs/marionette.region.md +745 -0
  28. package/dist/docs/docs/marionette.state.md +231 -0
  29. package/dist/docs/docs/marionette.view.md +396 -0
  30. package/dist/docs/docs/migration-from-v4.md +164 -0
  31. package/dist/docs/docs/optional-backbone.md +119 -0
  32. package/dist/docs/docs/production-and-performance.md +83 -0
  33. package/dist/docs/docs/public-api.md +77 -0
  34. package/dist/docs/docs/radio.md +296 -0
  35. package/dist/docs/docs/readme.md +61 -0
  36. package/dist/docs/docs/routing.md +177 -0
  37. package/dist/docs/docs/runtime-isolation.md +82 -0
  38. package/dist/docs/docs/security.md +95 -0
  39. package/dist/docs/docs/task-recipes.md +118 -0
  40. package/dist/docs/docs/terminology.md +85 -0
  41. package/dist/docs/docs/testing.md +103 -0
  42. package/dist/docs/docs/typescript.md +126 -0
  43. package/dist/docs/docs/utils.md +65 -0
  44. package/dist/docs/docs/view.lifecycle.md +305 -0
  45. package/dist/docs/docs/view.rendering.md +549 -0
  46. package/dist/docs/manifest.json +380 -0
  47. package/dist/docs/packages/adapters/readme.md +237 -0
  48. package/dist/docs/packages/data/readme.md +195 -0
  49. package/dist/docs/packages/radio/readme.md +75 -0
  50. package/dist/docs/packages/utils/readme.md +70 -0
  51. package/dist/docs/readme.md +11 -0
  52. package/dist/docs/skills/marionette/SKILL.md +79 -0
  53. package/dist/docs/skills/marionette/scripts/docs.mjs +110 -0
  54. package/dist/docs/starter/index.html +14 -0
  55. package/dist/docs/starter/main.mjs +18 -0
  56. package/dist/docs/starter/package-lock.json +1279 -0
  57. package/dist/docs/starter/package.json +13 -0
  58. package/dist/docs/starter/readme.md +30 -0
  59. package/dist/docs/starter/workspace.mjs +76 -0
  60. package/dist/docs/starter/workspace.test.mjs +60 -0
  61. package/dist/docs/test/fixtures/docs-application-guides/package.json +6 -0
  62. package/dist/docs/test/fixtures/docs-application-guides/validate.mjs +218 -0
  63. package/dist/docs/test/fixtures/docs-prerendered-content/package.json +10 -0
  64. package/dist/docs/test/fixtures/docs-prerendered-content/validate.mjs +48 -0
  65. package/dist/docs/test/fixtures/docs-region-lifecycle/package.json +12 -0
  66. package/dist/docs/test/fixtures/docs-region-lifecycle/validate.mjs +185 -0
  67. package/dist/docs/test/fixtures/docs-routing/package.json +10 -0
  68. package/dist/docs/test/fixtures/docs-routing/validate.mjs +154 -0
  69. package/dist/docs/upgradeGuide.md +475 -0
  70. package/dist/marionette.cjs +3425 -0
  71. package/dist/marionette.js +2671 -3113
  72. package/dist/marionette.min.js +1 -1
  73. package/dist/marionette.min.js.map +1 -1
  74. package/dist/marionette.umd.js +3457 -3042
  75. package/dist/marionette.umd.js.map +1 -1
  76. package/dist/types/cjs/create-marionette.d.ts +64 -0
  77. package/dist/types/cjs/index.d.ts +23 -0
  78. package/dist/types/cjs/mixins/behaviors.d.ts +38 -0
  79. package/dist/types/cjs/mixins/common.d.ts +19 -0
  80. package/dist/types/cjs/mixins/delegate-entity-events.d.ts +16 -0
  81. package/dist/types/cjs/mixins/destroy.d.ts +15 -0
  82. package/dist/types/cjs/mixins/radio.d.ts +16 -0
  83. package/dist/types/cjs/mixins/state.d.ts +25 -0
  84. package/dist/types/cjs/mixins/template-render.d.ts +29 -0
  85. package/dist/types/cjs/mixins/ui.d.ts +19 -0
  86. package/dist/types/cjs/mixins/view-events.d.ts +39 -0
  87. package/dist/types/cjs/mixins/view.d.ts +86 -0
  88. package/dist/types/cjs/modules/application.d.ts +77 -0
  89. package/dist/types/cjs/modules/behavior.d.ts +83 -0
  90. package/dist/types/cjs/modules/child-view-container.d.ts +86 -0
  91. package/dist/types/cjs/modules/collection-view.d.ts +109 -0
  92. package/dist/types/cjs/modules/common/build-region.d.ts +12 -0
  93. package/dist/types/cjs/modules/common/chainable-methods.d.ts +47 -0
  94. package/dist/types/cjs/modules/common/monitor-view-events.d.ts +3 -0
  95. package/dist/types/cjs/modules/common/view.d.ts +30 -0
  96. package/dist/types/cjs/modules/object.d.ts +76 -0
  97. package/dist/types/cjs/modules/region.d.ts +89 -0
  98. package/dist/types/cjs/modules/view.d.ts +129 -0
  99. package/dist/types/cjs/package.json +1 -0
  100. package/dist/types/cjs/runtime/data-api.d.ts +27 -0
  101. package/dist/types/cjs/runtime/dom-api.d.ts +38 -0
  102. package/dist/types/cjs/runtime/event-delegator.d.ts +26 -0
  103. package/dist/types/cjs/runtime/renderer.d.ts +4 -0
  104. package/dist/types/cjs/runtime/state-api.d.ts +12 -0
  105. package/dist/types/cjs/runtime-id.d.ts +2 -0
  106. package/dist/types/cjs/utils/extend.d.ts +14 -0
  107. package/dist/types/cjs/utils/subscribe-bindings.d.ts +5 -0
  108. package/dist/types/cjs/version.d.ts +2 -0
  109. package/dist/types/esm/create-marionette.d.ts +64 -0
  110. package/dist/types/esm/index.d.ts +23 -0
  111. package/dist/types/esm/mixins/behaviors.d.ts +38 -0
  112. package/dist/types/esm/mixins/common.d.ts +19 -0
  113. package/dist/types/esm/mixins/delegate-entity-events.d.ts +16 -0
  114. package/dist/types/esm/mixins/destroy.d.ts +15 -0
  115. package/dist/types/esm/mixins/radio.d.ts +16 -0
  116. package/dist/types/esm/mixins/state.d.ts +25 -0
  117. package/dist/types/esm/mixins/template-render.d.ts +29 -0
  118. package/dist/types/esm/mixins/ui.d.ts +19 -0
  119. package/dist/types/esm/mixins/view-events.d.ts +39 -0
  120. package/dist/types/esm/mixins/view.d.ts +86 -0
  121. package/dist/types/esm/modules/application.d.ts +77 -0
  122. package/dist/types/esm/modules/behavior.d.ts +83 -0
  123. package/dist/types/esm/modules/child-view-container.d.ts +86 -0
  124. package/dist/types/esm/modules/collection-view.d.ts +109 -0
  125. package/dist/types/esm/modules/common/build-region.d.ts +12 -0
  126. package/dist/types/esm/modules/common/chainable-methods.d.ts +47 -0
  127. package/dist/types/esm/modules/common/monitor-view-events.d.ts +3 -0
  128. package/dist/types/esm/modules/common/view.d.ts +30 -0
  129. package/dist/types/esm/modules/object.d.ts +76 -0
  130. package/dist/types/esm/modules/region.d.ts +89 -0
  131. package/dist/types/esm/modules/view.d.ts +129 -0
  132. package/dist/types/esm/runtime/data-api.d.ts +27 -0
  133. package/dist/types/esm/runtime/dom-api.d.ts +38 -0
  134. package/dist/types/esm/runtime/event-delegator.d.ts +26 -0
  135. package/dist/types/esm/runtime/renderer.d.ts +4 -0
  136. package/dist/types/esm/runtime/state-api.d.ts +12 -0
  137. package/dist/types/esm/runtime-id.d.ts +2 -0
  138. package/dist/types/esm/utils/extend.d.ts +14 -0
  139. package/dist/types/esm/utils/subscribe-bindings.d.ts +5 -0
  140. package/dist/types/esm/version.d.ts +2 -0
  141. package/package.json +144 -55
  142. package/readme.md +80 -100
  143. package/upgradeGuide.md +475 -0
  144. package/backbone.js +0 -12
  145. package/config/dom.js +0 -106
  146. package/config/event-delegator.js +0 -53
  147. package/config/features.js +0 -22
  148. package/config/renderer.js +0 -5
  149. package/index.js +0 -82
  150. package/mixins/behaviors.js +0 -106
  151. package/mixins/common.js +0 -55
  152. package/mixins/delegate-entity-events.js +0 -39
  153. package/mixins/destroy.js +0 -18
  154. package/mixins/events.js +0 -276
  155. package/mixins/radio.js +0 -37
  156. package/mixins/regions.js +0 -161
  157. package/mixins/requests.js +0 -121
  158. package/mixins/template-render.js +0 -90
  159. package/mixins/ui.js +0 -108
  160. package/mixins/view-events.js +0 -92
  161. package/mixins/view.js +0 -211
  162. package/modules/application.js +0 -72
  163. package/modules/behavior.js +0 -121
  164. package/modules/child-view-container.js +0 -184
  165. package/modules/collection-view.js +0 -804
  166. package/modules/common/bind-events.js +0 -56
  167. package/modules/common/bind-requests.js +0 -53
  168. package/modules/common/build-region.js +0 -37
  169. package/modules/common/get-option.js +0 -15
  170. package/modules/common/merge-options.js +0 -15
  171. package/modules/common/monitor-view-events.js +0 -89
  172. package/modules/common/normalize-methods.js +0 -22
  173. package/modules/common/radio.js +0 -37
  174. package/modules/common/trigger-method.js +0 -50
  175. package/modules/common/view.js +0 -57
  176. package/modules/object.js +0 -33
  177. package/modules/radio.js +0 -112
  178. package/modules/region.js +0 -441
  179. package/modules/view.js +0 -125
  180. package/utils/build-event-args.js +0 -24
  181. package/utils/call-handler.js +0 -10
  182. package/utils/deprecate.js +0 -32
  183. package/utils/error.js +0 -35
  184. package/utils/extend.js +0 -33
  185. package/utils/make-callback.js +0 -9
  186. package/utils/once-wrap.js +0 -14
  187. package/utils/proxy.js +0 -8
  188. package/version.js +0 -3
package/changelog.md CHANGED
@@ -1,7 +1,142 @@
1
- ### v5.0.0-alpha.2
1
+ ### v5.0.0-beta.1
2
2
 
3
+ * Established `@mnjs` as the companion package scope: utils, radio, data, and
4
+ adapters; the core package remains `marionette`
5
+ * Added a packaged application starter and beta trial guide, plus release
6
+ authorization restricted to one exact prerelease version
7
+
8
+ * Added optional `createMarionette()` runtime factories with independent class
9
+ families, mutable adapters, renderer configuration, and Radio channel registries;
10
+ ordinary named imports remain one default runtime built through the same composition
11
+ path
12
+ * Made ESM the canonical distribution for new applications while retaining
13
+ CommonJS and both UMD outputs as v5 compatibility distributions; UMD and AMD
14
+ consumers are asked to identify their usage in the public issue tracker before
15
+ the six-month post-5.0.0 distribution review
16
+ * Added a neutral DataApi for model identity, reads, serialization, ordered
17
+ model snapshots, entity subscriptions, and structural collection changes
18
+ * Renamed the pre-stable `DataApi.items(collection)` method to
19
+ `DataApi.models(collection)` without a compatibility alias
20
+ * Renamed the pre-stable serialized collection template property from `items` to
21
+ `models` without a compatibility alias
22
+ * Changed `Region#show` and `View#showChildView` to require an explicitly
23
+ constructed View-like instance; template functions, strings, and View-options
24
+ objects no longer allocate a hidden base View
25
+ * Split the internal View, Region, and declarative Region builder implementations
26
+ into owner-named modules and removed the obsolete combined source path
27
+ * Added explicit `View#renderAttributes()` and `CollectionView#renderAttributes()`
28
+ root-attribute refreshes; the default `DomApi.setAttributes` now removes
29
+ nullish entries while leaving omitted keys untouched
30
+ * Added the optional `@mnjs/data` package with observable Model and ordered
31
+ Collection sources plus matching DataApi and StateApi adapters
32
+ * Added the optional `@mnjs/adapters` package with explicit Backbone and
33
+ jQuery subpaths and no root barrel; removed the previous core adapter subpaths.
34
+ The Backbone integration configures DataApi and StateApi explicitly while
35
+ preserving native Backbone objects, prototypes, listeners, and event methods;
36
+ its `models()` method returns a copied ordered snapshot rather than exposing
37
+ Backbone's mutable internal collection array
38
+ * Changed the default model and collection contract to plain objects and arrays;
39
+ Backbone-specific data and event shapes now remain inside the explicit
40
+ `@mnjs/adapters/backbone` integration
41
+ * Removed `children.findByModelCid`; `findByModel` uses the configured DataApi key
42
+ * Replaced the alpha concrete `State` with exact state-source composition and an
43
+ independent StateApi observation contract; supplied sources are borrowed,
44
+ `createState(options)` results are owned, and the lazy default is a plain object
45
+ * Changed CollectionView structural updates to render in-place updates, recreate
46
+ child Views for immutable same-key replacements, drain reentrant observations,
47
+ recover the latest source after reconciliation hook failures, and move survivor
48
+ nodes without recreating or rerendering unchanged Views
49
+ * Changed `viewComparator: false` to disable presentation sorting while
50
+ `sortWithCollection` continues reconciling structural changes to source order;
51
+ use `sortWithCollection: false` to preserve manually managed child order
52
+ * Moved the optional jQuery-backed DomApi integration to
53
+ `@mnjs/adapters/dom/jquery`
54
+ operations and opt-in View, CollectionView, and Behavior `$el` compatibility
55
+ * Require concrete DOM elements for View and CollectionView `el`; resolve
56
+ selectors and unwrap jQuery collections at the call site
57
+ * Removed the undocumented alpha-only `Behavior#setElement`; retarget
58
+ Behaviors through their owning View's `setElement` method
59
+ * Fixed CollectionView child identity indexes so prototype-collision cids and
60
+ same-cid impostors cannot corrupt ownership or mutate unowned Views
61
+ * Fixed removal-only, unfiltered CollectionView updates with default collection
62
+ ordering or ordering disabled to preserve surviving child DOM, focus, selection,
63
+ media, and custom-element connection state without firing sort or child-render
64
+ lifecycles for unchanged survivors
65
+ * Removed the undocumented alpha-only named `Requests` export; request/reply
66
+ methods remain owned by the built-in `Radio` singleton and its channels
67
+ * Removed the alpha-only request/reply methods from `Application`, `Behavior`,
68
+ `CollectionView`, `MnObject`, `Region`, and `View`; use `Radio.channel(name)`,
69
+ the top-level `Radio` API, or an owner's `bindRequests`/`radioRequests`
70
+ integration instead
71
+ * Fixed selective `unbindRequests` cleanup to preserve a replacement reply
72
+ owned by another object
3
73
  * Fixed Radio circular dependency with log and debug
4
74
  * Fixed event interop with Backbone
75
+ * Fixed delegated event matching so nested matching ancestors fire once per event
76
+ * Fixed callable Behavior `events` and `triggers` to resolve after Behavior
77
+ initialization
78
+ * Fixed CollectionView empty Region construction to occur after `initialize`
79
+ * Removed the module-global feature registry and the `setEnabled` and `isEnabled`
80
+ exports; configure child event prefixes per View, trigger DOM behavior per
81
+ trigger, and application-owned values through a state source or explicit configuration
82
+ * Preserved `emptyView` resolver returns of `undefined`, `null`, or `false` as
83
+ disabled empty-view states
84
+ * Changed the base `Region#show`, `Region#empty`, and `Region#reset`
85
+ implementations to no-op once Region destruction begins
86
+ * Changed `Region#detachView` once destruction begins to return `undefined`
87
+ without transferring the current View out of Region-owned teardown
88
+ * Changed destroyed `View#render` and `CollectionView#render` calls to return the
89
+ instance without resolving templates or running the render lifecycle
90
+ * Changed base `View#setElement` and `CollectionView#setElement` calls once
91
+ destruction begins to return the instance without changing its element
92
+ * Changed base `CollectionView#addChildView` calls once destruction begins to
93
+ return the supplied View without inspecting or managing it
94
+ * Changed base `View#delegateEntityEvents` and
95
+ `CollectionView#delegateEntityEvents` calls once destruction begins to return
96
+ the instance without resolving host or Behavior maps or binding subscriptions
97
+ * Changed direct `Behavior#delegateEntityEvents` calls once the owning View's
98
+ destruction begins to return the Behavior without resolving maps or binding
99
+ subscriptions
100
+ * Changed base `View#bindUIElements`, `CollectionView#bindUIElements`, and
101
+ direct `Behavior#bindUIElements` calls once the owning View's destruction
102
+ begins to return the receiver without resolving or binding UI
103
+ * Changed `View#hasRegion` to check own registered Regions without rendering or
104
+ changing View lifecycle state
105
+ * Changed `View#getRegions` to return a safe Region snapshot without rendering;
106
+ `View#emptyRegions` remains a render-triggering mutator
107
+ * Changed `View#getRegion` to return an own registered Region without rendering;
108
+ child View operations now render before dispatching Region lookup overrides
109
+ * Added `Region#getOwner` and `Region#getName` as pure queries over the existing
110
+ registered View relationship
111
+ * Changed Region registration to treat the existing owner/name relationship as
112
+ an idempotent no-op and reject conflicting ownership or names with stable
113
+ diagnostic code `MN0030`
114
+ * Changed named View Region operations to require string names and reject
115
+ empty names with diagnostic code `MN0032`
116
+ * Changed Application lifecycle operations to return `Promise<boolean>`, added
117
+ `stop`, `restart`, and `isRunning`, and made later incompatible operations
118
+ cancel stale lifecycle success without rejecting ordinary cleanup races;
119
+ readiness hooks receive an operation context with a cooperative abort signal
120
+ * Added explicit named child Application ownership, pure owner-side child
121
+ queries, and deterministic owner-driven child destruction; parent references
122
+ remain private lifecycle state rather than public upward lookup
123
+ * Changed owned child Applications to start and stop sequentially with their
124
+ owner while conflicting direct child operations cancel owner completion
125
+ * Changed Application root View teardown to empty only its current View on stop,
126
+ destroy constructed Regions, and preserve borrowed host Regions
127
+ * Removed target-first common-method exports from the package root, including
128
+ their generic plain-object adapter; use the corresponding method on each
129
+ Marionette instance
130
+ * Trust declared argument shapes for option keys, callbacks, bindings, View and
131
+ Behavior configuration, and adapter methods; retire their custom shape errors
132
+ and type private immediate-child propagation as an array
133
+ * Removed the historically documented `Radio.log` and `Radio.debugLog`
134
+ replacement hooks; the built-in Radio now owns one diagnostic and tuning
135
+ output path
136
+ * Internalized the Radio Channel constructor and registry; obtain channels
137
+ through `Radio.channel(name)`
138
+ * Changed borrowed top-level Radio methods to dispatch through the imported
139
+ singleton instead of accepting an alternate receiver and registry
5
140
 
6
141
  ### v5.0.0-alpha.1
7
142
 
@@ -0,0 +1,79 @@
1
+ ---
2
+ name: marionette
3
+ description: Build and debug applications using Marionette v5 with the installed version's documentation, independent integration choices, and lifecycle-aware validation. Use for application work involving Marionette Views, Regions, CollectionViews, Application, state, or adapters; library maintenance follows its own repository instructions.
4
+ ---
5
+
6
+ # Build with Marionette
7
+
8
+ Use the application's installed contract. This skill does not select a package
9
+ version, authorize an upgrade, or replace the application's existing decisions.
10
+
11
+ ## Find the contract
12
+
13
+ Inspect the application's manifest, lockfile, and runtime configuration. Resolve
14
+ paths relative to the application being edited, including its workspace directory
15
+ in a monorepo. Do not use the skill's own directory as the application root.
16
+
17
+ Run the bundled helper with Node 24 or later (replace both absolute paths):
18
+
19
+ ```sh
20
+ node /path/to/marionette/scripts/docs.mjs --project /path/to/application --list
21
+ node /path/to/marionette/scripts/docs.mjs --project /path/to/application --page docs/agents.md
22
+ ```
23
+
24
+ The helper reads files only. It finds the installed `marionette` package without
25
+ executing project code, checks the packaged documentation's version and hashes,
26
+ and reports provenance. Use its returned paths to read further pages. It does not
27
+ search the internet or run a package manager. For an installation without a
28
+ `node_modules` tree, supply `--package-root /physical/path/to/marionette` obtained
29
+ from that project's package manager. Do not substitute a different workspace's
30
+ package just because it is available.
31
+
32
+ If the installed artifact has no `dist/docs`, inspect its exports and declarations
33
+ and obtain docs from that package's exact release or known source commit. An alpha
34
+ version string alone does not establish a source match. Report missing provenance;
35
+ do not silently use `master`, current website docs, or another project's package.
36
+ A hash check detects inconsistent documentation files, not whether a custom build's
37
+ JavaScript actually matches those docs. Validate uncertain behavior against the
38
+ installed runtime. A `sourceDirty: true` manifest describes local changes, not an
39
+ immutable release.
40
+
41
+ ## Read only what the task needs
42
+
43
+ Start with packaged `docs/agents.md`, then use these source paths from the manifest:
44
+
45
+ - New setup or an integration decision: `docs/installation.md` and
46
+ `docs/choosing-integrations.md`.
47
+ - UI ownership and replacement: `docs/marionette.view.md`,
48
+ `docs/marionette.region.md`, and `docs/view.lifecycle.md`.
49
+ - Changing lists: `docs/marionette.collectionview.md` and `docs/data.api.md`.
50
+ - Asynchronous features or routing: `docs/marionette.application.md` and
51
+ `docs/routing.md`.
52
+ - State or a diagnostic: `docs/marionette.state.md` or
53
+ `docs/diagnostic-catalog.md`.
54
+
55
+ The manifest is the available-page index. Follow direct links for the selected
56
+ task instead of loading the whole reference. For v4 work, use matching migration
57
+ material and installed APIs; these v5 instructions are not an upgrade plan.
58
+
59
+ ## Make the application decision
60
+
61
+ Preserve a compatible established integration. For a new application, use built-in
62
+ behavior when it supplies the capability; select an observable source when updates
63
+ need observation. Choose DataApi, StateApi, renderer, DomApi, EventDelegator, and
64
+ router independently. A Backbone router does not require Backbone data or state.
65
+ Register configuration before creating its consumers; use an isolated runtime only
66
+ when independent configurations must coexist.
67
+
68
+ Name the owner and cleanup operation for Views, subscriptions, widgets, and async
69
+ work. Use public lifecycle APIs. Check stale work before committing side effects;
70
+ framework cancellation cannot undo arbitrary writes by application code. Consult
71
+ the current reference for exact return and readiness behavior rather than inferring
72
+ it from a method name.
73
+
74
+ Use the application's own test commands. Exercise the requested behavior and its
75
+ relevant boundary: stale navigation, surviving edits/focus, rerendered event
76
+ handlers, or resource cleanup. Browser behavior needs a browser check. Report
77
+ commands actually run and untested boundaries; a successful build is not proof of
78
+ those interactions. Record changed integration decisions in the application's own
79
+ instructions without copying the library's maintainer policy.
@@ -0,0 +1,110 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile, realpath, stat } from 'node:fs/promises';
3
+ import { dirname, isAbsolute, relative, resolve, sep } from 'node:path';
4
+
5
+ const usage = 'Usage: node docs.mjs [--project PATH] [--package-root PATH] [--list | --page SOURCE]';
6
+ const hash = value => createHash('sha256').update(value).digest('hex');
7
+ const json = async path => JSON.parse(await readFile(path, 'utf8'));
8
+
9
+ async function installedPackage(project) {
10
+ let directory = await realpath(project);
11
+ if (!(await stat(directory)).isDirectory()) {
12
+ throw new Error('--project must name a directory.');
13
+ }
14
+ while (true) {
15
+ const candidate = resolve(directory, 'node_modules/marionette');
16
+ try {
17
+ return await realpath(candidate);
18
+ } catch (error) {
19
+ if (error.code !== 'ENOENT') { throw error; }
20
+ }
21
+ const parent = dirname(directory);
22
+ if (parent === directory) {
23
+ throw new Error('No installed marionette found. Use the application workspace or --package-root for its physical package directory.');
24
+ }
25
+ directory = parent;
26
+ }
27
+ }
28
+
29
+ async function main() {
30
+ const options = { project: process.cwd() };
31
+ const args = process.argv.slice(2);
32
+ let mode;
33
+ for (let index = 0; index < args.length; index++) {
34
+ const argument = args[index];
35
+ if (argument === '--help') { console.log(usage); return; }
36
+ if (argument === '--list') {
37
+ if (mode) { throw new Error(usage); }
38
+ mode = 'list';
39
+ } else if (['--project', '--package-root', '--page'].includes(argument)) {
40
+ const value = args[++index];
41
+ if (!value || value.startsWith('--')) { throw new Error(usage); }
42
+ if (argument === '--page') {
43
+ if (mode) { throw new Error(usage); }
44
+ mode = 'page';
45
+ }
46
+ options[argument.slice(2)] = value;
47
+ } else {
48
+ throw new Error(usage);
49
+ }
50
+ }
51
+ const packageRoot = options['package-root'] ? await realpath(options['package-root']) : await installedPackage(options.project);
52
+ const metadata = await json(resolve(packageRoot, 'package.json'));
53
+ const docsRoot = await realpath(resolve(packageRoot, 'dist/docs')).catch(() => {
54
+ throw new Error('This package has no dist/docs. Read its exports/declarations and obtain documentation from its exact release or known source revision; do not substitute current master.');
55
+ });
56
+ const docsLocal = relative(packageRoot, docsRoot);
57
+ if (docsLocal === '..' || docsLocal.startsWith(`..${sep}`) || isAbsolute(docsLocal)) {
58
+ throw new Error('Documentation root escapes its package.');
59
+ }
60
+ const manifest = await json(resolve(docsRoot, 'manifest.json'));
61
+ if (metadata.name !== 'marionette' || manifest.packageName !== metadata.name || manifest.packageVersion !== metadata.version) {
62
+ throw new Error('Documentation package/version does not match the installed marionette package.');
63
+ }
64
+ if (manifest.schemaVersion !== 1 || !/^[a-f0-9]{40}$/.test(manifest.sourceRevision) ||
65
+ typeof manifest.sourceDirty !== 'boolean' || !Array.isArray(manifest.pages) || !Array.isArray(manifest.assets)) {
66
+ throw new Error('Unsupported or incomplete documentation manifest.');
67
+ }
68
+ const entries = [...manifest.pages, ...manifest.assets];
69
+ const files = new Map();
70
+ for (const entry of entries) {
71
+ const source = entry.source;
72
+ if (typeof source !== 'string' || isAbsolute(source) || source.includes('\\') || source.split('/').some(part => !part || part === '..' || part === '.')) {
73
+ throw new Error('Unsafe documentation source path.');
74
+ }
75
+ if (files.has(source)) { throw new Error(`Duplicate documentation source: ${source}`); }
76
+ const path = await realpath(resolve(docsRoot, source));
77
+ const local = relative(docsRoot, path);
78
+ if (local === '..' || local.startsWith(`..${sep}`) || isAbsolute(local)) {
79
+ throw new Error(`Documentation source escapes its package: ${source}`);
80
+ }
81
+ const content = await readFile(path);
82
+ if (hash(content) !== entry.sha256) { throw new Error(`Documentation hash mismatch: ${source}`); }
83
+ files.set(source, { path, content });
84
+ }
85
+ const digest = hash(entries.sort((a, b) => a.source.localeCompare(b.source, 'en'))
86
+ .map(entry => `${entry.source}\0${entry.sha256}\n`).join(''));
87
+ if (digest !== manifest.contentSha256) { throw new Error('Documentation manifest content digest does not match.'); }
88
+ const provenance = {
89
+ packageRoot,
90
+ packageVersion: metadata.version,
91
+ sourceRevision: manifest.sourceRevision,
92
+ sourceDirty: manifest.sourceDirty,
93
+ contentSha256: digest,
94
+ };
95
+ if (mode === 'page') {
96
+ const page = manifest.pages.find(entry => entry.source === options.page);
97
+ if (!page) { throw new Error('Page is not in this package manifest. Use --list to find its exact source path.'); }
98
+ console.log(JSON.stringify({ ...provenance, source: page.source, sha256: page.sha256 }));
99
+ console.log(files.get(page.source).content.toString('utf8'));
100
+ } else {
101
+ console.log(JSON.stringify({ ...provenance, pages: manifest.pages.map(page => ({
102
+ source: page.source, title: page.title, section: page.section, path: files.get(page.source).path,
103
+ })) }, null, 2));
104
+ }
105
+ }
106
+
107
+ main().catch(error => {
108
+ console.error(`Marionette docs: ${error.message}`);
109
+ process.exitCode = 1;
110
+ });