Format the TypeScript files (#877)

This commit is contained in:
woxtu
2022-10-28 17:48:27 +09:00
committed by GitHub
parent 1c53d91c6b
commit 9543019336
13 changed files with 235 additions and 286 deletions

View File

@@ -47,13 +47,13 @@ export class PyBox extends HTMLElement {
// now we need to set widths
this.widths = [];
const widthsAttr = getAttribute( this, "widths" );
const widthsAttr = getAttribute(this, 'widths');
if (widthsAttr) {
for (const w of widthsAttr.split(';')) {
if (w.includes('/')){
this.widths.push(w.split('/')[0])
}else{
this.widths.push(w)
if (w.includes('/')) {
this.widths.push(w.split('/')[0]);
} else {
this.widths.push(w);
}
}
} else {
@@ -63,7 +63,7 @@ export class PyBox extends HTMLElement {
this.widths.forEach((width, index) => {
const node: ChildNode = mainDiv.childNodes[index];
(<HTMLElement>node).style.flex = width;
addClasses((<HTMLElement>node), ['py-box-child']);
addClasses(<HTMLElement>node, ['py-box-child']);
});
this.appendChild(mainDiv);

View File

@@ -1,5 +1,5 @@
import { getAttribute, addClasses, htmlDecode, ensureUniqueId } from '../utils';
import { getLogger } from '../logger'
import { getLogger } from '../logger';
import type { Runtime } from '../runtime';
const logger = getLogger('py-button');
@@ -18,14 +18,14 @@ export function make_PyButton(runtime: Runtime) {
this.defaultClass = ['py-button'];
const label = getAttribute(this, "label");
const label = getAttribute(this, 'label');
if (label) {
this.label = label;
}
// Styling does the same thing as class in normal HTML. Using the name "class" makes the style to malfunction
const styling = getAttribute(this, "styling");
if ( styling ) {
const styling = getAttribute(this, 'styling');
if (styling) {
const klass = styling.trim();
if (klass === '') {
this.class = this.defaultClass;
@@ -43,7 +43,7 @@ export function make_PyButton(runtime: Runtime) {
async connectedCallback() {
ensureUniqueId(this);
this.code = htmlDecode(this.innerHTML) || "";
this.code = htmlDecode(this.innerHTML) || '';
this.mount_name = this.id.split('-').join('_');
this.innerHTML = '';

View File

@@ -1,5 +1,5 @@
import { getAttribute, addClasses, htmlDecode, ensureUniqueId } from '../utils';
import { getLogger } from '../logger'
import { getLogger } from '../logger';
import type { Runtime } from '../runtime';
const logger = getLogger('py-inputbox');
@@ -14,7 +14,7 @@ export function make_PyInputBox(runtime: Runtime) {
constructor() {
super();
const label = getAttribute( this, "label");
const label = getAttribute(this, 'label');
if (label) {
this.label = label;
}

View File

@@ -1,6 +1,6 @@
import { basicSetup, EditorView } from 'codemirror';
import { python } from '@codemirror/lang-python';
import { indentUnit } from '@codemirror/language'
import { indentUnit } from '@codemirror/language';
import { Compartment } from '@codemirror/state';
import { keymap } from '@codemirror/view';
import { defaultKeymap } from '@codemirror/commands';
@@ -14,7 +14,6 @@ import { getLogger } from '../logger';
const logger = getLogger('py-repl');
export function make_PyRepl(runtime: Runtime) {
/* High level structure of py-repl DOM, and the corresponding JS names.
this <py-repl>
@@ -63,7 +62,7 @@ export function make_PyRepl(runtime: Runtime) {
makeEditor(pySrc: string): EditorView {
const languageConf = new Compartment();
const extensions = [
indentUnit.of(" "),
indentUnit.of(' '),
basicSetup,
languageConf.of(python()),
keymap.of([
@@ -181,22 +180,20 @@ export function make_PyRepl(runtime: Runtime) {
}
getOutputElement(): HTMLElement {
const outputID = getAttribute(this, "output");
const outputID = getAttribute(this, 'output');
if (outputID !== null) {
const el = document.getElementById(outputID);
if (el === null) {
const err = `py-repl ERROR: cannot find the output element #${outputID} in the DOM`
const err = `py-repl ERROR: cannot find the output element #${outputID} in the DOM`;
this.outDiv.innerText = err;
return undefined;
}
return el;
}
else {
} else {
return this.outDiv;
}
}
// XXX the autogenerate logic is very messy. We should redo it, and it
// should be the default.
autogenerateMaybe(): void {
@@ -210,19 +207,19 @@ export function make_PyRepl(runtime: Runtime) {
newPyRepl.setAttribute('root', this.getAttribute('root'));
newPyRepl.id = this.getAttribute('root') + '-' + nextExecId.toString();
if(this.hasAttribute('auto-generate')) {
if (this.hasAttribute('auto-generate')) {
newPyRepl.setAttribute('auto-generate', '');
this.removeAttribute('auto-generate');
}
const outputMode = getAttribute( this, 'output-mode')
if(outputMode) {
const outputMode = getAttribute(this, 'output-mode');
if (outputMode) {
newPyRepl.setAttribute('output-mode', outputMode);
}
const addReplAttribute = (attribute: string) => {
const attr = getAttribute( this, attribute)
if(attr) {
const attr = getAttribute(this, attribute);
if (attr) {
newPyRepl.setAttribute(attribute, attr);
}
};
@@ -230,13 +227,12 @@ export function make_PyRepl(runtime: Runtime) {
addReplAttribute('output');
newPyRepl.setAttribute('exec-id', nextExecId.toString());
if( this.parentElement ){
if (this.parentElement) {
this.parentElement.appendChild(newPyRepl);
}
}
}
}
return PyRepl
return PyRepl;
}

View File

@@ -6,9 +6,7 @@ import { pyExec } from '../pyexec';
const logger = getLogger('py-script');
export function make_PyScript(runtime: Runtime) {
class PyScript extends HTMLElement {
async connectedCallback() {
ensureUniqueId(this);
const pySrc = await this.getPySrc();
@@ -24,8 +22,7 @@ export function make_PyScript(runtime: Runtime) {
const url = this.getAttribute('src');
const response = await fetch(url);
return await response.text();
}
else {
} else {
return htmlDecode(this.innerHTML);
}
}
@@ -37,97 +34,97 @@ export function make_PyScript(runtime: Runtime) {
/** Defines all possible py-on* and their corresponding event types */
const pyAttributeToEvent: Map<string, string> = new Map<string, string>([
// Leaving pys-onClick and pys-onKeyDown for backward compatibility
["pys-onClick", "click"],
["pys-onKeyDown", "keydown"],
["py-onClick", "click"],
["py-onKeyDown", "keydown"],
['pys-onClick', 'click'],
['pys-onKeyDown', 'keydown'],
['py-onClick', 'click'],
['py-onKeyDown', 'keydown'],
// Window Events
["py-afterprint", "afterprint"],
["py-beforeprint", "beforeprint"],
["py-beforeunload", "beforeunload"],
["py-error", "error"],
["py-hashchange", "hashchange"],
["py-load", "load"],
["py-message", "message"],
["py-offline", "offline"],
["py-online", "online"],
["py-pagehide", "pagehide"],
["py-pageshow", "pageshow"],
["py-popstate", "popstate"],
["py-resize", "resize"],
["py-storage", "storage"],
["py-unload", "unload"],
['py-afterprint', 'afterprint'],
['py-beforeprint', 'beforeprint'],
['py-beforeunload', 'beforeunload'],
['py-error', 'error'],
['py-hashchange', 'hashchange'],
['py-load', 'load'],
['py-message', 'message'],
['py-offline', 'offline'],
['py-online', 'online'],
['py-pagehide', 'pagehide'],
['py-pageshow', 'pageshow'],
['py-popstate', 'popstate'],
['py-resize', 'resize'],
['py-storage', 'storage'],
['py-unload', 'unload'],
// Form Events
["py-blur", "blur"],
["py-change", "change"],
["py-contextmenu", "contextmenu"],
["py-focus", "focus"],
["py-input", "input"],
["py-invalid", "invalid"],
["py-reset", "reset"],
["py-search", "search"],
["py-select", "select"],
["py-submit", "submit"],
['py-blur', 'blur'],
['py-change', 'change'],
['py-contextmenu', 'contextmenu'],
['py-focus', 'focus'],
['py-input', 'input'],
['py-invalid', 'invalid'],
['py-reset', 'reset'],
['py-search', 'search'],
['py-select', 'select'],
['py-submit', 'submit'],
// Keyboard Events
["py-keydown", "keydown"],
["py-keypress", "keypress"],
["py-keyup", "keyup"],
['py-keydown', 'keydown'],
['py-keypress', 'keypress'],
['py-keyup', 'keyup'],
// Mouse Events
["py-click", "click"],
["py-dblclick", "dblclick"],
["py-mousedown", "mousedown"],
["py-mousemove", "mousemove"],
["py-mouseout", "mouseout"],
["py-mouseover", "mouseover"],
["py-mouseup", "mouseup"],
["py-mousewheel", "mousewheel"],
["py-wheel", "wheel"],
['py-click', 'click'],
['py-dblclick', 'dblclick'],
['py-mousedown', 'mousedown'],
['py-mousemove', 'mousemove'],
['py-mouseout', 'mouseout'],
['py-mouseover', 'mouseover'],
['py-mouseup', 'mouseup'],
['py-mousewheel', 'mousewheel'],
['py-wheel', 'wheel'],
// Drag Events
["py-drag", "drag"],
["py-dragend", "dragend"],
["py-dragenter", "dragenter"],
["py-dragleave", "dragleave"],
["py-dragover", "dragover"],
["py-dragstart", "dragstart"],
["py-drop", "drop"],
["py-scroll", "scroll"],
['py-drag', 'drag'],
['py-dragend', 'dragend'],
['py-dragenter', 'dragenter'],
['py-dragleave', 'dragleave'],
['py-dragover', 'dragover'],
['py-dragstart', 'dragstart'],
['py-drop', 'drop'],
['py-scroll', 'scroll'],
// Clipboard Events
["py-copy", "copy"],
["py-cut", "cut"],
["py-paste", "paste"],
['py-copy', 'copy'],
['py-cut', 'cut'],
['py-paste', 'paste'],
// Media Events
["py-abort", "abort"],
["py-canplay", "canplay"],
["py-canplaythrough", "canplaythrough"],
["py-cuechange", "cuechange"],
["py-durationchange", "durationchange"],
["py-emptied", "emptied"],
["py-ended", "ended"],
["py-loadeddata", "loadeddata"],
["py-loadedmetadata", "loadedmetadata"],
["py-loadstart", "loadstart"],
["py-pause", "pause"],
["py-play", "play"],
["py-playing", "playing"],
["py-progress", "progress"],
["py-ratechange", "ratechange"],
["py-seeked", "seeked"],
["py-seeking", "seeking"],
["py-stalled", "stalled"],
["py-suspend", "suspend"],
["py-timeupdate", "timeupdate"],
["py-volumechange", "volumechange"],
["py-waiting", "waiting"],
['py-abort', 'abort'],
['py-canplay', 'canplay'],
['py-canplaythrough', 'canplaythrough'],
['py-cuechange', 'cuechange'],
['py-durationchange', 'durationchange'],
['py-emptied', 'emptied'],
['py-ended', 'ended'],
['py-loadeddata', 'loadeddata'],
['py-loadedmetadata', 'loadedmetadata'],
['py-loadstart', 'loadstart'],
['py-pause', 'pause'],
['py-play', 'play'],
['py-playing', 'playing'],
['py-progress', 'progress'],
['py-ratechange', 'ratechange'],
['py-seeked', 'seeked'],
['py-seeking', 'seeking'],
['py-stalled', 'stalled'],
['py-suspend', 'suspend'],
['py-timeupdate', 'timeupdate'],
['py-volumechange', 'volumechange'],
['py-waiting', 'waiting'],
// Misc Events
["py-toggle", "toggle"],
]);
['py-toggle', 'toggle'],
]);
/** Initialize all elements with py-* handlers attributes */
export async function initHandlers(runtime: Runtime) {
@@ -142,22 +139,27 @@ async function createElementsWithEventListeners(runtime: Runtime, pyAttribute: s
const matches: NodeListOf<HTMLElement> = document.querySelectorAll(`[${pyAttribute}]`);
for (const el of matches) {
if (el.id.length === 0) {
throw new TypeError(`<${el.tagName.toLowerCase()}> must have an id attribute, when using the ${pyAttribute} attribute`)
throw new TypeError(
`<${el.tagName.toLowerCase()}> must have an id attribute, when using the ${pyAttribute} attribute`,
);
}
const handlerCode = el.getAttribute(pyAttribute);
const event = pyAttributeToEvent.get(pyAttribute);
if (pyAttribute === 'pys-onClick' || pyAttribute === 'pys-onKeyDown'){
console.warn("Use of pys-onClick and pys-onKeyDown attributes is deprecated in favor of py-onClick() and py-onKeyDown(). pys-on* attributes will be deprecated in a future version of PyScript.")
if (pyAttribute === 'pys-onClick' || pyAttribute === 'pys-onKeyDown') {
console.warn(
'Use of pys-onClick and pys-onKeyDown attributes is deprecated in favor of py-onClick() and py-onKeyDown(). pys-on* attributes will be deprecated in a future version of PyScript.',
);
const source = `
from pyodide.ffi import create_proxy
Element("${el.id}").element.addEventListener("${event}", create_proxy(${handlerCode}))
`;
await runtime.run(source);
}
else{
} else {
el.addEventListener(event, () => {
(async() => {await runtime.run(handlerCode)})();
(async () => {
await runtime.run(handlerCode);
})();
});
}
// TODO: Should we actually map handlers in JS instead of Python?
@@ -174,7 +176,6 @@ async function createElementsWithEventListeners(runtime: Runtime, pyAttribute: s
// // pyodide.runPython(handlerCode);
// }
}
}
/** Mount all elements with attribute py-mount into the Python namespace */

View File

@@ -1,10 +1,9 @@
import type { Runtime } from '../runtime';
import type {PyProxy} from "pyodide"
import type { PyProxy } from 'pyodide';
import { getLogger } from '../logger';
const logger = getLogger('py-register-widget');
function createWidget(runtime: Runtime, name: string, code: string, klass: string) {
class CustomWidget extends HTMLElement {
shadow: ShadowRoot;
@@ -65,14 +64,14 @@ export function make_PyWidget(runtime: Runtime) {
this.wrapper = document.createElement('slot');
this.shadow.appendChild(this.wrapper);
this.addAttributes('src','name','klass');
this.addAttributes('src', 'name', 'klass');
}
addAttributes(...attrs:string[]){
for (const each of attrs){
const property = each === "src" ? "source" : each;
addAttributes(...attrs: string[]) {
for (const each of attrs) {
const property = each === 'src' ? 'source' : each;
if (this.hasAttribute(each)) {
this[property]=this.getAttribute(each);
this[property] = this.getAttribute(each);
}
}
}

View File

@@ -42,14 +42,14 @@ function getLogger(prefix: string): Logger {
}
function _makeLogger(prefix: string): Logger {
prefix = "[" + prefix + "] ";
prefix = '[' + prefix + '] ';
function make(level: string) {
const out_fn = console[level].bind(console);
function fn(fmt: string, ...args: unknown[]) {
out_fn(prefix + fmt, ...args);
}
return fn
return fn;
}
// 'log' is intentionally omitted
@@ -58,7 +58,7 @@ function _makeLogger(prefix: string): Logger {
const warn = make('warn');
const error = make('error');
return {debug, info, warn, error};
return { debug, info, warn, error };
}
export { getLogger };

View File

@@ -7,18 +7,16 @@ import { make_PyScript, initHandlers, mountElements } from './components/pyscrip
import { PyLoader } from './components/pyloader';
import { PyodideRuntime } from './pyodide';
import { getLogger } from './logger';
import { handleFetchError, showError, globalExport } from './utils'
import { handleFetchError, showError, globalExport } from './utils';
import { createCustomElements } from './components/elements';
type ImportType = { [key: string]: unknown }
type ImportType = { [key: string]: unknown };
type ImportMapType = {
imports: ImportType | null
}
imports: ImportType | null;
};
const logger = getLogger('pyscript/main');
/* High-level overview of the lifecycle of a PyScript App:
1. pyscript.js is loaded by the browser. PyScriptApp().main() is called
@@ -51,9 +49,7 @@ More concretely:
- PyScriptApp.afterRuntimeLoad() implements all the points >= 5.
*/
class PyScriptApp {
config: AppConfig;
loader: PyLoader;
runtime: Runtime;
@@ -75,15 +71,16 @@ class PyScriptApp {
logger.info('searching for <py-config>');
const elements = document.getElementsByTagName('py-config');
let el: Element | null = null;
if (elements.length > 0)
el = elements[0];
if (elements.length > 0) el = elements[0];
if (elements.length >= 2) {
// XXX: ideally, I would like to have a way to raise "fatal
// errors" and stop the computation, but currently our life cycle
// is too messy to implement it reliably. We might want to revisit
// this once it's in a better shape.
showError("Multiple &lt;py-config&gt; tags detected. Only the first is " +
"going to be parsed, all the others will be ignored");
showError(
'Multiple &lt;py-config&gt; tags detected. Only the first is ' +
'going to be parsed, all the others will be ignored',
);
}
this.config = loadConfigFromElement(el);
logger.info('config loaded:\n' + JSON.stringify(this.config, null, 2));
@@ -102,17 +99,15 @@ class PyScriptApp {
loadRuntime() {
logger.info('Initializing runtime');
if (this.config.runtimes.length == 0) {
showError("Fatal error: config.runtimes is empty");
showError('Fatal error: config.runtimes is empty');
return;
}
if (this.config.runtimes.length > 1) {
showError("Multiple runtimes are not supported yet. " +
"Only the first will be used");
showError('Multiple runtimes are not supported yet. ' + 'Only the first will be used');
}
const runtime_cfg = this.config.runtimes[0];
this.runtime = new PyodideRuntime(this.config, runtime_cfg.src,
runtime_cfg.name, runtime_cfg.lang);
this.runtime = new PyodideRuntime(this.config, runtime_cfg.src, runtime_cfg.name, runtime_cfg.lang);
this.loader.log(`Downloading ${runtime_cfg.name}...`);
const script = document.createElement('script'); // create a script DOM node
script.src = this.runtime.src;
@@ -160,13 +155,12 @@ class PyScriptApp {
logger.info('PyScript page fully initialized');
}
// lifecycle (6)
async setupVirtualEnv(runtime: Runtime): Promise<void> {
// XXX: maybe the following calls could be parallelized, instead of
// await()ing immediately. For now I'm using await to be 100%
// compatible with the old behavior.
logger.info("Packages to install: ", this.config.packages);
logger.info('Packages to install: ', this.config.packages);
await runtime.installPackage(this.config.packages);
await this.fetchPaths(runtime);
}
@@ -178,7 +172,7 @@ class PyScriptApp {
// initialized. But we could easily do it in JS in parallel with the
// download/startup of pyodide.
const paths = this.config.paths;
logger.info("Paths to fetch: ", paths)
logger.info('Paths to fetch: ', paths);
for (const singleFile of paths) {
logger.info(` fetching path: ${singleFile}`);
try {
@@ -188,7 +182,7 @@ class PyScriptApp {
handleFetchError(<Error>e, singleFile);
}
}
logger.info("All paths fetched");
logger.info('All paths fetched');
}
// lifecycle (7)
@@ -239,7 +233,6 @@ class PyScriptApp {
}
}
}
}
function pyscript_get_config() {
@@ -251,4 +244,4 @@ globalExport('pyscript_get_config', pyscript_get_config);
const globalApp = new PyScriptApp();
globalApp.main();
export const runtime = globalApp.runtime
export const runtime = globalApp.runtime;

View File

@@ -1,7 +1,7 @@
import toml from '../src/toml'
import toml from '../src/toml';
import { getLogger } from './logger';
import { version } from './runtime';
import { getAttribute, readTextFromPath, showError } from './utils'
import { getAttribute, readTextFromPath, showError } from './utils';
const logger = getLogger('py-config');
@@ -31,29 +31,30 @@ export type RuntimeConfig = {
export type PyScriptMetadata = {
version?: string;
time?: string;
}
};
const allKeys = {
"string": ["name", "description", "version", "type", "author_name", "author_email", "license"],
"number": ["schema_version"],
"boolean": ["autoclose_loader"],
"array": ["runtimes", "packages", "paths", "plugins"]
string: ['name', 'description', 'version', 'type', 'author_name', 'author_email', 'license'],
number: ['schema_version'],
boolean: ['autoclose_loader'],
array: ['runtimes', 'packages', 'paths', 'plugins'],
};
export const defaultConfig: AppConfig = {
"schema_version": 1,
"type": "app",
"autoclose_loader": true,
"runtimes": [{
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.js",
"name": "pyodide-0.21.3",
"lang": "python"
}],
"packages":[],
"paths":[],
"plugins": []
}
schema_version: 1,
type: 'app',
autoclose_loader: true,
runtimes: [
{
src: 'https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.js',
name: 'pyodide-0.21.3',
lang: 'python',
},
],
packages: [],
paths: [],
plugins: [],
};
export function loadConfigFromElement(el: Element): AppConfig {
let srcConfig: AppConfig;
@@ -61,47 +62,41 @@ export function loadConfigFromElement(el: Element): AppConfig {
if (el === null) {
srcConfig = {};
inlineConfig = {};
}
else {
const configType = getAttribute(el, "type") || "toml";
} else {
const configType = getAttribute(el, 'type') || 'toml';
srcConfig = extractFromSrc(el, configType);
inlineConfig = extractFromInline(el, configType);
}
srcConfig = mergeConfig(srcConfig, defaultConfig);
const result = mergeConfig(inlineConfig, srcConfig);
result.pyscript = {
"version": version,
"time": new Date().toISOString()
version: version,
time: new Date().toISOString(),
};
return result;
}
function extractFromSrc(el: Element, configType: string) {
const src = getAttribute(el, "src")
const src = getAttribute(el, 'src');
if (src) {
logger.info('loading ', src)
logger.info('loading ', src);
return validateConfig(readTextFromPath(src), configType);
}
return {};
}
function extractFromInline(el: Element, configType: string) {
if (el.innerHTML !== '')
{
if (el.innerHTML !== '') {
logger.info('loading <py-config> content');
return validateConfig(el.innerHTML, configType);
}
return {};
}
function fillUserData(inputConfig: AppConfig, resultConfig: AppConfig): AppConfig
{
for (const key in inputConfig)
{
function fillUserData(inputConfig: AppConfig, resultConfig: AppConfig): AppConfig {
for (const key in inputConfig) {
// fill in all extra keys ignored by the validator
if (!(key in defaultConfig))
{
if (!(key in defaultConfig)) {
resultConfig[key] = inputConfig[key];
}
}
@@ -109,32 +104,22 @@ function fillUserData(inputConfig: AppConfig, resultConfig: AppConfig): AppConfi
}
function mergeConfig(inlineConfig: AppConfig, externalConfig: AppConfig): AppConfig {
if (Object.keys(inlineConfig).length === 0 && Object.keys(externalConfig).length === 0)
{
if (Object.keys(inlineConfig).length === 0 && Object.keys(externalConfig).length === 0) {
return defaultConfig;
}
else if (Object.keys(inlineConfig).length === 0)
{
} else if (Object.keys(inlineConfig).length === 0) {
return externalConfig;
}
else if(Object.keys(externalConfig).length === 0)
{
} else if (Object.keys(externalConfig).length === 0) {
return inlineConfig;
}
else
{
} else {
let merged: AppConfig = {};
for (const keyType in allKeys)
{
for (const keyType in allKeys) {
const keys: string[] = allKeys[keyType];
keys.forEach(function(item: string){
if (keyType === "boolean")
{
merged[item] = (typeof inlineConfig[item] !== "undefined") ? inlineConfig[item] : externalConfig[item];
}
else
{
keys.forEach(function (item: string) {
if (keyType === 'boolean') {
merged[item] =
typeof inlineConfig[item] !== 'undefined' ? inlineConfig[item] : externalConfig[item];
} else {
merged[item] = inlineConfig[item] || externalConfig[item];
}
});
@@ -149,20 +134,18 @@ function mergeConfig(inlineConfig: AppConfig, externalConfig: AppConfig): AppCon
}
}
function parseConfig(configText: string, configType = "toml") {
function parseConfig(configText: string, configType = 'toml') {
let config: object;
if (configType === "toml") {
if (configType === 'toml') {
try {
// TOML parser is soft and can parse even JSON strings, this additional check prevents it.
if (configText.trim()[0] === "{")
{
if (configText.trim()[0] === '{') {
const errMessage = `config supplied: ${configText} is an invalid TOML and cannot be parsed`;
showError(`<p>${errMessage}</p>`);
throw Error(errMessage);
}
config = toml.parse(configText);
}
catch (err) {
} catch (err) {
const errMessage: string = err.toString();
showError(`<p>config supplied: ${configText} is an invalid TOML and cannot be parsed: ${errMessage}</p>`);
// we cannot easily just "throw err" here, because for some reason
@@ -175,52 +158,42 @@ function parseConfig(configText: string, configType = "toml") {
// it's correctly handled by playwright.
throw SyntaxError(errMessage);
}
}
else if (configType === "json") {
} else if (configType === 'json') {
try {
config = JSON.parse(configText);
}
catch (err) {
} catch (err) {
const errMessage: string = err.toString();
showError(`<p>config supplied: ${configText} is an invalid JSON and cannot be parsed: ${errMessage}</p>`);
throw err;
}
}
else {
} else {
showError(`<p>type of config supplied is: ${configType}, supported values are ["toml", "json"].</p>`);
}
return config;
}
function validateConfig(configText: string, configType = "toml") {
function validateConfig(configText: string, configType = 'toml') {
const config = parseConfig(configText, configType);
const finalConfig: AppConfig = {}
const finalConfig: AppConfig = {};
for (const keyType in allKeys)
{
for (const keyType in allKeys) {
const keys: string[] = allKeys[keyType];
keys.forEach(function(item: string){
if (validateParamInConfig(item, keyType, config))
{
if (item === "runtimes")
{
keys.forEach(function (item: string) {
if (validateParamInConfig(item, keyType, config)) {
if (item === 'runtimes') {
finalConfig[item] = [];
const runtimes = config[item] as object[];
runtimes.forEach(function(eachRuntime: object){
runtimes.forEach(function (eachRuntime: object) {
const runtimeConfig: object = {};
for (const eachRuntimeParam in eachRuntime)
{
if (validateParamInConfig(eachRuntimeParam, "string", eachRuntime))
{
for (const eachRuntimeParam in eachRuntime) {
if (validateParamInConfig(eachRuntimeParam, 'string', eachRuntime)) {
runtimeConfig[eachRuntimeParam] = eachRuntime[eachRuntimeParam];
}
}
finalConfig[item].push(runtimeConfig);
});
}
else
{
} else {
finalConfig[item] = config[item];
}
}
@@ -231,9 +204,8 @@ function validateConfig(configText: string, configType = "toml") {
}
function validateParamInConfig(paramName: string, paramType: string, config: object): boolean {
if (paramName in config)
{
return paramType === "array" ? Array.isArray(config[paramName]) : typeof config[paramName] === paramType;
if (paramName in config) {
return paramType === 'array' ? Array.isArray(config[paramName]) : typeof config[paramName] === paramType;
}
return false;
}

View File

@@ -4,8 +4,7 @@ import type { Runtime } from './runtime';
const logger = getLogger('pyexec');
export async function pyExec(runtime: Runtime, pysrc: string, outElem: HTMLElement)
{
export async function pyExec(runtime: Runtime, pysrc: string, outElem: HTMLElement) {
// this is the python function defined in pyscript.py
const set_current_display_target = runtime.globals.get('set_current_display_target');
ensureUniqueId(outElem);
@@ -13,16 +12,14 @@ export async function pyExec(runtime: Runtime, pysrc: string, outElem: HTMLEleme
try {
try {
return await runtime.run(pysrc);
}
catch (err) {
} catch (err) {
// XXX: currently we display exceptions in the same position as
// the output. But we probably need a better way to do that,
// e.g. allowing plugins to intercept exceptions and display them
// in a configurable way.
displayPyException(err, outElem);
}
}
finally {
} finally {
set_current_display_target(undefined);
}
}
@@ -36,8 +33,7 @@ export async function pyExec(runtime: Runtime, pysrc: string, outElem: HTMLEleme
*/
export function pyDisplay(runtime: Runtime, obj: any, kwargs: object) {
const display = runtime.globals.get('display');
if (kwargs === undefined)
display(obj);
if (kwargs === undefined) display(obj);
else {
display.callKwargs(obj, kwargs);
}
@@ -46,18 +42,17 @@ export function pyDisplay(runtime: Runtime, obj: any, kwargs: object) {
function displayPyException(err: any, errElem: HTMLElement) {
//addClasses(errElem, ['py-error'])
const pre = document.createElement('pre');
pre.className = "py-error";
pre.className = 'py-error';
if (err.name === "PythonError") {
if (err.name === 'PythonError') {
// err.message contains the python-level traceback (i.e. a string
// starting with: "Traceback (most recent call last) ..."
logger.error("Python exception:\n" + err.message);
logger.error('Python exception:\n' + err.message);
pre.innerText = err.message;
}
else {
} else {
// this is very likely a normal JS exception. The best we can do is to
// display it as is.
logger.error("Non-python exception:\n" + err);
logger.error('Non-python exception:\n' + err);
pre.innerText = err;
}
errElem.appendChild(pre);

View File

@@ -80,9 +80,7 @@ export class PyodideRuntime extends Runtime {
async loadPackage(names: string | string[]): Promise<void> {
logger.info(`pyodide.loadPackage: ${names.toString()}`);
await this.interpreter.loadPackage(names,
logger.info.bind(logger),
logger.info.bind(logger));
await this.interpreter.loadPackage(names, logger.info.bind(logger), logger.info.bind(logger));
}
async installPackage(package_name: string | string[]): Promise<void> {
@@ -97,15 +95,13 @@ export class PyodideRuntime extends Runtime {
async loadFromFile(path: string): Promise<void> {
const pathArr = path.split('/');
const filename = pathArr.pop();
for(let i=0; i<pathArr.length; i++)
{
const eachPath = pathArr.slice(0, i+1).join('/');
const {exists, parentExists} = this.interpreter.FS.analyzePath(eachPath);
for (let i = 0; i < pathArr.length; i++) {
const eachPath = pathArr.slice(0, i + 1).join('/');
const { exists, parentExists } = this.interpreter.FS.analyzePath(eachPath);
if (!parentExists) {
throw new Error(`'INTERNAL ERROR! cannot create ${path}, this should never happen'`)
throw new Error(`'INTERNAL ERROR! cannot create ${path}, this should never happen'`);
}
if (!exists)
{
if (!exists) {
this.interpreter.FS.mkdir(eachPath);
}
}

View File

@@ -4,11 +4,9 @@ import { getLogger } from './logger';
const logger = getLogger('pyscript/runtime');
export const version = "<<VERSION>>";
export const version = '<<VERSION>>';
export type RuntimeInterpreter = PyodideInterface | null;
/*
Runtime class is a super class that all different runtimes must respect
and adhere to.
@@ -65,8 +63,8 @@ export abstract class Runtime extends Object {
* */
async runButDontRaise(code: string): Promise<unknown> {
return this.run(code).catch(err => {
const error = err as Error
logger.error("Error:", error);
const error = err as Error;
logger.error('Error:', error);
});
}

View File

@@ -11,7 +11,7 @@ export function removeClasses(element: HTMLElement, classes: string[]) {
}
export function escape(str: string): string {
return str.replace(/</g, "&lt;").replace(/>/g, "&gt;")
return str.replace(/</g, '&lt;').replace(/>/g, '&gt;');
}
export function htmlDecode(input: string): string | null {
@@ -36,8 +36,7 @@ export function ltrim(code: string): string {
let _uniqueIdCounter = 0;
export function ensureUniqueId(el: HTMLElement) {
if (el.id === "")
el.id = `py-internal-${_uniqueIdCounter++}`;
if (el.id === '') el.id = `py-internal-${_uniqueIdCounter++}`;
}
/*
@@ -48,7 +47,7 @@ export function ensureUniqueId(el: HTMLElement) {
export function showError(msg: string): void {
const warning = document.createElement('div');
// XXX: the style should go to css instead of here probably
warning.className = "py-error";
warning.className = 'py-error';
warning.style.backgroundColor = 'LightCoral';
warning.style.alignContent = 'center';
warning.style.margin = '4px';
@@ -83,7 +82,7 @@ export function handleFetchError(e: Error, singleFile: string) {
export function readTextFromPath(path: string) {
const request = new XMLHttpRequest();
request.open("GET", path, false);
request.open('GET', path, false);
request.send();
const returnValue = request.responseText;
@@ -99,14 +98,14 @@ export function globalExport(name: string, obj: object) {
// visible everywhere. Should be used very sparingly!
// `window` in the browser, `global` in node
const _global = (window || global);
const _global = window || global;
_global[name] = obj;
}
export function getAttribute(el:Element, attr:string ):string | null {
if( el.hasAttribute( attr ) ){
export function getAttribute(el: Element, attr: string): string | null {
if (el.hasAttribute(attr)) {
const value = el.getAttribute(attr);
if( value ){
if (value) {
return value;
}
}