format-support.mjs 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import { readFile } from 'node:fs/promises'
  2. import { join } from 'node:path'
  3. export function quotedValues(text) {
  4. return [...text.matchAll(/'([^']+)'/g)].map(match => match[1])
  5. }
  6. export async function readCoreRendererDefinitions(sourceRoot) {
  7. const formatSourcePath = join(sourceRoot, 'packages', 'core', 'src', 'registry', 'formats.ts')
  8. const source = await readFile(formatSourcePath, 'utf8')
  9. const constants = new Map()
  10. const constantPattern = /export const ([A-Z0-9_]+) = \[([\s\S]*?)\] as const;/g
  11. for (const match of source.matchAll(constantPattern)) {
  12. constants.set(match[1], quotedValues(match[2]))
  13. }
  14. const renderers = new Map()
  15. const rendererPattern = /\{\s*id:\s*'([^']+)'([\s\S]*?)capabilities:/g
  16. for (const match of source.matchAll(rendererPattern)) {
  17. const id = match[1]
  18. const body = match[2]
  19. const extensionMatch = body.match(/extensions:\s*(\[[\s\S]*?\]|[A-Z0-9_]+)/)
  20. if (!extensionMatch) {
  21. throw new Error(`Renderer ${id} does not declare extensions`)
  22. }
  23. const expression = extensionMatch[1].trim()
  24. const extensions = expression.startsWith('[')
  25. ? quotedValues(expression)
  26. : constants.get(expression)
  27. if (!extensions?.length) {
  28. throw new Error(`Renderer ${id} references unknown extension list ${expression}`)
  29. }
  30. renderers.set(id, {
  31. id,
  32. extensions: new Set(extensions),
  33. extensionList: extensions
  34. })
  35. }
  36. if (!renderers.size) {
  37. throw new Error('No renderer definitions were detected')
  38. }
  39. return renderers
  40. }
  41. export function summarizeRendererSupport(renderers) {
  42. const extensionOwners = new Map()
  43. const duplicateExtensions = []
  44. let rawExtensionCount = 0
  45. for (const renderer of renderers.values()) {
  46. rawExtensionCount += renderer.extensionList.length
  47. for (const extension of renderer.extensionList) {
  48. const normalized = extension.toLowerCase()
  49. const owner = extensionOwners.get(normalized)
  50. if (owner) {
  51. duplicateExtensions.push({
  52. extension: normalized,
  53. owners: [owner, renderer.id]
  54. })
  55. continue
  56. }
  57. extensionOwners.set(normalized, renderer.id)
  58. }
  59. }
  60. return {
  61. rendererCount: renderers.size,
  62. rawExtensionCount,
  63. uniqueExtensionCount: extensionOwners.size,
  64. duplicateExtensions,
  65. extensions: [...extensionOwners.keys()].sort()
  66. }
  67. }