Skip to content

Commit 173aba7

Browse files
authored
feat: validate manifests (#996)
1 parent 4902d8b commit 173aba7

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

src/resolve/manifestResolver.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
import { XMLParser } from 'fast-xml-parser';
8+
import { XMLParser, XMLValidator } from 'fast-xml-parser';
99
import { ensureArray } from '@salesforce/kit';
10+
import { SfError } from '@salesforce/core';
1011
import { MetadataType, RegistryAccess } from '../registry';
1112
import { NodeFSTreeContainer, TreeContainer } from './treeContainers';
1213
import { MetadataComponent } from './types';
@@ -52,15 +53,22 @@ export class ManifestResolver {
5253
public async resolve(manifestPath: string): Promise<ResolveManifestResult> {
5354
const components: MetadataComponent[] = [];
5455

55-
const file = await this.tree.readFile(manifestPath);
56-
56+
const file = (await this.tree.readFile(manifestPath)).toString();
57+
const validateResult = XMLValidator.validate(file);
58+
if (validateResult !== true) {
59+
const error = new SfError(
60+
`Invalid manifest file: ${manifestPath}. ${validateResult.err.code}: ${validateResult.err.msg} (Line ${validateResult.err.line} Column ${validateResult.err.col})`,
61+
'InvalidManifest'
62+
);
63+
error.setData(validateResult.err);
64+
throw error;
65+
}
5766
const parser = new XMLParser({
5867
stopNodes: ['version'],
5968
// In order to preserve the .0 on the apiVersion skip parsing it
6069
numberParseOptions: { leadingZeros: false, hex: false, skipLike: /\.0$/ },
6170
});
62-
const parsedManifest: ParsedPackageManifest = (parser.parse(String(file)) as { Package: ParsedPackageManifest })
63-
.Package;
71+
const parsedManifest: ParsedPackageManifest = (parser.parse(file) as { Package: ParsedPackageManifest }).Package;
6472
const packageTypeMembers = ensureArray(parsedManifest.types);
6573
const apiVersion = parsedManifest.version;
6674

test/resolve/manifestResolver.test.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
66
*/
77

8-
import { expect } from 'chai';
8+
import { assert, expect } from 'chai';
99
import { createSandbox } from 'sinon';
1010
import {
1111
ManifestResolver,
@@ -80,6 +80,33 @@ describe('ManifestResolver', () => {
8080
expect(result.components).to.deep.equal(expected);
8181
});
8282

83+
it('should throw on invalid xml', async () => {
84+
const badManifest: VirtualFile = {
85+
name: 'bad-package.xml',
86+
data: Buffer.from(`<?xml version="1.0" encoding="UTF-8"?>
87+
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
88+
<<types>
89+
<members></members>
90+
<name></name>
91+
</types>
92+
<version>52.0</version>
93+
</Package>\n`),
94+
};
95+
const tree = new VirtualTreeContainer([
96+
{
97+
dirPath: '.',
98+
children: [badManifest],
99+
},
100+
]);
101+
const resolver = new ManifestResolver(tree);
102+
try {
103+
await resolver.resolve(badManifest.name);
104+
expect(true, 'expected invalid types definition error').to.be.false;
105+
} catch (error) {
106+
assert(error instanceof Error);
107+
expect(error.name).to.equal('InvalidManifest');
108+
}
109+
});
83110
it('should throw when type is empty', async () => {
84111
const badManifest: VirtualFile = {
85112
name: 'bad-package.xml',

0 commit comments

Comments
 (0)