From 63a55722f21bec5d90f3b59656361de2c3aef788 Mon Sep 17 00:00:00 2001 From: alex-ketch Date: Fri, 26 Mar 2021 12:07:58 -0400 Subject: [PATCH] feat(Vega): Detect Vega library and version being used --- src/codecs/vega/index.ts | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/codecs/vega/index.ts b/src/codecs/vega/index.ts index d44768cf0..961b8d260 100644 --- a/src/codecs/vega/index.ts +++ b/src/codecs/vega/index.ts @@ -15,20 +15,17 @@ let page: puppeteer.Page | undefined /** * Ensure that `page` is defined. */ -async function ensureVegaPage(): Promise { +async function ensureVegaPage(vegaScriptSrc: string): Promise { if (page) return page page = await puppeteer.page() - // TODO: This currently assumes the latest version of Vega dependency. - // We should instead try to derive the version from the mimeType await page.setContent(` - - + @@ -42,20 +39,38 @@ async function ensureVegaPage(): Promise { } const vegaMediaTypes = [ - 'application/vnd.vega', + // Custom and generic Vega mimetype used by Stencila during encoding + 'application/vnd.vega+json', // Altair MIME bundle types // @see https://iliatimofeev.github.io/altair-viz.github.io/user_guide/display_frontends.html#renderer-api - 'application/vnd.vegalite.v2+json', 'application/vnd.vegalite.v1+json', 'application/vnd.vega.v3+json', 'application/vnd.vega.v2+json', ] -export const vegaMediaType = 'application/vnd.vega' +export const vegaMediaType = 'application/vnd.vega+json' export const isVegaMediaType = (mimeType: string): boolean => vegaMediaTypes.includes(mimeType) +/** + * RegEx to parse a Vega Spec `$schema` url and find the library and version number used + * Group 1: library used `vega` or `vega-lite | vegalite` + * Group 2: version number used + */ +const VegaVersionRegEx = /(vega|vega-?lite)[/.]v([0-9]+(?:\.[0-9]){0,2})/ + +/** + * Given a string, attempts to find the Vega library (`vega` vs `vega-lite`) + * and the version being used. + * Falls back to `vega` and `latest`. + */ +const getVegaVersion = (input: string): [library: string, version: string] => { + const [, library = 'vega', version = 'latest'] = + VegaVersionRegEx.exec(input) ?? [] + return [library.replace('lite', '-lite'), version] +} + /** * Define a Vega object to obviate the need to //@ts-ignore within * the `page.evaluate` function below. @@ -85,7 +100,10 @@ export class VegaCodec extends Codec implements Codec { const json = await vfile.dump(file) const spec = JSON.parse(json) - const page = await ensureVegaPage() + const [library, version] = getVegaVersion(spec) + const vegaScriptSrc = `https://unpkg.com/${library}@${version}` + + const page = await ensureVegaPage(vegaScriptSrc) // Wait until all resources are loaded await page.waitForFunction('vegaEmbed !== undefined')