Repository navigation
feat(cli): check each authored doc against its published authoring type - #7664
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
AI review status for this pull request.
|
PR Analysis Report📚 Storybook Preview🧪 Sandbox PreviewNo new or modified components detected. Bundle Size SummaryNo component packages changed. Accessibility AuditStatus: No accessibility violations detected. Visual Regression40 of 482 shot(s) changed. A change here is a question, not a failure: check whether the after is the
and 20 more. Generated by PR Enrichment workflow | Storybook | Sandbox | View full report |
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check in astryx doctor integration validate, the new data.docTypes field and the TemplateDoc.category widening rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec for these additions. Separately from that decision, please address these:
- A wrong-typed value hides the same doc's missing and unknown fields, and unknown fields stop after six per doc, so one run does not report everything (for example,
keywordand a missingdisplayNameonly appear after fixingusage.bestPractices[0].guidance). validate-integration.mjsnow walks the roots, reads docs and loads the project's TypeScript outside theintegrationsubject's adapter, whicharchitecture:cli-surfaceINV21 reserves for the adapter.- The docs say
data.docTypesis present whenever a manifest is found, but it is absent when the manifest fails to load or there are two manifests.
[Automated review]
| findings.push(finding); | ||
| } | ||
| } | ||
| if (removedMore) { |
There was a problem hiding this comment.
Only an unknown_field queues another pass, so a doc whose first pass reports a wrong_type is never re-checked: its missing and unknown fields stay hidden until that value is fixed. For example, a component doc with keyword, no displayName and guidance: 'yes' reports only usage.bestPractices[0].guidance. Setting reported wrong-typed values aside as well (for example, casting them to any in the virtual text) and re-checking would let one run report everything, as the PR describes.
| }; | ||
|
|
||
| /** How many times a doc is checked again after an unknown field. */ | ||
| const MAX_PASSES = 6; |
There was a problem hiding this comment.
With a fixed six passes, a doc with more than six unknown fields reports six and silently drops the rest (a doc with eight reports six). Consider looping until nothing new is found, or listing the doc in unchecked when the limit stops it.
| const integration = result.found ? result.integration : undefined; | ||
| const packageDir = integration?.__packageDir; | ||
| const docTypes = integration | ||
| ? await checkDocTypes(integrationDocFiles(integration), { |
There was a problem hiding this comment.
This walks the contribution roots, reads every doc and loads the project's typescript from a module that is not the subject's adapter. architecture:cli-surface INV21 keeps file reads, project-module loading and disk discovery in api/integration/_adapter.mjs or an underscore-prefixed helper only it imports.
|
|
||
| /** | ||
| * Each doc the package ships, checked against the published authoring type | ||
| * for its kind. Present whenever a manifest was found. `status: 'skipped'` |
There was a problem hiding this comment.
docTypes is absent when a manifest is found but fails to load (invalid_manifest) or is duplicated (multiple_manifests), because result.integration is unset then. Suggest “Present when the manifest loads” here, and the same wording in validateIntegration.doc.mjs, the README and response-types.doc.mjs.
3e68fdf to
9b9aeb8
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check in astryx doctor integration validate, the new data.docTypes field and the TemplateDoc.category widening rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec for these additions. The earlier findings are addressed, and one fix remains regardless of that decision: with a project TypeScript older than 4.9 and only .ts docs, the version guard in doc-types.mjs does not apply and the check prints [ok] Every doc matches its authoring type without checking anything, so please apply the floor to every doc (or treat syntax errors in the instrumented text as not checked) and add a test.
[Automated review]
| .split('.') | ||
| .map(Number); | ||
| const hasJs = files.some(file => !/\.ts$/.test(file.path)); | ||
| if (hasJs && major < 5) { |
There was a problem hiding this comment.
With a project typescript older than 4.9 and only .ts docs this guard does not apply, and the satisfies operator inserted for .ts docs (L563) is a syntax error there, so every doc comes back with no findings and the CLI prints [ok] Every doc matches its authoring type. Applying the version floor to every doc (or treating syntax diagnostics in the instrumented text as not checked) would keep the report from passing silently.
9b9aeb8 to
9c0365b
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check in astryx doctor integration validate, the new data.docTypes field and the TemplateDoc.category widening rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec for these additions. The version-floor fix works, and one change remains regardless of that decision: a wrong-typed field named type below a doc's top level (a prop's type, a content block's type) is never set aside, so that doc's other unknown and missing fields stay hidden until it is fixed (for example, a topic with titel, no title and a block with type: 'paragraph' reports only the block). Please keep the never-cast rule for the doc's own type, set aside the object that holds a deeper type, and add a test for that case.
[Automated review]
| } | ||
| } else if ( | ||
| finding.problem === 'wrong_type' && | ||
| !/(^|\.)type$/.test(finding.field) |
There was a problem hiding this comment.
This skips every field named type at any depth, so a wrong nested value (a prop's type, a content block's type) is never set aside and the doc is not checked again; the rest of the doc stays hidden. For example, a topic with titel, no title and a block {type: 'paragraph', text: 'x'} reports only sections[0].content[0].type, and a component doc with keyword and props[0].type: 5 reports only props[0].type. Keeping the rule for the doc's own type (finding.field === 'type') and casting the object that holds a deeper type to any would let one run report everything, as the PR describes.
9c0365b to
3640e4c
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the wider TemplateDoc.category type rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main). A maintainer needs to approve that requirement or identify another governing spec, and decide whether the published category type should widen. Separately from that decision, please drop the new clause in template.doc.mjs that says astryx doctor integration validate warns about a template without displayName or aspectRatio: nothing runs the check on this branch yet, and validate reports no warnings for such a template, so that sentence belongs in #7673.
[Automated review]
| { | ||
| type: 'prose', | ||
| text: 'When it loads, a template may leave out `displayName` and `aspectRatio` and use its own `category`, as integration templates already published do; a block with no `aspectRatio` previews at 1. Write to the type anyway; it is the contract.', | ||
| text: 'When it loads, a template may leave out `displayName` and `aspectRatio`, as integration templates already published do; a block with no `aspectRatio` previews at 1. Write to the type anyway; it is the contract, and `astryx doctor integration validate` warns about a template that leaves them out.', |
There was a problem hiding this comment.
This clause isn't true on this branch yet: nothing calls checkDocTypes() until #7673, and astryx doctor integration validate reports [ok] No integration issues found. with 0 warnings for a block template that has neither displayName nor aspectRatio. Suggest dropping it here and adding it in #7673, so the reference stays accurate in whichever release this lands.
3640e4c to
86a34e4
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the wider TemplateDoc.category rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec, and decide whether the published category type should widen. Separately from that decision, please fix these two:
- With TypeScript 7 installed (npm's current
latest),resolveProjectTypeScript()finds nocreateProgram, so the check says TypeScript is not installed and asks for it to be installed; report the installed version and that the check cannot use it, and add a test with a 7.x-style stub. - A translation that carries props is still told to add each prop's
type, becausePartial<>relaxes only top-level fields while the overlay always takestypefrom the base doc; relax the nested entries too (or narrow the stated rule) and add a test.
[Automated review]
| path.join(path.resolve(dir), 'package.json'), | ||
| ); | ||
| const ts = require('typescript'); | ||
| if (ts && typeof ts.createProgram === 'function') { |
There was a problem hiding this comment.
With TypeScript 7 (npm's current latest, 7.0.2) this check fails: its require('typescript') entry exports only version and versionMajorMinor, so this returns null and checkDocTypes() reports “TypeScript is not installed in this project … Install typescript and run this check again”, although TypeScript is installed. Telling “resolved without a compiler API” apart from “not found” (for example, returning the version without ts) would let the report name the installed version and say why the check cannot use it; a stub typescript that exports only version and versionMajorMinor would cover it in a test.
There was a problem hiding this comment.
Fixed at c058058. An installed TypeScript without createProgram is named: "TypeScript 7.0.0 is installed in this project, but it has no JavaScript compiler API (createProgram) to read types with, so docs were not checked." foundation/discovery/doc-types.test.mjs › "names an installed TypeScript it cannot use, rather than asking to install one" pins both 7.x shapes (an entry that exports no compiler, one that cannot be loaded). The prop comparison gives the same reason, through the same project-typescript.mjs.
| // field it leaves out: each field it writes must match, none is required. | ||
| if (translation) { | ||
| const full = componentType(shape); | ||
| return {typeExpr: `Partial<${full.typeExpr}>`, typeName: full.typeName}; |
There was a problem hiding this comment.
Partial<> relaxes only top-level fields, so a translation whose props carry translated text and leave type to the base doc gets “Add props[0].type: ComponentPropDoc requires it.” for each prop, although overlayProps always keeps the base doc's type (foundation/doc-compiler/overlays.mjs L151–L153). Making the nested prop and sub-component entries partial too (keeping name), or narrowing the rule in the comment above, would match how the CLI reads these translations.
There was a problem hiding this comment.
Fixed at c058058: a translation's prop and sub-component entries are checked with every field optional but name, as the overlay merges them by name and keeps the base doc's type. foundation/discovery/doc-types.test.mjs › "checks a translation that carries props for its fields, not for what only the base doc needs" pins a prop without type, a sub-component prop without type, a wrong-typed type (still reported) and an entry without name (reported).
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the wider TemplateDoc.category rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec, and decide whether the published category type should widen. The TypeScript 7 skip reason and the relaxed translation entries now work as described. If the widening stays, please also scope the closing note in the template reference (template.doc.mjs, “category uses the shared TemplateCategory taxonomy”) to Core templates, since the category row now lets an integration template use its own value.
[Automated review]
| type: 'TemplateCategory | string', | ||
| description: | ||
| "Functional gallery category following a 'Group - Variant' convention (e.g. 'Dashboard - Analytics', 'Table - Basic', 'Form - Wizard'). The overview groups by the text before ' - '.", | ||
| "Functional category. Core templates use a TemplateCategory value following a 'Group - Variant' convention (e.g. 'Dashboard - Analytics', 'Table - Basic', 'Form - Wizard'); the overview groups by the text before ' - '. An integration template may use its own value, and bare `astryx template` groups templates by it.", |
There was a problem hiding this comment.
This row now lets an integration template use its own category, but the closing note in this file still says “category uses the shared TemplateCategory taxonomy”, so the reference reads both ways. If the widening stays, scoping that note to Core templates would keep the two consistent.
There was a problem hiding this comment.
Fixed at fcb28b1: the closing note says the shared TemplateCategory taxonomy is for Core templates, and that an integration template may use its own value.
c058058 to
fcb28b1
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the wider TemplateDoc.category rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main), so a maintainer needs to approve that requirement or identify another governing spec, and decide whether the published category type should widen and with which Changeset tag, since code that reads category as a TemplateCategory no longer compiles. The closing note in the template reference now matches the category row. Separately from that decision, please set aside a .doc.ts doc's own TypeScript annotation the way the JSDoc @type already is: around a valid component doc, export const docs: ReferenceDoc = {…} is told both to remove and to add displayName, props and usage, and <ReferenceDoc>{…} is told to add them, so a .doc.ts case beside the existing annotation test would pin the fix.
[Automated review]
| for (const wrapper of wrappers) { | ||
| // ` satisfies X` / ` as X` after the value. | ||
| if ( | ||
| !ts.isParenthesizedExpression(wrapper) && | ||
| wrapper.end > wrapper.expression.end | ||
| ) { | ||
| if (!ts.isNonNullExpression(wrapper)) { | ||
| blankRanges.push([wrapper.expression.end, wrapper.end]); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
This sets aside only wrappers that end after the value (satisfies X, as X), and blank handles leading JSDoc. In a .doc.ts, a declaration's own type (export const docs: ReferenceDoc = {…}) and a prefix assertion (<ReferenceDoc>{…}) stay in the compiled text. Around a valid component doc, the first yields displayName, props and usage as unknown_field (“Remove …: ReferenceDoc has no field …”) and then, after the set-aside pass, as missing_field (“Add …: SingleComponentDoc requires it.”); the second yields three “Add …” findings. Blanking the declaration's type and the assertion's type, as the JSDoc @type is, and adding a .doc.ts case beside the annotation test would keep each value checked once against its root's type, as the comment above instrument says.
There was a problem hiding this comment.
Fixed in bd4443b. A variable's own annotation and a prefix type assertion are now blanked like the JSDoc @type, so each value is checked once, against its root's type. Test: 'ignores a .doc.ts doc's own annotation and type assertion, as it does a JSDoc one'. Its export const docs: ReferenceDoc = … and export default <ReferenceDoc>… each report only their keyword.
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the new published IntegrationTemplateDoc rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main). A maintainer needs to approve that requirement or identify another governing spec for both additions, and to settle whether integration templates should declare their own typed category, since the page-template guide and integration add template still point them at TemplateDoc. Apart from that decision, nothing needs to change: the .doc.ts annotation fix works and TemplateDoc is unchanged, though note that @astryxdesign/cli/doc and @astryxdesign/cli/template also export the two member interfaces, so the release adds three public type names rather than one.
[Automated review]
bd4443b to
257cec7
Compare
There was a problem hiding this comment.
Approval is waiting on a maintainer decision: the doc type check (checkDocTypes()) and the three new published integration template types (IntegrationTemplateDoc and its page and block members) rest on AST-039 FR13, which is only proposed in #7658 (AST-039 is still a draft on main). A maintainer needs to approve that requirement or identify another governing spec for both additions, and to settle whether integration templates should declare their own typed category, since the integration template guide and integration add template still point them at TemplateDoc. Apart from that decision, nothing needs to change: the Changeset now names all three new types, TemplateDoc is unchanged, and the tests and CI pass.
[Automated review]
257cec7 to
9e9f123
Compare
There was a problem hiding this comment.
Changes requested: the doc type check and the new integration template types now rest on architecture:cli-surface INV34, and the tests and CI pass, but one gap against INV34 remains. A doc whose own top-level type is wrong (for example type: 'generic' in the components root, or a misspelled theme stamp) reports only that type, so its unknown and missing fields stay hidden until the stamp is fixed, because checkDocTypes() never sets the doc's own type aside. Please keep checking the rest of the doc against its root's type where the root alone fixes the type (components, themes), list the doc as not fully checked where the stamp picks the type, and add a test with a wrong stamp beside an unknown and a missing field.
[Automated review]
| } | ||
| } else if ( | ||
| finding.problem === 'wrong_type' && | ||
| finding.field !== 'type' |
There was a problem hiding this comment.
A doc whose own type is wrong is never checked again, so TypeScript keeps reporting that type and hides the doc's unknown and missing fields, while architecture:cli-surface INV34 asks for every one. On this head, a components-root doc with type: 'generic', keyword and no displayName reports only type, and the same doc stamped 'component' reports both. Where the root alone fixes the type (components, themes), the type could be set aside once it is reported; where the stamp picks the type, the doc could be listed as not fully checked. A test with a wrong stamp beside an unknown and a missing field would pin it.
There was a problem hiding this comment.
Fixed in a623c61. Where the root alone fixes a doc's type (components, hooks, templates, themes, and the translations), a wrong top-level type is reported and set aside, and the rest of the doc is checked against the root's type. Where the type picks the type (a docs-root topic), only the stamp is reported, and the doc is listed as not fully checked, so it can't count toward [ok]. The test is a components-root doc with type: 'generic', an unknown field and a missing field, now reporting all three; it failed before. Next to it, a docs-root topic with a misspelled stamp is listed as not fully checked.
9e9f123 to
a623c61
Compare
There was a problem hiding this comment.
Changes requested, for scope only. The doc type check and the new integration template types match architecture:cli-surface INV34, the earlier wrong-type gap is fixed, and the tests and CI pass, but the diff is now 2,025 authored lines, more than the 2,000 a single pull request should carry. project-typescript.mjs and its doc-loads.test.mjs entry (65 lines) are byte-identical with #7681, so rebasing onto #7681 once it merges, or basing this branch on it, brings this PR to 1,960 lines; moving the three Integration*TemplateDoc types, their authoring doc and the Changeset into an earlier PR would also work. No other change is needed.
[Automated review]
| @@ -0,0 +1,61 @@ | |||
| // Copyright (c) Meta Platforms, Inc. and affiliates. | |||
There was a problem hiding this comment.
There was a problem hiding this comment.
A foundation check, `checkDocTypes`, reads each doc file's value (the export its root reads) and checks it the way TypeScript checks `value satisfies Type` against the type `@astryxdesign/cli/authoring` publishes for its kind, with the project's own TypeScript. Each unknown field, missing required field, or value outside its field's type is a warning naming the doc, line, field, and a fix. A value outside its type, an unknown field, or a nested object missing a field is set aside so the same run reports what it hid. Translations are checked against their translation types; one that carries props overlays the base doc, so none of its fields is required. Without TypeScript, or with one older than the docs need, nothing is checked and the report says why. The published `TemplateDoc` type admits an integration template's own `category`, which the loader always accepted and bare `astryx template` groups by. `astryx doctor integration validate` runs it in the follow-up PR, which also adds the repository test over Core's own docs.
… and relax translated entries With only a TypeScript that has no JavaScript compiler API installed (TypeScript 7), the check said TypeScript was not installed and asked for it. It now names the installed version and says it cannot read types with it. A translation that carries props is no longer told to add each prop's `type`: props and sub-component entries merge onto the base doc by name, which keeps each prop's type, so a translated entry needs only its name.
…ateDoc, keep TemplateDoc as it is, and set aside a .doc.ts doc's own annotation
`TemplateDoc` is back to main's, `category` a `TemplateCategory`. A new
`IntegrationTemplateDoc` (every `TemplateDoc` field, with the package's own
`category` string), exported from `@astryxdesign/cli/authoring` with its
own section in `astryx docs authoring`, is what the doc type check holds an
integration's templates to; Core's own templates keep `TemplateDoc`.
A `.doc.ts` doc's own annotation (`const docs: ReferenceDoc = …`) and type
assertion (`<ReferenceDoc>{…}`) are set aside the way a JSDoc `@type` is,
so the value is checked once, against its root's type.
a623c61 to
2d52ec0
Compare
User need
Every doc an integration ships is meant to be written to a type
@astryxdesign/cli/authoringpublishes:ComponentDoc,TemplateDoc,ReferenceDoc,ThemeDocand the translation types. The CLI's loader accepts a looser shape than those types, so a doc can pass every check and still fail a type check in its own repository. Today these all passastryx doctor integration validate:displayNameorusage, or with malformed usage, theming, playground or example entries;keyword:forkeywords:;type: 'generic'in a doc besideFoo.tsx;displayName, or a block withoutaspectRatio;docsZh,docsDense,<topic>.doc.<lang>.mjs) with fields its type doesn't have.Authors find these only when someone runs
tsc, if ever, and readers get docs the CLI then reads partly or not at all.Problem and solution fit
This PR adds the check; #7673, stacked on it, runs it in
astryx doctor integration validateand adds the repository test over Core's own docs. The two were one PR until a thorough fix took it past 2,000 lines; they split where the check meets the command.checkDocTypeschecks each doc file's value (the export its root reads) the waytscchecks a value written with the published type for its kind, using the project's owntypescript:ComponentDoc(read as TypeScript reads the union; messages name the member the doc's shape selects);ComponentTranslationDoc(andHookTranslationDoc); a translation that carries props overlays the base doc, so it is checked against the full type with no field required but each prop's and sub-component entry'sname;IntegrationTemplateDoc(TemplateDocfor Core's own templates); the docs root against the type a doc'stypenames (ReferenceDocwhen it names none), and topic overlays againstReferenceTranslationDoc; the themes root againstThemeDoc.Each finding is a warning naming the doc, the line, the field path (for example
usage.bestPractices[1].guidance), the problem (unknown_field,missing_fieldorwrong_type), TypeScript's message, and a fix: rename to the field TypeScript suggests, remove, add, or change to a value of type X. TypeScript stops at an object's first unknown field, and a value outside its type, or a nested object missing a field, hides the rest of the doc. So the check looks again, with each such field or object set aside, until nothing new appears: one run reports everything. Without TypeScript, or with one older than the docs need, nothing is checked and the report says why; with a TypeScript that has no JavaScript compiler API to read types with (TypeScript 7), the reason names the installed version instead of asking for TypeScript. With no doc files, the report says so, TypeScript or not.Current specification
Implements
architecture:cli-surfaceINV34, "Every descriptor satisfies its published authoring type" (AST-039 FR13, which now points to it; DEC-5), with #7673. Its evidence row names the doc-types, doctor-integration and core-doc-types tests.Public delta and caller burden
IntegrationPageTemplateDocandIntegrationBlockTemplateDoc(eachTemplateDocmember, withcategorythe package's own string) and their union,IntegrationTemplateDoc.@astryxdesign/cli/authoringexports the union;@astryxdesign/cli/docand@astryxdesign/cli/templateexport all three.TemplateDoc.categoryis the closedTemplateCategoryunion, which no integration template can meet, because bareastryx templategroups templates bycategoryand the loader always accepted any string.TemplateDocstays exactly as it is, so code that readscategoryas aTemplateCategorykeeps compiling. The check holds an integration's templates toIntegrationTemplateDoc, and Core's own toTemplateDoc.displayNameandaspectRatiostay required in both, as the template reference already says. The new type has its own section inastryx docs authoring.validatesection anddata.docTypes.Design and alternatives
satisfiescheck of its published type in memory and asks the project's compiler, so it can never disagree withtscand follows the types as they change. A doc's own annotation is set aside for the check, so each doc is checked once, against the type for its root: a JSDoc@type, and in a.doc.tsdoc a variable's annotation (const docs: ReferenceDoc = …), a type assertion (<ReferenceDoc>{…}),asorsatisfies.type: 'generic'besideFoo.tsx: the fix says to settype: 'component'or move the doc to the docs root.typeis never cast, because it picks the type. A deepertypesets aside the object that holds it. Messages from later passes say "this value" instead of quoting the edited text.TemplateDoc, and not a warning. The loader andastryx templatealready treat any string as valid, so a warning would be about a gap in the type, not in the doc. WideningTemplateDoc.categorywould break code that reads it as aTemplateCategory, which can't ship in a patch. An added type changes nothing that compiles today.Evidence
foundation/discovery/doc-types.test.mjs(20 tests): each problem kind; a package with no doc files, with and without TypeScript; a TypeScript 7-style install with no compiler API (one that exports none, one that can't be loaded); a TypeScript older than 4.9 with only.tsdocs; a doc the compiler cannot parse; a value outside its type that hid other fields; a wrongtypebelow the top level; a missing top-level field that nested missing fields hid, with no edited text quoted; eight unknown fields in one doc; a field reached only after an unknown one; a doc in another kind's root; an annotation naming another type, in JSDoc and in a.doc.tsdoc (a variable's annotation and a type assertion); translations, including ones that carry props, whose prop and sub-component entries need only theirname; a doc that re-exports its value; template, topic, overlay and theme, with an integration template's owncategoryaccepted and Core's held toTemplateCategory; no TypeScript installed.Since the first automated review
uncheckedas not fully checked..tsdocs (satisfies), 5.0 when any doc is JavaScript. Below it, the check is skipped with that reason.typebelow the top level (a content block's, a prop's) sets aside the object that holds it.After an independent audit
A reviewer who didn't write the code drove the real CLI over 53 package shapes on main, on each PR's head, and on all five merged together, and sorted Core's findings by hand. Fixed here, each with a test that failed first:
name,displayNameandusage, which only the base doc needs, although the CLI renders it correctly. That was all 41 of Core'sdocsZh usage missing_fieldentries.export {default} from './shared.mjs') was listed as exporting no doc. It now says the check doesn't follow re-exports.'{ guidance: any; }'). They say "this value" now.After the next review
astryx doctor integration validatewarns about a template withoutdisplayNameoraspectRatiomoved to feat(cli): doctor integration validate checks each doc against its published authoring type #7673, wherevalidatestarts doing it. This PR's own text claims only what is true on its head.After the review that followed
createProgram, the check said TypeScript wasn't installed and asked for it. It names the installed version now and says it can't read types with it.project-typescript.mjsand its doc-loads entry change the same way, byte for byte, in feat(cli): compare documented component props with the TypeScript source #7663.type, although the overlay always takestypefrom the base doc. Props and sub-component entries in a translation merge onto the base doc byname, so they are checked with every field optional butname; a field they do write must still match its type.After a release review
TemplateDocis back to main's, byte for byte, withcategoryaTemplateCategory. Widening it would have broken code that readscategoryas aTemplateCategory, and that can't ship in a patch. An integration's templates are checked against a newIntegrationTemplateDocinstead: everyTemplateDocfield, with the package's owncategorystring. It is exported from@astryxdesign/cli/authoringand documented in its own section ofastryx docs authoring. Core's own templates keepTemplateDoc. The template reference, the loader's comment and the changeset no longer mention widening..doc.tsdoc's own TypeScript annotation is set aside the way a JSDoc@typeis. Around a valid component doc,export const docs: ReferenceDoc = {…}was told both to remove and to adddisplayName,propsandusage, and<ReferenceDoc>{…}was told to add them. Both now check once, against the root's type.After the latest review
@astryxdesign/cli/docand@astryxdesign/cli/templateexport the two member interfaces as well as the union. Nothing else changed. The guides and theintegration add templatescaffold now declareIntegrationTemplateDocin feat(cli): doctor integration validate checks each doc against its published authoring type #7673, where the check becomes visible.Rebased
After the review of the doc's own type
typewas wrong reported only thetype: its unknown and missing fields stayed hidden until the stamp was fixed, because the check never set the doc's owntypeaside. Where the root alone fixes the doc's type (components, hooks, templates, themes, and translations), a wrong stamp is reported and set aside now, and the rest of the doc is checked against the root's type. Where thetypepicks the type (a docs-root topic), only the stamp is reported, and the doc is listed as not fully checked, so it can't count toward[ok]. What it would report against a type its stamp doesn't name is a guess.type: 'generic', an unknown field and a missing field, reporting all three, beside a docs-root topic with a misspelled stamp, listed as not fully checked. It failed before.Merge order
The order is required:
doctor integration components, stacked on feat(cli): compare documented component props with the TypeScript source #7663), then feat(cli): read two written TypeScript types as one when they differ only in how they are written #7684 (reading two written types as one, stacked on feat(cli): doctor integration components compares documented props with the code #7676), then feat(cli): doctor integration components judges documented prop types against the code #7667 (prop types, stacked on feat(cli): read two written TypeScript types as one when they differ only in how they are written #7684).validate, stacked on feat(cli): check each authored doc against its published authoring type #7664).integration check) last, after a rebase that adds these PRs' fields and codes to its failures list. Merged earlier, it breaks main.This PR must ship in the same release as
integration check, with #7673.Overlap with open PRs
foundation/discovery/project-typescript.mjs, and the entry this PR adds todoc-loads.test.mjs, are byte-identical in feat(cli): read a package's TypeScript project the way tsc reads it #7681, so the two merge cleanly in either order.astryx componentprints #7623, fix(cli): init writes agent docs every agent reads, at the project root, never in the home folder #7497, spec(AST-039, cli-surface): integration docs are found by their documented names and checked in one command #7658, feat(cli): a component doc can name a differently named export of the file beside it #7659, fix(cli): integration verify reads exports with the reader discovery uses #7660, feat(docsite): put the integration guide's pages under CLI Integrations in the sidebar #7661, feat(cli): integration family members are components under their own names #7674, or the other PRs in this set.Size
2,025 changed lines today; 65 of them are
project-typescript.mjsand itsdoc-loads.test.mjsentry, byte-identical with #7681. This PR merges after #7681: once #7681 lands, it is rebased onto main, which takes those lines out and brings it to 1,960, and reviewed again.Scope
Testing
On main 91cfb53 with this branch: copyright, sync-exports, the published
./apitype check,readme:check, the four CLI typechecks (strict, json-api, authoring-contract, template-docs),check:changesets,check:cli-structure,check:repo, eslint on the changed files, prettier on the new files, and the fullpnpm vitest run --project nodesuite: 10,302 tests pass. The 21 failures are in the npm pack, packed real-world package, theme resolution and CSS graph tests, plus one browser accessibility test that is flaky there, which fail the same way on current main on the same machine (they need a package registry it doesn't reach). With all nine PRs merged into main, the fourdoctor integrationsubcommands were run in text and JSON on 64 package shapes, against main: templates output is byte-identical everywhere;validateandcomponentsonly add their new section and JSON field;docsdiffers only where the doc-links PR fixes a link warning.integration checkexits 1 exactly when one of the four would, each of its sections is byte-identical to that subcommand's output, and onlyintegration check's three list tests fail until its planned rebase.