Skip to content

Commit 1ce5f88

Browse files
janechuCopilot
andcommitted
feat: remove declarative map helper exports
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 8acba4a commit 1ce5f88

32 files changed

Lines changed: 111 additions & 671 deletions

File tree

change/@microsoft-fast-element-61e3e3bd-e227-4449-9ff6-8edc104819d9.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"type": "major",
3-
"comment": "Move declarative HTML APIs into @microsoft/fast-element/declarative.js and remove the @microsoft/fast-html package.",
3+
"comment": "Move declarative HTML APIs into @microsoft/fast-element/declarative.js, expose schema map helpers from extension subpaths, and remove the @microsoft/fast-html package.",
44
"packageName": "@microsoft/fast-element",
55
"dependentChangeType": "none",
66
"email": "7559015+janechu@users.noreply.github.com"

packages/fast-element/DECLARATIVE_DESIGN.md

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,10 @@ An optional layer that uses the `Schema` to automatically:
118118
- Install property-change handlers that wrap newly assigned objects/arrays in `Proxy` instances.
119119
- Propagate deep property mutations back through FAST's observable system so bindings re-render.
120120

121-
Enabled via the `observerMap()` definition extension. Prefer importing the
122-
extension from `@microsoft/fast-element/extensions/observer-map.js`; the
123-
declarative entrypoint continues to re-export it for existing declarative
124-
imports. Calling `observerMap()` without arguments observes all root properties
125-
discovered in the template or supplied schema.
121+
Enabled via the `observerMap()` definition extension. Import the extension from
122+
`@microsoft/fast-element/extensions/observer-map.js`; the declarative entrypoint
123+
does not re-export it. Calling `observerMap()` without arguments observes all
124+
root properties discovered in the template or supplied schema.
126125

127126
#### Path-level observation control
128127

@@ -202,12 +201,11 @@ An optional layer that uses the `Schema` to automatically register `@attr`-style
202201
- Properties already decorated with `@attr` or `@observable` are left untouched.
203202
- `FASTElementDefinition.attributeLookup` is keyed by the HTML attribute name, and `propertyLookup` is keyed by the JS property name so `attributeChangedCallback` correctly delegates to the new `AttributeDefinition`.
204203

205-
Enabled via the `attributeMap()` definition extension. Prefer importing the
206-
extension from `@microsoft/fast-element/extensions/attribute-map.js`; the
207-
declarative entrypoint continues to re-export it for existing declarative
208-
imports. Calling `attributeMap()` without arguments uses the default
209-
`"camelCase"` strategy. To preserve binding keys exactly as written, pass
210-
`attributeMap({ "attribute-name-strategy": "none" })`. Outside declarative
204+
Enabled via the `attributeMap()` definition extension. Import the extension from
205+
`@microsoft/fast-element/extensions/attribute-map.js`; the declarative entrypoint
206+
does not re-export it. Calling `attributeMap()` without arguments uses the
207+
default `"camelCase"` strategy. To preserve binding keys exactly as written,
208+
pass `attributeMap({ "attribute-name-strategy": "none" })`. Outside declarative
211209
templates, `attributeMap()` uses the optional `schema` on the FAST element
212210
definition.
213211

