feat: add properties path tree to ObserverMapConfig in fast-html#7448
Merged
feat: add properties path tree to ObserverMapConfig in fast-html#7448
Conversation
There was a problem hiding this comment.
Pull request overview
Adds path-level configuration to @microsoft/fast-html’s observerMap option so templates can selectively observe specific root properties and nested subpaths, enabling granular opt-in/opt-out behavior while preserving the existing “observe all” default.
Changes:
- Extends
ObserverMapConfigwith apropertiespath tree (ObserverMapPathEntry/ObserverMapPathNode) and threads config intoObserverMap. - Stamps
$observeflags onto schema nodes and updates proxy/observation logic to skip excluded paths. - Adds unit + fixture coverage and updates public docs/API report to describe the new configuration.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/fast-html/src/components/template.ts | Defines new observer-map config/types and passes config into ObserverMap. |
| packages/fast-html/src/components/observer-map.ts | Implements config filtering at root and schema $observe stamping. |
| packages/fast-html/src/components/utilities.ts | Updates proxy assignment and traps to respect schema $observe. |
| packages/fast-html/src/components/schema.ts | Adds $observe?: boolean to schema nodes (used by observer-map stamping). |
| packages/fast-html/src/components/observer-map.spec.ts | Adds unit tests for properties config behavior (observe all/none, skip roots). |
| packages/fast-html/test/fixtures/observer-map-properties/entry.html | New fixture entry page for selective observer-map behavior. |
| packages/fast-html/test/fixtures/observer-map-properties/templates.html | New fixture templates exercising included/excluded subpaths. |
| packages/fast-html/test/fixtures/observer-map-properties/state.json | Fixture state for selective observation scenarios. |
| packages/fast-html/test/fixtures/observer-map-properties/main.ts | Fixture element implementations + TemplateElement.options() config examples. |
| packages/fast-html/test/fixtures/observer-map-properties/index.html | Generated fixture output used for hydration/fixture validation. |
| packages/fast-html/test/fixtures/observer-map-properties/fast-build.config.json | Fixture build configuration for fast-build. |
| packages/fast-html/test/fixtures/observer-map-properties/observer-map-properties.spec.ts | Playwright fixture tests validating selective observation end-to-end. |
| packages/fast-html/src/index.ts | Re-exports new observer-map config types from the package entrypoint. |
| packages/fast-html/src/components/index.ts | Re-exports new observer-map config types from components barrel. |
| packages/fast-html/docs/api-report.api.md | Updates API report for new public types and constructor signature. |
| packages/fast-html/README.md | Documents observerMap.properties path tree semantics and examples. |
| packages/fast-html/DESIGN.md | Documents config resolution algorithm and $observe stamping behavior. |
| change/@microsoft-fast-html-2751da26-46f3-4c7d-ae10-4437c26b800b.json | Adds a change file for the update (currently marked type: none). |
Comments suppressed due to low confidence (1)
packages/fast-html/src/components/utilities.ts:1664
- In the Proxy
settrap, the$observe: falsecheck short-circuits all assignments for excluded properties. This breaks the intended$observe:false+ re-include-children scenario when the excluded property is replaced with a new object/array: the new value won’t be proxied and no notification will fire, so observed descendants (e.g.charts.activeChart) won’t update. Consider only short-circuiting when the property schema is excluded and has no observed descendants, and otherwise proxy/notify using the child property’s schema.
const propName = typeof prop === "string" ? prop : String(prop);
// If the schema marks this property as not observed, assign without proxying or notifying
if (schemaProperties?.[propName]?.$observe === false) {
obj[prop] = value;
return true;
}
obj[prop] = assignObservables(
schema,
rootSchema,
value,
target,
rootProperty,
);
notifyObservables(proxy);
Add a `properties` key to the `ObserverMapConfig` interface so that developers can opt specific root properties and nested sub-paths in or out of automatic observer-map observation, rather than the current all-or-nothing approach. Each path entry can be: - `true` — observe this path and all descendants - `false` — skip this path and all descendants - An object with optional `$observe` boolean and child overrides When `properties` is omitted, current behavior is preserved (all root properties observed). When `properties` is present but empty, no root properties are observed. Resolves #7445 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the configEntry parameter that was threaded through 6+ proxy functions with a one-time schema pre-processing pass. applyConfigToSchema stamps $observe: false directly onto schema nodes, so the proxy system can check schema.$observe instead of needing a separate config tree. This eliminates: - configEntry param from assignObservables, assignProxyToItemsInObject, assignProxy, assignObservablesToArray, assignProxyToItemsInArray - 3 helper functions (getChildConfigEntry, shouldObserveAtPath, hasObservedDescendant) from utilities.ts - All child-config resolution at every proxy set trap invocation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update Data Flow diagram to show applyConfigToSchema step - Update Schema and Observer Map section with stamping details - Add JSDoc to JSONSchemaCommon.$observe field Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix deleteProperty and set traps to check hasObservedSchemaDescendant before suppressing notifications. Properties with $observe: false that have re-included descendants now correctly notify on delete/replace. - Update change file type from 'none' to 'prerelease' since this adds new public API surface (ObserverMapConfig.properties, exported types). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pattern into a single `isSchemaExcluded()` function. This consolidates 5 call sites (property iteration in assignProxyToItemsInObject and assignProxyToItemsInArray, set/deleteProperty traps in assignProxy, and the proxy creation check) into one readable predicate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ea817b1 to
a442ae3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
📖 Description
Adds a
propertieskey to theObserverMapConfiginterface in@microsoft/fast-htmlso that developers can opt specific root properties and nested sub-paths in or out of automatic observer-map observation, rather than the current all-or-nothing approach.Each path entry can be:
true— observe this path and all descendantsfalse— skip this path and all descendantsObserverMapPathNode— an object with optional$observeboolean and child overrides, enabling alternating opt-in/opt-out to arbitrary depthWhen
propertiesis omitted (observerMap: {}orobserverMap: "all"), current behavior is preserved. Whenpropertiesis present but empty ({ properties: {} }), no root properties are observed.🎫 Issues
👩💻 Reviewer Notes
Key areas to review:
observer-map.ts: NewhasObservedPathhelper and config filtering logic indefineProperties()utilities.ts: Config threading through the proxy system (assignObservables,assignProxyToItemsInObject,assignProxy), particularly thesettrap changes that skip notification for excluded propertiestemplate.ts: New types (ObserverMapPathEntry,ObserverMapPathNode) and config extraction forObserverMapconstructor📑 Test Plan
observer-map.spec.tscovering:falseroot properties{}){ properties: {} })observer-map-properties/covering:false)$observe: falsebranch✅ Checklist
General
$ npm run change