Skip to content

Xplat docs xplat json snippet support and refactor and automated docs testing - #497

Open
gmurray81 wants to merge 100 commits into
vnextfrom
docs/json-snippets
Open

Xplat docs xplat json snippet support and refactor and automated docs testing#497
gmurray81 wants to merge 100 commits into
vnextfrom
docs/json-snippets

Conversation

@gmurray81

Copy link
Copy Markdown
Member

Closes #

Checklist:

  • check topic's TOC/menu and paragraph headings
  • Include TOC topic labels in the topic content when it has a valuable update, is new, or is considered preview / beta
  • link to other topics using ./page.mdx or ../relative/path.mdx (.mdx extension required)
  • at the References section at the end of the topic add links to topics, samples, etc
  • reference API documentation instead of adding a section with API

  • use valid component names - [Data] Grid, IgxSelectComponent, <igx-combo>
  • use spell checker tool (VS Code, Grammarly, Microsoft Editor)
  • add inline code blocks for the names of classes / tags / properties
  • add language descriptor for the code blocks
  • check if links function by running the check-api/mdx npm commands
  • check if sample is working and fully visible in the topic
  • check if sample is working and fully visible in the StackBlitz
  • check if code blocks match the code in StackBlitz demo
  • add or update meaningful llms.description metadata and run npm run check:llms-metadata


  • do not resolve requested changes (leave that to the reviewer)

gmurray81 and others added 30 commits August 8, 2026 06:07
…ration