@@ -249,8 +247,8 @@ packages/fast-element/
249247
│ ├── template-bridge.ts # Registry/name bridge between definitions and publishers
250248
│ ├── template-parser.ts # TemplateParser — converts declarative HTML to ViewTemplate strings/values
251249
│ ├── schema.ts # Compatibility re-export for Schema
252-
│ ├── observer-map.ts # Compatibility re-export for observerMap()
253-
│ ├── attribute-map.ts # Compatibility re-export for attributeMap()
250+
│ ├── observer-map.ts # Internal observer-map extension alias (not a package export)
251+
│ ├── attribute-map.ts # Internal attribute-map extension alias (not a package export)
254252
│ ├── utilities.ts # Declarative parsing helpers
255253
│ └── syntax.ts # Syntax delimiter constants
256254
├── scripts/
@@ -307,43 +305,54 @@ import {
307305
} from "@microsoft/fast-element/extensions/observer-map.js";
308306
```
309307

310-
`@microsoft/fast-element/declarative.js` still re-exports `attributeMap()`,
311-
`observerMap()`, and their configuration types for existing declarative imports.
312-
The extension subpaths are preferred when a consumer only needs the maps or is
313-
using manually supplied schemas.
308+
The declarative entrypoint does not re-export the map helpers or their
309+
configuration types. Use the extension subpaths whether the maps are paired with
310+
declarative templates or manually supplied schemas.
314311

315-
Primary exports intended for application code:
312+
Primary exports from `@microsoft/fast-element/declarative.js` intended for
313+
application code:
316314

317315
| Export | Purpose |
318316
|---|---|
319317
| `declarativeTemplate()` | Template resolver for `FASTElement.define()`; auto-defines the internal `<f-template>` publisher and waits for the matching template. |
320-
| `attributeMap()` | Define extension that registers `@attr`-style properties for leaf bindings discovered during parsing or supplied by `definition.schema`. |
321-
| `observerMap()` | Define extension that defines observable root properties and proxy-based deep change tracking from `config.schema`, `definition.schema`, or a declarative template schema. |
322318
| `TemplateParser` | Standalone parser that converts declarative HTML into `ViewTemplate` strings/values. Can be used independently of `<f-template>` for programmatic template compilation. |
323319
| `Schema` | JSON schema builder that records binding paths discovered during template parsing. Each instance owns its own schema map and registers itself in the `schemaRegistry` for cross-element `$ref` resolution. |
324320
| `schemaRegistry` | Module-level `Map<string, Map<string, JSONSchema>>` that indexes schemas by custom element name. Used for cross-element lookups (e.g. nested component `$ref` resolution). |
325321

322+
Primary map extension exports:
323+
324+
| Export | Public subpath | Purpose |
325+
|---|---|---|
326+
| `attributeMap()` | `@microsoft/fast-element/extensions/attribute-map.js` | Define extension that registers `@attr`-style properties for leaf bindings discovered during parsing or supplied by `definition.schema`. |
327+
| `observerMap()` | `@microsoft/fast-element/extensions/observer-map.js` | Define extension that defines observable root properties and proxy-based deep change tracking from `config.schema`, `definition.schema`, or a declarative template schema. |
328+
326329
The implementation element class (`<f-template>`), `TemplateElement.config()`,
327330
`TemplateElement.options()`, `ElementOptions*`, and
328331
`HydrationLifecycleCallbacks` are not exported from the public declarative
329-
entrypoint. Use `declarativeTemplate()`, `attributeMap()`, `observerMap()`, and
330-
`enableHydration()` instead. The `AttributeMap` and `ObserverMap` implementation
331-
classes are available from their extension subpaths for advanced scenarios, but
332-
application code should normally use the extension factories.
332+
entrypoint. Use `declarativeTemplate()`, extension subpath `attributeMap()` and
333+
`observerMap()`, and `enableHydration()` instead. The `AttributeMap` and
334+
`ObserverMap` implementation classes are available from their extension subpaths
335+
for advanced scenarios, but application code should normally use the extension
336+
factories.
333337

334-
Additionally, the following types are exported:
338+
Additionally, `@microsoft/fast-element/declarative.js` exports these types:
335339

336340
| Type | Source Module | Purpose |
337341
|---|---|---|
338342
| `FASTElementExtension` | `fast-definitions.ts` | Definition extension callback signature used by `attributeMap()` and `observerMap()`. |
339343
| `TemplateLifecycleCallbacks` | `fast-definitions.ts` | Per-element lifecycle callbacks accepted by `declarativeTemplate()`. |
340-
| `ObserverMapConfig` | `extensions/observer-map.ts` | Configuration object for `observerMap()`; accepts optional `schema` and `properties` keys. |
341-
| `ObserverMapPathEntry` | `observer-map.ts` | `boolean \| ObserverMapPathNode` — a node in the observation path tree. |
342-
| `ObserverMapPathNode` | `observer-map.ts` | Object node with optional `$observe` and child property overrides. |
343-
| `AttributeMapConfig` | `extensions/attribute-map.ts` | Configuration object for `attributeMap()`; accepts `attribute-name-strategy`. |
344344
| `JSONSchema` | `components/schema.ts` | JSON Schema interface used by `Schema` for property structure. |
345345
| `CachedPathMap` | `components/schema.ts` | `Map<string, Map<string, JSONSchema>>` — the shape of the schema registry. |
346346

347+
The extension subpaths export their own configuration types:
348+
349+
| Type | Public subpath | Purpose |
350+
|---|---|---|
351+
| `ObserverMapConfig` | `@microsoft/fast-element/extensions/observer-map.js` | Configuration object for `observerMap()`; accepts optional `schema` and `properties` keys. |
352+
| `ObserverMapPathEntry` | `@microsoft/fast-element/extensions/observer-map.js` | `boolean \| ObserverMapPathNode` — a node in the observation path tree. |
353+
| `ObserverMapPathNode` | `@microsoft/fast-element/extensions/observer-map.js` | Object node with optional `$observe` and child property overrides. |
354+
| `AttributeMapConfig` | `@microsoft/fast-element/extensions/attribute-map.js` | Configuration object for `attributeMap()`; accepts `attribute-name-strategy`. |
355+
347356
---
348357

349358
## Template Syntax

packages/fast-element/DESIGN.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ For deep dives into specific areas, see the linked detailed documents.
4242
| Element authoring | `FASTElement` base class + `@customElement`, `@attr`, `@observable` decorators |
4343
| Reactive data binding | `Observable`, `ExpressionNotifier`, `oneWay`/`oneTime`/`listener` bindings |
4444
| Declarative templating | `html` tagged template literal → `ViewTemplate` → compiled `HTMLView` |
45-
| Declarative HTML runtime | `@microsoft/fast-element/declarative.js``declarativeTemplate()`, `TemplateParser`, `Schema`, `attributeMap()`, `observerMap()` |
45+
| Declarative HTML runtime | `@microsoft/fast-element/declarative.js``declarativeTemplate()`, `TemplateParser`, `Schema` |
4646
| Schema-driven extensions | `@microsoft/fast-element/extensions/attribute-map.js` and `@microsoft/fast-element/extensions/observer-map.js` → tree-shakeable map helpers usable with declarative or manually supplied schemas |
4747
| Async DOM updates | `Updates` queue (batched, `requestAnimationFrame`-aligned) |
4848
| Scoped styles | `css` tagged template literal → `ElementStyles``adoptedStylesheets` / `<style>` |
@@ -325,16 +325,14 @@ See `docs/di/api-report.api.md` for the full public API surface.
325325

326326
FAST Element also owns the declarative HTML runtime that previously lived in a
327327
separate package. The dedicated `@microsoft/fast-element/declarative.js`
328-
entrypoint exports the functional public API: `declarativeTemplate()`,
329-
`attributeMap()`, `observerMap()`, `TemplateParser`, `Schema`,
330-
`schemaRegistry`, and related config types. Existing declarative imports remain
331-
supported. For consumers that only need map helpers, the preferred entrypoints
332-
are `@microsoft/fast-element/extensions/attribute-map.js` and
333-
`@microsoft/fast-element/extensions/observer-map.js`. These subpaths keep the
334-
schema-driven map extensions factored away from declarative templating so they
335-
can also be used with manually supplied schemas. The `<f-template>` element is
336-
an internal native `HTMLElement` publisher that `declarativeTemplate()` defines
337-
in the target registry; it is not part of the public API.
328+
entrypoint exports the declarative runtime API: `declarativeTemplate()`,
329+
`TemplateParser`, `Schema`, `schemaRegistry`, and related parser/schema types.
330+
Import map helpers from `@microsoft/fast-element/extensions/attribute-map.js`
331+
and `@microsoft/fast-element/extensions/observer-map.js`. These subpaths keep
332+
the schema-driven map extensions factored away from declarative templating so
333+
they can also be used with manually supplied schemas. The `<f-template>` element
334+
is an internal native `HTMLElement` publisher that `declarativeTemplate()`
335+
defines in the target registry; it is not part of the public API.
338336

339337
The declarative runtime intentionally reuses the same FAST Element primitives as
340338
the imperative `html` API:
@@ -344,12 +342,13 @@ the imperative `html` API:
344342
bridge.
345343
- `TemplateParser` lowers declarative syntax to the same `strings` / `values`
346344
shape used by `ViewTemplate.create()`.
347-
- `attributeMap()` and `observerMap()` are `FASTElementExtension` factories.
348-
With `declarativeTemplate()` they register schema transforms on the element
349-
definition, and those transforms run after parsing in deterministic order
350-
(`attributeMap()` before `observerMap()`). Outside declarative templates,
351-
`attributeMap()` uses `definition.schema`, while `observerMap()` can use
352-
either `definition.schema` or `observerMap({ schema })`.
345+
- `attributeMap()` and `observerMap()` are `FASTElementExtension` factories
346+
exported from dedicated extension subpaths. With `declarativeTemplate()` they
347+
register schema transforms on the element definition, and those transforms run
348+
after parsing in deterministic order (`attributeMap()` before
349+
`observerMap()`). Outside declarative templates, `attributeMap()` uses
350+
`definition.schema`, while `observerMap()` can use either `definition.schema`
351+
or `observerMap({ schema })`.
353352

354353
The `src/declarative.ts` entrypoint is pure at module evaluation time. Running a
355354
declarative API lazily installs declarative debug messages only. Hydration hooks
@@ -571,8 +570,8 @@ src/
571570
│ ├── template-parser.ts # Declarative HTML parser → ViewTemplate strings/values
572571
│ ├── schema.ts # Compatibility re-export for Schema
573572
│ ├── definition-options.ts # Compatibility re-export for schema transforms
574-
│ ├── observer-map.ts # Compatibility re-export for observerMap()
575-
│ ├── attribute-map.ts # Compatibility re-export for attributeMap()
573+
│ ├── observer-map.ts # Internal observer-map extension alias (not a package export)
574+
│ ├── attribute-map.ts # Internal attribute-map extension alias (not a package export)
576575
│ ├── utilities.ts # Declarative parsing utilities
577576
│ └── syntax.ts # Declarative syntax constants
578577
├── state/

packages/fast-element/docs/declarative/api-report.api.md

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,6 @@ export interface AccessCachedPath extends CachedPathCommon {
1010
type: "access";
1111
}
1212

13-
// @public
14-
export function attributeMap(config?: AttributeMapConfig): FASTElementExtension;
15-
16-
// @public
17-
export interface AttributeMapConfig {
18-
"attribute-name-strategy"?: "none" | "camelCase";
19-
}
20-
2113
// @public
2214
export type CachedPath = DefaultCachedPath | RepeatCachedPath | AccessCachedPath | EventCachedPath;
2315

@@ -97,28 +89,6 @@ export interface JSONSchemaDefinition extends JSONSchemaCommon {
9789
$fast_parent_contexts: Array<string>;
9890
}
9991

100-
// @public
101-
export function observerMap(config?: ObserverMapConfig): FASTElementExtension;
102-
103-
// @public
104-
export interface ObserverMapConfig {
105-
properties?: {
106-
[rootProperty: string]: ObserverMapPathEntry;
107-
};
108-
schema?: Schema;
109-
}
110-
111-
// @public
112-
export type ObserverMapPathEntry = boolean | ObserverMapPathNode;
113-
114-
// @public
115-
export interface ObserverMapPathNode {
116-
// (undocumented)
117-
$observe?: boolean;
118-
// (undocumented)
119-
[propertyName: string]: ObserverMapPathEntry | undefined;
120-
}
121-
12292
// @public
12393
export interface RegisterPathConfig {
12494
// (undocumented)

packages/fast-element/src/declarative/index.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,6 @@ export type {
22
FASTElementExtension,
33
TemplateLifecycleCallbacks,
44
} from "../components/fast-definitions.js";
5-
export { type AttributeMapConfig, attributeMap } from "./attribute-map.js";
6-
export type {
7-
ObserverMapConfig,
8-
ObserverMapPathEntry,
9-
ObserverMapPathNode,
10-
} from "./observer-map.js";
11-
export { observerMap } from "./observer-map.js";
125
export {
136
type AccessCachedPath,
147
type CachedPath,

packages/fast-element/src/declarative/template-bridge.pw.spec.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,25 @@ test.describe("declarativeTemplate", () => {
180180
expect(result.declarativeTemplateAfterHydration).toBe(true);
181181
});
182182

183+
test("does not export map helpers from declarative entrypoint", async ({ page }) => {
184+
await page.goto("/");
185+
186+
const result = await page.evaluate(async pureEntrypointUrl => {
187+
// @ts-expect-error: Client module.
188+
const declarative = await import(pureEntrypointUrl);
189+
190+
return {
191+
hasAttributeMap: "attributeMap" in declarative,
192+
hasObserverMap: "observerMap" in declarative,
193+
};
194+
}, pureDeclarativeEntrypointUrl);
195+
196+
expect(result).toEqual({
197+
hasAttributeMap: false,
198+
hasObserverMap: false,
199+
});
200+
});
201+
183202
test("does not bundle map modules for plain declarativeTemplate", async () => {
184203
const result = await build({
185204
stdin: {
@@ -232,11 +251,13 @@ test.describe("declarativeTemplate", () => {
232251
const {
233252
FASTElement,
234253
FASTElementDefinition,
235-
attributeMap,
236254
declarativeTemplate,
237-
observerMap,
238255
uniqueElementName,
239256
} = await import("/declarative-main.js");
257+
// @ts-expect-error: Client module.
258+
const { attributeMap, observerMap } = await import(
259+
"/extension-subpaths-main.js"
260+
);
240261

241262
const elementName = uniqueElementName();
242263

packages/fast-element/test/declarative/fixtures/bindings/dot-syntax/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { FASTElement } from "@microsoft/fast-element";
2-
import { declarativeTemplate, observerMap } from "@microsoft/fast-element/declarative.js";
2+
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
3+
import { observerMap } from "@microsoft/fast-element/extensions/observer-map.js";
34
import { enableHydration } from "@microsoft/fast-element/hydration.js";
45

56
class TestElement extends FASTElement {

packages/fast-element/test/declarative/fixtures/directives/repeat/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { attr, FASTElement, observable } from "@microsoft/fast-element";
22
import { deepMerge } from "@microsoft/fast-element/declarative/utilities.js";
3-
import { declarativeTemplate, observerMap } from "@microsoft/fast-element/declarative.js";
3+
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
4+
import { observerMap } from "@microsoft/fast-element/extensions/observer-map.js";
45
import { enableHydration } from "@microsoft/fast-element/hydration.js";
56

67
export class TestElement extends FASTElement {

packages/fast-element/test/declarative/fixtures/ecosystem/lifecycle-callbacks/main.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { attr, FASTElement, observable } from "@microsoft/fast-element";
2-
import { declarativeTemplate, observerMap } from "@microsoft/fast-element/declarative.js";
2+
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
3+
import { observerMap } from "@microsoft/fast-element/extensions/observer-map.js";
34
import { enableHydration } from "@microsoft/fast-element/hydration.js";
45

56
// Track lifecycle callbacks for testing

packages/fast-element/test/declarative/fixtures/extensions/attribute-map-naming-strategy/main.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { FASTElement } from "@microsoft/fast-element";
2-
import {
3-
attributeMap,
4-
declarativeTemplate,
5-
} from "@microsoft/fast-element/declarative.js";
2+
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
3+
import { attributeMap } from "@microsoft/fast-element/extensions/attribute-map.js";
64

75
class NamingStrategyTestElement extends FASTElement {}
86

0 commit comments

Comments
 (0)