accel2spa 0.0.0-stage → 0.1.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/dist/cli.js ADDED
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, realpathSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { analyzeStorefront, writeOutputs } from './index.js';
6
+ const HELP = `accel2spa - turn a SAP Commerce Accelerator storefront into Spartacus migration specs
7
+
8
+ Usage:
9
+ accel2spa analyze <storefront-path> [--out <dir>] [--occ-fields <file>]
10
+
11
+ Options:
12
+ --out <dir> Output root (default: out). Writes <dir>/<storefront-name>/model.json
13
+ and <dir>/<storefront-name>/specs/<page>.md
14
+ --occ-fields <file> JSON file that extends/overrides the bundled OCC field reference
15
+ -h, --help Show this help
16
+ -v, --version Show version
17
+ `;
18
+ /** Safe folder name for a storefront path: its last segment, resolved when it is `.`, `..` or a drive root. */
19
+ export function storefrontFolderName(target) {
20
+ const bs = String.fromCharCode(92);
21
+ const sep = bs + bs + '/';
22
+ const lastSegment = (p) => p.replace(new RegExp(`[${sep}]+$`), '').split(new RegExp(`[${sep}]`)).pop() ?? '';
23
+ let last = lastSegment(target);
24
+ if (!last || last === '.' || last === '..' || /^[A-Za-z]:$/.test(last))
25
+ last = lastSegment(path.resolve(target));
26
+ const safe = last
27
+ .replace(/[<>:"|?*\u0000-\u001f]/g, '-')
28
+ .replace(/\s+/g, '-')
29
+ .replace(/^[.\s-]+|[.\s-]+$/g, '');
30
+ return safe || 'storefront';
31
+ }
32
+ function version() {
33
+ const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
34
+ return pkg.version;
35
+ }
36
+ export function main(argv) {
37
+ const args = argv.slice(2);
38
+ if (!args.length || args.includes('-h') || args.includes('--help')) {
39
+ process.stdout.write(HELP);
40
+ return 0;
41
+ }
42
+ if (args.includes('-v') || args.includes('--version')) {
43
+ process.stdout.write(version() + '\n');
44
+ return 0;
45
+ }
46
+ const [command, ...rest] = args;
47
+ if (command !== 'analyze') {
48
+ process.stderr.write(`Unknown command: ${command}\n\n${HELP}`);
49
+ return 2;
50
+ }
51
+ let target;
52
+ let out = 'out';
53
+ let occFields;
54
+ for (let i = 0; i < rest.length; i++) {
55
+ const a = rest[i];
56
+ if (a === '--out' || a === '--occ-fields') {
57
+ const v = rest[++i];
58
+ if (!v) {
59
+ process.stderr.write(`Missing value for ${a}\n`);
60
+ return 2;
61
+ }
62
+ if (a === '--out')
63
+ out = v;
64
+ else
65
+ occFields = v;
66
+ }
67
+ else if (a.startsWith('--out='))
68
+ out = a.slice(6);
69
+ else if (a.startsWith('--occ-fields='))
70
+ occFields = a.slice(13);
71
+ else if (a.startsWith('-')) {
72
+ process.stderr.write(`Unknown option: ${a}\n`);
73
+ return 2;
74
+ }
75
+ else if (!target)
76
+ target = a;
77
+ else {
78
+ process.stderr.write(`Unexpected argument: ${a}\n`);
79
+ return 2;
80
+ }
81
+ }
82
+ if (!target) {
83
+ process.stderr.write(`Missing <storefront-path>\n\n${HELP}`);
84
+ return 2;
85
+ }
86
+ try {
87
+ const model = analyzeStorefront(target, { occFieldsPath: occFields });
88
+ const outDir = path.join(out, storefrontFolderName(target));
89
+ const written = writeOutputs(model, outDir);
90
+ const show = (p) => p.split(path.sep).join('/');
91
+ const s = model.summary;
92
+ process.stdout.write([
93
+ `Analyzed ${model.storefront}: ${s.pages} page(s), ${s.components} CMS component(s), ${s.tagFiles} tag file(s), ${s.languages} language(s)`,
94
+ ` conditionals: ${s.conditionals}`,
95
+ ` OCC data gaps: ${s.dataGaps}`,
96
+ ` missing endpoints: ${s.missingEndpoints}`,
97
+ ` missing i18n keys: ${s.missingI18nKeys}`,
98
+ ` hardcoded strings: ${s.hardcodedStrings}`,
99
+ `Wrote ${show(path.join(outDir, 'model.json'))} and ${written.length} spec(s) in ${show(path.join(outDir, 'specs'))}`
100
+ ].join('\n') + '\n');
101
+ if (model.warnings.length)
102
+ process.stdout.write(`${model.warnings.length} warning(s); see model.json\n`);
103
+ return 0;
104
+ }
105
+ catch (e) {
106
+ process.stderr.write(`Error: ${e.message}\n`);
107
+ return 1;
108
+ }
109
+ }
110
+ const entry = process.argv[1];
111
+ if (entry && realpathSync(entry) === realpathSync(fileURLToPath(import.meta.url))) {
112
+ process.exitCode = main(process.argv);
113
+ }
@@ -0,0 +1,16 @@
1
+ import type { Model } from './model.js';
2
+ export { analyzeStorefront } from './analyze.js';
3
+ export type { AnalyzeOptions } from './analyze.js';
4
+ export { renderSpec } from './renderers/spec.js';
5
+ export { loadOccFields, OccReference } from './occ/reference.js';
6
+ export { scanTemplate } from './scanners/jsp.js';
7
+ export { scanJsEndpoints } from './scanners/js.js';
8
+ export { parseProperties } from './scanners/properties.js';
9
+ export { parseImpex, parseItemsXml, buildCmsTypes } from './scanners/cms.js';
10
+ export type * from './model.js';
11
+ /** Render every spec of a model, keyed by file name (`<id>.md`). */
12
+ export declare function renderAllSpecs(model: Model): Map<string, string>;
13
+ /** Write `model.json` and `specs/*.md` into `outDir`. Returns the written spec paths. */
14
+ export declare function writeOutputs(model: Model, outDir: string): string[];
15
+ /** Convenience: analyze and write in one call. */
16
+ export declare function analyzeAndWrite(storefrontPath: string, outDir: string, occFieldsPath?: string): Model;
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ /** Public API of accel2spa (reused by the CLI and, later, an MCP wrapper). */
2
+ import { mkdirSync, writeFileSync } from 'node:fs';
3
+ import path from 'node:path';
4
+ import { analyzeStorefront } from './analyze.js';
5
+ import { renderSpec } from './renderers/spec.js';
6
+ export { analyzeStorefront } from './analyze.js';
7
+ export { renderSpec } from './renderers/spec.js';
8
+ export { loadOccFields, OccReference } from './occ/reference.js';
9
+ export { scanTemplate } from './scanners/jsp.js';
10
+ export { scanJsEndpoints } from './scanners/js.js';
11
+ export { parseProperties } from './scanners/properties.js';
12
+ export { parseImpex, parseItemsXml, buildCmsTypes } from './scanners/cms.js';
13
+ /** Render every spec of a model, keyed by file name (`<id>.md`). */
14
+ export function renderAllSpecs(model) {
15
+ const out = new Map();
16
+ for (const unit of [...model.pages, ...model.components]) {
17
+ out.set(`${unit.id}.md`, renderSpec(unit, model));
18
+ }
19
+ return out;
20
+ }
21
+ /** Write `model.json` and `specs/*.md` into `outDir`. Returns the written spec paths. */
22
+ export function writeOutputs(model, outDir) {
23
+ const specsDir = path.join(outDir, 'specs');
24
+ mkdirSync(specsDir, { recursive: true });
25
+ writeFileSync(path.join(outDir, 'model.json'), JSON.stringify(model, null, 2) + '\n');
26
+ const written = [];
27
+ for (const [name, content] of renderAllSpecs(model)) {
28
+ const p = path.join(specsDir, name);
29
+ writeFileSync(p, content);
30
+ written.push(p);
31
+ }
32
+ return written;
33
+ }
34
+ /** Convenience: analyze and write in one call. */
35
+ export function analyzeAndWrite(storefrontPath, outDir, occFieldsPath) {
36
+ const model = analyzeStorefront(storefrontPath, { occFieldsPath });
37
+ writeOutputs(model, outDir);
38
+ return model;
39
+ }
@@ -0,0 +1,179 @@
1
+ /** Types of the intermediate `model.json` produced by `analyze`. */
2
+ export interface SourceRef {
3
+ file: string;
4
+ line: number;
5
+ }
6
+ export type ConditionalKind = 'if' | 'when' | 'otherwise';
7
+ export type ConditionalLayout = 'block' | 'row' | 'column' | 'item' | 'text';
8
+ export interface Conditional {
9
+ id: string;
10
+ kind: ConditionalKind;
11
+ /** The raw EL test expression (without `${ }`). Absent for `otherwise`. */
12
+ test?: string;
13
+ file: string;
14
+ line: number;
15
+ endLine: number;
16
+ /** Heuristic: what kind of layout element the condition controls. */
17
+ layout: ConditionalLayout;
18
+ depth: number;
19
+ parent?: string;
20
+ /** Shared by the `when`/`otherwise` branches of the same `c:choose`. */
21
+ chooseGroup?: string;
22
+ containsTags: string[];
23
+ containsI18nKeys: string[];
24
+ label: string;
25
+ }
26
+ export interface TagInclude {
27
+ /** e.g. `order:orderTotals` */
28
+ name: string;
29
+ /** Resolved .tag file, when found in the storefront. */
30
+ tagFile?: string;
31
+ file: string;
32
+ line: number;
33
+ }
34
+ export interface I18nUsage {
35
+ key: string;
36
+ refs: Array<SourceRef & {
37
+ tag: string;
38
+ }>;
39
+ /** Fallback text given inline (e.g. `<spring:theme code=".." text="..">`). */
40
+ defaultText?: string;
41
+ /** Text per language where the key is defined. */
42
+ texts: Record<string, string>;
43
+ /** Languages (among those found) in which the key is not defined. */
44
+ missingIn: string[];
45
+ }
46
+ export interface HardcodedText {
47
+ text: string;
48
+ file: string;
49
+ line: number;
50
+ kind: 'text' | 'attribute';
51
+ attribute?: string;
52
+ }
53
+ export type DataStatus = 'exposed' | 'missing' | 'unchecked';
54
+ export interface DataUse {
55
+ /** EL path, e.g. `order.deliveryCost.value` */
56
+ path: string;
57
+ root: string;
58
+ /** OCC type the root resolved to, e.g. `Order`. */
59
+ occType?: string;
60
+ status: DataStatus;
61
+ /** For `missing`: the first field that OCC does not expose. */
62
+ missingField?: string;
63
+ note?: string;
64
+ refs: SourceRef[];
65
+ }
66
+ export interface EndpointUse {
67
+ kind: 'ajax' | 'fetch' | 'xhr' | 'c:url' | 'form';
68
+ method: string;
69
+ /** Normalized URL; dynamic parts are `{param}`. */
70
+ url: string;
71
+ status: 'mapped' | 'missing' | 'external';
72
+ /** For `mapped`: the OCC endpoint it corresponds to. */
73
+ occEquivalent?: string;
74
+ refs: SourceRef[];
75
+ requestFields: string[];
76
+ responseFields: string[];
77
+ }
78
+ export interface Gap {
79
+ kind: 'data' | 'endpoint' | 'i18n' | 'hardcoded-text';
80
+ id: string;
81
+ summary: string;
82
+ refs: SourceRef[];
83
+ }
84
+ export interface ComponentNode {
85
+ /** `prefix:tag` for tag files, or the page/component file name for the root. */
86
+ name: string;
87
+ file: string;
88
+ /** Line of the usage in the parent. */
89
+ line?: number;
90
+ /** Already expanded earlier in the tree. */
91
+ repeated?: boolean;
92
+ children: ComponentNode[];
93
+ }
94
+ export interface I18nCoverage {
95
+ lang: string;
96
+ file: string;
97
+ present: number;
98
+ total: number;
99
+ }
100
+ export interface UnitModel {
101
+ id: string;
102
+ kind: 'page' | 'component';
103
+ /** Entry file (JSP). */
104
+ file: string;
105
+ /** All source files that contribute to this unit (entry, tags, includes, JS). */
106
+ files: string[];
107
+ currentUrl?: string;
108
+ route: string;
109
+ routeSource: 'known' | 'derived';
110
+ /** CMS type code for components. */
111
+ cmsType?: string;
112
+ cmsSlots: Array<SourceRef & {
113
+ position: string;
114
+ }>;
115
+ tree: ComponentNode;
116
+ tagIncludes: TagInclude[];
117
+ conditionals: Conditional[];
118
+ i18n: I18nUsage[];
119
+ dynamicI18n: Array<SourceRef & {
120
+ tag: string;
121
+ expression: string;
122
+ }>;
123
+ i18nCoverage: I18nCoverage[];
124
+ hardcoded: HardcodedText[];
125
+ data: DataUse[];
126
+ endpoints: EndpointUse[];
127
+ gaps: Gap[];
128
+ dependsOn: string[];
129
+ complexity: {
130
+ score: number;
131
+ level: 'low' | 'medium' | 'high';
132
+ };
133
+ warnings: string[];
134
+ }
135
+ export interface CmsComponentType {
136
+ code: string;
137
+ extends?: string;
138
+ attributes: Array<{
139
+ name: string;
140
+ type?: string;
141
+ file: string;
142
+ line: number;
143
+ source: 'items.xml' | 'impex';
144
+ }>;
145
+ instances: Array<{
146
+ uid: string;
147
+ name?: string;
148
+ file: string;
149
+ line: number;
150
+ }>;
151
+ jsp?: string;
152
+ }
153
+ export interface LanguageInfo {
154
+ lang: string;
155
+ file: string;
156
+ keyCount: number;
157
+ }
158
+ export interface Model {
159
+ version: 1;
160
+ storefront: string;
161
+ occFieldsSource: string;
162
+ languages: LanguageInfo[];
163
+ referenceLanguage?: string;
164
+ cmsComponentTypes: CmsComponentType[];
165
+ pages: UnitModel[];
166
+ components: UnitModel[];
167
+ summary: {
168
+ pages: number;
169
+ components: number;
170
+ tagFiles: number;
171
+ languages: number;
172
+ conditionals: number;
173
+ dataGaps: number;
174
+ missingEndpoints: number;
175
+ missingI18nKeys: number;
176
+ hardcodedStrings: number;
177
+ };
178
+ warnings: string[];
179
+ }
package/dist/model.js ADDED
@@ -0,0 +1,2 @@
1
+ /** Types of the intermediate `model.json` produced by `analyze`. */
2
+ export {};
@@ -0,0 +1,15 @@
1
+ {
2
+ "_note": "APPROXIMATION: storefront (Accelerator) URL patterns and the OCC endpoint that typically replaces them. `{param}` matches one path segment, `**` matches anything. Extend via `--occ-fields <file>` using an `endpoints` array of the same shape.",
3
+ "endpoints": [
4
+ { "accelerator": "/cart/add", "method": "POST", "occ": "POST /users/{userId}/carts/{cartId}/entries" },
5
+ { "accelerator": "/cart/update", "method": "POST", "occ": "PATCH /users/{userId}/carts/{cartId}/entries/{entryNumber}" },
6
+ { "accelerator": "/cart/remove", "method": "POST", "occ": "DELETE /users/{userId}/carts/{cartId}/entries/{entryNumber}" },
7
+ { "accelerator": "/search/autocomplete/{param}", "occ": "GET /products/suggestions" },
8
+ { "accelerator": "/search/**", "occ": "GET /products/search" },
9
+ { "accelerator": "/store-finder/**", "occ": "GET /stores" },
10
+ { "accelerator": "/my-account/orders", "occ": "GET /users/{userId}/orders" },
11
+ { "accelerator": "/my-account/order/{param}", "occ": "GET /users/{userId}/orders/{orderCode}" },
12
+ { "accelerator": "/my-account/address-book/**", "occ": "GET /users/{userId}/addresses" },
13
+ { "accelerator": "/my-account/update-profile", "method": "POST", "occ": "PATCH /users/{userId}" }
14
+ ]
15
+ }
@@ -0,0 +1,187 @@
1
+ {
2
+ "_note": "APPROXIMATION of fields typically returned by the SAP Commerce OCC API (FULL field set), written from general knowledge of the public OCC documentation. Real projects customize OCC mappings, so verify against your own /v2/api-docs. Override or extend with `accel2spa analyze --occ-fields <file>` (same shape; only the keys you provide are merged).",
3
+ "rootVars": {
4
+ "order": "Order",
5
+ "orderData": "Order",
6
+ "cart": "Cart",
7
+ "cartData": "Cart",
8
+ "product": "Product",
9
+ "productData": "Product",
10
+ "entry": "OrderEntry",
11
+ "orderEntry": "OrderEntry",
12
+ "address": "Address",
13
+ "deliveryAddress": "Address",
14
+ "component": "CMSComponent"
15
+ },
16
+ "types": {
17
+ "Price": {
18
+ "currencyIso": "string",
19
+ "value": "number",
20
+ "formattedValue": "string",
21
+ "priceType": "string",
22
+ "minQuantity": "number",
23
+ "maxQuantity": "number"
24
+ },
25
+ "Principal": { "uid": "string", "name": "string" },
26
+ "Address": {
27
+ "id": "string",
28
+ "title": "string",
29
+ "titleCode": "string",
30
+ "firstName": "string",
31
+ "lastName": "string",
32
+ "line1": "string",
33
+ "line2": "string",
34
+ "town": "string",
35
+ "postalCode": "string",
36
+ "phone": "string",
37
+ "email": "string",
38
+ "country": "Country",
39
+ "region": "Region",
40
+ "defaultAddress": "boolean",
41
+ "formattedAddress": "string",
42
+ "shippingAddress": "boolean",
43
+ "billingAddress": "boolean"
44
+ },
45
+ "Country": { "isocode": "string", "name": "string" },
46
+ "Region": { "isocode": "string", "name": "string", "countryIso": "string" },
47
+ "DeliveryMode": { "code": "string", "name": "string", "description": "string", "deliveryCost": "Price" },
48
+ "PaymentDetails": {
49
+ "id": "string",
50
+ "accountHolderName": "string",
51
+ "cardType": "CardType",
52
+ "cardNumber": "string",
53
+ "expiryMonth": "string",
54
+ "expiryYear": "string",
55
+ "billingAddress": "Address",
56
+ "defaultPayment": "boolean"
57
+ },
58
+ "CardType": { "code": "string", "name": "string" },
59
+ "Promotion": { "code": "string", "title": "string", "description": "string", "promotionType": "string" },
60
+ "PromotionResult": { "description": "string", "promotion": "Promotion" },
61
+ "Image": { "imageType": "string", "format": "string", "url": "string", "altText": "string", "galleryIndex": "number" },
62
+ "Stock": { "stockLevelStatus": "string", "stockLevel": "number", "isValueRounded": "boolean" },
63
+ "Category": { "code": "string", "name": "string", "url": "string", "image": "Image" },
64
+ "Product": {
65
+ "code": "string",
66
+ "name": "string",
67
+ "summary": "string",
68
+ "description": "string",
69
+ "url": "string",
70
+ "price": "Price",
71
+ "images": "Image[]",
72
+ "stock": "Stock",
73
+ "categories": "Category[]",
74
+ "manufacturer": "string",
75
+ "purchasable": "boolean",
76
+ "averageRating": "number",
77
+ "numberOfReviews": "number",
78
+ "baseOptions": "object",
79
+ "availableForPickup": "boolean"
80
+ },
81
+ "OrderEntry": {
82
+ "entryNumber": "number",
83
+ "quantity": "number",
84
+ "basePrice": "Price",
85
+ "totalPrice": "Price",
86
+ "product": "Product",
87
+ "updateable": "boolean",
88
+ "deliveryMode": "DeliveryMode",
89
+ "deliveryPointOfService": "object",
90
+ "statusSummaryList": "object[]",
91
+ "cancellableQuantity": "number",
92
+ "returnableQuantity": "number"
93
+ },
94
+ "Consignment": {
95
+ "code": "string",
96
+ "status": "string",
97
+ "statusDate": "date",
98
+ "trackingID": "string",
99
+ "entries": "object[]",
100
+ "shippingAddress": "Address"
101
+ },
102
+ "Order": {
103
+ "code": "string",
104
+ "guid": "string",
105
+ "user": "Principal",
106
+ "created": "date",
107
+ "status": "string",
108
+ "statusDisplay": "string",
109
+ "net": "boolean",
110
+ "calculated": "boolean",
111
+ "site": "string",
112
+ "store": "string",
113
+ "guestCustomer": "boolean",
114
+ "entries": "OrderEntry[]",
115
+ "totalItems": "number",
116
+ "totalUnitCount": "number",
117
+ "subTotal": "Price",
118
+ "totalPrice": "Price",
119
+ "totalPriceWithTax": "Price",
120
+ "totalTax": "Price",
121
+ "totalDiscounts": "Price",
122
+ "orderDiscounts": "Price",
123
+ "productDiscounts": "Price",
124
+ "deliveryCost": "Price",
125
+ "deliveryAddress": "Address",
126
+ "deliveryMode": "DeliveryMode",
127
+ "deliveryItemsQuantity": "number",
128
+ "pickupItemsQuantity": "number",
129
+ "paymentInfo": "PaymentDetails",
130
+ "appliedOrderPromotions": "PromotionResult[]",
131
+ "appliedProductPromotions": "PromotionResult[]",
132
+ "appliedVouchers": "object[]",
133
+ "consignments": "Consignment[]",
134
+ "unconsignedEntries": "OrderEntry[]",
135
+ "purchaseOrderNumber": "string",
136
+ "costCenter": "object"
137
+ },
138
+ "Cart": {
139
+ "code": "string",
140
+ "guid": "string",
141
+ "user": "Principal",
142
+ "entries": "OrderEntry[]",
143
+ "totalItems": "number",
144
+ "totalUnitCount": "number",
145
+ "subTotal": "Price",
146
+ "totalPrice": "Price",
147
+ "totalPriceWithTax": "Price",
148
+ "totalTax": "Price",
149
+ "totalDiscounts": "Price",
150
+ "orderDiscounts": "Price",
151
+ "productDiscounts": "Price",
152
+ "deliveryCost": "Price",
153
+ "deliveryAddress": "Address",
154
+ "deliveryMode": "DeliveryMode",
155
+ "paymentInfo": "PaymentDetails",
156
+ "net": "boolean",
157
+ "appliedOrderPromotions": "PromotionResult[]",
158
+ "appliedProductPromotions": "PromotionResult[]",
159
+ "appliedVouchers": "object[]",
160
+ "potentialOrderPromotions": "PromotionResult[]",
161
+ "potentialProductPromotions": "PromotionResult[]"
162
+ },
163
+ "CMSComponent": {
164
+ "uid": "string",
165
+ "uuid": "string",
166
+ "typeCode": "string",
167
+ "name": "string",
168
+ "modifiedtime": "date",
169
+ "container": "string",
170
+ "otherProperties": "object"
171
+ },
172
+ "CMSParagraphComponent": { "$extends": "CMSComponent", "content": "string" },
173
+ "CMSLinkComponent": {
174
+ "$extends": "CMSComponent",
175
+ "linkName": "string",
176
+ "url": "string",
177
+ "target": "string",
178
+ "external": "boolean"
179
+ },
180
+ "SimpleBannerComponent": {
181
+ "$extends": "CMSComponent",
182
+ "media": "Image",
183
+ "urlLink": "string",
184
+ "external": "boolean"
185
+ }
186
+ }
187
+ }
@@ -0,0 +1,38 @@
1
+ import type { AliasDecl } from '../scanners/jsp.js';
2
+ export type OccTypeDef = Record<string, string>;
3
+ export interface OccFields {
4
+ rootVars: Record<string, string>;
5
+ types: Record<string, OccTypeDef>;
6
+ endpoints: Array<{
7
+ accelerator: string;
8
+ method?: string;
9
+ occ: string;
10
+ }>;
11
+ }
12
+ export interface OccOverride {
13
+ rootVars?: Record<string, string>;
14
+ types?: Record<string, OccTypeDef>;
15
+ endpoints?: OccFields['endpoints'];
16
+ }
17
+ export declare function loadOccFields(overridePath?: string): {
18
+ fields: OccFields;
19
+ source: string;
20
+ };
21
+ export interface DataCheck {
22
+ status: 'exposed' | 'missing' | 'unchecked';
23
+ occType?: string;
24
+ missingField?: string;
25
+ }
26
+ export declare class OccReference {
27
+ readonly fields: OccFields;
28
+ constructor(fields: OccFields);
29
+ private lookup;
30
+ hasType(name: string): boolean;
31
+ /** Type of an EL root variable, following `forEach`/`set` aliases and tag attribute types. */
32
+ rootType(root: string, aliases: Record<string, AliasDecl>, overrides: Record<string, string>, depth?: number): string | undefined;
33
+ checkPath(path: string, aliases: Record<string, AliasDecl>, overrides: Record<string, string>, depth?: number): DataCheck & {
34
+ resultType?: string;
35
+ };
36
+ /** Which OCC endpoint replaces this storefront URL, if known. */
37
+ matchEndpoint(url: string, method: string): string | undefined;
38
+ }