A ```json-snippet block holds one sample as JSON and becomes this platform's
markup as the page is generated, replacing the four or five hand written blocks a
topic otherwise carries for the same sample.

Purely additive: every other block is left exactly as it was, so a topic can hold
both forms and a platform specific snippet with no JSON equivalent keeps working.
Verified by generating every platform against the unmodified repo — the platforms
whose blocks were not collapsed come out byte identical.

The emitter is the locally built renderer, loaded through a CommonJS bundle and
only when a page actually contains a json-snippet, so pages without one are
untouched. A failure fails the build rather than publishing a page with a hole
where a sample should be.

Collapses one section of bullet-graph as the first case: three PlatformBlocks and
76 lines become one 22 line block, and Angular, React and Web Components each
come out matching what was there before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Collapsing a per-platform snippet group into one JSON definition forces a single
answer. Where the platforms already agree that is mechanical; where they differ,
the difference is almost certainly a mistake that has to be fixed first, because
collapsing would otherwise silently pick a winner and change what some platform's
page has always shown.

Compares content rather than dialect: element names, attribute names, quoting and
layout all differ legitimately between platforms, so all of these read the same
and report nothing —

    <igx-bullet-graph minimumValue="5">      <IgrBulletGraph minimumValue={5}>
    <igc-bullet-graph minimum-value="5">     <IgbBulletGraph MinimumValue="5">

It reports when one of them says 55 and the others say 5.

Two things had to be got right before the output meant anything. Only elements
carrying a platform prefix count, so a topic wrapping a sample in a <div> and
XAML's property elements do not shift everything after them. And a group ends
when a platform repeats, not only when prose intervenes: not every sample carries
a block for every platform, and without that a group missing one swallows the
next sample's first block. That alone took the false "different component"
reports from 534 to 86.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…riance

The generator now states the style a documentation snippet is written in — one
line of attributes, no invented element names, and no dimensions on the XAML
platforms — so a sample only says what is particular to it.

The divergence check now sets aside the differences that are expected rather than
wrong:

  * dimensions, which are presentation and now handled by a style option
  * property renames, taken from the vendored apiMap rather than a hand kept
    list, so ItemsSource and dataSource are recognised as one property
  * binding syntax, so {Binding SalesData}, this.state.salesData and SalesData
    are recognised as naming the same thing
  * an absence explained by binding, where the platforms that do write the
    property are binding and another binds in code instead
  * colours and numbers, which the topics pick freely as illustration

What is left is content that says something: a field, a data type, an icon, a
class. 747 differences over 246 groups, down from 2008 over 455 when everything
was reported.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Lining elements up by position made one legitimate difference throw off every
comparison after it. A platform carries an element the others do not — XAML
declares the axes a CategoryChart infers, Angular groups columns in a layout —
and everything past that point was reported as different when only one thing was.
That was what "is a different component" and a bare "element count" were: 169
reports that said nothing usable.

Comparing per component instead says what is actually wrong, and where:

    how many column: Angular: 0, Blazor: 6, WebComponents: 6, React: 9
    column 2 datatype: Blazor: string, React: number

Also splits a platform showing none of a component from the platforms that show
it and disagree about how many. The first is a topic illustrating a feature with
a smaller piece of the sample, which is deliberate; the second is a real
disagreement.

Two further corrections to what the apiMap was doing. A rename was applied
globally, so one type renaming IconName to `name` turned every name attribute in
the docs into an icon — a rename is now ignored when the platform's name is
itself a canonical name elsewhere, or maps to more than one. And the plumbing
attributes are recognised on the name as written, before a rename can disguise
them. Razor's @salesdata now reads as the binding it is.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The product names a web-only description WebGridDescription, WebColumnDescription,
WebDatePickerDescription, while a component shared with the XAML platforms has no
such prefix — DataGridDescription, BulletGraphDescription. The presence of a
Web<Name>Description in the apiMap is therefore the product's own statement that
a component is web only, and those are out of scope: collapsing a group into one
definition pays where the definition serves every platform, and a web-only
component has no XAML counterpart to reconcile against.

That takes the field from 710 groups to 153, and the topics to reconcile from 116
to 49.

Renames are also looked up per component now rather than globally, since a rename
belongs to a type: ItemsSource is written dataSource on some types while
DataSource is a property in its own right on others.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The apiMap cannot answer what a XAML attribute is called canonically: its files
are generated per transpile target and XAML is the canonical side, so there is
nothing there to map from. The description metadata records every platform's name
for a property in one entry, and is the only thing that knows dataSource and
ItemsSource are one property. The check now asks it, through the snippet emitter
it already depends on.

A data source is a special case worth stating: the description carries both
DataSource and DataSourceRef — the value and a reference to a named one — and a
topic writes whichever suits it, XAML almost always the reference and a sample
configuring an inline source the value. They are one concept for comparing, so
the Ref is folded in.

Two things this needed. The metadata is keyed by the description's own casing
while a doc tag arrives lowercased, and a web-only description is also reachable
by its bare name since <igc-grid> canonicalises to "grid" rather than "webgrid".
And a PlatformBlock gates on groups as well as platforms — "Xaml" is not a
platform the metadata knows — so the block's audience is resolved to a member of
its group.

With that, the 25 reports of datagrid's data source splitting into two properties
become 14 real ones.

The apiMap is still what says a description is Web-prefixed, which is what scopes
the check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… peers

Decides whether a group can become a json-snippet referencing its sample, by
reading each platform's block back into the properties it states, resolving those
to their description names, and comparing each with the sample's value.

A group that is a subset of its sample can be collapsed mechanically: the sample
is provably the source, so the block becomes a reference plus the properties it
illustrates, and the topic stops being able to drift from what it shows. A group
that is not a subset needs a person, and the tool prints every platform's version
so the call is made from what the topic actually says.

Three things had to be right before the answer meant anything. A sample writes
its properties camel cased while a description names them Pascal cased, so
lookups go through a lower cased index. Web Components writes them spinal cased,
so the dashes come out before asking the metadata. And a sample sitting between
two blocks starts a new section — the topics write some platforms, then the
sample, then the rest — which without handling pairs a group with the wrong
sample and makes every property look like a disagreement.

Current reading: 4 collapsible, 56 needing a decision, 138 with no peered sample.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A platform stating the sample's own values settles that the sample is the
scenario the section is about. The others have drifted from it, so the group
collapses to the sample and they come back into line — bullet-graph's measures
section has React and Web Components on the sample's numbers while Blazor is on
an entirely different set and Xaml on a third.

Pairing decides which sample a group belongs to, and direction turned out to be
the wrong axis: a topic's opening sample sits above its first snippet while a
section further down writes the snippets and shows the sample under them. Both
orders occur, so pairing uses the enclosing heading section instead — a section
is about one thing, including its sample. A section with more than one sample is
left unpaired rather than guessed at.

--plan prints what each collapse changes, per platform, so the editorial
consequence is visible before anything is rewritten.

13 groups collapse on this rule, 14 have no platform agreeing with their sample
and need a decision, 171 have no sample in their section.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Splits the unpaired count into its causes: no sample in the section, more than
one, or a sample whose file is not in the examples checkout. The last is the
one that matters — it is not a property of the docs but of which branch of the
examples repo is being read, and the counts move with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… say

Three pairing rules were wrong before this one. Nearest by distance pairs a group
with the previous section's sample. Looking only backwards, or only forwards,
each mispairs about half, because a topic's opening sample sits above its first
snippet while a section further down shows the sample under them. Sectioning by
heading rejects pairings that are plainly related: of the blocks with a sample
within a screen's distance, more than half have a heading in between.

What actually separates one sample from another is another snippet group, so a
group owns everything between the group before it and the group after. That took
paired groups from 27 to 62.

Where position cannot decide, content can: a sample of the same component that
covers the properties a platform states is likely the one being illustrated.
Matched on which properties are set rather than their values, since values are
exactly what has drifted — a topic states value=70 beside a sample running
value=80, so matching on values finds nothing.

Also adds the fallback to igniteui-wc-examples: a sample missing from the
examples repo but present there is not missing, it is not yet back ported.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Many snippets appear to be written from scratch rather than narrowed from a
sample: for one gauge topic, twenty samples of that component existed and none
set even the same properties, let alone the same values. So requiring agreement
finds nothing, and the useful question is which sample best covers what the
snippet sets, preferring one the topic already shows.

That takes content matches from 3 to 26 and paired groups to 88 of 198.

Reported separately from positional pairing because the quality differs. It gets
the obvious ones right — geo-map-binding-data-csv to the csv sample — and pairs
some confidently wrong: a topic about binding multiple sources matches the csv
sample, because with values excluded the two set the same properties. A wrong
pairing is worse than none when the purpose is to re-anchor a snippet to the
sample's values, so these want confirming rather than applying.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t the schema

The topic carried five hand-written blocks per section saying the same thing in five
spellings, and they had drifted apart. Nine sections become nine JSON definitions, 1374
lines become 418, and en and jp are collapsed together.

Every XAML block in the topic turned out to have been written from the hero animation
sample rather than each section's own, in all six sections that have one. The XAML in these
topics has never been compiled or run, so where it disagreed with the web platforms the web
platforms won. SNIPPET-COLLAPSE-DECISIONS.md records that and the three sections that did
not collapse trivially.

Generation now emits the JSON schema and checks every json-snippet against the description
it names before writing any output, reporting all the problems at once rather than failing
on the first property the renderer happens to reach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The topics write isScaleInverted={false}, not "false". Matches how React's numbers were
already handled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hows

chart-annotations displays three data-chart samples while every one of its snippets is a
CategoryChart, and the CategoryChart annotation samples it was written from are never
mentioned on the page. Pairing on the embedded <Sample> reported it as needing samples
back-ported from another repo when the JSON was already in this one.

Indexes every sample by the property names it sets, compared without each platform's
spelling, and ranks by how much of the snippet a sample covers. Across the 125 DV snippet
groups, 42 have a sample covering at least 80% of what they set, and 29 of those name a
sample the page never shows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…n from

Every snippet on the page is a CategoryChart while the three samples it embeds are
DataCharts. The CategoryChart annotation samples the snippets came from are never mentioned
on the page, which is why this topic first looked like it needed samples back-ported from
another repo. The XAML binding to TemperatureAnnotatedData gives it away — that is
annotations-custom's own dataSourceRef.

Two of the three callout member paths named fields that do not exist in the data. Taken from
the running sample.

The XAML callout snippet sat after the Timeline Styling section rather than with the callout
markup it duplicates; folded in. en and jp collapsed together.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The emitter was dropping enum collections on every platform but XAML, so the property the
Callout Layer section describes appeared in no snippet. Now that it emits, it is in the JSON.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…y tool

radial-gauge goes from 1497 lines to 467, ten sections becoming ten JSON definitions in en
and jp together. Same cause as bullet-graph: every XAML block carried the hero animation
sample's values rather than its own section's.

The candidate matcher now prefers a sample of the same component. The gauges share most of
their property names, so a radial gauge section about ranges matched the linear gauge's and
the bullet graph's ranges samples at 100% on properties alone; only the element being shown
says which component the reader is looking at.

mirror-collapse-to-jp.mjs replaces the ad hoc scripts. It walks both copies as ordered
sequences of snippet positions rather than matching fences to groups, which misaligns as
soon as one group in a topic is left hand written — as Dependencies is here — and it refuses
to write at all when the counts disagree, since two copies that have drifted need a person.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1448 lines to 413, nine sections in en and jp together. Six matched their own sample
outright; the three that did not are recorded in SNIPPET-COLLAPSE-DECISIONS.md.

Every XAML block again carried the hero sample's values rather than its section's —
NeedleShape="Needle" where every web platform says Custom, #79797a where they say
DodgerBlue. Third topic in a row, and the same cause each time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… need code

Both topics carried a bare map plus, for every platform, a code block constructing the
imagery and assigning it to backgroundContent. backgroundContent is an ordinary described
property whose value is another description, so each becomes one JSON with the imagery
nested, and the generated markup needs no code at all.

check-snippet-code-channels.mjs is what makes that claim checkable rather than hopeful. Some
properties cannot be written as an attribute on some platforms — a data source on Web
Components is assigned in script — and a topic showing only markup would then tell the reader
to bind a source without saying where it comes from. The renderer already decides what it
cannot write as an attribute, so the check asks it: 2 of 32 collapsed snippets set something
in code, both Web Components in chart-annotations, and both still have a companion code block
beside them.

The mirror tool now aligns on heading sections rather than snippet positions, since a collapse
often replaces several groups with one JSON, which the positional match refused outright.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…dropped something

Some properties cannot be written as an attribute on some platforms — a data source or a
tooltip template on Web Components is assigned in script — and a topic showing only the
markup leaves that platform's reader with a series bound to nothing. The emitter is what
decided to leave it out, so it is what says a code block is needed: if anything was dropped
it appears, and if nothing was, nothing appears. Angular binds in the template and gets no
block; Web Components gets its two assignments.

What that block shows is the assignments alone, which is what 149 of the 192 code blocks in
the hand written topics show. The 36 that also show how the reference was obtained and the
27 that declare a field are the introductory pages: code="allCode" gets that fuller form,
and code="none" turns it off for a topic that would rather write its own. A ref= fence can
still name a channel explicitly.

geo-map-type-scatter-symbol-series is the first topic collapsed this way: eight hand written
blocks become one definition, and the generated shape matches the original per platform —
one block for Blazor and XAML, two for Web Components.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bubble series, polygon series, polyline series and the shapefile binding page: 37 hand
written blocks become four definitions, en and jp together. The shape data sources nest
declaratively, so the shapefile and database URLs are in the markup where the topics used
to assign them in code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ode blocks

Creating Series and Map Background collapse; the shapefile loading and per-record processing
sections stay, since they are handlers rather than configuration.

The collapse found a typo the hand written markup had carried: Web Components wrote
shape-memberPath where the attribute is shape-member-path, so that property had been doing
nothing.

Two faults in the mirror, both found by the Map Background section:

  - it grouped only markup fences, so a section whose blocks are all ts was not seen and the
    snippet was inserted after the blocks it should have replaced, leaving the page with
    both. Seven earlier mirrors had silently left the Japanese copy holding code blocks the
    English one had dropped; those are re-mirrored here from the pre-collapse originals.
  - replacing every group in a collapsed section would have taken the hand written Web
    Components block chart-annotations deliberately keeps. A block the English copy still has
    is now left alone, recognised by its body, since only the prose is translated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Data aggregations matched its sample outright. Its initialGroups and initialSummaries now
read Country and Sum(Sales) as Sales, from the sample, where the page wrote them lowercase;
the sample is what runs against the data.

The overlay text section had Web Components and XAML declaring a DataAnnotationSliceLayer
and Blazor building the same thing in a method with three styling properties the other two
did not show. Collapsed to the union, so every platform now shows the border thickness,
border radius and padding that only Blazor had.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… was missing

The XAML block under Chart Marker Size was the wrong snippet: the section is about
MarkerSize on a ScatterLineSeries and XAML showed a LineSeries chart with callout, final
value and crosshair layers and no marker size at all. Collapsed to what the three web
platforms agree on and the prose describes, so XAML now demonstrates the property the
section is named after. The web blocks referred to axes they never declared; the definition
declares them.

The reset example uses null, which is how the description API spells NaN.

The Japanese copy was missing the Chart Checkmark Marker Type section entirely, which is why
the mirror refused to run on this topic. Translated and added, so the two copies have the
same structure again. The translation is mine and has not been through localisation review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The window coordinate section offers two forms of the same thing — a windowRect, or the
three positional properties — so it becomes two snippets with the page's own "or" between
them, which is what it already said.

Geographic Coordinates is left alone: it calls zoomToGeographic, and a description says what
a thing is rather than what to call on it. The library has MapNavigationOnViewInit holding
exactly that call, so this wants the handler channel rather than hand written code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…t out

The Geographic Coordinates section showed a zoomToGeographic call, and the library already
holds exactly that call as MapNavigationOnViewInit. The snippet names the handler and the
build emits its body, per platform: a Rect literal on Blazor, a constructor on XAML, an
object on the web.

The new missing library item check earned itself immediately — it caught a dangling
tooltipTemplateRef the multiple shapes collapse had introduced, pointing at that page's own
ng-template rather than anything in the library, which would have emitted a reference to
nothing.

The mirror now refreshes a snippet that is already collapsed on both sides but has since
changed in English, which is how that stale reference would otherwise have survived in the
Japanese copy. Two snippets under one heading still cannot be placed automatically, but they
no longer block refreshing a section that has nothing left to place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CSV binding, JSON points binding and high density series pages each build their series in
a routine the library already holds — MapBindingDataCsvOnViewInit and the other two — so the
topics name the handler and the build writes it out per platform. 24 hand written blocks
become three definitions and three handler references.

Two faults in the mirror, both surfaced by these being the first topics with two snippets
under one heading:

  - it placed one snippet per section, so the second was silently dropped. A section is now
    replaced whole, with its snippets in the order English has them, which also removes the
    need to work out which snippet replaced which group.
  - its fence pattern required a body, and a ref fence has none, so those were invisible to
    it entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e with it

A few sections show two components side by side because the point is the comparison — an
ordinal axis on a FinancialChart and on a DataChart, markers off on a CategoryChart and on a
DataChart's LineSeries — and neither is a child of the other. A snippet body that is a JSON
array emits them in order, one blank line between, which is what the hand written block did.
This is the case that justified the form; nothing else in the set needed it.

The two guideline sections showed property assignments on a chart the reader already has and
now show the properties on the components, which is how the rest of the documentation states
them and what the comments in the original were already describing. It does change what those
sections demonstrate, and SNIPPET-COLLAPSE-DECISIONS.md says so, along with the two faults it
corrects: this.Chart.Resolution with a capital R on the platforms where that is not the
property, and the Blazor block setting it twice.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ling

The two guideline sections show a property being set on a chart the reader already has. That
is the lesson, so they are emitted as code rather than markup: asking for a component's code
channel now forces code behind, which is what that work was for. All five platforms show the
assignment again rather than a declaration.

Also stops two styling differences that the style options exist precisely to prevent:
selfCloseEmptyElements was set for React alone, though the topics close an empty element on
its own tag in Blazor and XAML as well.

An enum qualification option was added and then removed: the docs write MarkerType.Circle 315
times and the bare form never, so the emitter was already right and the one unqualified block
in chart-markers was an error.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Spreadsheet has no description type — not among the 1190 the schema is generated from, and
there are no spreadsheet sample JSONs in the examples repository at all. The renderer has
nothing to emit from, so this is a limit of what is described rather than a view about the
pages, and they become collapsible the day the component is described.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gmurray81 and others added 30 commits August 16, 2026 08:46
The load check has been failing in CI roughly one run in three, always with one
sample "only in sequence" and never the same one: data-model after
data-json-points once, data-json-points after data-csv the next. Every victim ran
directly after a geo map binding sample, and those initializers fetch their data
from static.infragistics.com.

The three waits a load already did -- idle, flush, animation -- all say that
nothing is queued. A request that has not come back yet is queued nowhere, so the
harness moved on while it was still on the wire, the response landed during the
next sample, and its handler reached for a map that had been torn down. The
report then blamed whichever sample happened to be loading, which is why the pair
changed run to run and why it never reproduced on a fast connection.

fetch is counted now, and a sample that ran an initializer waits for its requests
before the page is looked at. Waiting too long is a finding rather than a silent
pass, on the same timeout as the other waits.

304 of 304 still load clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Auditing what a XAML reader is actually served turned up two topics that are
about the web and nothing else. Grid theming is a table of CSS custom properties
-- --header-background, --grid-elevation -- for a grid that has no CSS, and the
data grid accessibility topic documents ARIA attributes on DOM elements, where
WinUI has UI Automation. Both are dropped for now rather than patched; the
accessibility one needs a UI Automation version written before it comes back.

Neither was gated, and the reason is the same fault. The toc's "Theming" entry
pointed at grids/theming-grid.mdx, which no longer exists in English: that topic
was split into one copy per grid family and nothing was in the toc for the three
real files, so every platform published them. Repointed at the Grid copy, and the
other two families -- which had no theming entry at all -- get one. Its Angular
exclusion is not carried across, so no web platform changes because of the href.

Accessibility sits under a section that is XAML only, so it publishes nowhere
until it is rewritten. Deleting one line restores it.

The Japanese copy had not been split with the English one: it still held the
shared grids/theming-grid.mdx that English had already broken into three. Split
the same way, so both languages now publish the same three pages and the toc
entries name real files on both sides.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…DV ones

Generation publishes any source file the toc does not exclude, so a file no toc
entry names goes to all six platforms. Thirty-five did. Nothing about them was a
decision.

Thirteen are web grid topics. grids/grid is the web Grid family, not the XAML
data grid, whose topics are the thirty-two under grids/data-grid -- all of which
are listed, so nothing there is missing. What a WinUI reader was served instead
was the web Grid's validation topic, telling them to use Forms validators and a
template-driven configuration against a component they do not have. They are
listed now beside their siblings, Web only, which is where the other ninety-odd
topics in those sections already sit.

Five more are data visualization topics that had never been listed anywhere, in
this repository or the docfx-era one: the chart titles topic, three geographic
map topics, and the Excel library's grids topic -- that last one Web only, since
its siblings are. Four of the five were also linked from nothing at all, so they
were published and unreachable by any route. Their names come from their own
headings.

Seventeen changelogs remain unlisted and are left alone: they are npm package
release histories, nothing links to them, and the toc's own four changelog
entries are Web only -- so the XAML platforms are offered no changelog by policy.
Wiring them up is a decision, not a leak.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An audit of the pages the toc actually offers the XAML platforms found prose
written for the web and never gated. Where the topic is cross-platform the words
are fixed rather than hidden, and only genuinely web-only material is gated.

Reworded: the charts overview promised charts "for your web and mobile apps"
designed "to work on every modern browser" -- now web, mobile and desktop, and
every modern platform, which is what the product does. Nine map topics described
themselves as a "{Platform} JavaScript map", which reads as "WinUI JavaScript
map". The grids topic called itself "The Lightweight {Platform} Web Components
table". None of that needed a second version; it needed to be true.

Gated: the supported browsers list, Internet Explorer 11 and polyfills included,
and the web worker section of the heat imagery topic -- whose per-platform blocks
were gated already while the heading and its paragraph were not, so a XAML reader
was shown a section about workers and then nothing under it.

Also the one Ig$TemplateColumn in the repository, where its four siblings write
TemplateColumn, and four double spaces before an inline link.

Fifty-one findings down to six, and the six are the docs page's own FAQ script,
the acronym in "JavaScript Object Notation", the Azure and Bing key pages saying
to get a key from a website, and a platform list that names WinUI itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A canonical API name in prose now renders as the name the reader's platform
uses, and a term that resolves to nothing is reported rather than shipped.
That report is the point: it catches a typo, which no amount of proofreading
a per-platform fork of the same sentence ever did.

Every topic states an apiTerms mode, with no default, so the decision is
made per document rather than inherited by accident. `full` looks names up
in the maps; `passthrough` resolves by rule for a component no generator
describes, still emitting an ApiLink; `none` leaves the code span alone.

Resolution tries the canonical spelling first, then reverses the platform
affixes, so a topic may write XamDataChart or DataChart and both arrive at
the same place. Type context comes from the page: a qualified Type.Member,
else the types the prose and its ApiLinks already name, else mentionedTypes.
A backticked term that is deliberately not an API name is escaped with a
leading backslash.

An ambiguous type fold is no longer reported before the page's context has
had its say. A name can be both an enum and a property -- TrendLineType is
each -- and once case is folded it collides with an unrelated type from
another product area. A page that named the chart it is about has already
answered which is meant.

Hand-exposed API gets an override, because a generator maps what it
generated and a member it was told to skip is absent from the map even
though the package ships it: ShapefileRecord.Points, whose web spelling
comes from the hand-written wrapper rather than a guess,
SeriesViewer.CheckmarkMarkerTemplate, whose whole family is suppressed on
every platform at once, and TriangulationSource, which reaches the web
packages by being exported rather than wrapped.

Terms that exist on one platform only are scoped with a PlatformBlock
instead of being offered to every reader -- the Blazor-only
SetCustomizedStringAsync, and treemap's synthesized NodeStylingScript. An
extension-only name that no map will ever hold stays out of a code span.

Both languages move together, en as the reference.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A topic is authored once and emitted per platform now, so reading the source
no longer tells you what a reader ends up with: the source is smaller than
what it replaced, and the question is whether the page still says what it
did. review-platform-diff.mjs generates both sides and diffs the output.

Changes are separated by the judgement they need. A topic whose only
difference is its apiTerms line is set aside as directive-only -- frontmatter
rides through to the output, as mentionedTypes and namespace always have, so
without that every topic differs and the ones that matter are buried: it was
339 of 339 for WebComponents, and is 78.

Comments are counted on their own, because interleaved explanation is the one
thing collapsing to a definition drops rather than corrects. A comment is only
counted lost when its text appears nowhere in the new page -- emitted code is
laid out differently, so a diff shows moved lines as removed and re-added, and
counting those overstated the loss by a seventh.

Of the 73 genuinely lost on WebComponents, most have a home already: one
explaining code inside a handler belongs in that handler's source in the
examples checkout, where it is emitted with the code, and an elision marker is
what the ... delimiter between channel names already writes. What was left is
explanation of generated code, which the renderer's own $comment sidecar
places ahead of the element it describes -- restored here for the chart
performance blocks, where the line saying which chart each applies to had gone
missing.

Also document how a backticked API name in prose becomes the reader's own
spelling: the required apiTerms modes, the resolution order, how a page says
which type it means, when to escape a term, and what the overrides are for.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The renderer's own $comment writes a remark ahead of an element, and because
elements nest, one on a series already lands mid-block. What it cannot do is
annotate a single property, and that is what a hand written block used most: a
line saying what the next assignment is for. The chart performance topic had
one above each of four blocks saying which chart it applied to, and collapsing
the blocks took it with them.

$comments is keyed by property, so it cannot be confused with the per platform
splay a sidecar value may itself be, and each entry lands above the line that
property produced, in the platform's own comment syntax. Anchoring is by
assignment rather than by mention: without that a comment on resolution lands
above the line declaring the chart, because the emitted variable name contains
the property name too. An entry matching nothing is reported rather than
dropped, since a property renamed out from under its comment would otherwise
take the explanation with it silently.

Two other things a block was losing:

An elision now separates a region's field declarations from the statements
below them. A handler that requires a supporting item is emitted with the field
holding it -- a class member -- followed by the handler's body, which is
statements inside a method. Those are excerpts from two parts of a file, which
is what the ... between channel names marks, but here they arrive inside one
region and that delimiter has nothing to sit between. Unmarked, the block reads
as one run of statements and a reader copying it puts a field declaration in
the middle of a method.

And a region is dedented rather than trimmed. trim() strips whitespace from the
ends of the string, which is the first line's indentation and no other line's,
so a method lifted out of a class emitted with its signature flush and its body
still indented -- and with a doc comment above the signature, the comment went
flush while the method stayed indented under it.

The sidecar table said $comment was never emitted, which is backwards; it also
now says where each kind of comment belongs, because a comment explaining code
inside a handler belongs in that handler's source and not in a sidecar at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The hand written block a handler fence replaced opened with the imports its
types needed, then an elision, then the handler. The fence emitted the handler
alone, so a reader who scrolled to the section they wanted saw code using types
whose imports were named somewhere further up the page.

channel="handlersImports...handler" restores it, and needs nothing new: the ...
delimiter already writes the elision between two regions, and a platform whose
handler needs no imports drops the region and its delimiter with it. Applied to
all twelve handler fences, in both languages.

The field elision now looks for a field anywhere in a block's preamble rather
than only at its start. With imports composed in front, the field that holds a
required supporting item is no longer the first line, and the mark that
separates it from the statements below stopped appearing exactly where it had
just started being needed.

A region of a supporting item cannot do the same. The item's file has an
imports region and the renderer publishes a doc:imports key for it, but the
content is empty -- the region is consumed to build the sample's import list
rather than exposed. Reading the file directly is not a way round it, since
Web.ts is written in the Web Components names that the renderer translates per
platform, so a raw read would put Igc types on the React and Angular pages.
Left as it stands and written down; it wants the renderer to fill that key in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
handlersImports beside a supporting item's region gives the requiring handler's
imports -- a list for code the block does not show, missing the types the shown
code casts to. Better to name the region alone than to print an import block a
reader would copy and find incomplete.

The renderer now writes those imports to a region of their own, supportingImports,
so these three fences can compose it once a build carrying that is vendored here.
Recorded in JSON-SNIPPETS.md so the next person reaching for handlersImports on a
supporting item finds out why it is the wrong one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"loaded in ShapefileRecord with of countries of the world" -- the sibling
sections either side of it read "with communication routes between major cities"
and "with locations of major cities", so the stray "of" is all that was wrong.

English only. The Japanese copy of the sentence is a translation and reads
correctly already.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two defects, 428 broken links between them, both from writing a canonical name
into a tag that does not want one.

ApiLink builds its own candidates -- `prefix + type` and `type`, each with and
without the platform class suffix -- and looks them up in a TypeDoc index of the
platform's own symbols. A canonical name written straight through therefore
arrives doubled on the web: XamDataChart became IgcXamDataChart, which is in no
index, and the component renders plain code where a link used to be. 256 of
those on WebComponents, from none before.

Stripping the affixes back off is guesswork and was my first attempt at this.
The platform name is not always prefix + short + suffix: plenty of types are
renamed outright -- ShapefileConverter is ShapeDataSource on the web -- and only
the classes predating the ApiGenerator carry Xam at all. So the guessing is
removed rather than reimplemented. We already know the actual resolution, because
the map records exactly what each platform calls the type, so that name is handed
over with prefixed={false} and the component looks up what it was given. suffix
is left alone: with an exact name it costs nothing and still covers a map that
records a name without its Component tail.

The second defect was an ApiLink emitted with no type at all -- 172 of them --
when a term resolved as a member the maps know without naming an owner, which is
what the unscoped lookup does. type is required, so every candidate was
prefix + undefined and the link could never resolve. Those keep the platform's
spelling as a code span now: that is the half of the job that needs no owner, and
it is not an authoring error, so reporting it would send someone hunting a typo
that is not there.

Xam* as an ApiLink type on the web goes 256 -> 0, typeless links 172 -> 0, on
both languages and all six platforms, with the term reports still empty. WinUI
and Uno keep Xam* names because that is what those platforms are called.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Following on from the previous commit, which handed ApiLink the platform's own
name with prefixing switched off. That was wrong twice over.

It assumed the platform name is prefix + short + suffix, which is guesswork: a
type may be renamed outright -- ShapefileConverter is ShapeDataSource on the web
-- and only the classes predating the ApiGenerator carry Xam at all. And a type
whose map name carries no prefix while the indexed symbol does, as Series does,
resolved before and stopped resolving once prefixing was suppressed for it.

So the name always goes out bare on both counts and the two flags say what this
type actually uses, from the map. Both are stated even when they match the
default: a default that happens to be right cannot be told from one nobody
thought about, and this is the attribute deciding whether the link resolves.

The suffix flag is judged on a platform that appends one, whichever platform is
being emitted. Whether a type is a component class taking `Component` is a fact
about the type, and suffix={true} is harmless where nothing is appended because
the component tries the bare name too -- so asking the platform in hand would
make the flag narrower than it was, and narrowest exactly where the answer is
invisible. DataChart now reads prefixed={true} suffix={true} on all six
platforms, TreemapLayoutType false on both everywhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A term was tried as a type before it was tried as a member, so any member
sharing a name with a type resolved the wrong way and the prose changed under
the reader: 18 pages came to say "the IDataSource property", 9 "setting
ChartType to Column".

IDataSource is the clearest case. It is a type whose Blazor name happens to be
DataSource, the reverse type table is keyed case insensitively -- which is right,
it is how IgcDataChartComponent finds XamDataChart -- and a loose match on it
therefore beat the member the page was plainly discussing. The docs almost
certainly never mention IDataSource at all.

The order is now the one the docfx transform used, which is why the pages it
produced said member="dataSource": the canonical type name written exactly, then
the implicit type -- the nearest type the prose has already named -- then
mentionedTypes in the order given, and only then a loose match on the term as a
type. Implicit has primacy because that is how the prose reads: name a component,
then name a property of it.

Case is not consulted. It is a clue to what the author meant, useful for finding
these, but not a thing to decide on: disambiguation is by qualified name, and
three sites take one now because no owner was in context there --
`CategoryChart.chartType`, `DomainChart.toolTipType`. That renders as the owner
and the member, which is what the pre-branch label said.

IDataSource 27 -> 0 and ChartType 32 -> 0 on every platform in both languages,
with the term reports still empty. MarkerType and ToolTipType keep a few, and
should: "the MarkerType enum" and "ToolTipType.Default" are types.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The counterpart to a qualified name, needed for the same reason and missing
until now. Context has primacy, so a name that is both an enum and a property of
the type the prose just named resolves to the property -- and where the enum is
what was meant there was no way to say so.

`global::ToolTipType` resolves as a type whatever the context implies, spelled
the way C# spells it because that is what it means and the audience reads C#.
The prefix is for the resolver: what renders is the type's own name, and an
unknown name behind it is still reported.

Nothing needs it today -- the MarkerType mentions that made me look still read as
the enum, because the member beside them is MarkerTypes -- but the gap was real
the moment context was given primacy.

API-TERMS.md now states the resolution order it actually uses, ending with the
loose type match, and says plainly that case is a clue to intent and not a thing
resolution decides on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1106 authored ApiLinks on apiTerms: full pages go back to backticked canonical
terms, so generation resolves them per platform instead of serving whatever
spelling was frozen into the source. resolve-api-links.mjs had written one
platform's answer into files serving six -- a Web Components page read
member="dataSource" label="ItemsSource", showing a web reader the XAML name.

Labels are no longer emitted at all. ApiLink derives the text from the type and
member it is given plus its own index: getIndexedDisplayName shortens the
resolved symbol back to the short type, and resolveIndexedMember returns the
index's own member spelling. Asserting a label was how a spelling drifted from
what the platform actually calls it, and the platform-specific topics already
show the better convention -- 1034 of them carry member= with no label.

Verified by round trip on the type/member identities, labels ignored. Web
Components is 7195 -> 7195 ApiLinks with zero identity changed. WinUI changes
two, and both are the frozen-spelling bug being fixed: ShapefileRecord.points
becomes .Points, and ShapeDataSource becomes ShapefileConverter, which is what
that platform calls it.

A conversion has to survive that round trip to be made. Without the guard,
`type="DataSource"` canonicalised to the interface IDataSource, which the maps
place on Blazor alone, so 15 links that resolved would have stopped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
DataSource is not a type anywhere in the maps -- it appears 63 times, always as
a member -- so the 14 `<ApiLink type="DataSource" />` tags were calling a
property a type, and the prose around every one of them is about the property.
The web spelling reverses to the canonical ItemsSource, which is what they say
now.

Each site's owner comes from the prose. ItemsSource is owned by 27 types, and
every page's named type reaches it: CategoryXAxis and TimeXAxis through
CategoryAxisBase, the DataAnnotation*Layer family through Series, DashboardTile
directly. Two needed the owner said outright -- dashboard-tile, whose
mentionedTypes lead with CategoryChart so a plain term resolved to the wrong
owner, and the four changelogs, whose type lists are long enough that naming it
is worth the words.

TileGenerator was the same shape and is real: TileGeneratorMapImagery owns it,
which is what the prose says -- "a TileGeneratorMapImagery object with a
HeatTileGenerator assigned to its TileGenerator property".

DashboardTile and TileGeneratorMapImagery are mapped on the four web platforms
only, so WinUI and Uno fall back to the canonical name with no error, which is
the designed outcome for a term no map places on a platform. They will pick up
the platform spelling when Dashboards.Core lands and its maps are ingested.

Also two lockstep breaks found on the way: en wrote the web spelling
`dataSource` in chart-overlays and the stale `DataSource` in chart-performance
where jp carried the frozen tag. Both now say ItemsSource, so the source holds
the canonical in both languages.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The internal surface disagrees here, so the docs need a canonical set imposed on
it. A margin is a Thickness in the C#. The web platforms keep it as a sub-object
and their maps record a path -- groupTextMargin.bottom, which Blazor names
GroupTextMarginBottom -- while the ApiGenerator flattens it into four Doubles and
recorded them under their flattened names. No topic could write one term that
resolved on both halves of the product.

The dotted path wins: four of the six platforms already record it, and it is what
a Thickness is. An override brings the rest to it -- WinUI and Uno to the
flattened property, WPF to the unflattened Thickness, where all four edges lead
to the same member because that is the only thing a WPF reader can set.

Forward resolution had to learn the shape too. A platform that keeps the object
records only the leaf, since the path is the canonical, so emitting its answer
alone told a reader to set `bottom`. A dotted canonical now composes the path
back. One term, `groupTextMargin.bottom`, resolves to
groupTextMargin.bottom on Web Components and Angular, GroupTextMarginBottom on
Blazor, WinUI and Uno, and GroupTextMargin on WPF.

The parent alone is deliberately not in the set. It is on no platform's public
surface, so a topic naming it names something no reader can set --
chart-data-legend and chart-data-tooltip do, and that is a doc fix rather than a
map one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…hole

Two of the systemic items in the queue.

Twelve of the seventeen Web Components pages that show a module registration
called ModuleManager.register without importing ModuleManager, so the setup code
a reader copies failed on an undefined name. It was never a de-duplication
artifact as the queue guessed -- only five pages ever had the import, and those
by accident from another block. Neither modulesImports nor moduleRegistration
contributes it: the first lists the modules being registered, the second the call.

Filled in at composition, which is not where it belongs. The region is the
renderer's to fill and a fix there needs a product release, while these pages are
wrong now; the comment says to remove this once modulesImports carries it. Web
Components only -- the other platforms register through the modules themselves and
never name ModuleManager. One hand written block in grids/_shared/row-drag.mdx
needed it too, since no fence emits that one. 17 of 17 now.

The escape is a run of backslashes rather than exactly one. Inside a code span a
backslash is a literal, not an escape, so an author doubling it -- as several did,
expecting MDX to need it -- meant the same thing, and stripping one left the other
on the page. Readers saw `\NaN`, `\MaxValue`, `\MinValue`, `\Low`. None now, on
either language and all six platforms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CodeGenHelper.getDescription(...) was reaching four published pages. It is the
sample harness asking its host for a description by name, and it is meant to be
rewritten to a direct reference before anyone reads it -- which is what happens
when the element carries a name, and did not here:

    name on the element   var map = this.geoMap;
    no name               var map = CodeGenHelper.getDescription<...>("content");

The renderer records a description's field only when the element has an explicit
Name or name. Without one it allocates an auto name and records nothing, so
HasDescription is false, the rewrite in TransformHandlerCode cannot fire, and the
ask survives into the page as an unresolvable symbol. Narrowing to a doc region
makes no difference; the name is the whole of it.

So the four definitions name their map. That also restores the link between the
two blocks a reader is given: the markup carries id="geoMap" again, which is what
the code behind it now refers to, and the queue noted its absence separately.

The renderer should record the auto name too, so an unnamed element still emits a
reference rather than the harness call. Recorded for the product side; naming the
element is right regardless, since the handler reaches for it by name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A sample invokes its handler from the component's init, and the recorded region
took that call in along with the body -- so a block teaching
mapBindingShpFileLoad ended by calling this.mapBindingShpFileLoad(), which reads
as part of the lesson and is not. Five blocks did it, none before this branch.

Matched against the handler's own name, so the only thing it can remove is the
handler calling itself; a call to anything else is code the reader needs. The name
comes from item= where a block shows one handler, and from the definition's init
lists where it shows whatever the sample runs -- two of the five had no item= and
were missed until the fallback.

Also checked and left alone: the top level .bind(this) statements the queue lists
are pre-existing, and there are fewer now than before -- 15 to 10 -- so they are
not this branch's doing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three blocks declared a field of a supporting type and constructed it --
`private mapGeodesics: MapGeodesics = new MapGeodesics()` -- with the class shown
nowhere on the page, so a reader copying the block got an undefined name. In a
sample the class is emitted into the same file, which is why it reads correctly
there and not here.

geo-map-binding-data-model and geo-map-binding-shp-file compose it in:
handlersImports...supportingTypes...handler, so the block runs imports, the class,
then the handler, with an elision between each because they are excerpts from
different parts of a file.

geo-map-binding-multiple-shapes does not, because its three reader methods each
have a section of their own further down and composing the class in would repeat
all three. The prose names the class instead and says where the methods are.

The prose on data-model also stopped pointing at a class it does not use. It links
the WorldUtility topic, which writes the same maths up as `WorldUtils`, while the
code constructs `MapGeodesics`; it now names what the snippet shows and keeps the
link as further reading. `MapGeodesics` is escaped, being a sample class rather
than product API.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four fences asked for the assignments alone, so `citiesSeries.dataSource = ...` arrived with nothing
that stood `citiesSeries` up, and three definitions were never named, so the emitter numbered them --
`categoryChart1` -- and no other part of the snippet knew that name.

`code="allCode"` on the four gets the `// fields:` and `// initialization:` sections back ahead of the
assignments, which is the declaration the reference wanted, and it restores the markup `id` with it.
`"name"` on the other three names the element outright.

