@dropins/mcp 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/LICENSE.md +127 -0
- package/README.md +314 -0
- package/dist/common/project-reader.d.ts +55 -0
- package/dist/common/project-reader.js +173 -0
- package/dist/common/registry-loader.d.ts +101 -0
- package/dist/common/registry-loader.js +386 -0
- package/dist/common/response-handling.d.ts +12 -0
- package/dist/common/response-handling.js +21 -0
- package/dist/common/sanitize.d.ts +8 -0
- package/dist/common/sanitize.js +45 -0
- package/dist/common/synonyms.d.ts +9 -0
- package/dist/common/synonyms.js +127 -0
- package/dist/common/telemetry.d.ts +14 -0
- package/dist/common/telemetry.js +54 -0
- package/dist/common/types.d.ts +308 -0
- package/dist/common/types.js +1 -0
- package/dist/common/version.d.ts +2 -0
- package/dist/common/version.js +14 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +136 -0
- package/dist/operations/analyze-project.d.ts +13 -0
- package/dist/operations/analyze-project.js +125 -0
- package/dist/operations/check-block-health.d.ts +19 -0
- package/dist/operations/check-block-health.js +1149 -0
- package/dist/operations/check-config.d.ts +13 -0
- package/dist/operations/check-config.js +228 -0
- package/dist/operations/explain-event-flow.d.ts +16 -0
- package/dist/operations/explain-event-flow.js +218 -0
- package/dist/operations/get-upgrade-diff.d.ts +13 -0
- package/dist/operations/get-upgrade-diff.js +144 -0
- package/dist/operations/list-api-functions.d.ts +13 -0
- package/dist/operations/list-api-functions.js +53 -0
- package/dist/operations/list-containers.d.ts +13 -0
- package/dist/operations/list-containers.js +44 -0
- package/dist/operations/list-design-tokens.d.ts +13 -0
- package/dist/operations/list-design-tokens.js +47 -0
- package/dist/operations/list-events.d.ts +16 -0
- package/dist/operations/list-events.js +39 -0
- package/dist/operations/list-graphql-queries.d.ts +19 -0
- package/dist/operations/list-graphql-queries.js +84 -0
- package/dist/operations/list-i18n-keys.d.ts +19 -0
- package/dist/operations/list-i18n-keys.js +105 -0
- package/dist/operations/list-models.d.ts +16 -0
- package/dist/operations/list-models.js +80 -0
- package/dist/operations/list-slots.d.ts +16 -0
- package/dist/operations/list-slots.js +81 -0
- package/dist/operations/scaffold-block.d.ts +31 -0
- package/dist/operations/scaffold-block.js +331 -0
- package/dist/operations/scaffold-extension.d.ts +28 -0
- package/dist/operations/scaffold-extension.js +346 -0
- package/dist/operations/scaffold-slot.d.ts +22 -0
- package/dist/operations/scaffold-slot.js +189 -0
- package/dist/operations/search-commerce-docs.d.ts +16 -0
- package/dist/operations/search-commerce-docs.js +101 -0
- package/dist/operations/search-docs.d.ts +23 -0
- package/dist/operations/search-docs.js +298 -0
- package/dist/operations/suggest-event-handler.d.ts +16 -0
- package/dist/operations/suggest-event-handler.js +175 -0
- package/dist/operations/suggest-slot-implementation.d.ts +19 -0
- package/dist/operations/suggest-slot-implementation.js +183 -0
- package/dist/registry/api-functions.json +3045 -0
- package/dist/registry/block-patterns.json +78 -0
- package/dist/registry/containers.json +2003 -0
- package/dist/registry/design-tokens.json +577 -0
- package/dist/registry/docs/boilerplate.json +55 -0
- package/dist/registry/docs/dropins-all.json +97 -0
- package/dist/registry/docs/dropins-b2b.json +607 -0
- package/dist/registry/docs/dropins-cart.json +163 -0
- package/dist/registry/docs/dropins-checkout.json +193 -0
- package/dist/registry/docs/dropins-order.json +139 -0
- package/dist/registry/docs/dropins-payment-services.json +73 -0
- package/dist/registry/docs/dropins-personalization.json +67 -0
- package/dist/registry/docs/dropins-product-details.json +139 -0
- package/dist/registry/docs/dropins-product-discovery.json +85 -0
- package/dist/registry/docs/dropins-recommendations.json +67 -0
- package/dist/registry/docs/dropins-user-account.json +121 -0
- package/dist/registry/docs/dropins-user-auth.json +103 -0
- package/dist/registry/docs/dropins-wishlist.json +85 -0
- package/dist/registry/docs/get-started.json +85 -0
- package/dist/registry/docs/how-tos.json +19 -0
- package/dist/registry/docs/index.json +139 -0
- package/dist/registry/docs/licensing.json +19 -0
- package/dist/registry/docs/merchants.json +523 -0
- package/dist/registry/docs/resources.json +13 -0
- package/dist/registry/docs/sdk.json +139 -0
- package/dist/registry/docs/setup.json +145 -0
- package/dist/registry/docs/troubleshooting.json +19 -0
- package/dist/registry/events.json +2200 -0
- package/dist/registry/examples/index.json +19 -0
- package/dist/registry/examples/storefront-checkout.json +377 -0
- package/dist/registry/examples/storefront-quote-management.json +49 -0
- package/dist/registry/extensions.json +272 -0
- package/dist/registry/graphql.json +3469 -0
- package/dist/registry/i18n.json +1873 -0
- package/dist/registry/models.json +1001 -0
- package/dist/registry/sdk.json +2357 -0
- package/dist/registry/slots.json +2270 -0
- package/dist/registry/tools-components.json +595 -0
- package/dist/resources/guides.d.ts +7 -0
- package/dist/resources/guides.js +625 -0
- package/dist/resources/handlers.d.ts +31 -0
- package/dist/resources/handlers.js +322 -0
- package/package.json +47 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ScaffoldBlockSchema: z.ZodObject<{
|
|
3
|
+
blockName: z.ZodString;
|
|
4
|
+
containers: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
5
|
+
dropin: z.ZodOptional<z.ZodString>;
|
|
6
|
+
containersByDropin: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
|
|
7
|
+
slots: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>>;
|
|
8
|
+
withEvents: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
projectDir: z.ZodString;
|
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
|
11
|
+
projectDir: string;
|
|
12
|
+
blockName: string;
|
|
13
|
+
dropin?: string | undefined;
|
|
14
|
+
slots?: Record<string, string[]> | undefined;
|
|
15
|
+
containers?: string[] | undefined;
|
|
16
|
+
containersByDropin?: Record<string, string[]> | undefined;
|
|
17
|
+
withEvents?: boolean | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
projectDir: string;
|
|
20
|
+
blockName: string;
|
|
21
|
+
dropin?: string | undefined;
|
|
22
|
+
slots?: Record<string, string[]> | undefined;
|
|
23
|
+
containers?: string[] | undefined;
|
|
24
|
+
containersByDropin?: Record<string, string[]> | undefined;
|
|
25
|
+
withEvents?: boolean | undefined;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function scaffoldBlock(params: z.infer<typeof ScaffoldBlockSchema>): Promise<{
|
|
28
|
+
success: boolean;
|
|
29
|
+
message: string;
|
|
30
|
+
data: unknown;
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { formatSuccessResponse, formatExceptionResponse, } from "../common/response-handling.js";
|
|
3
|
+
import { getContainersByDropin, getSlotsByContainer, getAllDropinNames, } from "../common/registry-loader.js";
|
|
4
|
+
import { projectDirGuard, INITIALIZER_ALIASES, } from "../common/project-reader.js";
|
|
5
|
+
import { validateBlockName, validateIdentifier, sanitizeForComment, } from "../common/sanitize.js";
|
|
6
|
+
export const ScaffoldBlockSchema = z.object({
|
|
7
|
+
blockName: z
|
|
8
|
+
.string()
|
|
9
|
+
.describe("Block name (e.g. commerce-custom-cart). Will be used as folder and file name."),
|
|
10
|
+
containers: z
|
|
11
|
+
.array(z.string())
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Container names for single-dropin mode (e.g. ["CartSummaryList", "OrderSummary"]). Requires dropin.'),
|
|
14
|
+
dropin: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Primary dropin for single-dropin mode (e.g. storefront-cart). Requires containers."),
|
|
18
|
+
containersByDropin: z
|
|
19
|
+
.record(z.string(), z.array(z.string()))
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Multi-dropin mode: map of dropin to containers, e.g. { "storefront-cart": ["MiniCart"], "storefront-wishlist": ["WishlistToggle"] }'),
|
|
22
|
+
slots: z
|
|
23
|
+
.record(z.string(), z.array(z.string()))
|
|
24
|
+
.optional()
|
|
25
|
+
.describe('Slots per container. Use "ContainerName" when unique, or "dropin/ContainerName" when the same container name exists in multiple dropins. E.g. { "CartSummaryList": ["Thumbnail"], "storefront-cart/EstimateShipping": ["Header"] }'),
|
|
26
|
+
withEvents: z
|
|
27
|
+
.boolean()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Include event bus wiring boilerplate (default: false)"),
|
|
30
|
+
projectDir: z
|
|
31
|
+
.string()
|
|
32
|
+
.describe("Absolute path to the merchant storefront project root"),
|
|
33
|
+
});
|
|
34
|
+
function dropinPrefix(dropin) {
|
|
35
|
+
const short = dropin.replace("storefront-", "");
|
|
36
|
+
return short
|
|
37
|
+
.split("-")
|
|
38
|
+
.map((s) => s.charAt(0).toUpperCase() + s.slice(1))
|
|
39
|
+
.join("");
|
|
40
|
+
}
|
|
41
|
+
function providerAlias(dropin, isSingle) {
|
|
42
|
+
if (isSingle)
|
|
43
|
+
return "provider";
|
|
44
|
+
const prefix = dropinPrefix(dropin);
|
|
45
|
+
return prefix.charAt(0).toLowerCase() + prefix.slice(1) + "Provider";
|
|
46
|
+
}
|
|
47
|
+
function resolveContainerIds(groups) {
|
|
48
|
+
const nameCount = new Map();
|
|
49
|
+
for (const g of groups) {
|
|
50
|
+
for (const c of g.containers) {
|
|
51
|
+
nameCount.set(c, (nameCount.get(c) ?? 0) + 1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const resolved = [];
|
|
55
|
+
for (const g of groups) {
|
|
56
|
+
for (const c of g.containers) {
|
|
57
|
+
const collides = (nameCount.get(c) ?? 0) > 1;
|
|
58
|
+
resolved.push({
|
|
59
|
+
name: c,
|
|
60
|
+
jsId: collides ? `${dropinPrefix(g.dropin)}${c}` : c,
|
|
61
|
+
dropin: g.dropin,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return resolved;
|
|
66
|
+
}
|
|
67
|
+
function generateImportsMulti(groups, resolved, withEvents) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
if (withEvents) {
|
|
70
|
+
lines.push("import { events } from '@dropins/tools/event-bus.js';");
|
|
71
|
+
}
|
|
72
|
+
for (const g of groups) {
|
|
73
|
+
lines.push(`import { render as ${g.alias} } from '@dropins/${g.dropin}/render.js';`);
|
|
74
|
+
const groupContainers = resolved.filter((r) => r.dropin === g.dropin);
|
|
75
|
+
for (const rc of groupContainers) {
|
|
76
|
+
if (rc.jsId !== rc.name) {
|
|
77
|
+
lines.push(`import { default as ${rc.jsId} } from '@dropins/${g.dropin}/containers/${rc.name}.js';`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
lines.push(`import ${rc.jsId} from '@dropins/${g.dropin}/containers/${rc.name}.js';`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
lines.push("");
|
|
85
|
+
lines.push("import { readBlockConfig } from '../../scripts/aem.js';");
|
|
86
|
+
for (const g of groups) {
|
|
87
|
+
const initName = INITIALIZER_ALIASES[g.dropin] ?? g.dropin.replace("storefront-", "");
|
|
88
|
+
lines.push(`import '../../scripts/initializers/${initName}.js';`);
|
|
89
|
+
}
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
function generateSlotStubs(dropin, containerName, slotNames) {
|
|
93
|
+
if (slotNames.length === 0)
|
|
94
|
+
return "";
|
|
95
|
+
const stubs = slotNames.map((slotName) => {
|
|
96
|
+
const containerSlots = getSlotsByContainer(dropin, containerName);
|
|
97
|
+
const slotDef = containerSlots?.slots?.find((s) => s.name === slotName);
|
|
98
|
+
const contextType = slotDef?.contextType ?? "DefaultSlotContext";
|
|
99
|
+
const description = slotDef?.description ?? `Custom ${slotName} slot`;
|
|
100
|
+
return ` ${slotName}: (ctx) => {
|
|
101
|
+
// ${sanitizeForComment(description)}
|
|
102
|
+
// Context type: ${sanitizeForComment(contextType)}
|
|
103
|
+
// Available methods: appendChild, prependChild, replaceWith, removeChild, replaceHTML
|
|
104
|
+
const element = document.createElement('div');
|
|
105
|
+
element.textContent = 'Custom ${slotName}';
|
|
106
|
+
ctx.appendChild(element);
|
|
107
|
+
},`;
|
|
108
|
+
});
|
|
109
|
+
return ` slots: {\n${stubs.join("\n")}\n },`;
|
|
110
|
+
}
|
|
111
|
+
function generateContainerRender(rc, slotNames, domVar, alias) {
|
|
112
|
+
const slotsCode = generateSlotStubs(rc.dropin, rc.name, slotNames);
|
|
113
|
+
if (slotsCode) {
|
|
114
|
+
return ` ${alias}.render(${rc.jsId}, {\n${slotsCode}\n })(${domVar});`;
|
|
115
|
+
}
|
|
116
|
+
return ` ${alias}.render(${rc.jsId}, {})(${domVar});`;
|
|
117
|
+
}
|
|
118
|
+
function generateLayout(containers) {
|
|
119
|
+
if (containers.length === 1) {
|
|
120
|
+
return ` block.textContent = '';
|
|
121
|
+
const $container = document.createElement('div');
|
|
122
|
+
$container.classList.add('block__content');
|
|
123
|
+
block.appendChild($container);`;
|
|
124
|
+
}
|
|
125
|
+
const vars = containers.map((_, i) => `$section${i + 1}`);
|
|
126
|
+
const declarations = containers
|
|
127
|
+
.map((name, i) => ` const ${vars[i]} = document.createElement('div');\n ${vars[i]}.classList.add('block__${name.toLowerCase()}');`)
|
|
128
|
+
.join("\n");
|
|
129
|
+
return ` block.textContent = '';
|
|
130
|
+
const $wrapper = document.createElement('div');
|
|
131
|
+
$wrapper.classList.add('block__content');
|
|
132
|
+
|
|
133
|
+
${declarations}
|
|
134
|
+
|
|
135
|
+
$wrapper.append(${vars.join(", ")});
|
|
136
|
+
block.appendChild($wrapper);`;
|
|
137
|
+
}
|
|
138
|
+
function generateEventStubs() {
|
|
139
|
+
return `
|
|
140
|
+
// Event wiring — subscribe to cross-dropin events
|
|
141
|
+
// events.on('cart/data', (cartData) => {
|
|
142
|
+
// // React to cart data changes
|
|
143
|
+
// });
|
|
144
|
+
//
|
|
145
|
+
// events.on('authenticated', ({ isAuthenticated }) => {
|
|
146
|
+
// // React to authentication state changes
|
|
147
|
+
// });`;
|
|
148
|
+
}
|
|
149
|
+
function generateCss(blockName, containers) {
|
|
150
|
+
const sections = containers.length > 1
|
|
151
|
+
? containers
|
|
152
|
+
.map((name) => `.${blockName} .block__${name.toLowerCase()} {
|
|
153
|
+
/* Styles for ${name} section */
|
|
154
|
+
}`)
|
|
155
|
+
.join("\n\n")
|
|
156
|
+
: "";
|
|
157
|
+
return `.${blockName} {
|
|
158
|
+
display: block;
|
|
159
|
+
max-width: var(--grid-5-columns, 1440px);
|
|
160
|
+
margin: 0 auto;
|
|
161
|
+
padding: var(--spacing-medium, 16px);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.${blockName} .block__content {
|
|
165
|
+
display: ${containers.length > 1 ? "grid" : "block"};${containers.length > 1
|
|
166
|
+
? "\n grid-template-columns: 1fr 1fr;\n gap: var(--spacing-large, 24px);"
|
|
167
|
+
: ""}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
${sections}
|
|
171
|
+
`;
|
|
172
|
+
}
|
|
173
|
+
export async function scaffoldBlock(params) {
|
|
174
|
+
try {
|
|
175
|
+
const blockNameError = validateBlockName(params.blockName);
|
|
176
|
+
if (blockNameError) {
|
|
177
|
+
return formatSuccessResponse("Invalid block name", {
|
|
178
|
+
error: blockNameError,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
let dropinContainerMap;
|
|
182
|
+
if (params.containersByDropin) {
|
|
183
|
+
dropinContainerMap = params.containersByDropin;
|
|
184
|
+
}
|
|
185
|
+
else if (params.dropin && params.containers) {
|
|
186
|
+
dropinContainerMap = { [params.dropin]: params.containers };
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
return formatSuccessResponse("Missing required parameters", {
|
|
190
|
+
error: 'Provide either "dropin" + "containers" for single-dropin mode, or "containersByDropin" for multi-dropin mode.',
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const allContainerNames = [];
|
|
194
|
+
for (const containers of Object.values(dropinContainerMap)) {
|
|
195
|
+
allContainerNames.push(...containers);
|
|
196
|
+
}
|
|
197
|
+
for (const container of allContainerNames) {
|
|
198
|
+
const containerError = validateIdentifier(container, "container name");
|
|
199
|
+
if (containerError) {
|
|
200
|
+
return formatSuccessResponse("Invalid container name", {
|
|
201
|
+
error: containerError,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (params.slots) {
|
|
206
|
+
for (const slotNames of Object.values(params.slots)) {
|
|
207
|
+
for (const slotName of slotNames) {
|
|
208
|
+
const slotError = validateIdentifier(slotName, "slot name");
|
|
209
|
+
if (slotError) {
|
|
210
|
+
return formatSuccessResponse("Invalid slot name", {
|
|
211
|
+
error: slotError,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const guard = projectDirGuard(params.projectDir);
|
|
218
|
+
if (guard)
|
|
219
|
+
return guard;
|
|
220
|
+
const isSingle = Object.keys(dropinContainerMap).length === 1;
|
|
221
|
+
const groups = [];
|
|
222
|
+
for (const [dropin, containers] of Object.entries(dropinContainerMap)) {
|
|
223
|
+
const dropinData = getContainersByDropin(dropin);
|
|
224
|
+
if (!dropinData) {
|
|
225
|
+
return formatSuccessResponse(`Dropin "${dropin}" not found`, {
|
|
226
|
+
availableDropins: getAllDropinNames(),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const availableContainers = dropinData.containers.map((c) => c.name);
|
|
230
|
+
const invalidContainers = containers.filter((c) => !availableContainers.includes(c));
|
|
231
|
+
if (invalidContainers.length > 0) {
|
|
232
|
+
return formatSuccessResponse(`Invalid container names for "${dropin}"`, {
|
|
233
|
+
invalidContainers,
|
|
234
|
+
availableContainers,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
groups.push({
|
|
238
|
+
dropin,
|
|
239
|
+
containers,
|
|
240
|
+
alias: providerAlias(dropin, isSingle),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
const withEvents = params.withEvents ?? false;
|
|
244
|
+
const slots = params.slots ?? {};
|
|
245
|
+
const resolved = resolveContainerIds(groups);
|
|
246
|
+
const imports = generateImportsMulti(groups, resolved, withEvents);
|
|
247
|
+
const layout = generateLayout(resolved.map((r) => r.jsId));
|
|
248
|
+
const aliasMap = new Map();
|
|
249
|
+
for (const g of groups) {
|
|
250
|
+
aliasMap.set(g.dropin, g.alias);
|
|
251
|
+
}
|
|
252
|
+
const collidingNames = new Set(resolved.filter((rc) => rc.jsId !== rc.name).map((rc) => rc.name));
|
|
253
|
+
function slotsForContainer(rc) {
|
|
254
|
+
const scopedKey = `${rc.dropin}/${rc.name}`;
|
|
255
|
+
if (slots[scopedKey])
|
|
256
|
+
return slots[scopedKey];
|
|
257
|
+
if (rc.jsId === rc.name)
|
|
258
|
+
return slots[rc.name] ?? [];
|
|
259
|
+
return [];
|
|
260
|
+
}
|
|
261
|
+
const resolvedSlotCounts = resolved.map((rc) => slotsForContainer(rc));
|
|
262
|
+
const effectiveSlotCount = resolvedSlotCounts.reduce((sum, s) => sum + s.length, 0);
|
|
263
|
+
const ignoredSlotKeys = Object.keys(slots).filter((key) => !key.includes("/") && collidingNames.has(key));
|
|
264
|
+
const renderCalls = resolved
|
|
265
|
+
.map((rc, i) => {
|
|
266
|
+
const containerSlots = slotsForContainer(rc);
|
|
267
|
+
const domVar = resolved.length === 1 ? "$container" : `$section${i + 1}`;
|
|
268
|
+
return generateContainerRender(rc, containerSlots, domVar, aliasMap.get(rc.dropin));
|
|
269
|
+
})
|
|
270
|
+
.join("\n\n");
|
|
271
|
+
const eventStubs = withEvents ? generateEventStubs() : "";
|
|
272
|
+
const jsContent = `${imports}
|
|
273
|
+
|
|
274
|
+
export default async function decorate(block) {
|
|
275
|
+
// Read block configuration from AEM metadata
|
|
276
|
+
// const config = readBlockConfig(block);
|
|
277
|
+
|
|
278
|
+
${layout}
|
|
279
|
+
|
|
280
|
+
// Render containers
|
|
281
|
+
${renderCalls}
|
|
282
|
+
${eventStubs}
|
|
283
|
+
}
|
|
284
|
+
`;
|
|
285
|
+
const cssContent = generateCss(params.blockName, resolved.map((r) => r.jsId));
|
|
286
|
+
const blockDir = `blocks/${params.blockName}`;
|
|
287
|
+
const jsPath = `${blockDir}/${params.blockName}.js`;
|
|
288
|
+
const cssPath = `${blockDir}/${params.blockName}.css`;
|
|
289
|
+
const slotInstruction = effectiveSlotCount > 0
|
|
290
|
+
? "Slot stubs are included - customize the implementation in each slot callback"
|
|
291
|
+
: ignoredSlotKeys.length > 0
|
|
292
|
+
? `Slot keys ignored because container name is ambiguous across dropins: ${ignoredSlotKeys.join(", ")}. Use scoped keys like "dropin/ContainerName" instead.`
|
|
293
|
+
: "No slots configured - add slots to customize container rendering";
|
|
294
|
+
return formatSuccessResponse(`Block "${params.blockName}" scaffolded successfully`, {
|
|
295
|
+
files: {
|
|
296
|
+
[jsPath]: jsContent,
|
|
297
|
+
[cssPath]: cssContent,
|
|
298
|
+
},
|
|
299
|
+
dropins: groups.map((g) => g.dropin),
|
|
300
|
+
ignoredSlotKeys: ignoredSlotKeys.length > 0 ? ignoredSlotKeys : undefined,
|
|
301
|
+
instructions: [
|
|
302
|
+
`Create directory: ${blockDir}/`,
|
|
303
|
+
`Write JS file: ${jsPath}`,
|
|
304
|
+
`Write CSS file: ${cssPath}`,
|
|
305
|
+
`The block will be auto-discovered when a "${params.blockName}" section is added to a page`,
|
|
306
|
+
slotInstruction,
|
|
307
|
+
withEvents
|
|
308
|
+
? "Event bus is imported - uncomment and wire the events you need"
|
|
309
|
+
: "Add withEvents: true to include event bus boilerplate",
|
|
310
|
+
groups.length > 1
|
|
311
|
+
? `Multi-dropin block: ${groups.map((g) => `${g.alias} (${g.dropin})`).join(", ")}`
|
|
312
|
+
: "",
|
|
313
|
+
].filter(Boolean),
|
|
314
|
+
containersSummary: resolved.map((rc) => {
|
|
315
|
+
const dropinData = getContainersByDropin(rc.dropin);
|
|
316
|
+
const containerDef = dropinData.containers.find((c) => c.name === rc.name);
|
|
317
|
+
return {
|
|
318
|
+
name: rc.name,
|
|
319
|
+
jsId: rc.jsId,
|
|
320
|
+
dropin: rc.dropin,
|
|
321
|
+
description: containerDef?.description,
|
|
322
|
+
availableSlots: containerDef?.slotNames ?? [],
|
|
323
|
+
configuredSlots: slotsForContainer(rc),
|
|
324
|
+
};
|
|
325
|
+
}),
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
return formatExceptionResponse(error, "scaffolding block");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ScaffoldExtensionSchema: z.ZodObject<{
|
|
3
|
+
extensionName: z.ZodString;
|
|
4
|
+
extensionId: z.ZodString;
|
|
5
|
+
hooks: z.ZodArray<z.ZodString, "many">;
|
|
6
|
+
externalScripts: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
|
+
externalStyles: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
8
|
+
projectDir: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
projectDir: string;
|
|
11
|
+
extensionName: string;
|
|
12
|
+
extensionId: string;
|
|
13
|
+
hooks: string[];
|
|
14
|
+
externalScripts?: string[] | undefined;
|
|
15
|
+
externalStyles?: string[] | undefined;
|
|
16
|
+
}, {
|
|
17
|
+
projectDir: string;
|
|
18
|
+
extensionName: string;
|
|
19
|
+
extensionId: string;
|
|
20
|
+
hooks: string[];
|
|
21
|
+
externalScripts?: string[] | undefined;
|
|
22
|
+
externalStyles?: string[] | undefined;
|
|
23
|
+
}>;
|
|
24
|
+
export declare function scaffoldExtension(params: z.infer<typeof ScaffoldExtensionSchema>): Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
message: string;
|
|
27
|
+
data: unknown;
|
|
28
|
+
}>;
|