70 lines
4.5 KiB
JavaScript
70 lines
4.5 KiB
JavaScript
'use strict';
|
|
|
|
var fs = require('fs');
|
|
var path = require('path');
|
|
var root = path.resolve(__dirname, '..');
|
|
var passed = 0;
|
|
|
|
function read(file) { return fs.readFileSync(path.join(root, file), 'utf8'); }
|
|
function json(file) { return JSON.parse(read(file)); }
|
|
function assert(condition, message) { if (!condition) { throw new Error(message); } passed++; }
|
|
|
|
var packageJson = json('package.json');
|
|
var solution = json('config/package-solution.json').solution;
|
|
var config = json('config/config.json');
|
|
var manifest = json('src/webparts/accordion/AccordionWebPart.manifest.json');
|
|
var webPart = read('src/webparts/accordion/AccordionWebPart.ts');
|
|
var component = read('src/webparts/accordion/components/Accordion.tsx');
|
|
var sanitizer = read('src/webparts/accordion/AccordionHtmlSanitizer.ts');
|
|
var styles = read('src/webparts/accordion/components/Accordion.module.scss');
|
|
|
|
assert(packageJson.version === '1.2.1', 'Package version must be 1.2.1.');
|
|
assert(solution.version === '1.2.1.0', 'Solution version must be 1.2.1.0.');
|
|
assert(solution.includeClientSideAssets === true, 'Client-side assets must be included.');
|
|
assert(solution.skipFeatureDeployment === true, 'Solution must support central deployment.');
|
|
assert(packageJson.name === 'accordion-web-part' && solution.name === 'accordion-web-part' &&
|
|
solution.title === 'accordion-web-part', 'Accordion package naming is inconsistent.');
|
|
assert(json('config/package-solution.json').paths.zippedPackage === 'solution/accordion-web-part.sppkg',
|
|
'Accordion package file name is inconsistent.');
|
|
assert(manifest.componentType === 'WebPart', 'Component must be a web part.');
|
|
assert(!!config.bundles['accordion-web-part'], 'Accordion bundle is missing.');
|
|
assert(webPart.indexOf("PropertyPaneDropdown('listId'") >= 0, 'Dynamic list selection is missing.');
|
|
assert(webPart.indexOf("PropertyPaneTextField('title'") >= 0 &&
|
|
component.indexOf('styles.webPartHeading') >= 0,
|
|
'Configurable web part title is missing.');
|
|
assert(webPart.indexOf("String(this.properties.title || '').trim()") >= 0,
|
|
'An empty web part title must remain hidden.');
|
|
assert(webPart.indexOf("PropertyPaneDropdown('contentField'") >= 0, 'Dynamic content field selection is missing.');
|
|
assert(webPart.indexOf("PropertyPaneDropdown('categoryField'") >= 0, 'Category field selection is missing.');
|
|
assert(webPart.indexOf("PropertyPaneDropdown('selectedCategory'") >= 0, 'Category value filter is missing.');
|
|
assert(read('src/webparts/accordion/AccordionDataService.ts').indexOf('getCategoryValues') >= 0,
|
|
'Dynamic category values are missing.');
|
|
var dataService = read('src/webparts/accordion/AccordionDataService.ts');
|
|
var categoryValues = read('src/webparts/accordion/AccordionCategoryValues.ts');
|
|
assert(dataService.indexOf("'TaxonomyFieldType'") >= 0 &&
|
|
dataService.indexOf("'TaxonomyFieldTypeMulti'") >= 0 &&
|
|
dataService.indexOf('getAccordionCategoryValues') >= 0 &&
|
|
categoryValues.indexOf('entry.Label') >= 0 && categoryValues.indexOf("candidate.indexOf(';#')") >= 0,
|
|
'Managed Metadata category support is missing.');
|
|
assert(dataService.indexOf('FieldValuesAsText/') >= 0 &&
|
|
dataService.indexOf('itemCategoryValues') >= 0 && categoryValues.indexOf('splitPlainSemicolon') >= 0,
|
|
'Managed Metadata labels must be resolved instead of displaying WSS IDs.');
|
|
assert(dataService.indexOf("getbytitle('TaxonomyHiddenList')") >= 0 &&
|
|
dataService.indexOf('loadTaxonomyLabels') >= 0 &&
|
|
categoryValues.indexOf('replaceAccordionCategoryIds') >= 0,
|
|
'Numeric WSS IDs must be resolved through the site collection TaxonomyHiddenList.');
|
|
assert(component.indexOf('items[i].categories') >= 0 && component.indexOf('nameIndex') >= 0,
|
|
'Multi-value category grouping is missing.');
|
|
assert(component.indexOf("aria-expanded={open}") >= 0 && component.indexOf("role='region'") >= 0,
|
|
'Accessible accordion semantics are missing.');
|
|
assert(component.indexOf('sanitizeAccordionHtml(item.content)') >= 0, 'Rich text is not sanitized before rendering.');
|
|
var allowedTags = sanitizer.substring(sanitizer.indexOf('const AllowedTags'), sanitizer.indexOf('const DropContentTags'));
|
|
assert(allowedTags.indexOf("'script'") < 0 && allowedTags.indexOf("'img'") < 0 &&
|
|
sanitizer.indexOf("'script'") >= 0,
|
|
'Unsafe rich-text elements must be removed rather than allow-listed.');
|
|
['neutralPrimary', 'neutralLight', 'neutralLighter', 'themePrimary', 'white'].forEach(function (slot) {
|
|
assert(styles.indexOf('[theme: ' + slot + ', default:') >= 0, 'SharePoint theme slot is missing: ' + slot);
|
|
});
|
|
|
|
console.log('Accordion project validation passed:', passed);
|