The jp copy of geo-map-type-scatter-symbol-series had been left behind on an earlier pass; comparing
every json-snippet fence header across en and jp found no other divergence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… its points

geo-map-binding-shp-file called the loader `ShapefileRecord` throughout -- the table of
ShapefileSource / DatabaseSource, the sentence about ImportAsync, the event -- and a ShapefileRecord is
one of the records the loader produces, so two classes were described as one. It predates the branch;
the reverse pass carried it forward because a real name that is the wrong name resolves like any other.

The loader is canonically ShapefileConverter, which every web platform maps to *ShapeDataSource and the
desktop platforms keep as-is. Writing the canonical is what lets all six resolve. jp's mentionedTypes
already said so while en said ShapefileRecord.

The closing section promised the Points mapping under a snippet from binding-shp-polylines, which maps
nothing; it now shows binding-shp-file, whose series carries shapeMemberPath, and the demo at the top
is that sample too. ImportCompleted moves to its real owner as a qualified term, and the frontmatter
description no longer names a type that is spelled differently on every platform.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ly take

Both pages promised something the code no longer shows: a lead-in saying the series is bound "using the
ShapefileRecord", over a snippet that hands the series a ShapefileDataSource and names no record, and a
Data Requirements section describing only the dataSource + ShapeMemberPath route.

