Skip to content

Commit

Permalink
Merge pull request #936 from vega/next
Browse files Browse the repository at this point in the history
  • Loading branch information
kanitw authored Jun 13, 2022
2 parents 71dccd9 + 6509384 commit 8ad265b
Show file tree
Hide file tree
Showing 10 changed files with 1,819 additions and 1,737 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:
if: "!contains(github.event.head_commit.message, 'ci skip') && !contains(github.event.head_commit.message, 'skip ci')"

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: actions/setup-node@v2.5.1
- uses: actions/setup-node@v3
with:
registry-url: "https://registry.npmjs.org"
node-version: "16"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v2.5.1
uses: actions/setup-node@v3
with:
node-version: "16"

Expand All @@ -32,4 +32,4 @@ jobs:
run: yarn jest test/ --collectCoverage=true

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2.1.0
uses: codecov/codecov-action@v3.1.0
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

### Directly in the Browser

You can import Vega-Embed from a local copy or (as shown below) [from jsDelivr](https://www.jsdelivr.com/package/npm/vega-embed). Please replace `[VERSION]` with the correct [Vega](https://www.jsdelivr.com/package/npm/vega), [Vega-Lite](https://www.jsdelivr.com/package/npm/vega-lite), and [Vega-Embed](https://www.jsdelivr.com/package/npm/vega-embed) versions. We recommend that you specify the major versions (`vega@5`, `vega-lite@4`, `vega-embed@6`).
You can import Vega-Embed from a local copy or (as shown below) [from jsDelivr](https://www.jsdelivr.com/package/npm/vega-embed). Please replace `[VERSION]` with the correct [Vega](https://www.jsdelivr.com/package/npm/vega), [Vega-Lite](https://www.jsdelivr.com/package/npm/vega-lite), and [Vega-Embed](https://www.jsdelivr.com/package/npm/vega-embed) versions. We recommend that you specify the major versions (`vega@5`, `vega-lite@5`, `vega-embed@6`).

```html
<!DOCTYPE html>
Expand Down Expand Up @@ -159,6 +159,7 @@ var opt = {

formatLocale: ...,
timeFormatLocale: ...,
expressionFunctions: ...,

ast: ...,
expr: ...,
Expand Down Expand Up @@ -198,6 +199,7 @@ var opt = {
| `downloadFileName` | String | Sets the file name (default: `visualization`) for charts downloaded using the `png` or `svg` action. |
| `formatLocale` | Object | Sets the default locale definition for number formatting. See the [d3-format locale collection](https://github.com/d3/d3-format/tree/master/locale) for definition files for a variety of languages. Note that this is a global setting. |
| `timeFormatLocale` | Object | Sets the default locale definition for date/time formatting. See the [d3-time-format locale collection](https://github.com/d3/d3-time-format/tree/master/locale) for definition files for a variety of languages. Note that this is a global setting. |
| `expressionFunctions` | Object | Sets custom expression functions. Maps a function name to a JavaScript `function`, or an Object with the `fn`, and `visitor` parameters. See [Vega Expression Functions](https://vega.github.io/vega/docs/api/extensibility/#expressionFunction) for more information. |
| `ast` | Boolean | Generate an [Abstract Syntax Tree (AST)](https://en.wikipedia.org/wiki/Abstract_syntax_tree) instead of expressions and use an interpreter instead of native evaluation. While the interpreter is slower, it adds support for Vega expressions that are [Content Security Policy (CSP)](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)-compliant. |
| `expr` | Object | Custom Vega Expression interpreter. |
| `viewClass` | Class | Class which extends [Vega `View`](https://vega.github.io/vega/docs/api/view/#view) for custom rendering. |
Expand Down
36 changes: 18 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,39 @@
"patches"
],
"devDependencies": {
"@auto-it/conventional-commits": "^10.32.6",
"@auto-it/first-time-contributor": "^10.32.6",
"@babel/plugin-transform-runtime": "^7.17.0",
"@rollup/plugin-commonjs": "21.0.1",
"@auto-it/conventional-commits": "^10.37.1",
"@auto-it/first-time-contributor": "^10.37.1",
"@babel/plugin-transform-runtime": "^7.18.2",
"@rollup/plugin-commonjs": "22.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-node-resolve": "^13.3.0",
"@types/semver": "^7.3.9",
"auto": "^10.32.6",
"browser-sync": "^2.27.7",
"concurrently": "^7.0.0",
"auto": "^10.37.1",
"browser-sync": "^2.27.10",
"concurrently": "^7.2.1",
"del-cli": "^4.0.1",
"jest-canvas-mock": "^2.3.1",
"jest-canvas-mock": "^2.4.0",
"patch-package": "^6.4.7",
"postinstall-postinstall": "^2.1.0",
"rollup": "2.67.2",
"rollup": "2.75.6",
"rollup-plugin-bundle-size": "^1.0.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-ts": "^2.0.5",
"sass": "^1.49.7",
"typescript": "^4.5.5",
"vega": "^5.21.0",
"vega-lite": "^5.0.0",
"rollup-plugin-ts": "^3.0.0",
"sass": "^1.52.1",
"typescript": "^4.7.2",
"vega": "^5.22.1",
"vega-lite": "^5.2.0",
"vega-lite-dev-config": "^0.20.0"
},
"peerDependencies": {
"vega": "^5.21.0",
"vega-lite": "*"
},
"dependencies": {
"fast-json-patch": "^3.1.0",
"fast-json-patch": "^3.1.1",
"json-stringify-pretty-compact": "^3.0.0",
"semver": "^7.3.5",
"tslib": "^2.3.1",
"semver": "^7.3.7",
"tslib": "^2.4.0",
"vega-interpreter": "^1.0.4",
"vega-schema-url-parser": "^2.2.0",
"vega-themes": "^2.10.0",
Expand Down
72 changes: 0 additions & 72 deletions rollup.config.js

This file was deleted.

72 changes: 72 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import resolve from "@rollup/plugin-node-resolve";
import ts from "rollup-plugin-ts";
import bundleSize from "rollup-plugin-bundle-size";
import { terser } from "rollup-plugin-terser";

import pkg from "./package.json" assert { type: "json" };

const plugins = (browserslist, declaration) => [
resolve(),
commonjs(),
json(),
ts({
tsconfig: (resolvedConfig) => ({
...resolvedConfig,
declaration,
declarationMap: declaration,
}),
transpiler: "babel",
babelConfig: { presets: ["@babel/preset-env"] },
browserslist,
}),
bundleSize(),
];

const outputs = [
{
input: "src/embed.ts",
output: {
file: "build/vega-embed.module.js",
format: "esm",
sourcemap: true,
},
plugins: plugins(undefined, true),
external: [...Object.keys(pkg.dependencies), ...Object.keys(pkg.peerDependencies)],
},
];

for (const build of ["es5", "es6"]) {
const buildFolder = build === "es5" ? "build-es5" : "build";
outputs.push({
input: "src/index.ts",
output: [
{
file: `${buildFolder}/vega-embed.js`,
format: "umd",
sourcemap: true,
name: "vegaEmbed",
globals: {
vega: "vega",
"vega-lite": "vegaLite",
},
},
{
file: `${buildFolder}/vega-embed.min.js`,
format: "umd", // cannot do iife because rollup generates code that expects Vega-Lite to be present
sourcemap: true,
name: "vegaEmbed",
globals: {
vega: "vega",
"vega-lite": "vegaLite",
},
plugins: [terser()],
},
],
plugins: plugins(build === "es5" ? "defaults" : "defaults and not IE 11", false),
external: ["vega", "vega-lite"],
});
}

export default outputs;
20 changes: 16 additions & 4 deletions src/embed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import * as themes from 'vega-themes';
import {Handler, Options as TooltipOptions} from 'vega-tooltip';
import post from './post';
import embedStyle from './style';
import {Config, Mode} from './types';
import {Config, ExpressionFunction, Mode} from './types';
import {mergeDeep} from './util';
import pkg from '../package.json';

Expand Down Expand Up @@ -91,6 +91,7 @@ export interface EmbedOptions<S = string, R = Renderers> {
downloadFileName?: string;
formatLocale?: Record<string, unknown>;
timeFormatLocale?: Record<string, unknown>;
expressionFunctions?: ExpressionFunction;
ast?: boolean;
expr?: typeof expressionInterpreter;
viewClass?: typeof View;
Expand Down Expand Up @@ -163,8 +164,7 @@ export function guessMode(spec: VisualizationSpec, providedMode?: Mode): Mode {
const parsed = schemaParser(spec.$schema);
if (providedMode && providedMode !== parsed.library) {
console.warn(
`The given visualization spec is written in ${NAMES[parsed.library]}, but mode argument sets ${
NAMES[providedMode] ?? providedMode
`The given visualization spec is written in ${NAMES[parsed.library]}, but mode argument sets ${NAMES[providedMode] ?? providedMode
}.`
);
}
Expand Down Expand Up @@ -352,6 +352,18 @@ async function _embed(
vega.timeFormatLocale(opts.timeFormatLocale);
}

// Set custom expression functions
if (opts.expressionFunctions) {
for (const name in opts.expressionFunctions) {
const expressionFunction = opts.expressionFunctions[name];
if ('fn' in expressionFunction) {
vega.expressionFunction(name, expressionFunction.fn, expressionFunction['visitor']);
} else if (expressionFunction instanceof Function) {
vega.expressionFunction(name, expressionFunction);
}
}
}

const {ast} = opts;

// Do not apply the config to Vega when we have already applied it to Vega-Lite.
Expand Down Expand Up @@ -384,7 +396,7 @@ async function _embed(
const handler = isTooltipHandler(opts.tooltip)
? opts.tooltip
: // user provided boolean true or tooltip options
new Handler(opts.tooltip === true ? {} : opts.tooltip).call;
new Handler(opts.tooltip === true ? {} : opts.tooltip).call;

view.tooltip(handler);
}
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {Config as VlConfig} from 'vega-lite';
export type Mode = 'vega' | 'vega-lite';
export type Config = VlConfig | VgConfig;

export type ExpressionFunction = Record<string, any | {fn: any; visitor?: any}>;

export interface MessageData {
spec: string;
file?: unknown;
Expand Down
54 changes: 54 additions & 0 deletions test/embed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ const vlSpec: TopLevelSpec = {

const vgSpec = compile(vlSpec).spec;

const vlSpecCustomFunction: TopLevelSpec = {
data: {values: [1, 2, 3]},
encoding: {
y: {
axis: {
format: '',
formatType: 'simpleFunction',
},
},
},
mark: 'point',
transform: [
{calculate: 'simpleFunction()', as: 'result1'},
{calculate: 'functionWithVisitor()', as: 'result2'},
],
};

test('embed returns result', async () => {
const el = document.createElement('div');
const result = await embed(el, vlSpec);
Expand Down Expand Up @@ -242,6 +259,43 @@ test('can set locale', async () => {
expect(result).toBeTruthy();
});

test('throws error when expressionFunction does not exist', async () => {
const el = document.createElement('div');

const getErrorFromEmbed = async () => {
try {
await embed(el, vlSpecCustomFunction);

throw Error('No Thrown Error');
} catch (e: any) {
return e;
}
};

const error = await getErrorFromEmbed();
expect(error.message).toBe('Unrecognized function: simpleFunction');
});

test('can set and use expressionFunctions', async () => {
const el = document.createElement('div');
const result = await embed(el, vlSpecCustomFunction, {
expressionFunctions: {
simpleFunction: () => {
return 'test';
},
functionWithVisitor: {
fn: () => {
return 'test';
},
visitor: () => {
return 'test';
},
},
},
});
expect(result).toBeTruthy();
});

test('can set tooltip theme', async () => {
const el = document.createElement('div');
const result = await embed(el, vlSpec, {
Expand Down
Loading

0 comments on commit 8ad265b

Please sign in to comment.