Published
Edited
Mar 12, 2019
Importers
Insert cell
Insert cell
// Note that the latest version of "Imports: tips and tricks" can't be imported because there's a syntax error
// which breaks the module object generated by the API.
// In particular, see this element of the variables array in m0:
// {
// value: throw new SyntaxError("Unexpected keyword 'viewof' (1:24)")
// },
// moduleTest = importModule('https://api.observablehq.com/@bryangingechen/imports-tips-and-tricks.js')
moduleTest = importModule('https://api.observablehq.com/@bryangingechen/imports-tips-and-tricks@556.js')
Insert cell
moduleTestSource = fromV1(moduleTest)
Insert cell
Insert cell
moduleTestSource[26].value
Insert cell
Insert cell
moduleScratch = importModule('https://api.observablehq.com/d/10ffc3f281b8b72f@745.js')
Insert cell
viewof moduleScratch1 = {
const hello = html`<div style="height:200px; overflow:scroll;border: thick double #555;padding:25px">`;
const fV1 = fromV1(moduleScratch);
const coord = await toV1(({id:'10ffc3f281b8b72f', version:'745', nodes:fV1}));
const moduleCoord = await importModule(`data:text/javascript;base64,${utoa(coord)}`);
observable.Runtime.load(moduleCoord.default, observable.Inspector.into(hello));
hello.value = moduleCoord;
return hello;
}
Insert cell
Insert cell
{
const hello = html`<div style="height:200px; overflow:scroll;border: thick double #555;padding:25px">`;
const fV1 = fromV1(moduleScratch1);
const coord = await toV1(({id:'10ffc3f281b8b72f', version:'745', nodes:fV1}));
const moduleCoord = await importModule(`data:text/javascript;base64,${utoa(coord)}`);
observable.Runtime.load(moduleCoord.default, observable.Inspector.into(hello));
return hello;
}
Insert cell
Insert cell
function fromV1(module) {
const {default:{modules:[{variables}]}} = module;
const nodes = [];

function pushToNodes(value, inputs, prefix) {
const valueArray = value.toString().split('\n');
if (valueArray[1] && valueArray[1].match(/^(async +)?function/)) // very, very crude regex,
// will not work if there are comments between async and function
// (I really hope there aren't such things in the wild...)
prefix = '';
let cellArray = valueArray[0].match(/return\($/) ?
// Function cells are wrapped : block cells are just functions
valueArray.slice(1,-1) : valueArray.slice(1);
// put back in viewof, mutable, if needed
if (inputs) {
inputs.filter(inp => inp.startsWith('viewof ')).forEach(
(inp, i) => cellArray = cellArray.map(
// replace all `$i` with `viewof X`
line => line.replace(new RegExp(`\\$${i}`,'g'), inp)));
inputs.filter(inp => inp.startsWith('mutable ')).forEach(
// replace all `$i.value` with `mutable Y`
(inp, i) => cellArray = cellArray.map(
line => line.replace(new RegExp(`\\$${i}\.value`,'g'), inp)));
}
nodes.push({id:nodes.length, pinned:false, value:prefix+cellArray.join('\n')});
}
for (let j = 0; j < variables.length; j++) {
const {name, inputs, value, from, remote} = variables[j];
if (from === undefined) {
if (value) {
let prefix = '';
if (name) {
// check for viewof (assume viewof X -> X)
if (name.startsWith('viewof ')) {
prefix +=`${name} = `;
pushToNodes(value, inputs, prefix);
j++;
} // check for mutable (assume initial X -> mutable X -> X)
else if (name.startsWith('initial ')) {
const mutName = name.replace('initial', 'mutable');
prefix += `${mutName} = `;
pushToNodes(value, inputs, prefix);
j+=2;
} else {
// ordinary variable -> ordinary cell
prefix += `${name} = `;
pushToNodes(value, inputs, prefix);
}
} else {
pushToNodes(value, inputs, prefix);
}
} else {
// empty cells will be ignored! (these mostly come from comment-only cells...)
}
} else {
// make import cell, combine with previous
// IF THERE ARE INJECTIONS, THE FOLLOWING WON'T BE CORRECT!
let currFrom = from;
let currName = name;
let currRemote = remote;
let imported = [];
while (currFrom === from && ++j < variables.length) {
const {from:nextFrom, name:nextName, remote:nextRemote} = variables[j];
if (currFrom === nextFrom && // if the next "from" is "viewof" or "mutable", change the import
(nextRemote === 'viewof '+currRemote || nextRemote === 'mutable '+currRemote)) {
imported.push(`${nextRemote} as ${currName}`);
++j;
currFrom = variables[j].from;
currName = variables[j].name;
currRemote = variables[j].remote;
} else {
imported.push(currRemote === currName ? currRemote : `${currRemote} as ${currName}`);
currFrom = nextFrom;
currName = nextName;
currRemote = nextRemote;
}
}
nodes.push({id:nodes.length, pinned:false, value:`import {${imported.join(', ')}} from '${from}'`});
j--;
}
}
return nodes;
}
Insert cell
import {importModule} from '@bryangingechen/dynamic-import-polyfill'
Insert cell
import {toV1, utoa, observable, parser} from '@bryangingechen/from-raw-notebook-source-to-observable-runtime-v1-modules'
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more