Both routes are real, so both are described now: map a data column of your own with ShapeMemberPath, or
give the series a shape file directly and let it read the points itself, which is what these two
samples do. The other route has a topic of its own, and each page links it.

The per-country grouping the hand-written blocks taught -- getPointData, fieldValues.RoadType, three
styled series -- is not restored. No sample ran it, on any platform; it was page-only code, and
reinstating it would recreate exactly the drift between page and sample this collapse removes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"The following snippet shows both methods of adding an Icon" sat over a ToolActionLabel that names an
icon collection and registers nothing, so neither RegisterIconFromText nor RegisterIconFromDataURL
appeared anywhere on the page. ToolbarCustomIconOnViewInit does exactly both, and two samples run it;
the section now emits that handler, then keeps the ToolActionLabel to show how a tool asks for what was
registered.

The jp copy had never been collapsed here at all -- four hand-written `ts` blocks were still in place,
showing TypeScript to a Blazor or WinUI reader and duplicating the same two methods twice over. Both
languages now carry the same six fences.

An earlier attempt at this emitted nothing, twice, because the reduced fence body kept a
targetRef="chart" with no chart description in it. check-snippet-emission says so in as many words --
"sample refers to library items that do not exist: chart" -- which is worth remembering as the thing to
read when a fence comes out empty.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…tility

