Skip to content

Commit 81360ba

Browse files
committed
Resolve include selectors with parameters
1 parent 178458f commit 81360ba

5 files changed

Lines changed: 89 additions & 2 deletions

File tree

acumate-plugin/src/services/html-field-context-service.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { findParentViewName, findViewNameAtOrAbove } from '../providers/html-sha
1616
import { resolveIncludeFilePath } from './include-service';
1717
import {
1818
BaseScreenDocument,
19+
createParameterizedHtmlDocument,
1920
getCustomizationSelectorAttributes,
2021
isCustomizationSelectorAttribute,
2122
loadHtmlDocument,
@@ -342,11 +343,17 @@ export function getIncludeFieldContext(options: {
342343
return undefined;
343344
}
344345

346+
const parameterValues = getIncludeParameterValues(includeNode);
347+
const templateDocument = templateContext.templateDocument
348+
? createParameterizedHtmlDocument(templateContext.templateDocument, parameterValues)
349+
: undefined;
350+
345351
return {
346352
...templateContext,
353+
templateDocument,
347354
includeNode,
348355
includePath: normalizedIncludePath,
349-
parameterValues: getIncludeParameterValues(includeNode),
356+
parameterValues,
350357
hostScreenClasses: options.hostScreenClasses,
351358
};
352359
}

acumate-plugin/src/services/screen-html-service.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface SelectorQueryResult {
2323
error?: string;
2424
}
2525

26-
const customizationSelectorAttributes = ["before", "after", "append", "prepend", "prepand", "move", "remove"] as const;
26+
const customizationSelectorAttributes = ["modify", "before", "after", "append", "prepend", "prepand", "move", "remove"] as const;
2727
const customizationSelectorAttributeSet = new Set<string>(
2828
customizationSelectorAttributes.map(attribute => attribute.toLowerCase())
2929
);
@@ -134,6 +134,20 @@ export function queryBaseScreenElements(document: BaseScreenDocument, selector:
134134
}
135135
}
136136

137+
export function createParameterizedHtmlDocument(
138+
document: BaseScreenDocument,
139+
parameterValues: Map<string, string>
140+
): BaseScreenDocument {
141+
const dom = parseHtml(document.content);
142+
applyTemplateParametersToNodes(dom, parameterValues);
143+
144+
return {
145+
filePath: document.filePath,
146+
content: document.content,
147+
dom,
148+
};
149+
}
150+
137151
export function getDocumentForNode(
138152
document: BaseScreenDocument,
139153
node: any
@@ -173,6 +187,33 @@ function parseHtml(content: string): any[] {
173187
return domTree;
174188
}
175189

190+
function applyTemplateParametersToNodes(
191+
nodes: any[] | undefined,
192+
parameterValues: Map<string, string>
193+
) {
194+
if (!nodes) {
195+
return;
196+
}
197+
198+
for (const node of nodes) {
199+
if (node?.attribs) {
200+
for (const [attributeName, attributeValue] of Object.entries(node.attribs)) {
201+
if (typeof attributeValue === "string") {
202+
node.attribs[attributeName] = applyTemplateParameters(attributeValue, parameterValues);
203+
}
204+
}
205+
}
206+
207+
applyTemplateParametersToNodes(node?.children, parameterValues);
208+
}
209+
}
210+
211+
function applyTemplateParameters(value: string, parameterValues: Map<string, string>): string {
212+
return value.replace(/{{\s*([^#\/^}\s]+)\s*}}/g, (match, parameterName: string) => (
213+
parameterValues.has(parameterName) ? parameterValues.get(parameterName) ?? "" : match
214+
));
215+
}
216+
176217
function tryGetMtime(targetPath: string): number | undefined {
177218
try {
178219
return fs.statSync(targetPath).mtimeMs;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<qp-root>
2+
<qp-include
3+
url="src/test/fixtures/includes/form-contact-document.html"
4+
fs-id="contactPanel"
5+
contact-view="ContactView"
6+
>
7+
<field modify="#contactPanel [name='Email']" after="#contactPanel [name='Attention']"></field>
8+
</qp-include>
9+
</qp-root>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<qp-root>
2+
<qp-include
3+
url="src/test/fixtures/includes/form-contact-document.html"
4+
fs-id="contactPanel"
5+
contact-view="ContactView"
6+
>
7+
<field modify="#contactPanel [name='MissingEmail']" after="#contactPanel [name='Attention']"></field>
8+
</qp-include>
9+
</qp-root>

acumate-plugin/src/test/suite/htmlValidation.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,27 @@ describe('HTML validation diagnostics', () => {
357357
);
358358
});
359359

360+
it('validates qp-include child selectors after applying include parameters', async () => {
361+
const document = await openFixtureDocument('TestParameterizedIncludeSelectors.html');
362+
await validateHtmlFile(document);
363+
const diagnostics = AcuMateContext.HtmlValidator?.get(document.uri) ?? [];
364+
assert.strictEqual(
365+
diagnostics.filter(d => d.message.includes('selector')).length,
366+
0,
367+
'Expected no selector diagnostics for parameterized qp-include selectors'
368+
);
369+
});
370+
371+
it('reports invalid qp-include modify selectors after applying include parameters', async () => {
372+
const document = await openFixtureDocument('TestParameterizedIncludeSelectorsInvalid.html');
373+
await validateHtmlFile(document);
374+
const diagnostics = AcuMateContext.HtmlValidator?.get(document.uri) ?? [];
375+
assert.ok(
376+
diagnostics.some(d => d.message.includes('modify selector') && d.message.includes('MissingEmail')),
377+
'Expected diagnostic for invalid parameterized qp-include modify selector'
378+
);
379+
});
380+
360381
it('accepts qp-template name values defined by ScreenTemplates', async () => {
361382
const document = await openFixtureDocument('TestQpTemplate.html');
362383
await validateHtmlFile(document);

0 commit comments

Comments
 (0)