coretik-block-generator-mcp 1.0.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.
Files changed (59) hide show
  1. package/CLAUDE_INSTRUCTIONS.md +30 -0
  2. package/README.md +193 -0
  3. package/dist/constants.d.ts +55 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +27 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/conventions.d.ts +19 -0
  8. package/dist/conventions.d.ts.map +1 -0
  9. package/dist/conventions.js +158 -0
  10. package/dist/conventions.js.map +1 -0
  11. package/dist/index.d.ts +9 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +518 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/schemas/learned-conventions.d.ts +53 -0
  16. package/dist/schemas/learned-conventions.d.ts.map +1 -0
  17. package/dist/schemas/learned-conventions.js +47 -0
  18. package/dist/schemas/learned-conventions.js.map +1 -0
  19. package/dist/services/convention-store.d.ts +9 -0
  20. package/dist/services/convention-store.d.ts.map +1 -0
  21. package/dist/services/convention-store.js +84 -0
  22. package/dist/services/convention-store.js.map +1 -0
  23. package/dist/services/feedback.d.ts +29 -0
  24. package/dist/services/feedback.d.ts.map +1 -0
  25. package/dist/services/feedback.js +199 -0
  26. package/dist/services/feedback.js.map +1 -0
  27. package/dist/services/naming.d.ts +51 -0
  28. package/dist/services/naming.d.ts.map +1 -0
  29. package/dist/services/naming.js +87 -0
  30. package/dist/services/naming.js.map +1 -0
  31. package/dist/services/pattern-extractor.d.ts +14 -0
  32. package/dist/services/pattern-extractor.d.ts.map +1 -0
  33. package/dist/services/pattern-extractor.js +310 -0
  34. package/dist/services/pattern-extractor.js.map +1 -0
  35. package/dist/services/registration.d.ts +31 -0
  36. package/dist/services/registration.d.ts.map +1 -0
  37. package/dist/services/registration.js +275 -0
  38. package/dist/services/registration.js.map +1 -0
  39. package/dist/templates/generators.d.ts +59 -0
  40. package/dist/templates/generators.d.ts.map +1 -0
  41. package/dist/templates/generators.js +79 -0
  42. package/dist/templates/generators.js.map +1 -0
  43. package/dist/templates/html-template.d.ts +12 -0
  44. package/dist/templates/html-template.d.ts.map +1 -0
  45. package/dist/templates/html-template.js +189 -0
  46. package/dist/templates/html-template.js.map +1 -0
  47. package/dist/templates/php-class.d.ts +19 -0
  48. package/dist/templates/php-class.d.ts.map +1 -0
  49. package/dist/templates/php-class.js +271 -0
  50. package/dist/templates/php-class.js.map +1 -0
  51. package/dist/templates/scss.d.ts +7 -0
  52. package/dist/templates/scss.d.ts.map +1 -0
  53. package/dist/templates/scss.js +102 -0
  54. package/dist/templates/scss.js.map +1 -0
  55. package/dist/utils.d.ts +18 -0
  56. package/dist/utils.d.ts.map +1 -0
  57. package/dist/utils.js +56 -0
  58. package/dist/utils.js.map +1 -0
  59. package/package.json +48 -0