Two of the topics whose teaching the audit read as lost.

inputs/color-editor ends on a handler body -- `console.log("selected color: " + args.newValue)` -- with
no signature above it, so `args` arrives from nowhere. The signature is not the block's to show: an
item's eventHandler region is injected into a method the sample generates, and the recorded region is
the body. So the prose names what the handler is passed, as canonical terms, which resolve to
newValue on the web platforms and NewValue on Blazor and WinUI and link to each.

geo-map-shape-styling styles shapes through four classes it never says where to get. It is the Shape
Styling Utility topic that publishes them, and nothing linked it any more -- only the toc did.

geo-map-resources-world-connections was on the same list for losing its imports. Its prose already
names both scripts it depends on and links both topics, which is the honest form here: a generated
sample declares those types as peers of the component, so there is no import for the block to carry.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… reads

Two of the semantic differences in the collapse audit, and they turned out to be opposite kinds.

chart-performance authored `includedProperties: ["Year", "USA", "RUS"]` beside a block pushing
`{ "Year": ..., "USA": ... }`, and the emitted filter read `["year", "uSA", "rUS"]` -- the web emitters
camelise a member path so it matches data whose properties they also camelise, and a fence with no sample
has no such data. Copying it filtered nothing. The fence states skipAlterDataCasing, which the emitter
honours at the sample level, so it is written in that form.

