From e7efd04b423c643e0dfa6ac194e6c91c799b3a33 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:07:28 +0000 Subject: [PATCH 1/4] Initial plan From 445946e717c78f1bc6ee31201132eaa08e438830 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:20:08 +0000 Subject: [PATCH 2/4] Implement better error messaging for incorrect XML tag casing Co-authored-by: TwitchBronBron <2544493+TwitchBronBron@users.noreply.github.com> --- src/DiagnosticMessages.ts | 5 ++++ src/parser/SGParser.spec.ts | 52 +++++++++++++++++++++++++++++++++++++ src/parser/SGParser.ts | 22 ++++++++++++---- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/DiagnosticMessages.ts b/src/DiagnosticMessages.ts index 7f9f3f975..5e3ff19bc 100644 --- a/src/DiagnosticMessages.ts +++ b/src/DiagnosticMessages.ts @@ -354,6 +354,11 @@ export let DiagnosticMessages = { code: 1065, severity: DiagnosticSeverity.Error }), + xmlTagCaseMismatch: (tagName: string, expectedTagName: string) => ({ + message: `Tag '${tagName}' must be all lower case. Use '${expectedTagName}' instead.`, + code: 1143, + severity: DiagnosticSeverity.Error + }), expectedStatementOrFunctionCallButReceivedExpression: () => ({ message: `Expected statement or function call but instead found expression`, code: 1066, diff --git a/src/parser/SGParser.spec.ts b/src/parser/SGParser.spec.ts index 22f7f451e..d4963ce0a 100644 --- a/src/parser/SGParser.spec.ts +++ b/src/parser/SGParser.spec.ts @@ -113,6 +113,58 @@ describe('SGParser', () => { }); }); + it('Adds error when incorrect casing is used for children tag', () => { + const parser = new SGParser(); + parser.parse( + 'pkg:/components/ParentScene.xml', trim` + + + + + + `); + expect(parser.diagnostics).to.be.lengthOf(1); + expect(parser.diagnostics[0]).to.deep.include({ + ...DiagnosticMessages.xmlTagCaseMismatch('Children', 'children'), + range: Range.create(2, 5, 2, 13) + }); + }); + + it('Adds error when incorrect casing is used for interface tag', () => { + const parser = new SGParser(); + parser.parse( + 'pkg:/components/ParentScene.xml', trim` + + + + + + + `); + expect(parser.diagnostics).to.be.lengthOf(1); + expect(parser.diagnostics[0]).to.deep.include({ + ...DiagnosticMessages.xmlTagCaseMismatch('Interface', 'interface'), + range: Range.create(2, 5, 2, 14) + }); + }); + + it('Adds error when incorrect casing is used for script tag', () => { + const parser = new SGParser(); + parser.parse( + 'pkg:/components/ParentScene.xml', trim` + + + + + `); + program.validate(); + expectDiagnostics(program, [ + { + ...DiagnosticMessages.xmlTagCaseMismatch('Script', 'script'), + range: Range.create(2, 5, 2, 11) + } + ]); + }); + + it('Adds error when incorrect casing is used for field tag in interface', () => { + file = program.setFile('components/ChildScene.xml', trim` + + + + + + + `); + program.validate(); + expectDiagnostics(program, [ + { + ...DiagnosticMessages.xmlTagCaseMismatch('Field', 'field'), + range: Range.create(3, 9, 3, 14) + } + ]); + }); + + it('Does not add error for correctly cased tags', () => { + file = program.setFile('components/ChildScene.xml', trim` + + + + + + + + + + `); + program.validate(); + expectZeroDiagnostics(program); + }); + + it('Catches casing issues when plugins modify AST after parsing', () => { + // This is the test requested in the comment - plugins modify tag casing and validation catches it + program.plugins.add({ + name: 'test-plugin-modify-casing', + afterFileParse: (file) => { + if (isXmlFile(file) && file.parser.ast.component?.children) { + // Plugin modifies the children tag to incorrect casing + file.parser.ast.component.children.tag.text = 'Children'; + } + } + }); + + file = program.setFile('components/ChildScene.xml', trim` + + + + + + `); + program.validate(); + expectDiagnostics(program, [ + { + ...DiagnosticMessages.xmlTagCaseMismatch('Children', 'children'), + range: Range.create(2, 5, 2, 13) + } + ]); + }); + }); }); diff --git a/src/parser/SGParser.spec.ts b/src/parser/SGParser.spec.ts index d4963ce0a..2ef9060c8 100644 --- a/src/parser/SGParser.spec.ts +++ b/src/parser/SGParser.spec.ts @@ -113,7 +113,7 @@ describe('SGParser', () => { }); }); - it('Adds error when incorrect casing is used for children tag', () => { + it('Does not add case mismatch error during parsing (now handled in validation)', () => { const parser = new SGParser(); parser.parse( 'pkg:/components/ParentScene.xml', trim` @@ -124,14 +124,10 @@ describe('SGParser', () => { `); - expect(parser.diagnostics).to.be.lengthOf(1); - expect(parser.diagnostics[0]).to.deep.include({ - ...DiagnosticMessages.xmlTagCaseMismatch('Children', 'children'), - range: Range.create(2, 5, 2, 13) - }); + expect(parser.diagnostics).to.be.lengthOf(0); }); - it('Adds error when incorrect casing is used for interface tag', () => { + it('Does not add case mismatch error during parsing for interface tag (now handled in validation)', () => { const parser = new SGParser(); parser.parse( 'pkg:/components/ParentScene.xml', trim` @@ -142,14 +138,10 @@ describe('SGParser', () => { `); - expect(parser.diagnostics).to.be.lengthOf(1); - expect(parser.diagnostics[0]).to.deep.include({ - ...DiagnosticMessages.xmlTagCaseMismatch('Interface', 'interface'), - range: Range.create(2, 5, 2, 14) - }); + expect(parser.diagnostics).to.be.lengthOf(0); }); - it('Adds error when incorrect casing is used for script tag', () => { + it('Does not add case mismatch error during parsing for script tag (now handled in validation)', () => { const parser = new SGParser(); parser.parse( 'pkg:/components/ParentScene.xml', trim` @@ -158,11 +150,7 @@ describe('SGParser', () => {