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

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more