geo-map-binding-data-csv was read as taking population from the wrong column. It is not: the file the
sample fetches is `CityName,Lat,Lon,Population`, four columns, so columns[3] is population and the guard
on `columns.length < 4` matches. What was wrong is the page, which showed an eight-column header --
City,Lat,Lon,State,Code,County,Density,Population -- that the file has not had. Both blocks now show the
first rows of the real file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d to

The Map Background section asked for channel="code", which forces code behind -- the component built
rather than declared -- so the block constructed a second GeographicMap and set backgroundContent on
that. Followed literally it yields a map that never renders, and it is not what the topic taught: the
hand-written blocks declared a field, elided, and assigned to the map already there.

Nothing needs forcing. backgroundContent is an ExportedType, and a null one is gated on
WritesNullAsAttribute: Angular, React and Web Components return false, so it goes through MustSetInCode
and is emitted as an assignment; WPF, WinUI, Uno and Blazor return true and write it as an attribute.
So the default channel gives each platform the form it actually uses, with the companion asked for the
fuller shape so the field declaration comes with it.

Against the originals: Web Components matches (field, then the assignment on the existing map), Blazor
matches its `BackgroundContent="@null"` attribute exactly, and Angular and React now state it
declaratively rather than imperatively -- the same lesson in the idiom those platforms bind in. WinUI and
Uno had no block before and get the attribute.

