@bettercms-ai/convert 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +145 -0
- package/dist/cli.js +1418 -30
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +294 -4
- package/dist/index.js +1348 -18
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -285,12 +285,31 @@ interface AttrNode {
|
|
|
285
285
|
expression: boolean;
|
|
286
286
|
/** The whole `name="value"` span, so an attribute can be replaced outright. */
|
|
287
287
|
range: Range;
|
|
288
|
+
/**
|
|
289
|
+
* The braces of an expression-valued attribute, `{` and `}` included. Null when there are none.
|
|
290
|
+
*
|
|
291
|
+
* 🔴 `range` IS NOT THE EXPRESSION FOR A SHORTHAND. Astro reports `{title}` and `{...props}` at
|
|
292
|
+
* the offset of the IDENTIFIER, four characters into the spread — so a reader that looked for the
|
|
293
|
+
* first `{` inside `range` found none and concluded the attribute held no code. The section then
|
|
294
|
+
* travelled without whatever `title` was, into a component file that does not build. Every parser
|
|
295
|
+
* that has an expression says where it starts, rather than leaving each reader to scan for it.
|
|
296
|
+
*/
|
|
297
|
+
expressionRange: Range | null;
|
|
288
298
|
}
|
|
289
299
|
type Node = {
|
|
290
300
|
type: "element";
|
|
291
301
|
tag: string;
|
|
292
302
|
/** The `<` of the open tag. */
|
|
293
303
|
start: number;
|
|
304
|
+
/**
|
|
305
|
+
* One past the element's LAST byte — the `>` of `</section>`, or of `<img … />`.
|
|
306
|
+
*
|
|
307
|
+
* Carried because the componentize lane lifts a whole element out of a page and into a file
|
|
308
|
+
* of its own: `start` and `inner` describe where a value goes, and neither says where the
|
|
309
|
+
* subtree stops. Recomputing it from `inner.end + "</tag>".length` would assume the closing
|
|
310
|
+
* tag holds no whitespace, and every parser here already reports the real end.
|
|
311
|
+
*/
|
|
312
|
+
end: number;
|
|
294
313
|
/** Where an attribute may be inserted: after the last attribute, before `/` and `>`. */
|
|
295
314
|
attrInsertAt: number;
|
|
296
315
|
/** Everything between the tags. Null for void and self-closing elements. */
|
|
@@ -634,7 +653,7 @@ declare function attrsFor(path: string, kind: string, props?: AttrBinding[], sco
|
|
|
634
653
|
declare function propsAttribute(props: AttrBinding[]): string;
|
|
635
654
|
|
|
636
655
|
/** Bumped whenever the emitted source changes. `isKnownHelper` upgrades anything older. */
|
|
637
|
-
declare const HELPER_VERSION =
|
|
656
|
+
declare const HELPER_VERSION = 3;
|
|
638
657
|
/** Where each dialect's helper lives. Null = this dialect reads nothing at build time. */
|
|
639
658
|
declare const HELPER_PATH: Record<Dialect, string | null>;
|
|
640
659
|
/** The directory the snapshots live in, at the repository root. */
|
|
@@ -698,8 +717,17 @@ declare function resolveSpecifier(fromFile: string, specifier: string, files: Se
|
|
|
698
717
|
/** What one local name was imported from, and WHICH export of it. */
|
|
699
718
|
interface ImportedFrom {
|
|
700
719
|
specifier: string;
|
|
701
|
-
/** The exported name, or null for a default import. */
|
|
720
|
+
/** The exported name, or null for a default OR namespace import. @see kind */
|
|
702
721
|
imported: string | null;
|
|
722
|
+
/**
|
|
723
|
+
* WHICH OF THE THREE, because they are three different statements to write back.
|
|
724
|
+
*
|
|
725
|
+
* 🔴 A NAMESPACE IMPORT IS NOT A NAMED ONE. `import * as Icons from "./icons"` was recorded with
|
|
726
|
+
* `imported: "Icons"` — the local name, because babel reports no `imported` for it — so a lane
|
|
727
|
+
* re-emitting the import wrote `import { Icons } from "./icons"`, which binds a named export
|
|
728
|
+
* nobody declared and fails at build. The distinction is on the specifier node; it is kept.
|
|
729
|
+
*/
|
|
730
|
+
kind: "default" | "named" | "namespace";
|
|
703
731
|
}
|
|
704
732
|
/**
|
|
705
733
|
* Local name → what it was imported from, for one file.
|
|
@@ -802,6 +830,268 @@ interface FileDeclaration {
|
|
|
802
830
|
/** Every path one file declares, with the lane it declares it on. */
|
|
803
831
|
declare function readDeclarations(file: string, content: string): Promise<FileDeclaration[]>;
|
|
804
832
|
|
|
833
|
+
/**
|
|
834
|
+
* A dynamic route reads ITS OWN entry, and the route parameter is how it says which.
|
|
835
|
+
*
|
|
836
|
+
* 🔴 WITHOUT THE PARAMETER THE PAGE IS WRONG, NOT INCOMPLETE. `bcms(page, "title", "…")` on
|
|
837
|
+
* `[slug].astro` resolves the same value for every URL the route serves, so a hundred posts render
|
|
838
|
+
* the first post's title — a conversion that builds, passes every attribute check, and is visibly
|
|
839
|
+
* broken. So a dynamic route either gets its parameter or reports `DYNAMIC_PARAMS_UNAVAILABLE`
|
|
840
|
+
* and stays as it was.
|
|
841
|
+
*
|
|
842
|
+
* Astro hands it over for free (`Astro.params`). Next does not: `params` is an argument to the
|
|
843
|
+
* page component, so the SIGNATURE has to be edited — and on Next 15 `params` is a promise, which
|
|
844
|
+
* is why an already-`async` component gets `(await params).slug` and a synchronous one does not.
|
|
845
|
+
*/
|
|
846
|
+
|
|
847
|
+
/** `src/pages/[slug].astro`, `app/blog/[slug]/page.tsx` — a segment in brackets. */
|
|
848
|
+
declare const isDynamicRoute: (file: string) => boolean;
|
|
849
|
+
/**
|
|
850
|
+
* Which route does this FILE serve, or null when it is not a page at all.
|
|
851
|
+
*
|
|
852
|
+
* 🔴 A ROUTE IS NOT A FILE, AND IT IS NOT A SEARCH EITHER. Picking the page by "which file mentions
|
|
853
|
+
* this field group" reads whichever file holds the most matches — and a `hero` group is on every
|
|
854
|
+
* landing page, so `/about`'s sections were resolved against `/`'s file and one route's codemod
|
|
855
|
+
* rewrote another route's page. The router's own convention answers the question the route is
|
|
856
|
+
* actually asking.
|
|
857
|
+
*
|
|
858
|
+
* Every framework this package converts is here, including the two it cannot extract from
|
|
859
|
+
* (SvelteKit, Nuxt) — a page it can NAME is a page it can refuse by dialect, and a page it cannot
|
|
860
|
+
* name is `NOT_IN_SOURCE`, which are different facts.
|
|
861
|
+
*/
|
|
862
|
+
declare function routeOfFile(file: string): string | null;
|
|
863
|
+
/**
|
|
864
|
+
* Every file that serves this route, in path order.
|
|
865
|
+
*
|
|
866
|
+
* More than one is not a tie to break: two files claiming one URL is a repository whose own router
|
|
867
|
+
* has to pick, and a codemod that picks differently edits a page nobody serves.
|
|
868
|
+
*/
|
|
869
|
+
declare function pageFilesFor(route: string, files: Iterable<string>): string[];
|
|
870
|
+
|
|
871
|
+
type Element = Extract<Node, {
|
|
872
|
+
type: "element";
|
|
873
|
+
}>;
|
|
874
|
+
interface Carried {
|
|
875
|
+
/** `import Card from "../Card.astro";` — the page's own imports, re-based onto the new file. */
|
|
876
|
+
imports: string[];
|
|
877
|
+
/** Module-scope statements the markup depends on, in the page's own source order. */
|
|
878
|
+
declarations: string[];
|
|
879
|
+
/** Names nothing can account for. Non-empty means the section is refused, not written. */
|
|
880
|
+
free: string[];
|
|
881
|
+
}
|
|
882
|
+
/**
|
|
883
|
+
* Everything one section root needs, resolved against the page it is leaving.
|
|
884
|
+
*
|
|
885
|
+
* `provided` is what the component file declares for itself — its props, the snapshot local it
|
|
886
|
+
* redeclares, and the helper names it imports — so those are never carried and never free.
|
|
887
|
+
*/
|
|
888
|
+
declare function carryFor(options: {
|
|
889
|
+
dialect: Dialect;
|
|
890
|
+
fromFile: string;
|
|
891
|
+
toFile: string;
|
|
892
|
+
content: string;
|
|
893
|
+
parsed: ParsedFile;
|
|
894
|
+
root: Element;
|
|
895
|
+
provided: Iterable<string>;
|
|
896
|
+
/** Repository paths that must never be carried as an import — the helper, the snapshots. */
|
|
897
|
+
skipSpecifier: (repoPath: string, specifier: string) => boolean;
|
|
898
|
+
}): Carried;
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* The plan, as `get_componentize_plan` returns it.
|
|
902
|
+
*
|
|
903
|
+
* READ DEFENSIVELY. A newer server may carry fields this version has never heard of, and the
|
|
904
|
+
* customer runs whichever `npx @bettercms-ai/convert` npm hands them — so every field this module
|
|
905
|
+
* does not need is `unknown`, every field it does need is optional with a stated fallback, and
|
|
906
|
+
* an unexpected extra key is simply carried past. The shape is frozen; the reader is not brittle.
|
|
907
|
+
*/
|
|
908
|
+
interface ComponentizePlanField {
|
|
909
|
+
/** The leaf's key inside the group — `title`, `items[0].q`. */
|
|
910
|
+
key?: string;
|
|
911
|
+
/** The whole page path — `hero.title`. Derived from `groupKey` + `key` when absent. */
|
|
912
|
+
path?: string;
|
|
913
|
+
type?: string;
|
|
914
|
+
label?: string;
|
|
915
|
+
current?: unknown;
|
|
916
|
+
}
|
|
917
|
+
interface ComponentizePlanSection {
|
|
918
|
+
groupKey: string;
|
|
919
|
+
sectionType?: string;
|
|
920
|
+
label?: string;
|
|
921
|
+
order?: number;
|
|
922
|
+
shapeHash?: string;
|
|
923
|
+
fields?: ComponentizePlanField[];
|
|
924
|
+
/** Which component renders this placement — a proposed one, or one the project already has. */
|
|
925
|
+
reuse?: {
|
|
926
|
+
componentId?: string;
|
|
927
|
+
proposedSlug?: string;
|
|
928
|
+
};
|
|
929
|
+
/** The SERVER already decided it cannot place this one. Not this codemod's to extract. */
|
|
930
|
+
pending?: {
|
|
931
|
+
reason?: string;
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
interface ComponentizePlanPage {
|
|
935
|
+
pageId?: string;
|
|
936
|
+
route: string;
|
|
937
|
+
sections?: ComponentizePlanSection[];
|
|
938
|
+
}
|
|
939
|
+
interface ComponentizePlanComponent {
|
|
940
|
+
proposedSlug: string;
|
|
941
|
+
/** Present when the plan reuses a component the project already has. */
|
|
942
|
+
componentId?: string;
|
|
943
|
+
sectionType?: string;
|
|
944
|
+
name?: string;
|
|
945
|
+
category?: string;
|
|
946
|
+
placements?: number;
|
|
947
|
+
}
|
|
948
|
+
interface ComponentizePlan {
|
|
949
|
+
pages: ComponentizePlanPage[];
|
|
950
|
+
components?: ComponentizePlanComponent[];
|
|
951
|
+
digest?: string;
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Why a section is not a component in this repository.
|
|
955
|
+
*
|
|
956
|
+
* Every one of them is a fact about the SOURCE rather than an apology:
|
|
957
|
+
* `SECTION_ROOT_AMBIGUOUS` its fields do not sit under one element, or two sections nest.
|
|
958
|
+
* `SECTION_NOT_CONTIGUOUS` the page's section roots do not share a container at all. The
|
|
959
|
+
* component IS written; the page is left exactly as it was.
|
|
960
|
+
* `SECTION_FREE_IDENTIFIERS` the markup uses a name the component file cannot be given — a
|
|
961
|
+
* local of the page's own component body, or an expression this
|
|
962
|
+
* version cannot read.
|
|
963
|
+
* `COMPONENT_CONFLICT` a file already sits at the component's path and this package did
|
|
964
|
+
* not write it.
|
|
965
|
+
* `REGISTRY_CONFLICT` the same, for the registry or the sections library.
|
|
966
|
+
* `ROUTE_FILE_AMBIGUOUS` two files serve one route; the repository's own router has to
|
|
967
|
+
* pick, and a codemod that picks differently edits a dead page.
|
|
968
|
+
* `DIALECT_UNSUPPORTED` the page is svelte / vue / html; nothing is written for it.
|
|
969
|
+
* `HELPER_CONFLICT` `src/bcms-content.ts` is a module this package did not write.
|
|
970
|
+
* `SNAPSHOT_INVALID` `bcms-content/<page>.json` is not JSON this can add `blocks` to.
|
|
971
|
+
* `NOT_IN_SOURCE` no file we were given renders the group, or the route names no
|
|
972
|
+
* page file this package can find.
|
|
973
|
+
*/
|
|
974
|
+
type SectionPendingReason = "SECTION_ROOT_AMBIGUOUS" | "SECTION_NOT_CONTIGUOUS" | "SECTION_FREE_IDENTIFIERS" | "COMPONENT_CONFLICT" | "REGISTRY_CONFLICT" | "ROUTE_FILE_AMBIGUOUS" | "DIALECT_UNSUPPORTED" | "HELPER_CONFLICT" | "SNAPSHOT_INVALID" | "NOT_IN_SOURCE";
|
|
975
|
+
interface PendingSection {
|
|
976
|
+
route: string;
|
|
977
|
+
groupKey: string;
|
|
978
|
+
reason: SectionPendingReason;
|
|
979
|
+
/** What exactly could not be done. Informative; the reason is the contract. */
|
|
980
|
+
message?: string;
|
|
981
|
+
}
|
|
982
|
+
interface SectionsReceipt {
|
|
983
|
+
/** Component written AND the page's run replaced by `<Sections page="…" />`. */
|
|
984
|
+
extracted: number;
|
|
985
|
+
/**
|
|
986
|
+
* Component written, but the page keeps CALLING it in place.
|
|
987
|
+
*
|
|
988
|
+
* The run was not contiguous — a sibling that belongs to no section sits between two roots — so
|
|
989
|
+
* a loop over `pageSections()` would silently reorder the page. Each root becomes its own
|
|
990
|
+
* `<Hero …/>` instead: the markup is componentised, the ORDER stays the repository's.
|
|
991
|
+
*/
|
|
992
|
+
inlineOnly: number;
|
|
993
|
+
/**
|
|
994
|
+
* Already ours, from a previous run — its fields now live in a file carrying our marker.
|
|
995
|
+
*
|
|
996
|
+
* 🔴 ITS OWN BUCKET, NOT `extracted`. The round trip has to be observable: a second run over an
|
|
997
|
+
* already-componentised tree reports `extracted: 0, pending: []`, and it can only do that AND
|
|
998
|
+
* account for every section of the plan if "done earlier" is a bucket of its own.
|
|
999
|
+
*/
|
|
1000
|
+
alreadyExtracted: number;
|
|
1001
|
+
pending: PendingSection[];
|
|
1002
|
+
}
|
|
1003
|
+
interface ComponentizeReceipt {
|
|
1004
|
+
/** The plan this run was made against, carried so a receipt can be matched to one. */
|
|
1005
|
+
planDigest: string;
|
|
1006
|
+
sections: SectionsReceipt;
|
|
1007
|
+
/** The component slugs this run wrote a file for, sorted. */
|
|
1008
|
+
components: string[];
|
|
1009
|
+
/**
|
|
1010
|
+
* Sections the SERVER already marked pending (`NO_GROUP_ROOT`, `ALREADY_COMPONENTIZED`, …).
|
|
1011
|
+
*
|
|
1012
|
+
* Outside the arithmetic below on purpose: the plan says they are not to be placed, so a repo
|
|
1013
|
+
* that does not place them has done exactly what it was told.
|
|
1014
|
+
*/
|
|
1015
|
+
planPending: number;
|
|
1016
|
+
}
|
|
1017
|
+
/** Raised when the receipt does not account for every section. Never caught inside this package. */
|
|
1018
|
+
declare class SectionInvariantError extends Error {
|
|
1019
|
+
readonly code = "SECTION_INVARIANT";
|
|
1020
|
+
constructor(message: string);
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* The invariant, checked where the receipt is built.
|
|
1024
|
+
*
|
|
1025
|
+
* A section in none of the buckets is a section the codemod forgot, and forgetting is the failure
|
|
1026
|
+
* this whole lane exists to make impossible — the same reasoning, and the same shape, as P2's
|
|
1027
|
+
* `assertReceipt`.
|
|
1028
|
+
*/
|
|
1029
|
+
declare function assertSections(total: number, sections: SectionsReceipt): SectionsReceipt;
|
|
1030
|
+
interface ComponentizeOptions {
|
|
1031
|
+
/** Replace a helper module this package did not write, instead of refusing. The CLI's flag. */
|
|
1032
|
+
overwriteHelper?: boolean;
|
|
1033
|
+
}
|
|
1034
|
+
/** The marker that says a file is OURS. Idempotence is decided on it, never on a path. */
|
|
1035
|
+
declare const SECTION_MARKER = "// @bettercms-ai/convert section v1";
|
|
1036
|
+
/** The same, for the two modules that hold the registry rather than a section. */
|
|
1037
|
+
declare const REGISTRY_MARKER = "// @bettercms-ai/convert sections v1";
|
|
1038
|
+
/** Where the generated components live. Fixed, so a second run knows its own output on sight. */
|
|
1039
|
+
declare const COMPONENT_DIR = "src/components/bcms";
|
|
1040
|
+
/** The module that reads `blocks` out of the committed snapshots. */
|
|
1041
|
+
declare const SECTIONS_LIB = "src/lib/bcms-sections.ts";
|
|
1042
|
+
declare function componentizeSources(briefIn: Brief, planIn: ComponentizePlan, sources: SourceFile[], options?: ComponentizeOptions): Promise<{
|
|
1043
|
+
files: PlanFile[];
|
|
1044
|
+
receipt: ComponentizeReceipt;
|
|
1045
|
+
}>;
|
|
1046
|
+
/**
|
|
1047
|
+
* The plan, checked at INGRESS.
|
|
1048
|
+
*
|
|
1049
|
+
* Every value the codemod turns into a path or writes into generated source is validated before it
|
|
1050
|
+
* can reach either — `../package` as a page slug is a `package.json` this would have overwritten.
|
|
1051
|
+
* @see validate.ts
|
|
1052
|
+
*/
|
|
1053
|
+
declare function readComponentizePlan(value: unknown): ComponentizePlan;
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* The brief and the plan, checked at INGRESS — before a single byte is written.
|
|
1057
|
+
*
|
|
1058
|
+
* 🔴 A SLUG FROM THE WIRE BECOMES A PATH ON DISK. `bcms-content/<page.slug>.json` is composed from
|
|
1059
|
+
* a string this package did not choose: a page slugged `../package` names the repository's own
|
|
1060
|
+
* `package.json`, and the codemod would have written `{"blocks": []}` over it. The CLI's `--root`
|
|
1061
|
+
* check catches an escape out of the tree; it cannot catch an escape WITHIN it, because the target
|
|
1062
|
+
* is still under `--root`. So the value is refused where it enters, not where it is used.
|
|
1063
|
+
*
|
|
1064
|
+
* The same reasoning covers `groupKey` and `proposedSlug`: both are written into generated source
|
|
1065
|
+
* as object keys and one of them decides a component's file name.
|
|
1066
|
+
*
|
|
1067
|
+
* NO ZOD. This package ships to `npx` in somebody else's repository and its dependency list is the
|
|
1068
|
+
* five parsers; a validator for two known shapes is forty lines, and forty lines is cheaper than a
|
|
1069
|
+
* dependency in every install. The checks are the ones zod would express: a type per field, a
|
|
1070
|
+
* pattern per string that becomes a path, and a refusal that names the field it refused.
|
|
1071
|
+
*/
|
|
1072
|
+
|
|
1073
|
+
type ValidationCode = "BRIEF_INVALID" | "PLAN_INVALID";
|
|
1074
|
+
/** Raised at ingress. The run is refused whole: nothing is written on a value this cannot trust. */
|
|
1075
|
+
declare class ValidationError extends Error {
|
|
1076
|
+
readonly code: ValidationCode;
|
|
1077
|
+
constructor(code: ValidationCode, message: string);
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* The brief, checked for everything the codemod reads off it.
|
|
1081
|
+
*
|
|
1082
|
+
* `slug` is the one that becomes a path. `route` is matched against the plan's and against the
|
|
1083
|
+
* router's own conventions, so it has to be a URL path rather than an arbitrary string.
|
|
1084
|
+
*/
|
|
1085
|
+
declare function readBrief(value: unknown): Brief;
|
|
1086
|
+
/**
|
|
1087
|
+
* The plan, checked for everything the codemod reads off it.
|
|
1088
|
+
*
|
|
1089
|
+
* PERMISSIVE ABOUT SHAPE, STRICT ABOUT VALUES: a newer server may add fields, and an unknown key
|
|
1090
|
+
* is carried past untouched — but every field this version actually consumes is typed, and the two
|
|
1091
|
+
* that become file names or source keys are `groupKey` and `proposedSlug`.
|
|
1092
|
+
*/
|
|
1093
|
+
declare function readPlan(value: unknown): ComponentizePlan;
|
|
1094
|
+
|
|
805
1095
|
/** One file operation, exactly as `src/lib/github/plan-digest.ts` spells it. */
|
|
806
1096
|
interface PlanFile {
|
|
807
1097
|
path: string;
|
|
@@ -831,9 +1121,9 @@ interface Splice {
|
|
|
831
1121
|
end: number;
|
|
832
1122
|
text: string;
|
|
833
1123
|
}
|
|
834
|
-
declare function convertSources(
|
|
1124
|
+
declare function convertSources(briefIn: Brief, sources: SourceFile[], options?: ConvertOptions): Promise<{
|
|
835
1125
|
files: PlanFile[];
|
|
836
1126
|
receipt: ConversionReceipt;
|
|
837
1127
|
}>;
|
|
838
1128
|
|
|
839
|
-
export { type AstNode, type AttrBinding, type Brief, type BriefPage, type BriefPath, CONTENT_DIR, type ConversionReceipt, ConvertError, type ConvertErrorCode, type ConvertOptions, DIALECT_RULES, type Dialect, type DynamicBinding, type FileDeclaration, type FindSitesResult, HELPER_PATH, HELPER_VERSION, type ImportedFrom, type LlmFallback, type LocatedPath, type Node, PARSE_FILE, type ParsedFile, type ParserError, type PathLocator, type PendingPath, type PendingReason, type PlanFile, type ReceiptFile, ReceiptInvariantError, type Rewrite, SKIP_DIRS, SKIP_FILES, SOURCE_EXTENSIONS, STUB_CONTENT, type Site, type SiteWhere, type SourceFile, type Splice, type TargetIdentity, type UnlocatedPath, aliasesFrom, assertReceipt, attrsFor, briefDigest, convertSources, convertedHere, coverageOf, declaringElements, dialectOf, exportedFunction, findSites, findSitesTolerant, flat, helperSource, importsIn, isKnownHelper, isSourceCandidate, locate, overlapping, parseFile, propsAttribute, readDeclarations, readExpr, relativeImport, resolveSpecifier, rewriteFile, stripTags, walkAst };
|
|
1129
|
+
export { type AstNode, type AttrBinding, type Brief, type BriefPage, type BriefPath, COMPONENT_DIR, CONTENT_DIR, type Carried, type ComponentizeOptions, type ComponentizePlan, type ComponentizePlanComponent, type ComponentizePlanField, type ComponentizePlanPage, type ComponentizePlanSection, type ComponentizeReceipt, type ConversionReceipt, ConvertError, type ConvertErrorCode, type ConvertOptions, DIALECT_RULES, type Dialect, type DynamicBinding, type FileDeclaration, type FindSitesResult, HELPER_PATH, HELPER_VERSION, type ImportedFrom, type LlmFallback, type LocatedPath, type Node, PARSE_FILE, type ParsedFile, type ParserError, type PathLocator, type PendingPath, type PendingReason, type PendingSection, type PlanFile, REGISTRY_MARKER, type ReceiptFile, ReceiptInvariantError, type Rewrite, SECTIONS_LIB, SECTION_MARKER, SKIP_DIRS, SKIP_FILES, SOURCE_EXTENSIONS, STUB_CONTENT, SectionInvariantError, type SectionPendingReason, type SectionsReceipt, type Site, type SiteWhere, type SourceFile, type Splice, type TargetIdentity, type UnlocatedPath, type ValidationCode, ValidationError, aliasesFrom, assertReceipt, assertSections, attrsFor, briefDigest, carryFor, componentizeSources, convertSources, convertedHere, coverageOf, declaringElements, dialectOf, exportedFunction, findSites, findSitesTolerant, flat, helperSource, importsIn, isDynamicRoute, isKnownHelper, isSourceCandidate, locate, overlapping, pageFilesFor, parseFile, propsAttribute, readBrief, readComponentizePlan, readDeclarations, readExpr, readPlan, relativeImport, resolveSpecifier, rewriteFile, routeOfFile, stripTags, walkAst };
|