blob: e7b8521b8d072ff1edcbb9acf4a0f87bf865a2bd [file] [log] [blame]
/**
* @module skottie-compatibility-sk
* @description <h2><code>skottie-compatibility-sk</code></h2>
*
* <p>
* A skottie compatibility report. Reports the input lottie with various
* JSON schemas.
* </p>
*/
import { html } from 'lit/html.js';
import { define } from '../../../elements-sk/modules/define';
import { ElementSk } from '../../../infra-sk/modules/ElementSk';
import { LottieAnimation } from '../types';
import '../skottie-button-sk';
import { ProfileValidator, LottieError } from './profile-validator';
import { lottieSchema } from './schemas/lottie.schema';
import { lowPowerLottieProfileSchema } from './schemas/low-power-lottie-profile.schema';
type SchemaEntry = {
name: string;
validator: ProfileValidator;
featureErrorsOnly?: boolean;
};
export class SkottieCompatibilitySk extends ElementSk {
private _animation: LottieAnimation | null = null;
private schemas: SchemaEntry[] = [];
tabIndex = 0;
constructor() {
super(SkottieCompatibilitySk.template);
this.schemas = [
{
name: 'Low Power Profile (WIP)',
validator: new ProfileValidator(lowPowerLottieProfileSchema),
featureErrorsOnly: true,
},
{
name: 'Lottie Specfication 1.0 (WIP)',
validator: new ProfileValidator(lottieSchema),
},
];
}
connectedCallback() {
super.connectedCallback();
this._render();
}
disconnectedCallback() {
super.disconnectedCallback();
}
setTabIndex(tabIndex: number) {
this.tabIndex = tabIndex;
this._render();
}
private static tabContainer = (ele: SkottieCompatibilitySk) => html`
<div class="tab-container">
${ele.schemas.map((schema, index) => {
const errors = schema.validator.getErrors(
ele._animation,
schema.featureErrorsOnly
);
const resultSummary =
errors.length === 0 ? 'Pass' : `Fail (${errors.length})`;
return html`
<skottie-button-sk
id="Report-${index}"
@select=${() => ele.setTabIndex(index)}
type="outline"
.content=${`${schema.name} - ${resultSummary}`}
.classes=${ele.tabIndex === index ? ['active-tab'] : []}>
</skottie-button-sk>
`;
})}
</div>
`;
private static template = (ele: SkottieCompatibilitySk) => html`
<div>${this.tabContainer(ele)}</div>
<div>${this.report(ele)}</div>
`;
private static report = (ele: SkottieCompatibilitySk) => {
const tabIndex = ele.tabIndex;
const schema = ele.schemas[tabIndex];
const lottie = ele._animation;
const errors = schema.validator.getErrors(lottie, schema.featureErrorsOnly);
if (errors.length === 0) {
return html`<div class="pass-message">Pass</div>`;
}
if (schema.featureErrorsOnly) {
return this.featureErrorReport(schema, ele._animation);
}
return this.schemaReport(schema, ele._animation);
};
private static schemaReport(schema: SchemaEntry, lottie: any) {
const errors = schema.validator.getErrors(lottie, schema.featureErrorsOnly);
return html`
<table>
<tr>
<th>Element Name</th>
<th>JSON Path</th>
<th>Error</th>
<th>Details</th>
<th>Schema Path</th>
</tr>
${errors.map(
(error) =>
html`<tr>
<td>${`${error.nameHierarchy?.join(' > ')}`}</td>
<td>${error.instancePath}</td>
<td>${error.message}</td>
<td>${JSON.stringify(error.params)}</td>
<td>${error.schemaPath}</td>
</tr>`
)}
</table>
`;
}
private static featureErrorReport = (
schemaEntry: SchemaEntry,
lottie: any
) => {
const errors = schemaEntry.validator.getErrors(
lottie,
schemaEntry.featureErrorsOnly
);
const featureToErrorList: Map<string, LottieError[]> = errors.reduce(
(map, error) => {
const { featureCode } = error;
if (!featureCode) {
return map;
}
if (!map.get(featureCode)) {
map.set(featureCode, []);
}
map.get(featureCode)?.push(error);
return map;
},
new Map<string, LottieError[]>()
);
return html`<table>
<tr>
<th>Feature ID</th>
<th>Element Name</th>
<th>JSON Path</th>
</tr>
${[...featureToErrorList].map(([featureCode, errorList]) =>
errorList.map(
(error, index) => html`
<tr>
${index === 0
? html`<td class="feature-id-cell" rowspan=${errorList.length}>
<a
href="https://canilottie.com/${error.featureLink ??
error.featureCode}"
>${error.featureCode}</a
>
${error.featureLevel === 'partial'
? 'partially supported'
: 'not supported'}
${error.featureDetails
? html` <div>${error.featureDetails}</div> `
: null}
</td>`
: null}
<td>${error.nameHierarchy?.join(' > ')}</td>
<td>${error.instancePath}</td>
</tr>
`
)
)}
</table>`;
};
set animation(val: LottieAnimation) {
if (this._animation !== val) {
this._animation = val;
// Errors are persisted in each validator object
this.schemas.forEach((schema) => {
schema.validator.validate(this._animation);
});
this._render();
}
}
}
define('skottie-compatibility-sk', SkottieCompatibilitySk);