Two attempts before this were wrong and worth naming: channel="allCode" shows only the code region, which
is empty on the platforms whose form is the attribute, and adding source= to a forced-code fence still
constructed the map.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ge is about

Two more from the audit, checked against the pre-branch pages and against the files and samples involved.

geo-map-binding-data-json-points was read as having lost a JSON-to-model projection. The projection is
gone, and it did not need to be there: the real WorldCities.json has cap, pop, lat, lon, country and name,
so filtering on `cap` and binding `lat` / `lon` reads it directly. What was wrong is the page's Data
Example, which showed `{ "name": "Sydney Island", "lat": ..., "lon": ... }` -- three rows from some other
dataset, without the `cap` the snippet beside it filters on. It now shows rows from the file, including a
capital and a non-capital so the filter has something to mean.

menus/toolbar registered CategoryChartModule and CategoryChartToolbarModule on a page whose every snippet
comes from a DataChart sample. The fence names that sample and then overrode its module list with the
wrong chart's. It now lists what the sample declares, which is also what the topic documented before:
ToolbarModule with the six DataChart modules.

bullet-graph was on the list for dropping IgcBulletGraphCoreModule, where React never listed one. Nothing
to restore: BulletGraphModule registers BulletGraphCoreModule itself, and Angular's module imports and
exports it, so the separate line was redundant and React had it right.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…y what it is

The page reached the sparkline through cellUpdatingRef, which taught the event on every platform because
that was the only form the library item had. It refers to templateRef now and asks for the template
channel, so each platform's page shows its own template: a lit-html one for Web Components, a functional
component for React, an ng-template for Angular, and a keyed DataTemplate for the XAML platforms.

generate.mjs picked the fence language from the channel alone, so a template whose content is markup was
fenced as ts on WPF and WinUI. It now looks at the content: markup gets the platform's markup language
whatever channel carried it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants