| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import { existsSync } from 'node:fs'
- import { readFile } from 'node:fs/promises'
- import { extname, join } from 'node:path'
- import { readCoreRendererDefinitions } from './lib/format-support.mjs'
- const sourceRoot = process.cwd()
- const matrixPath = join(sourceRoot, 'ecosystem', 'smoke-matrix.json')
- const wrapperManifestPath = join(sourceRoot, 'ecosystem', 'wrappers.json')
- const examplesRoot = join(sourceRoot, 'apps', 'viewer-demo', 'public', 'example')
- const vitePluginSourcePath = join(sourceRoot, 'packages', 'presets', 'vite-plugin', 'src', 'index.ts')
- const pluginEnginePackages = new Set([
- '@file-viewer/pptx',
- '@file-viewer/eda-layout',
- '@file-viewer/eda-orcad',
- '@file-viewer/geometry-engine'
- ])
- function fail(message) {
- throw new Error(`[smoke-matrix] ${message}`)
- }
- async function readJson(path) {
- return JSON.parse(await readFile(path, 'utf8'))
- }
- function assertUnique(items, label, selectId = item => item.id) {
- const seen = new Set()
- for (const item of items) {
- const id = selectId(item)
- if (!id) {
- fail(`${label} contains an item without id`)
- }
- if (seen.has(id)) {
- fail(`${label} contains duplicate id ${id}`)
- }
- seen.add(id)
- }
- }
- function assertSampleExists(sample, label) {
- const samplePath = join(examplesRoot, sample)
- if (!existsSync(samplePath)) {
- fail(`${label} sample does not exist: apps/viewer-demo/public/example/${sample}`)
- }
- }
- function sampleExtension(sample, explicitExtension) {
- if (explicitExtension) {
- return explicitExtension.toLowerCase()
- }
- return extname(sample).replace(/^\./, '').toLowerCase()
- }
- function quotedValues(text) {
- return [...String(text).matchAll(/'([^']+)'/g)].map(match => match[1])
- }
- async function readViteRendererPackageDescriptors() {
- const source = await readFile(vitePluginSourcePath, 'utf8')
- const rendererModuleMatch = source.match(
- /const rendererModules:[\s\S]*?=\s*\[([\s\S]*?)\]\s*\n\nconst descriptorsById/
- )
- if (!rendererModuleMatch) {
- fail('Could not find rendererModules in @file-viewer/vite-plugin source')
- }
- const descriptors = new Map()
- const rendererObjectPattern = /\{\s*id:\s*'([^']+)'([\s\S]*?)chunkName:\s*'[^']+'\s*\}/g
- for (const match of rendererModuleMatch[1].matchAll(rendererObjectPattern)) {
- const id = match[1]
- const body = match[2]
- const packageName = body.match(/packageName:\s*'([^']+)'/)?.[1]
- const rendererIdsSource = body.match(/rendererIds:\s*\[([\s\S]*?)\]/)?.[1]
- if (!packageName || !rendererIdsSource) {
- fail(`Could not parse renderer package descriptor for ${id}`)
- }
- if (descriptors.has(packageName)) {
- fail(`Vite renderer package descriptor contains duplicate package ${packageName}`)
- }
- const rendererIds = quotedValues(rendererIdsSource)
- if (!rendererIds.length) {
- fail(`Vite renderer package descriptor ${packageName} does not expose renderer ids`)
- }
- descriptors.set(packageName, {
- id,
- packageName,
- rendererIds
- })
- }
- if (!descriptors.size) {
- fail('No Vite renderer package descriptors were detected')
- }
- return descriptors
- }
- function assertRendererSample(entry, label) {
- const renderer = renderers.get(entry.rendererId)
- if (!renderer) {
- fail(`${label} references unknown renderer ${entry.rendererId}`)
- }
- const extension = sampleExtension(entry.sample, entry.extension)
- if (!renderer.extensions.has(extension)) {
- fail(`${label} extension ${extension} is not supported by renderer ${entry.rendererId}`)
- }
- assertSampleExists(entry.sample, label)
- }
- const [matrix, wrapperManifest, renderers, viteRendererPackages] = await Promise.all([
- readJson(matrixPath),
- readJson(wrapperManifestPath),
- readCoreRendererDefinitions(sourceRoot),
- readViteRendererPackageDescriptors()
- ])
- if (matrix.schemaVersion !== 1) {
- fail(`Unsupported schemaVersion ${matrix.schemaVersion}`)
- }
- const surfaces = new Set(matrix.surfaces || [])
- for (const surface of ['main-demo', 'compare-page', 'script-tag']) {
- if (!surfaces.has(surface)) {
- fail(`Missing required smoke surface ${surface}`)
- }
- }
- assertUnique(matrix.wrappers || [], 'wrappers')
- const matrixWrappers = new Map((matrix.wrappers || []).map(wrapper => [wrapper.id, wrapper]))
- for (const wrapper of wrapperManifest.wrappers) {
- const matrixWrapper = matrixWrappers.get(wrapper.id)
- if (!matrixWrapper) {
- fail(`Smoke matrix is missing wrapper ${wrapper.id}`)
- }
- if (matrixWrapper.packageName !== wrapper.packageName) {
- fail(`Wrapper ${wrapper.id} package mismatch: ${matrixWrapper.packageName} !== ${wrapper.packageName}`)
- }
- if (!surfaces.has(matrixWrapper.surface)) {
- fail(`Wrapper ${wrapper.id} references unknown surface ${matrixWrapper.surface}`)
- }
- }
- assertUnique(matrix.cases || [], 'cases')
- const coveredRendererIds = new Set()
- const coveredFamilies = new Set()
- for (const smokeCase of matrix.cases || []) {
- assertRendererSample(smokeCase, `Case ${smokeCase.id}`)
- if (!Array.isArray(smokeCase.surfaces) || !smokeCase.surfaces.length) {
- fail(`Case ${smokeCase.id} must declare at least one surface`)
- }
- for (const surface of smokeCase.surfaces) {
- if (!surfaces.has(surface)) {
- fail(`Case ${smokeCase.id} references unknown surface ${surface}`)
- }
- }
- if (!Array.isArray(smokeCase.assertions) || !smokeCase.assertions.length) {
- fail(`Case ${smokeCase.id} must declare at least one assertion`)
- }
- coveredRendererIds.add(smokeCase.rendererId)
- coveredFamilies.add(smokeCase.family)
- }
- if (matrix.coverage?.requireAllRendererIds) {
- for (const rendererId of renderers.keys()) {
- if (!coveredRendererIds.has(rendererId)) {
- fail(`Smoke matrix does not cover renderer ${rendererId}`)
- }
- }
- }
- let coveredRendererPackageCount = 0
- if (matrix.coverage?.requireAllRendererPackages) {
- for (const rendererPackage of wrapperManifest.renderers || []) {
- if (pluginEnginePackages.has(rendererPackage.packageName)) {
- continue
- }
- const descriptor = viteRendererPackages.get(rendererPackage.packageName)
- if (!descriptor) {
- fail(`Smoke matrix cannot resolve renderer package ${rendererPackage.packageName} through @file-viewer/vite-plugin`)
- }
- const missingRendererIds = descriptor.rendererIds.filter(rendererId => !coveredRendererIds.has(rendererId))
- if (missingRendererIds.length) {
- fail(
- `Smoke matrix does not cover renderer package ${rendererPackage.packageName}; missing renderer ids: ${missingRendererIds.join(', ')}`
- )
- }
- coveredRendererPackageCount += 1
- }
- }
- for (const family of matrix.coverage?.requiredFormatFamilies || []) {
- if (!coveredFamilies.has(family)) {
- fail(`Smoke matrix does not cover required family ${family}`)
- }
- }
- assertUnique(matrix.wrapperCases || [], 'wrapperCases')
- const wrapperCaseIds = new Set()
- for (const wrapperCase of matrix.wrapperCases || []) {
- if (!matrixWrappers.has(wrapperCase.wrapperId)) {
- fail(`Wrapper case ${wrapperCase.id} references unknown wrapper ${wrapperCase.wrapperId}`)
- }
- if (!surfaces.has(wrapperCase.surface)) {
- fail(`Wrapper case ${wrapperCase.id} references unknown surface ${wrapperCase.surface}`)
- }
- assertSampleExists(wrapperCase.sample, `Wrapper case ${wrapperCase.id}`)
- wrapperCaseIds.add(wrapperCase.wrapperId)
- }
- for (const wrapper of wrapperManifest.wrappers) {
- if (!wrapperCaseIds.has(wrapper.id)) {
- fail(`Smoke matrix does not include a wrapper case for ${wrapper.id}`)
- }
- }
- const requiredWrapperFamilies = matrix.wrapperCoverage?.requiredFamilies || []
- assertUnique(requiredWrapperFamilies, 'wrapperCoverage.requiredFamilies', item => item.family)
- if (matrix.wrapperCoverage?.requireEveryWrapper && !requiredWrapperFamilies.length) {
- fail('wrapperCoverage.requireEveryWrapper is enabled but no requiredFamilies were declared')
- }
- for (const family of requiredWrapperFamilies) {
- assertRendererSample(family, `Wrapper required family ${family.family}`)
- if (!Array.isArray(family.assertions) || !family.assertions.length) {
- fail(`Wrapper required family ${family.family} must declare at least one assertion`)
- }
- }
- let wrapperTargetCount = 0
- if (matrix.wrapperCoverage?.requireEveryWrapper) {
- for (const wrapper of wrapperManifest.wrappers) {
- const matrixWrapper = matrixWrappers.get(wrapper.id)
- if (!matrixWrapper) {
- fail(`Wrapper coverage cannot find wrapper ${wrapper.id}`)
- }
- for (const family of requiredWrapperFamilies) {
- wrapperTargetCount += 1
- }
- }
- }
- console.log(
- `[smoke-matrix] Verified ${matrix.cases.length} format cases, ${matrix.wrapperCases.length} wrapper cases, ${wrapperTargetCount} wrapper family targets, ${renderers.size} renderer pipelines, and ${coveredRendererPackageCount} renderer packages.`
- )
|