@@ -0,0 +1,59 @@
1
+ import type { LearnedConventions } from '../schemas/learned-conventions.js';
2
+ /**
3
+ * Field definition as expected by index.ts tool schema.
4
+ */
5
+ export interface BlockFieldDefinition {
6
+ name: string;
7
+ type: string;
8
+ label: string;
9
+ required?: boolean;
10
+ instructions?: string;
11
+ defaultValue?: string;
12
+ returnFormat?: string;
13
+ choices?: Array<{
14
+ value: string;
15
+ label: string;
16
+ }>;
17
+ width?: string;
18
+ subFields?: BlockFieldDefinition[];
19
+ rows?: number;
20
+ mediaUpload?: boolean;
21
+ conditional?: {
22
+ field: string;
23
+ operator: string;
24
+ value: string;
25
+ };
26
+ }
27
+ /**
28
+ * Block definition as expected by index.ts tool schema.
29
+ */
30
+ export interface BlockDefinition {
31
+ name: string;
32
+ label: string;
33
+ type: 'component' | 'block' | 'composite';
34
+ fields: BlockFieldDefinition[];
35
+ components?: Array<{
36
+ key: string;
37
+ className: string;
38
+ required?: boolean;
39
+ }>;
40
+ renderingType?: 'Html' | 'Array' | 'Object';
41
+ gutenberg?: boolean;
42
+ }
43
+ /**
44
+ * Generate the PHP class for any block type.
45
+ */
46
+ export declare function generateBlockPhp(def: BlockDefinition, rootNamespace: string, learned?: LearnedConventions | null): string;
47
+ /**
48
+ * Generate the HTML template.
49
+ */
50
+ export declare function generateTemplate(def: BlockDefinition, learned?: LearnedConventions | null): string;
51
+ /**
52
+ * Generate the SCSS stylesheet.
53
+ */
54
+ export declare function generateScss(def: BlockDefinition, learned?: LearnedConventions | null): string;
55
+ /**
56
+ * Generate a placeholder SVG thumbnail for the block.
57
+ */
58
+ export declare function generatePlaceholderSvg(def: BlockDefinition): string;
59
+ //# sourceMappingURL=generators.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generators.d.ts","sourceRoot":"","sources":["../../src/templates/generators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAM5E;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;IAC1C,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC3E,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAgCD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAoBzH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAIlG;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAG9F;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAQnE"}
@@ -0,0 +1,79 @@
1
+ import { generateBlockClass, generateComponentClass, generateCompositeClass } from './php-class.js';
2
+ import { generateHtmlTemplate } from './html-template.js';
3
+ import { generateScss as generateScssInternal } from './scss.js';
4
+ import { toKebabCase } from '../services/naming.js';
5
+ /**
6
+ * Convert BlockFieldDefinition to BlockField (internal format).
7
+ */
8
+ function toBlockField(def) {
9
+ return {
10
+ name: def.name,
11
+ type: def.type,
12
+ label: def.label,
13
+ required: def.required,
14
+ defaultValue: def.defaultValue,
15
+ choices: def.choices?.map(c => c.value),
16
+ instructions: def.instructions,
17
+ subFields: def.subFields?.map(toBlockField),
18
+ };
19
+ }
20
+ /**
21
+ * Convert BlockDefinition to BlockSpec (internal format).
22
+ */
23
+ function toBlockSpec(def) {
24
+ return {
25
+ label: def.label,
26
+ name: def.name,
27
+ type: def.type,
28
+ fields: def.fields.map(toBlockField),
29
+ components: def.components?.map(c => c.className),
30
+ blockTypeSupport: def.gutenberg,
31
+ };
32
+ }
33
+ /**
34
+ * Generate the PHP class for any block type.
35
+ */
36
+ export function generateBlockPhp(def, rootNamespace, learned) {
37
+ const spec = toBlockSpec(def);
38
+ switch (def.type) {
39
+ case 'component':
40
+ return generateComponentClass(spec, rootNamespace, learned);
41
+ case 'composite':
42
+ return generateCompositeClass(spec, rootNamespace, (def.components || []).map(c => ({
43
+ key: c.key,
44
+ className: c.className,
45
+ fqcn: `${rootNamespace}\\Component\\${c.className}`,
46
+ })), learned);
47
+ case 'block':
48
+ default:
49
+ return generateBlockClass(spec, rootNamespace, learned);
50
+ }
51
+ }
52
+ /**
53
+ * Generate the HTML template.
54
+ */
55
+ export function generateTemplate(def, learned) {
56
+ const spec = toBlockSpec(def);
57
+ const components = def.components?.map(c => ({ key: c.key, className: c.className }));
58
+ return generateHtmlTemplate(spec, learned, components);
59
+ }
60
+ /**
61
+ * Generate the SCSS stylesheet.
62
+ */
63
+ export function generateScss(def, learned) {
64
+ const spec = toBlockSpec(def);
65
+ return generateScssInternal(spec, learned);
66
+ }
67
+ /**
68
+ * Generate a placeholder SVG thumbnail for the block.
69
+ */
70
+ export function generatePlaceholderSvg(def) {
71
+ const kebab = toKebabCase(def.name);
72
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 120" fill="none">
73
+ <rect width="200" height="120" rx="4" fill="#f0f0f0"/>
74
+ <text x="100" y="55" text-anchor="middle" fill="#666" font-family="sans-serif" font-size="12">${def.label}</text>
75
+ <text x="100" y="75" text-anchor="middle" fill="#999" font-family="sans-serif" font-size="10">${kebab}</text>
76
+ </svg>
77
+ `;
78
+ }
79
+ //# sourceMappingURL=generators.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generators.js","sourceRoot":"","sources":["../../src/templates/generators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { BlockSpec } from '../constants.js';
2
+ import type { LearnedConventions } from '../schemas/learned-conventions.js';
3
+ /**
4
+ * Generate the PHP/HTML template file for a block.
5
+ * For composites, generates component method calls ($component->render(), etc.)
6
+ * For components, generates field-level HTML with short echo tags.
7
+ */
8
+ export declare function generateHtmlTemplate(spec: BlockSpec, learned?: LearnedConventions | null, components?: Array<{
9
+ key: string;
10
+ className: string;
11
+ }>): string;
12
+ //# sourceMappingURL=html-template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-template.d.ts","sourceRoot":"","sources":["../../src/templates/html-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAG5E;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,EACf,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,EACnC,UAAU,CAAC,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,GACrD,MAAM,CAYR"}
@@ -0,0 +1,189 @@
1
+ import { toBemBase, toKebabCase } from '../services/naming.js';
2
+ /**
3
+ * Generate the PHP/HTML template file for a block.
4
+ * For composites, generates component method calls ($component->render(), etc.)
5
+ * For components, generates field-level HTML with short echo tags.
6
+ */
7
+ export function generateHtmlTemplate(spec, learned, components) {
8
+ const bemBase = toBemBase(spec.label, spec.type);
9
+ // Composite blocks use <section>, components use <div>
10
+ const defaultTag = spec.type === 'component' ? 'div' : 'section';
11
+ const wrapperTag = learned?.template.wrapperTag || defaultTag;
12
+ if (spec.type === 'composite' && components && components.length > 0) {
13
+ return generateCompositeTemplate(spec, bemBase, wrapperTag, components);
14
+ }
15
+ return generateFieldTemplate(spec, bemBase, wrapperTag, learned);
16
+ }
17
+ /**
18
+ * Generate a template for a composite block using component method calls.
19
+ */
20
+ function generateCompositeTemplate(spec, bemBase, wrapperTag, components) {
21
+ const lines = [];
22
+ lines.push('<?php');
23
+ lines.push(`/**`);
24
+ lines.push(` * Block: ${spec.label}`);
25
+ lines.push(` *`);
26
+ for (const comp of components) {
27
+ lines.push(` * @var \\Coretik\\PageBuilder\\Core\\Block\\BlockComponent $${comp.key}`);
28
+ }
29
+ lines.push(` */`);
30
+ lines.push('');
31
+ // Class list with context awareness (real Coretik pattern)
32
+ lines.push(`use Coretik\\PageBuilder\\Core\\Block\\Context\\BlockContextType;`);
33
+ lines.push('');
34
+ lines.push(`$classlist = ['${bemBase}'];`);
35
+ lines.push(`if (!empty($context) && $context['type'] === BlockContextType::CONTAINER->name) {`);
36
+ lines.push(` $classlist[] = 'contained';`);
37
+ lines.push(`}`);
38
+ lines.push('?>');
39
+ lines.push(`<${wrapperTag} class="<?= implode(' ', $classlist) ?>">`);
40
+ lines.push(` <div class="container">`);
41
+ for (const comp of components) {
42
+ lines.push(` <?php if (!empty($${comp.key})) : ?>`);
43
+ lines.push(` <div class="${bemBase}__${toKebabCase(comp.key)}">`);
44
+ lines.push(` <?php $${comp.key}->render(); ?>`);
45
+ lines.push(` </div>`);
46
+ lines.push(` <?php endif; ?>`);
47
+ }
48
+ lines.push(` </div>`);
49
+ lines.push(`</${wrapperTag}>`);
50
+ return lines.join('\n') + '\n';
51
+ }
52
+ /**
53
+ * Generate a template for a component/block using direct field HTML.
54
+ */
55
+ function generateFieldTemplate(spec, bemBase, wrapperTag, learned) {
56
+ const docParams = spec.fields
57
+ .map(f => ` * @var ${phpTypeFromAcf(f.type)} $${f.name}`)
58
+ .join('\n');
59
+ const htmlContent = generateFieldsHtml(spec.fields, bemBase, ' ', learned);
60
+ return `<?php
61
+ /**
62
+ * Block: ${spec.label}
63
+ *
64
+ ${docParams}
65
+ */
66
+ ?>
67
+ <${wrapperTag} class="${bemBase}">
68
+ ${htmlContent}
69
+ </${wrapperTag}>
70
+ `;
71
+ }
72
+ /**
73
+ * Generate HTML for each field based on its ACF type.
74
+ */
75
+ function generateFieldsHtml(fields, bemBase, indent = ' ', learned) {
76
+ return fields.map(field => {
77
+ const elementClass = `${bemBase}__${toKebabCase(field.name)}`;
78
+ return generateSingleFieldHtml(field, elementClass, indent, learned);
79
+ }).join('\n');
80
+ }
81
+ function generateSingleFieldHtml(field, cssClass, indent, learned) {
82
+ const imgFn = learned?.template.imageRenderFunction || 'wp_get_attachment_image';
83
+ switch (field.type) {
84
+ case 'image':
85
+ return `${indent}<?php if (!empty($${field.name})) : ?>
86
+ ${indent}<div class="${cssClass}">
87
+ ${indent} <?= ${imgFn}($${field.name}, 'large', false, ['class' => '${cssClass}-img']) ?>
88
+ ${indent}</div>
89
+ ${indent}<?php endif; ?>`;
90
+ case 'wysiwyg':
91
+ return `${indent}<?php if (!empty($${field.name})) : ?>
92
+ ${indent}<div class="${cssClass}">
93
+ ${indent} <?= $${field.name} ?>
94
+ ${indent}</div>
95
+ ${indent}<?php endif; ?>`;
96
+ case 'link':
97
+ return `${indent}<?php if (!empty($${field.name})) : ?>
98
+ ${indent}<a class="${cssClass}" href="<?= $${field.name}['url'] ?>" target="<?= $${field.name}['target'] ?: '_self' ?>">
99
+ ${indent} <?= $${field.name}['title'] ?>
100
+ ${indent}</a>
101
+ ${indent}<?php endif; ?>`;
102
+ case 'gallery':
103
+ return `${indent}<?php if (!empty($${field.name})) : ?>
104
+ ${indent}<div class="${cssClass}">
105
+ ${indent} <?php foreach ($${field.name} as $image) : ?>
106
+ ${indent} <?= ${imgFn}($image, 'medium', false, ['class' => '${cssClass}-img']) ?>
107
+ ${indent} <?php endforeach; ?>
108
+ ${indent}</div>
109
+ ${indent}<?php endif; ?>`;
110
+ case 'repeater':
111
+ const subHtml = (field.subFields || [])
112
+ .map(sub => {
113
+ const subClass = `${cssClass}-item__${toKebabCase(sub.name)}`;
114
+ return generateSingleFieldHtml(sub, subClass, indent + ' ', learned);
115
+ })
116
+ .join('\n');
117
+ return `${indent}<?php if (!empty($${field.name})) : ?>
118
+ ${indent}<div class="${cssClass}">
119
+ ${indent} <?php foreach ($${field.name} as $item) : ?>
120
+ ${indent} <div class="${cssClass}-item">
121
+ ${subHtml}
122
+ ${indent} </div>
123
+ ${indent} <?php endforeach; ?>
124
+ ${indent}</div>
125
+ ${indent}<?php endif; ?>`;
126
+ case 'true_false':
127
+ return `${indent}<?php if ($${field.name}) : ?>
128
+ ${indent}<div class="${cssClass}">
129
+ ${indent} <!-- ${field.label} -->
130
+ ${indent}</div>
131
+ ${indent}<?php endif; ?>`;
132
+ case 'select':
133
+ case 'radio':
134
+ return `${indent}<?php if (!empty($${field.name})) : ?>
135
+ ${indent}<div class="${cssClass}" data-value="<?= $${field.name} ?>">
136
+ ${indent} <?= $${field.name} ?>
137
+ ${indent}</div>
138
+ ${indent}<?php endif; ?>`;
139
+ case 'oembed':
140
+ return `${indent}<?php if (!empty($${field.name})) : ?>
141
+ ${indent}<div class="${cssClass}">
142
+ ${indent} <?= $${field.name} ?>
143
+ ${indent}</div>
144
+ ${indent}<?php endif; ?>`;
145
+ case 'text':
146
+ case 'textarea':
147
+ case 'email':
148
+ case 'url':
149
+ case 'number':
150
+ default:
151
+ return `${indent}<?php if (!empty($${field.name})) : ?>
152
+ ${indent}<div class="${cssClass}">
153
+ ${indent} <?= $${field.name} ?>
154
+ ${indent}</div>
155
+ ${indent}<?php endif; ?>`;
156
+ }
157
+ }
158
+ function phpTypeFromAcf(type) {
159
+ const map = {
160
+ text: 'string',
161
+ textarea: 'string',
162
+ wysiwyg: 'string',
163
+ image: 'int|array',
164
+ gallery: 'array',
165
+ file: 'int|array',
166
+ select: 'string|array',
167
+ radio: 'string',
168
+ checkbox: 'array',
169
+ true_false: 'bool',
170
+ link: 'array',
171
+ url: 'string',
172
+ number: 'int|float',
173
+ range: 'int|float',
174
+ email: 'string',
175
+ repeater: 'array',
176
+ group: 'array',
177
+ relationship: 'array',
178
+ post_object: 'int|WP_Post',
179
+ taxonomy: 'int|WP_Term',
180
+ user: 'int|WP_User',
181
+ color_picker: 'string',
182
+ date_picker: 'string',
183
+ date_time_picker: 'string',
184
+ time_picker: 'string',
185
+ oembed: 'string',
186
+ };
187
+ return map[type] || 'mixed';
188
+ }
189
+ //# sourceMappingURL=html-template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html-template.js","sourceRoot":"","sources":["../../src/templates/html-template.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAe,EACf,OAAmC,EACnC,UAAsD;IAEtD,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjD,uDAAuD;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IACjE,MAAM,UAAU,GAAG,OAAO,EAAE,QAAQ,CAAC,UAAU,IAAI,UAAU,CAAC;IAE9D,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrE,OAAO,yBAAyB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,qBAAqB,CAAC,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC;AAED;;GAEG;AACH,SAAS,yBAAyB,CAChC,IAAe,EACf,OAAe,EACf,UAAkB,EAClB,UAAqD;IAErD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACtC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,gEAAgE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACzF,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,2DAA2D;IAC3D,KAAK,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;IAChF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,kBAAkB,OAAO,KAAK,CAAC,CAAC;IAC3C,KAAK,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;IAChG,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjB,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,2CAA2C,CAAC,CAAC;IACtE,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAE1C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,6BAA6B,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;QAC3D,KAAK,CAAC,IAAI,CAAC,uBAAuB,OAAO,KAAK,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzE,KAAK,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,GAAG,gBAAgB,CAAC,CAAC;QAC3D,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACzB,KAAK,CAAC,IAAI,CAAC,KAAK,UAAU,GAAG,CAAC,CAAC;IAE/B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,IAAe,EACf,OAAe,EACf,UAAkB,EAClB,OAAmC;IAEnC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;SACxD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,WAAW,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAE9E,OAAO;;YAEG,IAAI,CAAC,KAAK;;EAEpB,SAAS;;;GAGR,UAAU,WAAW,OAAO;EAC7B,WAAW;IACT,UAAU;CACb,CAAC;AACF,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,MAAoB,EAAE,OAAe,EAAE,SAAiB,MAAM,EAAE,OAAmC;IAC7H,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACxB,MAAM,YAAY,GAAG,GAAG,OAAO,KAAK,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9D,OAAO,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAiB,EAAE,QAAgB,EAAE,MAAc,EAAE,OAAmC;IACvH,MAAM,KAAK,GAAG,OAAO,EAAE,QAAQ,CAAC,mBAAmB,IAAI,yBAAyB,CAAC;IAEjF,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,OAAO;YACV,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,WAAW,KAAK,KAAK,KAAK,CAAC,IAAI,kCAAkC,QAAQ;EAC/E,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,SAAS;YACZ,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,YAAY,KAAK,CAAC,IAAI;EAC5B,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,MAAM;YACT,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,aAAa,QAAQ,gBAAgB,KAAK,CAAC,IAAI,4BAA4B,KAAK,CAAC,IAAI;EAC3F,MAAM,YAAY,KAAK,CAAC,IAAI;EAC5B,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,SAAS;YACZ,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,uBAAuB,KAAK,CAAC,IAAI;EACvC,MAAM,eAAe,KAAK,0CAA0C,QAAQ;EAC5E,MAAM;EACN,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,UAAU;YACb,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,EAAE,CAAC;iBACpC,GAAG,CAAC,GAAG,CAAC,EAAE;gBACT,MAAM,QAAQ,GAAG,GAAG,QAAQ,UAAU,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9D,OAAO,uBAAuB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,OAAO,CAAC,CAAC;YAC9E,CAAC,CAAC;iBACD,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,uBAAuB,KAAK,CAAC,IAAI;EACvC,MAAM,mBAAmB,QAAQ;EACjC,OAAO;EACP,MAAM;EACN,MAAM;EACN,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,YAAY;YACf,OAAO,GAAG,MAAM,cAAc,KAAK,CAAC,IAAI;EAC5C,MAAM,eAAe,QAAQ;EAC7B,MAAM,YAAY,KAAK,CAAC,KAAK;EAC7B,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO;YACV,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ,sBAAsB,KAAK,CAAC,IAAI;EAC7D,MAAM,YAAY,KAAK,CAAC,IAAI;EAC5B,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,QAAQ;YACX,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,YAAY,KAAK,CAAC,IAAI;EAC5B,MAAM;EACN,MAAM,iBAAiB,CAAC;QAEtB,KAAK,MAAM,CAAC;QACZ,KAAK,UAAU,CAAC;QAChB,KAAK,OAAO,CAAC;QACb,KAAK,KAAK,CAAC;QACX,KAAK,QAAQ,CAAC;QACd;YACE,OAAO,GAAG,MAAM,qBAAqB,KAAK,CAAC,IAAI;EACnD,MAAM,eAAe,QAAQ;EAC7B,MAAM,YAAY,KAAK,CAAC,IAAI;EAC5B,MAAM;EACN,MAAM,iBAAiB,CAAC;IACxB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,GAAG,GAA2B;QAClC,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,QAAQ;QAClB,OAAO,EAAE,QAAQ;QACjB,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,cAAc;QACtB,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,MAAM;QAClB,IAAI,EAAE,OAAO;QACb,GAAG,EAAE,QAAQ;QACb,MAAM,EAAE,WAAW;QACnB,KAAK,EAAE,WAAW;QAClB,KAAK,EAAE,QAAQ;QACf,QAAQ,EAAE,OAAO;QACjB,KAAK,EAAE,OAAO;QACd,YAAY,EAAE,OAAO;QACrB,WAAW,EAAE,aAAa;QAC1B,QAAQ,EAAE,aAAa;QACvB,IAAI,EAAE,aAAa;QACnB,YAAY,EAAE,QAAQ;QACtB,WAAW,EAAE,QAAQ;QACrB,gBAAgB,EAAE,QAAQ;QAC1B,WAAW,EAAE,QAAQ;QACrB,MAAM,EAAE,QAAQ;KACjB,CAAC;IACF,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { BlockSpec } from '../constants.js';
2
+ import type { LearnedConventions } from '../schemas/learned-conventions.js';
3
+ /**
4
+ * Generate a Block PHP class.
5
+ */
6
+ export declare function generateBlockClass(spec: BlockSpec, rootNamespace: string, learned?: LearnedConventions | null): string;
7
+ /**
8
+ * Generate a Component PHP class.
9
+ */
10
+ export declare function generateComponentClass(spec: BlockSpec, rootNamespace: string, learned?: LearnedConventions | null): string;
11
+ /**
12
+ * Generate a Composite PHP class.
13
+ */
14
+ export declare function generateCompositeClass(spec: BlockSpec, rootNamespace: string, componentsMap: Array<{
15
+ key: string;
16
+ className: string;
17
+ fqcn: string;
18
+ }>, learned?: LearnedConventions | null): string;
19
+ //# sourceMappingURL=php-class.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"php-class.d.ts","sourceRoot":"","sources":["../../src/templates/php-class.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAc,MAAM,iBAAiB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAsF5E;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAmEtH;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAuE1H;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,EACf,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EACtE,OAAO,CAAC,EAAE,kBAAkB,GAAG,IAAI,GAClC,MAAM,CAkDR"}
@@ -0,0 +1,271 @@
1
+ import { toBlockName, toClassName, toPascalCase, toBemBase, } from '../services/naming.js';
2
+ /**
3
+ * Generate the ACF FieldsBuilder method chain for a single field.
4
+ */
5
+ function generateFieldBuilder(field, indent = ' ') {
6
+ const lines = [];
7
+ const addMethod = getAddMethod(field.type);
8
+ let fieldLine = `${indent}->${addMethod}('${field.name}')`;
9
+ lines.push(fieldLine);
10
+ lines.push(`${indent} ->setLabel('${escapePhp(field.label)}')`);
11
+ if (field.required) {
12
+ lines.push(`${indent} ->setRequired()`);
13
+ }
14
+ if (field.instructions) {
15
+ lines.push(`${indent} ->setInstructions('${escapePhp(field.instructions)}')`);
16
+ }
17
+ if (field.defaultValue !== undefined) {
18
+ lines.push(`${indent} ->setDefaultValue('${escapePhp(field.defaultValue)}')`);
19
+ }
20
+ if (field.choices && field.choices.length > 0) {
21
+ for (const choice of field.choices) {
22
+ lines.push(`${indent} ->addChoice('${escapePhp(choice)}')`);
23
+ }
24
+ }
25
+ // Handle repeater/group sub-fields
26
+ if (field.subFields && field.subFields.length > 0) {
27
+ for (const sub of field.subFields) {
28
+ lines.push(generateFieldBuilder(sub, indent + ' '));
29
+ }
30
+ lines.push(`${indent} ->endRepeater()`);
31
+ }
32
+ return lines.join('\n');
33
+ }
34
+ function getAddMethod(type) {
35
+ const map = {
36
+ text: 'addText',
37
+ textarea: 'addTextarea',
38
+ wysiwyg: 'addWysiwyg',
39
+ image: 'addImage',
40
+ gallery: 'addGallery',
41
+ file: 'addFile',
42
+ select: 'addSelect',
43
+ radio: 'addRadio',
44
+ checkbox: 'addCheckbox',
45
+ true_false: 'addTrueFalse',
46
+ link: 'addLink',
47
+ url: 'addUrl',
48
+ number: 'addNumber',
49
+ range: 'addRange',
50
+ email: 'addEmail',
51
+ password: 'addPassword',
52
+ repeater: 'addRepeater',
53
+ group: 'addGroup',
54
+ relationship: 'addRelationship',
55
+ post_object: 'addPostObject',
56
+ taxonomy: 'addTaxonomy',
57
+ user: 'addUser',
58
+ color_picker: 'addColorPicker',
59
+ date_picker: 'addDatePicker',
60
+ date_time_picker: 'addDateTimePicker',
61
+ time_picker: 'addTimePicker',
62
+ oembed: 'addOembed',
63
+ };
64
+ return map[type] || 'addText';
65
+ }
66
+ function escapePhp(str) {
67
+ return str.replace(/'/g, "\\'");
68
+ }
69
+ /**
70
+ * Generate a Block PHP class.
71
+ */
72
+ export function generateBlockClass(spec, rootNamespace, learned) {
73
+ const className = spec.name ? toPascalCase(spec.name) : toClassName(spec.label, 'block');
74
+ const blockName = toBlockName(spec.label, 'block');
75
+ const namespace = `${rootNamespace}\\Block`;
76
+ const vis = learned?.php.propertyVisibility || 'protected';
77
+ const properties = spec.fields.map(f => ` ${vis} $${f.name};`).join('\n');
78
+ const fieldsBuilder = spec.fields.map(f => generateFieldBuilder(f)).join('\n');
79
+ const toArrayEntries = spec.fields
80
+ .map(f => ` '${f.name}' => $this->${f.name},`)
81
+ .join('\n');
82
+ const blockTypeImports = spec.blockTypeSupport
83
+ ? `\nuse Coretik\\PageBuilder\\Core\\Contract\\ShouldBuildBlockType;\nuse Coretik\\PageBuilder\\Core\\Block\\Traits\\BlockType;`
84
+ : '';
85
+ const blockTypeImplements = spec.blockTypeSupport ? ' implements ShouldBuildBlockType' : '';
86
+ const blockTypeTrait = spec.blockTypeSupport ? '\n use BlockType;\n' : '';
87
+ // Learned extra imports
88
+ const learnedImports = buildLearnedImports(learned, [
89
+ 'Coretik\\PageBuilder\\Core\\Block\\Block',
90
+ 'StoutLogic\\AcfBuilder\\FieldsBuilder',
91
+ ]);
92
+ // Learned traits
93
+ const learnedTraits = buildLearnedTraits(learned, spec.blockTypeSupport ? ['BlockType'] : []);
94
+ // Learned extra methods
95
+ const learnedMethods = buildLearnedMethods(learned);
96
+ const useSettingsLine = (!learned || learned.php.useSettingsPattern)
97
+ ? '\n $this->useSettingsOn($field);' : '';
98
+ return `<?php
99
+
100
+ namespace ${namespace};
101
+
102
+ use Coretik\\PageBuilder\\Core\\Block\\Block;${blockTypeImports}
103
+ use StoutLogic\\AcfBuilder\\FieldsBuilder;${learnedImports}
104
+
105
+ class ${className} extends Block${blockTypeImplements}
106
+ {${blockTypeTrait}${learnedTraits}
107
+ const NAME = '${blockName}';
108
+ const LABEL = '${escapePhp(spec.label)}';
109
+
110
+ ${properties}
111
+
112
+ public function fieldsBuilder(): FieldsBuilder
113
+ {
114
+ $field = $this->createFieldsBuilder();
115
+ $field
116
+ ${fieldsBuilder};
117
+ ${useSettingsLine}
118
+ return $field;
119
+ }
120
+
121
+ public function toArray()
122
+ {
123
+ return [
124
+ ${toArrayEntries}
125
+ ];
126
+ }${learnedMethods}
127
+ }
128
+ `;
129
+ }
130
+ /**
131
+ * Generate a Component PHP class.
132
+ */
133
+ export function generateComponentClass(spec, rootNamespace, learned) {
134
+ const className = spec.name ? toPascalCase(spec.name) : toClassName(spec.label, 'component');
135
+ const blockName = toBlockName(spec.label, 'component');
136
+ const namespace = `${rootNamespace}\\Component`;
137
+ const bemBase = toBemBase(spec.label, 'component');
138
+ const vis = learned?.php.propertyVisibility || 'protected';
139
+ const properties = spec.fields.map(f => ` ${vis} $${f.name};`).join('\n');
140
+ const fieldsBuilder = spec.fields.map(f => generateFieldBuilder(f)).join('\n');
141
+ const toArrayEntries = spec.fields
142
+ .map(f => ` '${f.name}' => $this->${f.name},`)
143
+ .join('\n');
144
+ const blockTypeImports = spec.blockTypeSupport
145
+ ? `\nuse Coretik\\PageBuilder\\Core\\Contract\\ShouldBuildBlockType;\nuse Coretik\\PageBuilder\\Core\\Block\\Traits\\BlockType;`
146
+ : '';
147
+ const blockTypeImplements = spec.blockTypeSupport ? ' implements ShouldBuildBlockType' : '';
148
+ const blockTypeTrait = spec.blockTypeSupport ? '\n use BlockType;\n' : '';
149
+ const learnedImports = buildLearnedImports(learned, [
150
+ 'Coretik\\PageBuilder\\Core\\Block\\BlockComponent',
151
+ 'StoutLogic\\AcfBuilder\\FieldsBuilder',
152
+ ]);
153
+ const learnedTraits = buildLearnedTraits(learned, spec.blockTypeSupport ? ['BlockType'] : []);
154
+ const learnedMethods = buildLearnedMethods(learned);
155
+ const useSettingsLine = (!learned || learned.php.useSettingsPattern)
156
+ ? '\n $this->useSettingsOn($field);' : '';
157
+ return `<?php
158
+
159
+ namespace ${namespace};
160
+
161
+ use Coretik\\PageBuilder\\Core\\Block\\BlockComponent;${blockTypeImports}
162
+ use StoutLogic\\AcfBuilder\\FieldsBuilder;${learnedImports}
163
+
164
+ class ${className} extends BlockComponent${blockTypeImplements}
165
+ {${blockTypeTrait}${learnedTraits}
166
+ const NAME = '${blockName}';
167
+ const LABEL = '${escapePhp(spec.label)}';
168
+
169
+ ${properties}
170
+
171
+ public function fieldsBuilder(): FieldsBuilder
172
+ {
173
+ $field = $this->createFieldsBuilder();
174
+ $field
175
+ ${fieldsBuilder};
176
+ ${useSettingsLine}
177
+ return $field;
178
+ }
179
+
180
+ public function toArray()
181
+ {
182
+ return [
183
+ ${toArrayEntries}
184
+ ];
185
+ }
186
+
187
+ protected function getPlainHtml(array $parameters): string
188
+ {
189
+ return sprintf(
190
+ '<div class="${bemBase}">%s</div>',
191
+ implode('', array_values($parameters))
192
+ );
193
+ }${learnedMethods}
194
+ }
195
+ `;
196
+ }
197
+ /**
198
+ * Generate a Composite PHP class.
199
+ */
200
+ export function generateCompositeClass(spec, rootNamespace, componentsMap, learned) {
201
+ const className = spec.name ? toPascalCase(spec.name) : toClassName(spec.label, 'composite');
202
+ const blockName = toBlockName(spec.label, 'composite');
203
+ const namespace = `${rootNamespace}\\Composite`;
204
+ const bemBase = toBemBase(spec.label, 'composite');
205
+ const useStatements = componentsMap
206
+ .map(c => `use ${c.fqcn};`)
207
+ .join('\n');
208
+ const prepareEntries = componentsMap
209
+ .map(c => ` '${c.key}' => ${c.className}::class,`)
210
+ .join('\n');
211
+ const htmlParts = componentsMap
212
+ .map(c => `$parameters['${c.key}']`)
213
+ .join(', ');
214
+ const blockTypeImports = spec.blockTypeSupport
215
+ ? `\nuse Coretik\\PageBuilder\\Core\\Contract\\ShouldBuildBlockType;\nuse Coretik\\PageBuilder\\Core\\Block\\Traits\\BlockType;`
216
+ : '';
217
+ const blockTypeImplements = spec.blockTypeSupport ? ' implements ShouldBuildBlockType' : '';
218
+ const blockTypeTrait = spec.blockTypeSupport ? '\n use BlockType;\n' : '';
219
+ return `<?php
220
+
221
+ namespace ${namespace};
222
+
223
+ use Coretik\\PageBuilder\\Core\\Block\\BlockComposite;${blockTypeImports}
224
+ ${useStatements}
225
+
226
+ class ${className} extends BlockComposite${blockTypeImplements}
227
+ {${blockTypeTrait}
228
+ const NAME = '${blockName}';
229
+ const LABEL = '${escapePhp(spec.label)}';
230
+
231
+ protected function prepareComponents(): array
232
+ {
233
+ return [
234
+ ${prepareEntries}
235
+ ];
236
+ }
237
+
238
+ protected function getPlainHtml(array $parameters): string
239
+ {
240
+ return sprintf('<div class="${bemBase}">%s</div>', implode('', [${htmlParts}]));
241
+ }
242
+ }
243
+ `;
244
+ }
245
+ // ─── Learned Convention Helpers ─────────────────────────────────────────────
246
+ function buildLearnedImports(learned, alreadyImported) {
247
+ if (!learned?.php.imports.length)
248
+ return '';
249
+ const existing = new Set(alreadyImported);
250
+ const extra = learned.php.imports.filter(i => !existing.has(i));
251
+ if (extra.length === 0)
252
+ return '';
253
+ return '\n' + extra.map(i => `use ${i};`).join('\n');
254
+ }
255
+ function buildLearnedTraits(learned, alreadyUsed) {
256
+ if (!learned?.php.traits.length)
257
+ return '';
258
+ const existing = new Set(alreadyUsed);
259
+ const extra = learned.php.traits.filter(t => !existing.has(t));
260
+ if (extra.length === 0)
261
+ return '';
262
+ return '\n' + extra.map(t => ` use ${t};`).join('\n');
263
+ }
264
+ function buildLearnedMethods(learned) {
265
+ if (!learned?.php.extraMethods.length)
266
+ return '';
267
+ return '\n\n' + learned.php.extraMethods
268
+ .map(m => ` // TODO: Implement ${m}() — pattern detected in existing blocks`)
269
+ .join('\n');
270
+ }
271
+ //# sourceMappingURL=php-class.js.map