From e48e6276e15b5510ced7af265a26dfee7d9c58a1 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 17 Aug 2023 17:12:55 +0200 Subject: [PATCH 001/105] [next] PyScript Next basic documentation (#1634) --- pyscript.core/docs/README.md | 254 ++++++++++++++++++++++++++++++++ pyscript.core/package-lock.json | 4 +- pyscript.core/package.json | 11 +- 3 files changed, 262 insertions(+), 7 deletions(-) create mode 100644 pyscript.core/docs/README.md diff --git a/pyscript.core/docs/README.md b/pyscript.core/docs/README.md new file mode 100644 index 00000000..7b2d8afc --- /dev/null +++ b/pyscript.core/docs/README.md @@ -0,0 +1,254 @@ +# PyScript Next + +A summary of @pyscript/core features + +### Getting started + +Differently from [pyscript classic](https://github.com/pyscript/pyscript), where "*classic*" is the disambiguation name we use to describe the two versions of the project, `@pyscript/core` is an *ECMAScript Module* with the follow benefits: + + * it doesn't block the page like a regular script, without a `deferred` attribute, would + * it allows modularity in the future + * it bootstraps itself once but it allows exports via the module + +Accordingly, this is the bare minimum required output to bootstrap *PyScript Next* in your page via a CDN: + +```html + + + + + + + +``` + +Once the module is loaded, any `` on the page, or any `` tag, would automatically run its own code or the file defined as `src` attribute, after bootstrapping the *pyodide* interpreter. + +If no ` +``` + +#### CSS + +If you are planning to use either `` or `` tags on the page, where latter case is usually better off with ` +``` + + +## Tag attributes API + +Either ``. Both `async` and `config` attributes are also available and used to bootstrap the worker as desired. + +Please note that other [polyscript's attributes](https://pyscript.github.io/polyscript/#script-attributes) are available too but their usage is more advanced. + + +## JS Module API + +The module itself is currently exporting the following utilities: + + * **PyWorker**, which allows to bootstrap a *worker* with *pyodide* and the *pyscript* module available within the code. This callback accepts a file as argument, and an additional, and optional, `options` object literal, able to understand a `config`, which could also be directly a *JS* object literal instead of a JSON string or a file to point at, and `async` which if `true` will run the worker code with top level await enabled. Please note that the returned reference is exactly the same as [the polyscript's XWorker](https://pyscript.github.io/polyscript/#the-xworker-reference), exposing exact same utilities but granting on bootstrap all hooks are in place and the type is always *pyodide*. + * **hooks**, which allows plugins to define *ASAP* callbacks or strings that should be executed either in the main thread or the worker before, or after, the code has been executed. + +```js +import { hooks } from "https://unpkg.com/@pyscript/core"; + +// example +hooks.onInterpreterReady.add((utils, element) => { + console.lot(element, 'found', 'pyscript is ready'); +}); + +// the hooks namespace +({ + // each function is invoked before or after python gets executed + // via: callback(pyScriptUtils, currentElement) + /** @type {Set} */ + onBeforeRun: new Set(), + /** @type {Set} */ + onBeforeRunAync: new Set(), + /** @type {Set} */ + onAfterRun: new Set(), + /** @type {Set} */ + onAfterRunAsync: new Set(), + + // each function is invoked once when PyScript is ready + // and for each element via: callback(pyScriptUtils, currentElement) + /** @type {Set} */ + onInterpreterReady: new Set(), + + // each string is prepended or appended to the worker code + /** @type {Set} */ + codeBeforeRunWorker: new Set(), + /** @type {Set} */ + codeBeforeRunWorkerAsync: new Set(), + /** @type {Set} */ + codeAfterRunWorker: new Set(), + /** @type {Set} */ + codeAfterRunWorkerAsync: new Set(), +}) +``` + +Please note that a *worker* is a completely different environment and it's not possible, by specifications, to pass a callback to it, which is why worker sets are strings and not functions. + +However, each worker string can use `from pyscript import x, y, z` as that will be available out of the box. + +## PyScript Module API + +The python module offers various utilities in either the main thread or the worker. + +The commonly shared utilities are: + + * **window** in both main and worker, refers to the actual main thread global window context. In classic PyScript that'd be the equivalent of `import js` in the main, which is still available in *PyScript Next*. However, to make code easily portable between main and workers, we decided to offer this named export but please note that in workers, this is still the *main* window, not the worker global context, which would be reachable instead still via `import js`. + * **document** in both main and worker, refers to the actual main page `document`. In classic PyScript, this is the equivalent of `from js import document` on the main thread, but this won't ever work in a worker because there is no `document` in there. Fear not though, *PyScript Next* `document` will instead work out of the box, still accessing the main document behind the scene, so that `from pyscript import document` is granted to work in both main and workers seamlessly. + * **display** in both main and worker, refers to the good old `display` utility except: + * in the *main* it automatically uses the current script `target` to display content + * in the *worker* it still needs to know *where* to display content using the `target="dom-id"` named argument, as workers don't get a default target attached + * in both main and worker, the `append=Flase` is the *default* behavior, which is a breaking change compared to classic PyScript, but because there is no `Element` with its `write(content)` utility, which would have used that `append=False` behind the scene, we've decided that `false` as append default is more desired, specially after porting most examples in *PyScript Next*, where `append=True` is the exception, not the norm. + +#### Extra main-only features + + * **PyWorker** which allows Python code to create a PyScript worker with the *pyscript* module pre-bundled. Please note that running PyScript on the main requires *pyodide* bootstrap, but also every worker requires *pyodide* bootstrap a part, as each worker is an environment / sandbox a part. This means that using *PyWorker* in the main will take, even if the main interpreter is already up and running, a bit of time to bootstrap the worker, also accordingly to the config files or packages in it. + + +#### Extra worker-only features + + * **sync** which allows both main and the worker to seamlessly pass any serializable data around, without the need to convert Python dictionaries to JS object literals, as that's done automatically. + +```html + +``` + +```python +from pyscript import sync + +sync.alert_message("Hello Main!") +``` + +### Worker requirements + +To make it possible to use what looks like *synchronous* DOM APIs, or any other API available via the `window` within a *worker*, we are using latest Web features such as [Atomics](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics). + +Without going into too many details, this means that the *SharedArrayBuffer* primitive must be available, and to do so, the server should enable the following headers: + +``` +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: cross-origin +``` + +These headers allow local files to be secured and yet able to load resources from the Web (i.e. pyodide library or its packages). + +> ℹ️ **Careful**: we are using and testing these headers on both Desktop and Mobile to be sure all major browsers work as expected (Safari, Firefox, Chromium based browsers). If you change the value of these headers please be sure you test your target devices and browsers properly. + +Please note that if you don't have control over your server's headers, it is possible to simply put [mini-coi](https://github.com/WebReflection/mini-coi#readme) script at the root of your *PyScript with Workers* enabled folder (site root, or any subfolder). + +```sh +cd project-folder + +# grab mini-coi content and save it locally as mini-coi.js +curl -Ls https://unpkg.com/mini-coi -o mini-coi.js +``` + +With either these two solutions, it should be now possible to bootstrap a *PyScript Worker* without any issue. + +#### mini-coi example +```html + + + + + +``` + +Please note that a local or remote web server is still needed to allow the Service Worker and `python -m http.server` would do locally, *except* we need to reach `http://localhost:8000/`, not `http://0.0.0.0:8000/`, because the browser does not consider safe non localhost sites when the insecure `http://` protocol, instead of `https://`, is reached. + + +#### local server example +If you'd like to test locally these headers, without needing the *mini-coi* Service Worker, you can use various projects or, if you have *NodeJS* available, simply run the following command in the folder containing the site/project: + +```sh +# bootstrap a local server with all headers needed +npx static-handler --cors --coep --coop --corp . +``` + + +### F.A.Q. + +
+ why config attribute can also contain JSON but not TOML? +
+ +The *JSON* standard doesn't require new lines or indentation so it felt quick and desired to allow inline JSON as attribute content. + +It's true that HTML attributes can be multi-line too, if properly embedded, but that looked too awkward and definitively harder to explain to me. + +We might decide to allow TOML too in the future, but the direct config as attribute, instead of a proper file, or the usage of ``, is meant for quick and simple packages or files dependencies and not much else. + +
+
+ +
+ why worker attribute needs an external file? +
+ +It would create confusion to have worker code embedded directly in the page and let *PyScript* forward the content to be executed as worker, but the separation of concerns felt more aligned with the meaning of bootstrapping a worker: it inevitably happens elsewhere and with little caveats or features here and there, so it's OK for now to keep that separation explicit. + +
+
+ +
+ what are the worker's caveats? +
+ +When interacting with `window` or `document` it's important to understand that these use, behind the scene, an orchestrated [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) dance. + +This means that some kind of data that cannot be passed around, specially not compatible with the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm). + +In short, please try to stick with *JS* references when passing along, or dealing with, *DOM* or other *APIs*. + +
+
diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 18ad96b5..8b5ee21c 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.1.5", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index e3e0be72..fce7ca02 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,19 +1,20 @@ { "name": "@pyscript/core", - "version": "0.1.4", + "version": "0.1.5", "type": "module", "description": "PyScript", - "main": "core.js", - "module": "core.js", + "main": "./core.js", + "module": "./core.js", + "unpkg": "./core.js", "exports": { ".": { "types": "./types/esm/core.d.ts", "import": "./esm/core.js" }, - "./core": { + "./js": { "import": "./core.js" }, - "./core.css": { + "./css": { "import": "./core.css" }, "./package.json": "./package.json" From 93539c9b5a1843e8b8f09de59a9ee30bbda3a83a Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 29 Aug 2023 22:32:05 +0200 Subject: [PATCH 002/105] Fix #1651 - Avoid leaks from the registered module (#1655) --- pyscript.core/core.js | 4 +-- pyscript.core/package-lock.json | 44 ++++++++++++++++----------------- pyscript.core/package.json | 10 ++++---- pyscript.core/src/core.js | 20 ++++++++------- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/pyscript.core/core.js b/pyscript.core/core.js index e56ffa52..345a0ae1 100644 --- a/pyscript.core/core.js +++ b/pyscript.core/core.js @@ -1,2 +1,2 @@ -Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var h=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const y="0811fd41-1b6b-49f1-8344-96210ac283f1",m="M"+y,g="T"+y;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:S}=A,{isArray:j}=Array,{notify:k,wait:P,waitAsync:x}=Atomics,{fromCharCode:M}=String,R=(e,t)=>e?(x||w)(t,0):(P(t,0),{value:{then:e=>e()}}),$=new WeakSet,T=new WeakMap;let W=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!T.has(e)){const s=(t,...r)=>e.postMessage({[y]:r},{transfer:t});T.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,o)=>"then"===o?null:(...r)=>{const a=W++;let i=new b(new _(E)),c=[];$.has(r.at(-1)||c)&&$.delete(c=r.pop()),s(c,a,i,o,n?r.map(n):r);const l=e!==globalThis;return R(l,i).value.then((()=>{const e=i[0];if(!e)return;const r=S*e;return i=new b(new _(r+r%E)),s([],a,i),R(l,i).value.then((()=>t(M(...new A(i.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[y];if(j(s)){e.stopImmediatePropagation();const[o,a,...i]=s;if(i.length){const[e,s]=i;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);{const i=await t.get(e)(...s);if(void 0!==i){const e=r(i);n.set(o,e),a[0]=e.length}}}else{const e=n.get(o);n.delete(o);for(let t=new A(a.buffer),r=0;r($.add(e),e);const F="object",B="function",I="number",L="string",N="undefined",C="symbol",{defineProperty:J,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Y,setPrototypeOf:Q}=Reflect,{assign:X,create:G}=Object,Z=D(Int8Array),K="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case B:return e(r,t);case"boolean":case I:case L:case N:case"bigint":return ee(r,t);case C:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===C)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",he="ownKeys",ye="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;J(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?X(G(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),h=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===I)return l.get(r);if(!(r instanceof Z))for(const e in r)r[e]=h(r[e]);return r;case B:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(B,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case C:return ne(r)}return r},y={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(J(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,V(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[he]:e=>ee(F,z(e).map(f)),[ye]:e=>f(q(e)),[me]:(e,t,r)=>f(Y(e,t,r)),[ge]:(e,t)=>f(Q(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=h(r[0]),r[1]=r[1].map(h);break;case ae:r[0]=r[0].map(h);break;case ie:{const[e,t]=r;r[0]=h(e);const{get:n,set:s,value:o}=t;n&&(t.get=h(n)),s&&(t.set=h(s)),o&&(t.value=h(o));break}default:r=r.map(h)}return y[e](h(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===B?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[K],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===B){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof Z))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),h=e=>{const[t,r]=e;if(!f.has(r)){const n=t===B?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===I?h(e):r;case B:return typeof r===L?n.get(r):h(e);case C:return ne(r)}return r},m=(e,t,...r)=>y(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===B&&(r.get=c(n)),typeof s===B&&(r.set=c(s)),typeof o===B&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&V(r,y)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[he]:e=>m(he,e).map(y),[ye]:e=>m(ye,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return y(t).apply(y(s),o.map(y));case we:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[K];return J(Array,K,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window");const _e=new WeakMap,Ae=(e,...t)=>{const r=O(e,...t);if(!_e.has(r)){const t=e instanceof Worker?be:ve;_e.set(r,t(r,m,g))}return _e.get(r)};Ae.transfer=O.transfer;const{isArray:Ee}=Array,{assign:Se,create:je,defineProperties:ke,defineProperty:Pe,entries:xe}=Object,{all:Me,resolve:Re}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),$e=(e,t=location.href)=>new URL(e,t).href,Te=e=>e.arrayBuffer(),We=e=>e.json(),Oe=e=>e.text(),Fe=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Be{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Fe)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Fe)this[t]&&(e[t]=this[t]);return e}}var Ie=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="0811fd41-1b6b-49f1-8344-96210ac283f1",d="M"+p,g="T"+p;var y=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:h,Map:w,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=h,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||y)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,x=new WeakMap;let k=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!x.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});x.set(e,new Proxy(new w,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,o)=>"then"===o?null:(...r)=>{const a=k++;let i=new h(new m(v)),c=[];_.has(r.at(-1)||c)&&_.delete(c=r.pop()),s(c,a,i,o,n?r.map(n):r);const l=e!==globalThis;return $(l,i).value.then((()=>{const e=i[0];if(!e)return;const r=S*e;return i=new h(new m(r+r%v)),s([],a,i),$(l,i).value.then((()=>t(j(...new b(i.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new w;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[o,a,...i]=s;if(i.length){const[e,s]=i;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);{const i=await t.get(e)(...s);if(void 0!==i){const e=r(i);n.set(o,e),a[0]=e.length}}}else{const e=n.get(o);n.delete(o);for(let t=new b(a.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ge="setPrototypeOf",ye="delete";var he=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ye,Q(R,e))})),g=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=g(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},y={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ge]:(e,t)=>p(z(e,t)),[ye](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=g(r[0]),r[1]=r[1].map(g);break;case ne:r[0]=r[0].map(g);break;case se:{const[e,t]=r;r[0]=g(e);const{get:n,set:s,value:o}=t;n&&(t.get=g(n)),s&&(t.set=g(s)),o&&(t.value=g(o));break}default:r=r.map(g)}return y[e](g(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),we=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ye,c(e))})),g=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,w),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?g(e):r;case F:return typeof r===R?n.get(r):g(e);case J:return ee(r)}return r},h=(e,t,...r)=>y(f(e,o(t),...r)),w={[re]:(e,t,r)=>h(re,e,c(t),r.map(c)),[ne]:(e,t)=>h(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),h(se,e,c(t),r)},[oe]:(e,t)=>h(oe,e,c(t)),[ce]:e=>h(ce,e),[ae]:(e,t)=>t===s?e:h(ae,e,c(t)),[ie]:(e,t)=>{const r=h(ie,e,c(t));return r&&V(r,y)},[le]:(e,t)=>t===s||h(le,e,c(t)),[ue]:e=>h(ue,e),[fe]:e=>h(fe,e).map(y),[pe]:e=>h(pe,e),[de]:(e,t,r)=>h(de,e,c(t),c(r)),[ge]:(e,t)=>h(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return y(t).apply(y(s),o.map(y));case ye:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],w),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window");const me=new WeakMap,be=(e,...t)=>{const r=T(e,...t);if(!me.has(r)){const t=e instanceof Worker?he:we;me.set(r,t(r,d,g))}return me.get(r)};be.transfer=T.transfer;const{isArray:ve}=Array,{assign:Se,create:Pe,defineProperties:Ae,defineProperty:Ee,entries:Me}=Object,{all:je,resolve:$e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),_e=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),ke=e=>e.json(),Te=e=>e.text(),Oe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),Fe=new WeakMap,We=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Fe.set(t,r),t}}},Re=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Be=e=>{const t=e.split("/");return t.pop(),t.join("/")},Je=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Le=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},Ie=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},He=new WeakMap,Ce=(e,t,r)=>je((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ve(n))return n.map((r=>({url:Ie([e,r]),path:Ie([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:Ie([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(_e(t,He.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),De=(e,t,r)=>{e.registerJsModule(t,r)},Ne=(e,t)=>{try{return e.runPython(Oe(t))}catch(t){Fe.get(e).stderr(t)}},Ue=(e,t)=>{try{return e.runPythonAsync(Oe(t))}catch(t){Fe.get(e).stderr(t)}},ze=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Fe.get(e).stderr(t)}};var qe={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=We();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ce(this,a,t.fetch),a},registerJSModule:De,run:Ne,runAsync:Ue,runEvent:ze,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Re({FS:e,PATH:t,PATH_FS:r},n,s)};const Ke={dict_converter:Object.fromEntries};var Ye={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=We(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ce(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:De,run:Ne,runAsync:Ue,runEvent:ze,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ke):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Re({FS:e,PATH:t,PATH_FS:r},n,s)};const Ge="ruby-wasm-wasi",Ve=Ge.replace(/\\W+/g,"_");var Qe={type:Ge,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ce(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of Me(r)){const r=`__module_${Ve}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t)=>e.eval(Oe(t)),runAsync:(e,t)=>e.evalAsync(Oe(t)),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Ve}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ge}`)}};var Xe={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=We(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ce(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of Me(r))e.global.set(t,n)},run:(e,t)=>{try{return e.doStringSync(Oe(t))}catch(t){Fe.get(e).stderr(t)}},runAsync:(e,t)=>{try{return e.doString(Oe(t))}catch(t){Fe.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Fe.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Je(e,Be(t)),t=Le(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const Ze=new Map,et=new Map,tt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=Ze.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{et.set(t,e);const a=e?.fetch;return a&&He.set(a,o),s(n,e,r)}))}}),rt=e=>{for(const t of[].concat(e.type))Ze.set(t,e)};for(const e of[qe,Ye,Qe,Xe])rt(e);const nt=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let st,ot,at;const it=(e,t)=>{addEventListener(e,t||(async t=>{try{await st,ot(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:ct,stringify:lt}=f,{proxy:ut,window:ft,isWindowProxy:pt}=be(self,{parse:ct,stringify:lt,transform:e=>at?at(e):e}),dt={sync:ut,window:ft,isWindowProxy:pt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};it("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{st=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(ke),t=_e(t);else if(t.endsWith(".toml"))r=fetch(t).then(Te).then(nt),t=_e(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=nt(t)}t=_e("./config.txt")}return $e(r).then((r=>tt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Pe(Ze.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r)=>e(t,`${r}\\n${o}`)}if(a){const e=l[u].bind(l);l[u]=(t,r)=>e(t,`${a}\\n${r}`)}}return l.registerJSModule(c,"polyscript",{xworker:dt}),ot=l.runEvent.bind(l,c),at=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),it("error"),it("message"),it("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Be;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=$e(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Oe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return ke(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ae(n,h).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Le=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Ne=new WeakMap,Ce=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Ne.set(t,r),t}}},Je=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},He=e=>{const t=e.split("/");return t.pop(),t.join("/")},De=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ue=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},ze=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},qe=new WeakMap,Ye=(e,t,r)=>Me((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Ee(n))return n.map((r=>({url:ze([e,r]),path:ze([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:ze([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch($e(t,qe.get(e))))(r,n).then(Te).then((r=>e.writeFile(t,s,r)))))),Qe=(e,t,r)=>{e.registerJsModule(t,r)},Xe=(e,t)=>{try{return e.runPython(Le(t))}catch(t){Ne.get(e).stderr(t)}},Ge=(e,t)=>{try{return e.runPythonAsync(Le(t))}catch(t){Ne.get(e).stderr(t)}},Ze=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ne.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Ce();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Qe,run:Xe,runAsync:Ge,runEvent:Ze,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Je({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve={dict_converter:Object.fromEntries};var et={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Ce(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Qe,run:Xe,runAsync:Ge,runEvent:Ze,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ve):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Je({FS:e,PATH:t,PATH_FS:r},n,s)};const tt="ruby-wasm-wasi",rt=tt.replace(/\W+/g,"_");var nt={type:tt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of xe(r)){const r=`__module_${rt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t)=>e.eval(Le(t)),runAsync:(e,t)=>e.evalAsync(Le(t)),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${rt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${tt}`)}};var st={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Ce(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of xe(r))e.global.set(t,n)},run:(e,t)=>{try{return e.doStringSync(Le(t))}catch(t){Ne.get(e).stderr(t)}},runAsync:(e,t)=>{try{return e.doString(Le(t))}catch(t){Ne.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ne.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(De(e,He(t)),t=Ue(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const ot=new Map,at=new Map,it=[],ct=[],lt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=ot.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{at.set(t,e);const a=e?.fetch;return a&&qe.set(a,o),s(n,e,r)}))}}),ut=e=>{for(const t of[].concat(e.type))ot.set(t,e),it.push(`script[type="${t}"]`),ct.push(`${t}-`)};for(const e of[Ke,et,nt,st])ut(e);const pt=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),ft=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(We),t=$e(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(pt),t=$e(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=pt(t)}t=$e("./config.txt")}return Re(r).then((r=>lt[e](r,t)))},dt=(e,t="")=>`${e}@${t}`.replace(/@$/,""),ht=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},yt=new WeakMap,mt={get(){let e=yt.get(this);return e||(e=document.createElement(`${this.type}-script`),yt.set(this,e),_t(this)),e},set(e){"string"==typeof e?yt.set(this,ht(this,e)):(yt.set(this,e),_t(this))}},gt=new WeakMap,wt=new Map,bt=(e,t)=>{const r=e?.value;return r?t+r:""},vt=(e,t,r,n,s,o=e)=>{if(!wt.has(t)){const a={interpreter:ft(r,s),queue:Re(),XWorker:Ie(e,n)};wt.set(t,a),wt.has(e)||wt.set(e,a),wt.has(o)||wt.set(o,a)}return wt.get(t)},_t=async e=>{if(gt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=dt(c,l);let p=bt(r,"|");const f=bt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Ie(c,l))(d,{async:!!t,config:p});return void gt.set(Pe(e,"xworker",{value:r}),{xworker:r})}const h=bt(s,""),y=vt(c,f,u,l,p);gt.set(Pe(e,"target",mt),y),h&&yt.set(e,ht(e,h));const m=i?fetch(i).then(Oe):e.textContent;y.queue=y.queue.then((()=>(async(e,t,r,n)=>{const s=ot.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await Me([gt.get(e).interpreter,t]);try{return Pe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,y.XWorker,!!t)))}};new Proxy(je(null),{get:(e,t)=>At(t)});const At=async e=>{if(wt.has(e)){const{interpreter:t,queue:r}=wt.get(e);return(await Me([t,r]))[0]}const t=wt.size?`Available interpreters are: ${[...wt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},Et=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${ct.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await At(a.getAttribute(`${s}-env`)||s);ot.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${ct.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,Et)},jt=[],kt=new Map,Pt=new Map,xt=e=>{for(const t of jt)if(e.matches(t)){const r=kt.get(t),{resolve:n}=Pt.get(r),{options:s,known:o}=Mt.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=$t.call(new Be(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return Pe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=dt(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:h}=vt(r,f,p,i,a,t);d.then((o=>{const a=je(ot.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Be(o,s),y=function(...e){return h.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o){r&&r.call(this,m,e);const a=s.call(this,t,o);return n&&n.call(this,m,e),a}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o){r&&await r.call(this,m,e);const a=await s.call(this,t,o);return n&&await n.call(this,m,e),a}}a.registerJSModule(o,"polyscript",{XWorker:y});const m={type:r,interpreter:o,XWorker:y,io:Ne.get(o),config:structuredClone(at.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},Mt=new Map,Rt=e=>(Pt.has(e)||Pt.set(e,Promise.withResolvers()),Pt.get(e).promise),$t=Ie(),Tt=it.join(","),Wt=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Tt))_t(e);else{if(t(Tt,e).forEach(_t),!jt.length)continue;xt(e),t(jt.join(","),e).forEach(xt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of ct)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,Et)}break}}}})),Ot=e=>(Wt.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:Ft}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ot(Ft.call(this,e))}}),St(Ot(document)),t(Tt,document).forEach(_t);var Bt='# ⚠️ WARNING - both `document` and `window` are added at runtime\n\nimport base64\nimport html\nimport io\nimport re\n\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" + + + From 74cd7c840aa995b617fa9a5eba307e8a9b3c8372 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 31 Aug 2023 10:43:28 +0200 Subject: [PATCH 004/105] [next] Sanitize content + deprecate html content (#1663) --- pyscript.core/core.js | 2 +- pyscript.core/src/core.js | 19 ++++++++++++++----- pyscript.core/src/utils.js | 6 ++++++ pyscript.core/test/html-decode.html | 13 +++++++++++++ pyscript.core/types/utils.d.ts | 1 + 5 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 pyscript.core/src/utils.js create mode 100644 pyscript.core/test/html-decode.html create mode 100644 pyscript.core/types/utils.d.ts diff --git a/pyscript.core/core.js b/pyscript.core/core.js index 305d11c3..2fb42792 100644 --- a/pyscript.core/core.js +++ b/pyscript.core/core.js @@ -1,2 +1,2 @@ Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var h=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const y="891249cd-eb53-4bc8-ae48-b0a5a277d24a",m="M"+y,g="T"+y;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:k}=A,{isArray:S}=Array,{notify:j,wait:P,waitAsync:x}=Atomics,{fromCharCode:R}=String,$=(e,t)=>e?(x||w)(t,0):(P(t,0),{value:{then:e=>e()}}),M=new WeakSet,W=new WeakMap;let T=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!W.has(e)){const s=(t,...r)=>e.postMessage({[y]:r},{transfer:t});let o=!1;W.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=T++;let c=new b(new _(E)),l=[];M.has(r.at(-1)||l)&&M.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let p=0;return o&&u&&(p=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(p);const e=c[0];if(!e)return;const r=k*e;return c=new b(new _(r+r%E)),s([],i,c),$(u,c).value.then((()=>t(R(...new A(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[y];if(S(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new A(i.buffer),r=0;r(M.add(e),e);const F="object",B="function",I="number",L="string",N="undefined",J="symbol",{defineProperty:C,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Q,setPrototypeOf:Y}=Reflect,{assign:X,create:G}=Object,K=D(Int8Array),V="isArray",Z=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case B:return e(r,t);case"boolean":case I:case L:case N:case"bigint":return ee(r,t);case J:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",he="ownKeys",ye="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;C(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?X(G(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),h=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===I)return l.get(r);if(!(r instanceof K))for(const e in r)r[e]=h(r[e]);return r;case B:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(B,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ne(r)}return r},y={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(C(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,Z(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[he]:e=>ee(F,z(e).map(f)),[ye]:e=>f(q(e)),[me]:(e,t,r)=>f(Q(e,t,r)),[ge]:(e,t)=>f(Y(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=h(r[0]),r[1]=r[1].map(h);break;case ae:r[0]=r[0].map(h);break;case ie:{const[e,t]=r;r[0]=h(e);const{get:n,set:s,value:o}=t;n&&(t.get=h(n)),s&&(t.set=h(s)),o&&(t.value=h(o));break}default:r=r.map(h)}return y[e](h(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===B?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[V],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===B){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof K))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),h=e=>{const[t,r]=e;if(!f.has(r)){const n=t===B?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===I?h(e):r;case B:return typeof r===L?n.get(r):h(e);case J:return ne(r)}return r},m=(e,t,...r)=>y(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===B&&(r.get=c(n)),typeof s===B&&(r.set=c(s)),typeof o===B&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&Z(r,y)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[he]:e=>m(he,e).map(y),[ye]:e=>m(ye,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return y(t).apply(y(s),o.map(y));case we:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[V];return C(Array,V,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window"),_e="function"==typeof Worker?Worker:class{};const Ae=new WeakMap,Ee=(e,...t)=>{const r=O(e,...t);if(!Ae.has(r)){const t=e instanceof _e?be:ve;Ae.set(r,t(r,m,g))}return Ae.get(r)};Ee.transfer=O.transfer;const{isArray:ke}=Array,{assign:Se,create:je,defineProperties:Pe,defineProperty:xe,entries:Re}=Object,{all:$e,resolve:Me}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),We=(e,t=location.href)=>new URL(e,t).href,Te=e=>e.arrayBuffer(),Oe=e=>e.json(),Fe=e=>e.text(),Be=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Ie{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Be)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Be)this[t]&&(e[t]=this[t]);return e}}var Le=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="891249cd-eb53-4bc8-ae48-b0a5a277d24a",d="M"+p,y="T"+p;var g=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:w,Map:h,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=w,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||g)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,k=new WeakMap;let x=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!k.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});let o=!1;k.set(e,new Proxy(new h,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=x++;let c=new w(new m(v)),l=[];_.has(r.at(-1)||l)&&_.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let f=0;return o&&u&&(f=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(f);const e=c[0];if(!e)return;const r=S*e;return c=new w(new m(r+r%v)),s([],i,c),$(u,c).value.then((()=>t(j(...new b(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new h;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new b(i.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ye="setPrototypeOf",ge="delete";var we=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ge,Q(R,e))})),y=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=y(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},g={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ye]:(e,t)=>p(z(e,t)),[ge](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=y(r[0]),r[1]=r[1].map(y);break;case ne:r[0]=r[0].map(y);break;case se:{const[e,t]=r;r[0]=y(e);const{get:n,set:s,value:o}=t;n&&(t.get=y(n)),s&&(t.set=y(s)),o&&(t.value=y(o));break}default:r=r.map(y)}return g[e](y(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),he=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ge,c(e))})),y=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,h),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},g=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?y(e):r;case F:return typeof r===R?n.get(r):y(e);case J:return ee(r)}return r},w=(e,t,...r)=>g(f(e,o(t),...r)),h={[re]:(e,t,r)=>w(re,e,c(t),r.map(c)),[ne]:(e,t)=>w(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),w(se,e,c(t),r)},[oe]:(e,t)=>w(oe,e,c(t)),[ce]:e=>w(ce,e),[ae]:(e,t)=>t===s?e:w(ae,e,c(t)),[ie]:(e,t)=>{const r=w(ie,e,c(t));return r&&V(r,g)},[le]:(e,t)=>t===s||w(le,e,c(t)),[ue]:e=>w(ue,e),[fe]:e=>w(fe,e).map(g),[pe]:e=>w(pe,e),[de]:(e,t,r)=>w(de,e,c(t),c(r)),[ye]:(e,t)=>w(ye,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return g(t).apply(g(s),o.map(g));case ge:{const e=g(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],h),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window"),me="function"==typeof Worker?Worker:class{};const be=new WeakMap,ve=(e,...t)=>{const r=T(e,...t);if(!be.has(r)){const t=e instanceof me?we:he;be.set(r,t(r,d,y))}return be.get(r)};ve.transfer=T.transfer;const{isArray:Se}=Array,{assign:Pe,create:Ae,defineProperties:Ee,defineProperty:Me,entries:je}=Object,{all:$e,resolve:_e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),ke=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),Te=e=>e.json(),Oe=e=>e.text(),Fe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),We=new WeakMap,Re=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return We.set(t,r),t}}},Be=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Je=e=>{const t=e.split("/");return t.pop(),t.join("/")},Le=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ie=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},He=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Ce=new WeakMap,De=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Se(n))return n.map((r=>({url:He([e,r]),path:He([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:He([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(ke(t,Ce.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),Ne=(e,t,r)=>{e.registerJsModule(t,r)},Ue=(e,t,...r)=>{try{return e.runPython(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},ze=async(e,t,...r)=>{try{return await e.runPythonAsync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},qe=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Re();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await De(this,a,t.fetch),a},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ye={dict_converter:Object.fromEntries};var Ge={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Re(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await De(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ye):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve="ruby-wasm-wasi",Qe=Ve.replace(/\\W+/g,"_");var Xe={type:Ve,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await De(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of je(r)){const r=`__module_${Qe}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Fe(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Fe(t),...r),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Qe}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ve}`)}};var Ze={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Re(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await De(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of je(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Le(e,Je(t)),t=Ie(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const et=new Map,tt=new Map,rt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=et.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{tt.set(t,e);const a=e?.fetch;return a&&Ce.set(a,o),s(n,e,r)}))}}),nt=e=>{for(const t of[].concat(e.type))et.set(t,e)};for(const e of[Ke,Ge,Xe,Ze])nt(e);const st=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let ot,at,it;const ct=(e,t)=>{addEventListener(e,t||(async t=>{try{await ot,at(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:lt,stringify:ut}=f,{proxy:ft,window:pt,isWindowProxy:dt}=ve(self,{parse:lt,stringify:ut,transform:e=>it?it(e):e}),yt={sync:ft,window:pt,isWindowProxy:dt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};ct("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{ot=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Te),t=ke(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(st),t=ke(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=st(t)}t=ke("./config.txt")}return _e(r).then((r=>rt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Ae(et.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${r}\\n${o}`,...n)}if(a){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${a}\\n${r}`,...n)}}return l.registerJSModule(c,"polyscript",{xworker:yt}),at=l.runEvent.bind(l,c),it=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),ct("error"),ct("message"),ct("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Ie;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=We(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Fe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return Pe(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ee(n,h).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Ne=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Je=new WeakMap,Ce=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Je.set(t,r),t}}},He=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},De=e=>{const t=e.split("/");return t.pop(),t.join("/")},Ue=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},ze=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},qe=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Qe=new WeakMap,Ye=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ke(n))return n.map((r=>({url:qe([e,r]),path:qe([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:qe([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(We(t,Qe.get(e))))(r,n).then(Te).then((r=>e.writeFile(t,s,r)))))),Xe=(e,t,r)=>{e.registerJsModule(t,r)},Ge=(e,t,...r)=>{try{return e.runPython(Ne(t),...r)}catch(t){Je.get(e).stderr(t)}},Ke=async(e,t,...r)=>{try{return await e.runPythonAsync(Ne(t),...r)}catch(t){Je.get(e).stderr(t)}},Ve=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Je.get(e).stderr(t)}};var Ze={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Ce();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const et={dict_converter:Object.fromEntries};var tt={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Ce(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(et):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const rt="ruby-wasm-wasi",nt=rt.replace(/\W+/g,"_");var st={type:rt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of Re(r)){const r=`__module_${nt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Ne(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Ne(t),...r),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${nt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${rt}`)}};var ot={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Ce(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of Re(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Ne(t),...r)}catch(t){Je.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Ne(t),...r)}catch(t){Je.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Je.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Ue(e,De(t)),t=ze(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const at=new Map,it=new Map,ct=[],lt=[],ut=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=at.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{it.set(t,e);const a=e?.fetch;return a&&Qe.set(a,o),s(n,e,r)}))}}),pt=e=>{for(const t of[].concat(e.type))at.set(t,e),ct.push(`script[type="${t}"]`),lt.push(`${t}-`)};for(const e of[Ze,tt,st,ot])pt(e);const ft=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),dt=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Oe),t=We(t);else if(t.endsWith(".toml"))r=fetch(t).then(Fe).then(ft),t=We(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=ft(t)}t=We("./config.txt")}return Me(r).then((r=>ut[e](r,t)))},ht=(e,t="")=>`${e}@${t}`.replace(/@$/,""),yt=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},mt=new WeakMap,gt={get(){let e=mt.get(this);return e||(e=document.createElement(`${this.type}-script`),mt.set(this,e),At(this)),e},set(e){"string"==typeof e?mt.set(this,yt(this,e)):(mt.set(this,e),At(this))}},wt=new WeakMap,bt=new Map,vt=(e,t)=>{const r=e?.value;return r?t+r:""},_t=(e,t,r,n,s,o=e)=>{if(!bt.has(t)){const a={interpreter:dt(r,s),queue:Me(),XWorker:Le(e,n)};bt.set(t,a),bt.has(e)||bt.set(e,a),bt.has(o)||bt.set(o,a)}return bt.get(t)},At=async e=>{if(wt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=ht(c,l);let p=vt(r,"|");const f=vt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Le(c,l))(d,{async:!!t,config:p});return void wt.set(xe(e,"xworker",{value:r}),{xworker:r})}const h=vt(s,""),y=_t(c,f,u,l,p);wt.set(xe(e,"target",gt),y),h&&mt.set(e,yt(e,h));const m=i?fetch(i).then(Fe):e.textContent;y.queue=y.queue.then((()=>(async(e,t,r,n)=>{const s=at.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await $e([wt.get(e).interpreter,t]);try{return xe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,y.XWorker,!!t)))}};new Proxy(je(null),{get:(e,t)=>Et(t)});const Et=async e=>{if(bt.has(e)){const{interpreter:t,queue:r}=bt.get(e);return(await $e([t,r]))[0]}const t=bt.size?`Available interpreters are: ${[...bt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},kt=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${lt.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await Et(a.getAttribute(`${s}-env`)||s);at.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${lt.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,kt)},jt=[],Pt=new Map,xt=new Map,Rt=e=>{for(const t of jt)if(e.matches(t)){const r=Pt.get(t),{resolve:n}=xt.get(r),{options:s,known:o}=$t.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=Wt.call(new Ie(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return xe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=ht(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:h}=_t(r,f,p,i,a,t);d.then((o=>{const a=je(at.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Ie(o,s),y=function(...e){return h.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o,...a){r&&r.call(this,m,e);const i=s.call(this,t,o,...a);return n&&n.call(this,m,e),i}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o,...a){r&&await r.call(this,m,e);const i=await s.call(this,t,o,...a);return n&&await n.call(this,m,e),i}}a.registerJSModule(o,"polyscript",{XWorker:y});const m={type:r,interpreter:o,XWorker:y,io:Je.get(o),config:structuredClone(it.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},$t=new Map,Mt=e=>(xt.has(e)||xt.set(e,Promise.withResolvers()),xt.get(e).promise),Wt=Le(),Tt=ct.join(","),Ot=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Tt))At(e);else{if(t(Tt,e).forEach(At),!jt.length)continue;Rt(e),t(jt.join(","),e).forEach(Rt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of lt)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,kt)}break}}}})),Ft=e=>(Ot.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:Bt}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ft(Bt.call(this,e))}}),St(Ft(document)),t(Tt,document).forEach(At);var It='# ⚠️ WARNING - both `document` and `window` are added at runtime\n\nimport base64\nimport html\nimport io\nimport re\n\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" + + + + import js; js.console.log(1<2, 1>2) + js.console.log("
")
+ + + diff --git a/pyscript.core/types/utils.d.ts b/pyscript.core/types/utils.d.ts new file mode 100644 index 00000000..266953e3 --- /dev/null +++ b/pyscript.core/types/utils.d.ts @@ -0,0 +1 @@ +export function htmlDecode(html: any): string; From 4cc9647dc6c2cb9c07b8d7f960b57d4d199a16fd Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 31 Aug 2023 14:23:01 +0200 Subject: [PATCH 005/105] [next] allow document.createElement(py-script) (#1662) --- pyscript.core/core.js | 2 +- pyscript.core/src/core.js | 17 ++++++++---- pyscript.core/test/create-element.html | 36 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 pyscript.core/test/create-element.html diff --git a/pyscript.core/core.js b/pyscript.core/core.js index 2fb42792..e346e9cd 100644 --- a/pyscript.core/core.js +++ b/pyscript.core/core.js @@ -1,2 +1,2 @@ Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var h=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const y="891249cd-eb53-4bc8-ae48-b0a5a277d24a",m="M"+y,g="T"+y;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:k}=A,{isArray:S}=Array,{notify:j,wait:P,waitAsync:x}=Atomics,{fromCharCode:M}=String,R=(e,t)=>e?(x||w)(t,0):(P(t,0),{value:{then:e=>e()}}),$=new WeakSet,T=new WeakMap;let W=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!T.has(e)){const s=(t,...r)=>e.postMessage({[y]:r},{transfer:t});let o=!1;T.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=W++;let c=new b(new _(E)),l=[];$.has(r.at(-1)||l)&&$.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let p=0;return o&&u&&(p=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),R(u,c).value.then((()=>{clearTimeout(p);const e=c[0];if(!e)return;const r=k*e;return c=new b(new _(r+r%E)),s([],i,c),R(u,c).value.then((()=>t(M(...new A(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[y];if(S(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new A(i.buffer),r=0;r($.add(e),e);const F="object",B="function",I="number",L="string",N="undefined",C="symbol",{defineProperty:J,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Q,setPrototypeOf:Y}=Reflect,{assign:X,create:G}=Object,K=D(Int8Array),V="isArray",Z=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case B:return e(r,t);case"boolean":case I:case L:case N:case"bigint":return ee(r,t);case C:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===C)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",he="ownKeys",ye="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;J(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?X(G(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),h=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===I)return l.get(r);if(!(r instanceof K))for(const e in r)r[e]=h(r[e]);return r;case B:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(B,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case C:return ne(r)}return r},y={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(J(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,Z(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[he]:e=>ee(F,z(e).map(f)),[ye]:e=>f(q(e)),[me]:(e,t,r)=>f(Q(e,t,r)),[ge]:(e,t)=>f(Y(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=h(r[0]),r[1]=r[1].map(h);break;case ae:r[0]=r[0].map(h);break;case ie:{const[e,t]=r;r[0]=h(e);const{get:n,set:s,value:o}=t;n&&(t.get=h(n)),s&&(t.set=h(s)),o&&(t.value=h(o));break}default:r=r.map(h)}return y[e](h(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===B?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[V],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===B){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof K))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),h=e=>{const[t,r]=e;if(!f.has(r)){const n=t===B?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===I?h(e):r;case B:return typeof r===L?n.get(r):h(e);case C:return ne(r)}return r},m=(e,t,...r)=>y(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===B&&(r.get=c(n)),typeof s===B&&(r.set=c(s)),typeof o===B&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&Z(r,y)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[he]:e=>m(he,e).map(y),[ye]:e=>m(ye,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return y(t).apply(y(s),o.map(y));case we:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[V];return J(Array,V,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window"),_e="function"==typeof Worker?Worker:class{};const Ae=new WeakMap,Ee=(e,...t)=>{const r=O(e,...t);if(!Ae.has(r)){const t=e instanceof _e?be:ve;Ae.set(r,t(r,m,g))}return Ae.get(r)};Ee.transfer=O.transfer;const{isArray:ke}=Array,{assign:Se,create:je,defineProperties:Pe,defineProperty:xe,entries:Me}=Object,{all:Re,resolve:$e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),Te=(e,t=location.href)=>new URL(e,t).href,We=e=>e.arrayBuffer(),Oe=e=>e.json(),Fe=e=>e.text(),Be=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Ie{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Be)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Be)this[t]&&(e[t]=this[t]);return e}}var Le=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="891249cd-eb53-4bc8-ae48-b0a5a277d24a",d="M"+p,y="T"+p;var g=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:w,Map:h,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=w,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||g)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,k=new WeakMap;let x=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!k.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});let o=!1;k.set(e,new Proxy(new h,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=x++;let c=new w(new m(v)),l=[];_.has(r.at(-1)||l)&&_.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let f=0;return o&&u&&(f=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(f);const e=c[0];if(!e)return;const r=S*e;return c=new w(new m(r+r%v)),s([],i,c),$(u,c).value.then((()=>t(j(...new b(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new h;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new b(i.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ye="setPrototypeOf",ge="delete";var we=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ge,Q(R,e))})),y=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=y(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},g={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ye]:(e,t)=>p(z(e,t)),[ge](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=y(r[0]),r[1]=r[1].map(y);break;case ne:r[0]=r[0].map(y);break;case se:{const[e,t]=r;r[0]=y(e);const{get:n,set:s,value:o}=t;n&&(t.get=y(n)),s&&(t.set=y(s)),o&&(t.value=y(o));break}default:r=r.map(y)}return g[e](y(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),he=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ge,c(e))})),y=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,h),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},g=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?y(e):r;case F:return typeof r===R?n.get(r):y(e);case J:return ee(r)}return r},w=(e,t,...r)=>g(f(e,o(t),...r)),h={[re]:(e,t,r)=>w(re,e,c(t),r.map(c)),[ne]:(e,t)=>w(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),w(se,e,c(t),r)},[oe]:(e,t)=>w(oe,e,c(t)),[ce]:e=>w(ce,e),[ae]:(e,t)=>t===s?e:w(ae,e,c(t)),[ie]:(e,t)=>{const r=w(ie,e,c(t));return r&&V(r,g)},[le]:(e,t)=>t===s||w(le,e,c(t)),[ue]:e=>w(ue,e),[fe]:e=>w(fe,e).map(g),[pe]:e=>w(pe,e),[de]:(e,t,r)=>w(de,e,c(t),c(r)),[ye]:(e,t)=>w(ye,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return g(t).apply(g(s),o.map(g));case ge:{const e=g(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],h),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window"),me="function"==typeof Worker?Worker:class{};const be=new WeakMap,ve=(e,...t)=>{const r=T(e,...t);if(!be.has(r)){const t=e instanceof me?we:he;be.set(r,t(r,d,y))}return be.get(r)};ve.transfer=T.transfer;const{isArray:Se}=Array,{assign:Pe,create:Ae,defineProperties:Ee,defineProperty:Me,entries:je}=Object,{all:$e,resolve:_e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),ke=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),Te=e=>e.json(),Oe=e=>e.text(),Fe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),We=new WeakMap,Re=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return We.set(t,r),t}}},Be=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Je=e=>{const t=e.split("/");return t.pop(),t.join("/")},Le=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ie=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},He=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Ce=new WeakMap,De=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Se(n))return n.map((r=>({url:He([e,r]),path:He([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:He([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(ke(t,Ce.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),Ne=(e,t,r)=>{e.registerJsModule(t,r)},Ue=(e,t,...r)=>{try{return e.runPython(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},ze=async(e,t,...r)=>{try{return await e.runPythonAsync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},qe=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Re();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await De(this,a,t.fetch),a},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ye={dict_converter:Object.fromEntries};var Ge={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Re(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await De(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ye):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve="ruby-wasm-wasi",Qe=Ve.replace(/\\W+/g,"_");var Xe={type:Ve,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await De(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of je(r)){const r=`__module_${Qe}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Fe(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Fe(t),...r),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Qe}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ve}`)}};var Ze={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Re(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await De(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of je(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Le(e,Je(t)),t=Ie(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const et=new Map,tt=new Map,rt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=et.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{tt.set(t,e);const a=e?.fetch;return a&&Ce.set(a,o),s(n,e,r)}))}}),nt=e=>{for(const t of[].concat(e.type))et.set(t,e)};for(const e of[Ke,Ge,Xe,Ze])nt(e);const st=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let ot,at,it;const ct=(e,t)=>{addEventListener(e,t||(async t=>{try{await ot,at(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:lt,stringify:ut}=f,{proxy:ft,window:pt,isWindowProxy:dt}=ve(self,{parse:lt,stringify:ut,transform:e=>it?it(e):e}),yt={sync:ft,window:pt,isWindowProxy:dt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};ct("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{ot=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Te),t=ke(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(st),t=ke(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=st(t)}t=ke("./config.txt")}return _e(r).then((r=>rt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Ae(et.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${r}\\n${o}`,...n)}if(a){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${a}\\n${r}`,...n)}}return l.registerJSModule(c,"polyscript",{xworker:yt}),at=l.runEvent.bind(l,c),it=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),ct("error"),ct("message"),ct("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Ie;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=Te(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Fe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return Pe(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ee(n,h).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Ne=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Ce=new WeakMap,Je=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Ce.set(t,r),t}}},He=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},De=e=>{const t=e.split("/");return t.pop(),t.join("/")},Ue=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},ze=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},qe=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Qe=new WeakMap,Ye=(e,t,r)=>Re((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ke(n))return n.map((r=>({url:qe([e,r]),path:qe([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:qe([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(Te(t,Qe.get(e))))(r,n).then(We).then((r=>e.writeFile(t,s,r)))))),Xe=(e,t,r)=>{e.registerJsModule(t,r)},Ge=(e,t,...r)=>{try{return e.runPython(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ke=async(e,t,...r)=>{try{return await e.runPythonAsync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ve=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}};var Ze={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Je();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const et={dict_converter:Object.fromEntries};var tt={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Je(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(et):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const rt="ruby-wasm-wasi",nt=rt.replace(/\W+/g,"_");var st={type:rt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of Me(r)){const r=`__module_${nt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Ne(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Ne(t),...r),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${nt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${rt}`)}};var ot={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Je(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of Me(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Ue(e,De(t)),t=ze(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const at=new Map,it=new Map,ct=[],lt=[],ut=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=at.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{it.set(t,e);const a=e?.fetch;return a&&Qe.set(a,o),s(n,e,r)}))}}),pt=e=>{for(const t of[].concat(e.type))at.set(t,e),ct.push(`script[type="${t}"]`),lt.push(`${t}-`)};for(const e of[Ze,tt,st,ot])pt(e);const ft=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),dt=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Oe),t=Te(t);else if(t.endsWith(".toml"))r=fetch(t).then(Fe).then(ft),t=Te(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=ft(t)}t=Te("./config.txt")}return $e(r).then((r=>ut[e](r,t)))},ht=(e,t="")=>`${e}@${t}`.replace(/@$/,""),yt=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},mt=new WeakMap,gt={get(){let e=mt.get(this);return e||(e=document.createElement(`${this.type}-script`),mt.set(this,e),At(this)),e},set(e){"string"==typeof e?mt.set(this,yt(this,e)):(mt.set(this,e),At(this))}},wt=new WeakMap,bt=new Map,vt=(e,t)=>{const r=e?.value;return r?t+r:""},_t=(e,t,r,n,s,o=e)=>{if(!bt.has(t)){const a={interpreter:dt(r,s),queue:$e(),XWorker:Le(e,n)};bt.set(t,a),bt.has(e)||bt.set(e,a),bt.has(o)||bt.set(o,a)}return bt.get(t)},At=async e=>{if(wt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=ht(c,l);let p=vt(r,"|");const f=vt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Le(c,l))(d,{async:!!t,config:p});return void wt.set(xe(e,"xworker",{value:r}),{xworker:r})}const h=vt(s,""),y=_t(c,f,u,l,p);wt.set(xe(e,"target",gt),y),h&&mt.set(e,yt(e,h));const m=i?fetch(i).then(Fe):e.textContent;y.queue=y.queue.then((()=>(async(e,t,r,n)=>{const s=at.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await Re([wt.get(e).interpreter,t]);try{return xe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,y.XWorker,!!t)))}};new Proxy(je(null),{get:(e,t)=>Et(t)});const Et=async e=>{if(bt.has(e)){const{interpreter:t,queue:r}=bt.get(e);return(await Re([t,r]))[0]}const t=bt.size?`Available interpreters are: ${[...bt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},kt=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${lt.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await Et(a.getAttribute(`${s}-env`)||s);at.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${lt.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,kt)},jt=[],Pt=new Map,xt=new Map,Mt=e=>{for(const t of jt)if(e.matches(t)){const r=Pt.get(t),{resolve:n}=xt.get(r),{options:s,known:o}=Rt.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=Tt.call(new Ie(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return xe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=ht(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:h}=_t(r,f,p,i,a,t);d.then((o=>{const a=je(at.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Ie(o,s),y=function(...e){return h.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o,...a){r&&r.call(this,m,e);const i=s.call(this,t,o,...a);return n&&n.call(this,m,e),i}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o,...a){r&&await r.call(this,m,e);const i=await s.call(this,t,o,...a);return n&&await n.call(this,m,e),i}}a.registerJSModule(o,"polyscript",{XWorker:y});const m={type:r,interpreter:o,XWorker:y,io:Ce.get(o),config:structuredClone(it.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},Rt=new Map,$t=e=>(xt.has(e)||xt.set(e,Promise.withResolvers()),xt.get(e).promise),Tt=Le(),Wt=ct.join(","),Ot=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Wt))At(e);else{if(t(Wt,e).forEach(At),!jt.length)continue;Mt(e),t(jt.join(","),e).forEach(Mt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of lt)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,kt)}break}}}})),Ft=e=>(Ot.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:Bt}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ft(Bt.call(this,e))}}),St(Ft(document)),t(Wt,document).forEach(At);const It={"<":"<",">":">"},Lt=e=>{return(new DOMParser).parseFromString((t=e,t.replace(/[<>]/g,(e=>It[e]))),"text/html").documentElement.textContent;var t};var Nt='# ⚠️ WARNING - both `document` and `window` are added at runtime\n\nimport base64\nimport html\nimport io\nimport re\n\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" + + + From da3b43abddbe0f9970aed091cb520ba136f1b00a Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 31 Aug 2023 15:37:17 +0200 Subject: [PATCH 006/105] [next] xworker.sync pollution example (#1659) --- pyscript.core/core.js | 4 ++-- pyscript.core/src/core.js | 8 +++++++- pyscript.core/src/sync.js | 5 +++++ pyscript.core/test/worker.py | 6 +++++- pyscript.core/types/core.d.ts | 1 + pyscript.core/types/sync.d.ts | 4 ++++ 6 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 pyscript.core/src/sync.js create mode 100644 pyscript.core/types/sync.d.ts diff --git a/pyscript.core/core.js b/pyscript.core/core.js index e346e9cd..48b36654 100644 --- a/pyscript.core/core.js +++ b/pyscript.core/core.js @@ -1,2 +1,2 @@ -Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var h=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const y="891249cd-eb53-4bc8-ae48-b0a5a277d24a",m="M"+y,g="T"+y;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:k}=A,{isArray:S}=Array,{notify:j,wait:P,waitAsync:x}=Atomics,{fromCharCode:M}=String,R=(e,t)=>e?(x||w)(t,0):(P(t,0),{value:{then:e=>e()}}),$=new WeakSet,T=new WeakMap;let W=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!T.has(e)){const s=(t,...r)=>e.postMessage({[y]:r},{transfer:t});let o=!1;T.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=W++;let c=new b(new _(E)),l=[];$.has(r.at(-1)||l)&&$.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let p=0;return o&&u&&(p=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),R(u,c).value.then((()=>{clearTimeout(p);const e=c[0];if(!e)return;const r=k*e;return c=new b(new _(r+r%E)),s([],i,c),R(u,c).value.then((()=>t(M(...new A(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[y];if(S(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new A(i.buffer),r=0;r($.add(e),e);const F="object",B="function",I="number",L="string",N="undefined",C="symbol",{defineProperty:J,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Q,setPrototypeOf:Y}=Reflect,{assign:X,create:G}=Object,K=D(Int8Array),V="isArray",Z=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case B:return e(r,t);case"boolean":case I:case L:case N:case"bigint":return ee(r,t);case C:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===C)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",he="ownKeys",ye="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;J(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?X(G(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),h=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===I)return l.get(r);if(!(r instanceof K))for(const e in r)r[e]=h(r[e]);return r;case B:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(B,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case C:return ne(r)}return r},y={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(J(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,Z(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[he]:e=>ee(F,z(e).map(f)),[ye]:e=>f(q(e)),[me]:(e,t,r)=>f(Q(e,t,r)),[ge]:(e,t)=>f(Y(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=h(r[0]),r[1]=r[1].map(h);break;case ae:r[0]=r[0].map(h);break;case ie:{const[e,t]=r;r[0]=h(e);const{get:n,set:s,value:o}=t;n&&(t.get=h(n)),s&&(t.set=h(s)),o&&(t.value=h(o));break}default:r=r.map(h)}return y[e](h(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===B?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[V],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===B){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof K))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),h=e=>{const[t,r]=e;if(!f.has(r)){const n=t===B?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},y=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===I?h(e):r;case B:return typeof r===L?n.get(r):h(e);case C:return ne(r)}return r},m=(e,t,...r)=>y(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===B&&(r.get=c(n)),typeof s===B&&(r.set=c(s)),typeof o===B&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&Z(r,y)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[he]:e=>m(he,e).map(y),[ye]:e=>m(ye,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return y(t).apply(y(s),o.map(y));case we:{const e=y(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[V];return J(Array,V,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window"),_e="function"==typeof Worker?Worker:class{};const Ae=new WeakMap,Ee=(e,...t)=>{const r=O(e,...t);if(!Ae.has(r)){const t=e instanceof _e?be:ve;Ae.set(r,t(r,m,g))}return Ae.get(r)};Ee.transfer=O.transfer;const{isArray:ke}=Array,{assign:Se,create:je,defineProperties:Pe,defineProperty:xe,entries:Me}=Object,{all:Re,resolve:$e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),Te=(e,t=location.href)=>new URL(e,t).href,We=e=>e.arrayBuffer(),Oe=e=>e.json(),Fe=e=>e.text(),Be=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Ie{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Be)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Be)this[t]&&(e[t]=this[t]);return e}}var Le=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="891249cd-eb53-4bc8-ae48-b0a5a277d24a",d="M"+p,y="T"+p;var g=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:w,Map:h,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=w,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||g)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,k=new WeakMap;let x=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!k.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});let o=!1;k.set(e,new Proxy(new h,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=x++;let c=new w(new m(v)),l=[];_.has(r.at(-1)||l)&&_.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let f=0;return o&&u&&(f=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(f);const e=c[0];if(!e)return;const r=S*e;return c=new w(new m(r+r%v)),s([],i,c),$(u,c).value.then((()=>t(j(...new b(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new h;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new b(i.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ye="setPrototypeOf",ge="delete";var we=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ge,Q(R,e))})),y=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=y(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},g={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ye]:(e,t)=>p(z(e,t)),[ge](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=y(r[0]),r[1]=r[1].map(y);break;case ne:r[0]=r[0].map(y);break;case se:{const[e,t]=r;r[0]=y(e);const{get:n,set:s,value:o}=t;n&&(t.get=y(n)),s&&(t.set=y(s)),o&&(t.value=y(o));break}default:r=r.map(y)}return g[e](y(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),he=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ge,c(e))})),y=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,h),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},g=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?y(e):r;case F:return typeof r===R?n.get(r):y(e);case J:return ee(r)}return r},w=(e,t,...r)=>g(f(e,o(t),...r)),h={[re]:(e,t,r)=>w(re,e,c(t),r.map(c)),[ne]:(e,t)=>w(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),w(se,e,c(t),r)},[oe]:(e,t)=>w(oe,e,c(t)),[ce]:e=>w(ce,e),[ae]:(e,t)=>t===s?e:w(ae,e,c(t)),[ie]:(e,t)=>{const r=w(ie,e,c(t));return r&&V(r,g)},[le]:(e,t)=>t===s||w(le,e,c(t)),[ue]:e=>w(ue,e),[fe]:e=>w(fe,e).map(g),[pe]:e=>w(pe,e),[de]:(e,t,r)=>w(de,e,c(t),c(r)),[ye]:(e,t)=>w(ye,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return g(t).apply(g(s),o.map(g));case ge:{const e=g(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],h),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window"),me="function"==typeof Worker?Worker:class{};const be=new WeakMap,ve=(e,...t)=>{const r=T(e,...t);if(!be.has(r)){const t=e instanceof me?we:he;be.set(r,t(r,d,y))}return be.get(r)};ve.transfer=T.transfer;const{isArray:Se}=Array,{assign:Pe,create:Ae,defineProperties:Ee,defineProperty:Me,entries:je}=Object,{all:$e,resolve:_e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),ke=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),Te=e=>e.json(),Oe=e=>e.text(),Fe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),We=new WeakMap,Re=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return We.set(t,r),t}}},Be=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Je=e=>{const t=e.split("/");return t.pop(),t.join("/")},Le=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ie=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},He=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Ce=new WeakMap,De=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Se(n))return n.map((r=>({url:He([e,r]),path:He([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:He([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(ke(t,Ce.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),Ne=(e,t,r)=>{e.registerJsModule(t,r)},Ue=(e,t,...r)=>{try{return e.runPython(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},ze=async(e,t,...r)=>{try{return await e.runPythonAsync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},qe=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Re();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await De(this,a,t.fetch),a},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ye={dict_converter:Object.fromEntries};var Ge={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Re(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await De(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ye):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve="ruby-wasm-wasi",Qe=Ve.replace(/\\W+/g,"_");var Xe={type:Ve,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await De(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of je(r)){const r=`__module_${Qe}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Fe(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Fe(t),...r),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Qe}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ve}`)}};var Ze={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Re(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await De(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of je(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Le(e,Je(t)),t=Ie(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const et=new Map,tt=new Map,rt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=et.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{tt.set(t,e);const a=e?.fetch;return a&&Ce.set(a,o),s(n,e,r)}))}}),nt=e=>{for(const t of[].concat(e.type))et.set(t,e)};for(const e of[Ke,Ge,Xe,Ze])nt(e);const st=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let ot,at,it;const ct=(e,t)=>{addEventListener(e,t||(async t=>{try{await ot,at(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:lt,stringify:ut}=f,{proxy:ft,window:pt,isWindowProxy:dt}=ve(self,{parse:lt,stringify:ut,transform:e=>it?it(e):e}),yt={sync:ft,window:pt,isWindowProxy:dt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};ct("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{ot=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Te),t=ke(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(st),t=ke(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=st(t)}t=ke("./config.txt")}return _e(r).then((r=>rt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Ae(et.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${r}\\n${o}`,...n)}if(a){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${a}\\n${r}`,...n)}}return l.registerJSModule(c,"polyscript",{xworker:yt}),at=l.runEvent.bind(l,c),it=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),ct("error"),ct("message"),ct("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Ie;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=Te(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Fe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return Pe(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ee(n,h).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Ne=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Ce=new WeakMap,Je=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Ce.set(t,r),t}}},He=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},De=e=>{const t=e.split("/");return t.pop(),t.join("/")},Ue=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},ze=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},qe=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Qe=new WeakMap,Ye=(e,t,r)=>Re((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ke(n))return n.map((r=>({url:qe([e,r]),path:qe([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:qe([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(Te(t,Qe.get(e))))(r,n).then(We).then((r=>e.writeFile(t,s,r)))))),Xe=(e,t,r)=>{e.registerJsModule(t,r)},Ge=(e,t,...r)=>{try{return e.runPython(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ke=async(e,t,...r)=>{try{return await e.runPythonAsync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ve=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}};var Ze={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Je();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const et={dict_converter:Object.fromEntries};var tt={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Je(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Xe,run:Ge,runAsync:Ke,runEvent:Ve,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(et):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const rt="ruby-wasm-wasi",nt=rt.replace(/\W+/g,"_");var st={type:rt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of Me(r)){const r=`__module_${nt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Ne(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Ne(t),...r),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${nt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${rt}`)}};var ot={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Je(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of Me(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Ue(e,De(t)),t=ze(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const at=new Map,it=new Map,ct=[],lt=[],ut=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=at.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{it.set(t,e);const a=e?.fetch;return a&&Qe.set(a,o),s(n,e,r)}))}}),pt=e=>{for(const t of[].concat(e.type))at.set(t,e),ct.push(`script[type="${t}"]`),lt.push(`${t}-`)};for(const e of[Ze,tt,st,ot])pt(e);const ft=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),dt=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Oe),t=Te(t);else if(t.endsWith(".toml"))r=fetch(t).then(Fe).then(ft),t=Te(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=ft(t)}t=Te("./config.txt")}return $e(r).then((r=>ut[e](r,t)))},ht=(e,t="")=>`${e}@${t}`.replace(/@$/,""),yt=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},mt=new WeakMap,gt={get(){let e=mt.get(this);return e||(e=document.createElement(`${this.type}-script`),mt.set(this,e),At(this)),e},set(e){"string"==typeof e?mt.set(this,yt(this,e)):(mt.set(this,e),At(this))}},wt=new WeakMap,bt=new Map,vt=(e,t)=>{const r=e?.value;return r?t+r:""},_t=(e,t,r,n,s,o=e)=>{if(!bt.has(t)){const a={interpreter:dt(r,s),queue:$e(),XWorker:Le(e,n)};bt.set(t,a),bt.has(e)||bt.set(e,a),bt.has(o)||bt.set(o,a)}return bt.get(t)},At=async e=>{if(wt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=ht(c,l);let p=vt(r,"|");const f=vt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Le(c,l))(d,{async:!!t,config:p});return void wt.set(xe(e,"xworker",{value:r}),{xworker:r})}const h=vt(s,""),y=_t(c,f,u,l,p);wt.set(xe(e,"target",gt),y),h&&mt.set(e,yt(e,h));const m=i?fetch(i).then(Fe):e.textContent;y.queue=y.queue.then((()=>(async(e,t,r,n)=>{const s=at.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await Re([wt.get(e).interpreter,t]);try{return xe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,y.XWorker,!!t)))}};new Proxy(je(null),{get:(e,t)=>Et(t)});const Et=async e=>{if(bt.has(e)){const{interpreter:t,queue:r}=bt.get(e);return(await Re([t,r]))[0]}const t=bt.size?`Available interpreters are: ${[...bt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},kt=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${lt.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await Et(a.getAttribute(`${s}-env`)||s);at.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${lt.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,kt)},jt=[],Pt=new Map,xt=new Map,Mt=e=>{for(const t of jt)if(e.matches(t)){const r=Pt.get(t),{resolve:n}=xt.get(r),{options:s,known:o}=Rt.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=Tt.call(new Ie(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return xe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=ht(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:h}=_t(r,f,p,i,a,t);d.then((o=>{const a=je(at.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Ie(o,s),y=function(...e){return h.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o,...a){r&&r.call(this,m,e);const i=s.call(this,t,o,...a);return n&&n.call(this,m,e),i}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o,...a){r&&await r.call(this,m,e);const i=await s.call(this,t,o,...a);return n&&await n.call(this,m,e),i}}a.registerJSModule(o,"polyscript",{XWorker:y});const m={type:r,interpreter:o,XWorker:y,io:Ce.get(o),config:structuredClone(it.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},Rt=new Map,$t=e=>(xt.has(e)||xt.set(e,Promise.withResolvers()),xt.get(e).promise),Tt=Le(),Wt=ct.join(","),Ot=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Wt))At(e);else{if(t(Wt,e).forEach(At),!jt.length)continue;Mt(e),t(jt.join(","),e).forEach(Mt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of lt)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,kt)}break}}}})),Ft=e=>(Ot.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:Bt}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ft(Bt.call(this,e))}}),St(Ft(document)),t(Wt,document).forEach(At);const It={"<":"<",">":">"},Lt=e=>{return(new DOMParser).parseFromString((t=e,t.replace(/[<>]/g,(e=>It[e]))),"text/html").documentElement.textContent;var t};var Nt='# ⚠️ WARNING - both `document` and `window` are added at runtime\n\nimport base64\nimport html\nimport io\nimport re\n\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" + {extra_head} diff --git a/pyscriptjs/tests/integration/test_01_basic.py b/pyscriptjs/tests/integration/test_01_basic.py index 1170adc7..b53d8cbd 100644 --- a/pyscriptjs/tests/integration/test_01_basic.py +++ b/pyscriptjs/tests/integration/test_01_basic.py @@ -2,7 +2,7 @@ import re import pytest -from .support import PyScriptTest, skip_worker +from .support import PyScriptTest class TestBasic(PyScriptTest): @@ -17,6 +17,11 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines == ["hello pyscript"] + # TODO: I think this test actually should test that we don't load anything if there aren't + # any pyscrpt related tags or features. Meaning that the Platform is not invasive. + @pytest.mark.skip( + reason="DIFFERENT BEHAVIOUR: We don't print anything in the console once loaded" + ) def test_execution_thread(self): self.pyscript_run( """ @@ -26,12 +31,15 @@ class TestBasic(PyScriptTest): ) assert self.execution_thread in ("main", "worker") if self.execution_thread == "main": - where = "the main thread" + pass elif self.execution_thread == "worker": - where = "a web worker" - expected = f"[pyscript/main] Starting the interpreter in {where}" + pass + expected = ("[pyscript/main] PyScript Ready",) assert expected in self.console.info.lines + @pytest.mark.skip( + reason="FIXME: No banner and should also add a WARNING about CORS" + ) def test_no_cors_headers(self): self.disable_cors_headers() self.pyscript_run( @@ -66,6 +74,7 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello pyscript" + @pytest.mark.skip("FIXME: No banner") def test_python_exception(self): self.pyscript_run( """ @@ -80,8 +89,7 @@ class TestBasic(PyScriptTest): # # check that we sent the traceback to the console tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" + assert tb_lines[0] == "Python Error: Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error" # # check that we show the traceback in the page. Note that here we @@ -93,12 +101,13 @@ class TestBasic(PyScriptTest): assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error" + @pytest.mark.skip(reason="FIX TEST: Works on CHROME") def test_python_exception_in_event_handler(self): self.pyscript_run( """ - + - def onclick(): + def onclick(event): raise Exception("this is an error inside handler") """ @@ -142,6 +151,7 @@ class TestBasic(PyScriptTest): "four", ] + @pytest.mark.skip(reason="FIXME: log('
') now logs an empty string.") def test_escaping_of_angle_brackets(self): """ Check that py-script tags escape angle brackets @@ -155,12 +165,11 @@ class TestBasic(PyScriptTest): assert self.console.log.lines[-2:] == ["true false", "
"] + @pytest.mark.skip(reason="FIX TEST: Works on CHROME") def test_packages(self): self.pyscript_run( """ - # we use asciitree because it's one of the smallest packages - # which are built and distributed with pyodide packages = ["asciitree"] @@ -177,7 +186,7 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] - @skip_worker("FIXME: the banner doesn't appear") + @pytest.mark.skip("FIXME: No banner") def test_non_existent_package(self): self.pyscript_run( """ @@ -198,7 +207,7 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") - @skip_worker("FIXME: the banner doesn't appear") + @pytest.mark.skip("FIXME: No banner") def test_no_python_wheel(self): self.pyscript_run( """ @@ -218,18 +227,20 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't find a pure Python 3 wheel for 'opsdroid'") + @pytest.mark.skip("""FIXME: Dynamically adding a py-script tag fails""") def test_dynamically_add_py_script_tag(self): self.pyscript_run( """ - """ + """, + timeout=20000, ) self.page.locator("button").click() @@ -245,6 +256,7 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello from foo" + @pytest.mark.skip("FIXME: No banner") def test_py_script_src_not_found(self): self.pyscript_run( """ @@ -263,6 +275,7 @@ class TestBasic(PyScriptTest): self.check_js_errors(expected_msg) + @pytest.mark.skip("DIFFERENT BEHAVIOUR?: we don't expose pyscript on window") def test_js_version(self): self.pyscript_run( """ @@ -277,6 +290,7 @@ class TestBasic(PyScriptTest): is not None ) + @pytest.mark.skip("DIFFERENT BEHAVIOUR?: we don't expose pyscript on window") def test_python_version(self): self.pyscript_run( """ @@ -300,7 +314,7 @@ class TestBasic(PyScriptTest): is not None ) - @skip_worker("FIXME: showWarning()") + @pytest.mark.skip("FIXME: No banner") def test_assert_no_banners(self): """ Test that the DOM doesn't contain error/warning banners @@ -314,31 +328,29 @@ class TestBasic(PyScriptTest): """ ) + + # check that we have 2 banners with pytest.raises(AssertionError, match="Found 2 alert banners"): self.assert_no_banners() def test_getPySrc_returns_source_code(self): self.pyscript_run( """ - - print("hello world!") - + print("hello world!") """ ) pyscript_tag = self.page.locator("py-script") assert pyscript_tag.inner_html() == "" - assert ( - pyscript_tag.evaluate("node => node.getPySrc()") - == 'print("hello world!")\n' - ) + assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello world!")' + @pytest.mark.skip(reason="FIX TEST: works in chrome!") def test_py_attribute_without_id(self): self.pyscript_run( """ - + - def myfunc(): + def myfunc(event): print("hello world!") """ @@ -349,6 +361,8 @@ class TestBasic(PyScriptTest): assert self.console.log.lines[-1] == "hello world!" assert self.console.error.lines == [] + # TODO: THis can actually be removed since we are removing `py-mount` + @pytest.mark.skip("REMOVE TEST: No py-mount anymore") def test_py_mount_shows_deprecation_warning(self): # last non-deprecated version: 2023.03.1 self.pyscript_run( diff --git a/pyscriptjs/tests/integration/test_02_display.py b/pyscriptjs/tests/integration/test_02_display.py index 532e1c6b..ee1d941d 100644 --- a/pyscriptjs/tests/integration/test_02_display.py +++ b/pyscriptjs/tests/integration/test_02_display.py @@ -1,53 +1,67 @@ import base64 -import html import io import os import re import numpy as np +import pytest from PIL import Image -from .support import PyScriptTest, skip_worker, wait_for_render +from .support import ( + PyScriptTest, + filter_inner_text, + filter_page_content, + wait_for_render, +) + +DISPLAY_OUTPUT_ID_PATTERN = r'[id^="py-"]' class TestDisplay(PyScriptTest): - @skip_worker("FIXME: display()") + @pytest.mark.skip( + "DIFFERENT BEHAVIOUR!: display w/o target renders as TXT without
tag" + ) def test_simple_display(self): self.pyscript_run( """ - display('hello world') + print('ciao') + from pyscript import display + display("hello world") - """ + """, + timeout=20000, ) - node_list = self.page.query_selector_all(r'[id^="py-internal"]') + node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) pattern = r"
hello world
" - assert re.search(pattern, node_list[0].inner_html()) + assert node_list[0].inner_html() == pattern assert len(node_list) == 1 - @skip_worker("FIXME: display()") def test_consecutive_display(self): self.pyscript_run( """ + from pyscript import display display('hello 1')

hello 2

+ from pyscript import display display('hello 3') """ ) inner_text = self.page.inner_text("body") lines = inner_text.splitlines() - lines = [line for line in lines if line != ""] # remove empty lines + + lines = [line for line in filter_page_content(lines)] # remove empty lines assert lines == ["hello 1", "hello 2", "hello 3"] - @skip_worker("FIXME: display()") def test_target_attribute(self): self.pyscript_run( """ + from pyscript import display display('hello world', target="mydiv")
@@ -56,32 +70,35 @@ class TestDisplay(PyScriptTest): mydiv = self.page.locator("#mydiv") assert mydiv.inner_text() == "hello world" - @skip_worker("FIXME: display()") def test_consecutive_display_target(self): self.pyscript_run( """ + from pyscript import display display('hello 1')

hello in between 1 and 2

+ from pyscript import display display('hello 2', target="second") + from pyscript import display display('hello 3') """ ) inner_text = self.page.inner_text("body") lines = inner_text.splitlines() - lines = [line for line in lines if line != ""] # remove empty lines + lines = [line for line in filter_page_content(lines)] # remove empty lines assert lines == ["hello 1", "hello in between 1 and 2", "hello 2", "hello 3"] - @skip_worker("FIXME: display()") + @pytest.mark.skip("DIFFERENT BEHAVIOUR!: display is not appending by default") def test_multiple_display_calls_same_tag(self): self.pyscript_run( """ + from pyscript import display display('hello') display('world') @@ -89,18 +106,20 @@ class TestDisplay(PyScriptTest): ) tag = self.page.locator("py-script") lines = tag.inner_text().splitlines() + # TODO: Did the default change to append=False? assert lines == ["hello", "world"] - @skip_worker("FIXME: display()") def test_implicit_target_from_a_different_tag(self): self.pyscript_run( """ + from pyscript import display def say_hello(): display('hello') + from pyscript import display say_hello() """ @@ -110,11 +129,14 @@ class TestDisplay(PyScriptTest): assert py1.inner_text() == "" assert py2.inner_text() == "hello" - @skip_worker("FIXME: display()") + @pytest.mark.skip( + "DIFFERENT BEHAVIOUR!: display is not raising Implicit target exception" + ) def test_no_implicit_target(self): self.pyscript_run( """ + from pyscript import display def display_hello(): # this fails because we don't have any implicit target # from event handlers @@ -127,6 +149,8 @@ class TestDisplay(PyScriptTest): self.check_py_errors("Implicit target not allowed here") ## error in console tb_lines = self.console.error.lines[-1].splitlines() + + # TODO: This does seem like a regression assert tb_lines[0] == "[pyexec] Python exception:" assert tb_lines[1] == "Traceback (most recent call last):" assert ( @@ -137,11 +161,11 @@ class TestDisplay(PyScriptTest): text = self.page.text_content("body") assert "hello world" not in text - @skip_worker("FIXME: display()") def test_explicit_target_pyscript_tag(self): self.pyscript_run( """ + from pyscript import display def display_hello(): display('hello', target='second-pyscript-tag') @@ -153,26 +177,31 @@ class TestDisplay(PyScriptTest): text = self.page.locator("id=second-pyscript-tag").inner_text() assert text == "hello" - @skip_worker("FIXME: display()") + @pytest.mark.skip( + "FIXME: in Chrome fails with the error:" + ' The interpreter "py" was not found. Available interpreters are: "py-script", "pyodide".' + ) def test_explicit_target_on_button_tag(self): self.pyscript_run( """ + from pyscript import display def display_hello(): display('hello', target='my-button') - + """ ) self.page.locator("text=Click me").click() text = self.page.locator("id=my-button").inner_text() + # TODO: This does seem like a regression that assert "hello" in text - @skip_worker("FIXME: display()") def test_explicit_different_target_from_call(self): self.pyscript_run( """ + from pyscript import display def display_hello(): display('hello', target='second-pyscript-tag') @@ -187,25 +216,26 @@ class TestDisplay(PyScriptTest): text = self.page.locator("id=second-pyscript-tag").all_inner_texts() assert "hello" in text - @skip_worker("FIXME: display()") def test_append_true(self): self.pyscript_run( """ + from pyscript import display display('hello world', append=True) """ ) - node_list = self.page.query_selector_all(r'[id^="py-internal"]') + node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) pattern = r"
hello world
" - assert re.search(pattern, node_list[0].inner_html()) + + assert node_list[0].inner_html() == pattern assert len(node_list) == 1 - @skip_worker("FIXME: display()") def test_append_false(self): self.pyscript_run( """ + from pyscript import display display('hello world', append=False) """ @@ -214,11 +244,12 @@ class TestDisplay(PyScriptTest): pattern = r'hello world' assert re.search(pattern, inner_html) - @skip_worker("FIXME: display()") + @pytest.mark.skip("FIXME: display doesn't seem to have append=True as default") def test_display_multiple_values(self): self.pyscript_run( """ + from pyscript import display hello = 'hello' world = 'world' display(hello, world) @@ -228,11 +259,11 @@ class TestDisplay(PyScriptTest): inner_text = self.page.inner_text("html") assert inner_text == "hello\nworld" - @skip_worker("FIXME: display()") def test_display_multiple_append_false(self): self.pyscript_run( """ + from pyscript import display display('hello', append=False) display('world', append=False) @@ -242,12 +273,13 @@ class TestDisplay(PyScriptTest): pattern = r'world' assert re.search(pattern, inner_html) - @skip_worker("FIXME: display()") + @pytest.mark.skip("WEIRDLY BROKEN not because of Display?") def test_display_multiple_append_false_with_target(self): self.pyscript_run( """
- + """ ) assert self.console.log.lines[-1] == "hello from foo" - @skip_worker("FIXME: js.document") + def test_script_type_py_worker_attribute(self): + self.writefile("foo.py", "print('hello from foo')") + self.pyscript_run( + """ + + """ + ) + assert self.console.log.lines[-1] == "hello from foo" + + @pytest.mark.skip("FIXME: script output attribute is broken") def test_script_type_py_output_attribute(self): self.pyscript_run( """
- """ @@ -93,7 +103,7 @@ class TestScriptTypePyScript(PyScriptTest): text = self.page.locator("#first").text_content() assert "

Hello

" in text - @skip_worker("FIXME: js.document") + @pytest.mark.skip("FIXME: script stderr attribute is broken") def test_script_type_py_stderr_attribute(self): self.pyscript_run( """ diff --git a/pyscriptjs/tests/integration/test_shadow_root.py b/pyscriptjs/tests/integration/test_shadow_root.py index ca662142..67b75664 100644 --- a/pyscriptjs/tests/integration/test_shadow_root.py +++ b/pyscriptjs/tests/integration/test_shadow_root.py @@ -1,8 +1,11 @@ -from .support import PyScriptTest, skip_worker +import pytest + +from .support import PyScriptTest class TestShadowRoot(PyScriptTest): - @skip_worker("FIXME: js.document") + # @skip_worker("FIXME: js.document") + @pytest.mark.skip("FIXME: Element missing from PyScript") def test_reachable_shadow_root(self): self.pyscript_run( r""" diff --git a/pyscriptjs/tests/integration/test_splashscreen.py b/pyscriptjs/tests/integration/test_splashscreen.py index 9aff3b91..72fe9215 100644 --- a/pyscriptjs/tests/integration/test_splashscreen.py +++ b/pyscriptjs/tests/integration/test_splashscreen.py @@ -1,7 +1,12 @@ +import pytest from playwright.sync_api import expect from .support import PyScriptTest, skip_worker +pytest.skip( + reason="DECIDE: Should we remove the splashscreen?", allow_module_level=True +) + class TestSplashscreen(PyScriptTest): def test_autoshow_and_autoclose(self): diff --git a/pyscriptjs/tests/integration/test_stdio_handling.py b/pyscriptjs/tests/integration/test_stdio_handling.py index 09c982f9..6bc1dddd 100644 --- a/pyscriptjs/tests/integration/test_stdio_handling.py +++ b/pyscriptjs/tests/integration/test_stdio_handling.py @@ -1,5 +1,9 @@ +import pytest + from .support import PyScriptTest, skip_worker +pytest.skip(reason="FIXME: entire stdio should be reviewed", allow_module_level=True) + class TestOutputHandling(PyScriptTest): # Source of a script to test the TargetedStdio functionality diff --git a/pyscriptjs/tests/integration/test_style.py b/pyscriptjs/tests/integration/test_style.py index 54c28704..e544a8b1 100644 --- a/pyscriptjs/tests/integration/test_style.py +++ b/pyscriptjs/tests/integration/test_style.py @@ -1,7 +1,13 @@ +import pytest from playwright.sync_api import expect from .support import PyScriptTest, skip_worker +pytest.skip( + reason="FIX TESTS: These tests should reflect new PyScript and remove/change css ", + allow_module_level=True, +) + class TestStyle(PyScriptTest): def test_pyscript_not_defined(self): diff --git a/pyscriptjs/tests/integration/test_warnings_and_banners.py b/pyscriptjs/tests/integration/test_warnings_and_banners.py index 3e001376..933e8ea8 100644 --- a/pyscriptjs/tests/integration/test_warnings_and_banners.py +++ b/pyscriptjs/tests/integration/test_warnings_and_banners.py @@ -1,5 +1,9 @@ +import pytest + from .support import PyScriptTest +pytest.skip(reason="FIXME: Restore the banner", allow_module_level=True) + class TestWarningsAndBanners(PyScriptTest): # Test the behavior of generated warning banners diff --git a/pyscriptjs/tests/integration/test_zz_examples.py b/pyscriptjs/tests/integration/test_zz_examples.py index a2dc3335..70e7696d 100644 --- a/pyscriptjs/tests/integration/test_zz_examples.py +++ b/pyscriptjs/tests/integration/test_zz_examples.py @@ -11,6 +11,9 @@ from PIL import Image from .support import ROOT, PyScriptTest, wait_for_render, with_execution_thread +@pytest.mark.skip( + reason="SKIPPING EXAMPLES: these should be moved elsewhere and updated" +) @with_execution_thread(None) @pytest.mark.usefixtures("chdir") class TestExamples(PyScriptTest): diff --git a/pyscriptjs/tests/integration/test_zzz_docs_snippets.py b/pyscriptjs/tests/integration/test_zzz_docs_snippets.py index 0c857304..cf2c6379 100644 --- a/pyscriptjs/tests/integration/test_zzz_docs_snippets.py +++ b/pyscriptjs/tests/integration/test_zzz_docs_snippets.py @@ -1,8 +1,12 @@ import re +import pytest from .support import PyScriptTest, skip_worker +@pytest.mark.skip( + reason="SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs" +) class TestDocsSnippets(PyScriptTest): @skip_worker("FIXME: js.document") def test_tutorials_py_click(self): From 94b0bf41311ff147b2d27ece3dd834183acf5d7a Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Mon, 4 Sep 2023 10:04:12 +0200 Subject: [PATCH 009/105] [next] Updated latest Polyscript bringing in worker attribute (#1667) --- pyscript.core/core.js | 2 +- pyscript.core/package-lock.json | 8 ++++---- pyscript.core/package.json | 2 +- pyscript.core/src/core.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyscript.core/core.js b/pyscript.core/core.js index 48aec3f5..d4501c37 100644 --- a/pyscript.core/core.js +++ b/pyscript.core/core.js @@ -1,2 +1,2 @@ Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const e=(e,t=document)=>t.querySelector(e),t=(e,t=document)=>[...t.querySelectorAll(e)],r=(e,t=document)=>{const r=(new XPathEvaluator).createExpression(e).evaluate(t,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),n=[];for(let e=0,{snapshotLength:t}=r;e((e,t)=>{const r=(t,r)=>(e.set(r,t),t),s=o=>{if(e.has(o))return e.get(o);const[a,i]=t[o];switch(a){case 0:case-1:return r(i,o);case 1:{const e=r([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=r({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return r(new Date(i),o);case 4:{const{source:e,flags:t}=i;return r(new RegExp(e,t),o)}case 5:{const e=r(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=r(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:e,message:t}=i;return r(new n[e](t),o)}case 8:return r(BigInt(i),o);case"BigInt":return r(Object(BigInt(i)),o)}return r(new n[a](i),o)};return s})(new Map,e)(0),o="",{toString:a}={},{keys:i}=Object,c=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const r=a.call(e).slice(8,-1);switch(r){case"Array":return[1,o];case"Object":return[2,o];case"Date":return[3,o];case"RegExp":return[4,o];case"Map":return[5,o];case"Set":return[6,o]}return r.includes("Array")?[1,r]:r.includes("Error")?[7,r]:[2,r]},l=([e,t])=>0===e&&("function"===t||"symbol"===t),u=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const s=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},o=n=>{if(r.has(n))return r.get(n);let[a,u]=c(n);switch(a){case 0:{let t=n;switch(u){case"bigint":a=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return s([-1],n)}return s([a,t],n)}case 1:{if(u)return s([u,[...n]],n);const e=[],t=s([a,e],n);for(const t of n)e.push(o(t));return t}case 2:{if(u)switch(u){case"BigInt":return s([u,n.toString()],n);case"Boolean":case"Number":case"String":return s([u,n.valueOf()],n)}if(t&&"toJSON"in n)return o(n.toJSON());const r=[],p=s([a,r],n);for(const t of i(n))!e&&l(c(n[t]))||r.push([o(t),o(n[t])]);return p}case 3:return s([a,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return s([a,{source:e,flags:t}],n)}case 5:{const t=[],r=s([a,t],n);for(const[r,s]of n)(e||!l(c(r))&&!l(c(s)))&&t.push([o(r),o(s)]);return r}case 6:{const t=[],r=s([a,t],n);for(const r of n)!e&&l(c(r))||t.push(o(r));return r}}const{message:p}=n;return s([a,{name:u,message:p}],n)};return o})(!(t||r),!!t,new Map,n)(e),n},{parse:p,stringify:f}=JSON,d={json:!0,lossy:!0};var y=Object.freeze({__proto__:null,parse:e=>s(p(e)),stringify:e=>f(u(e,d))});const h="891249cd-eb53-4bc8-ae48-b0a5a277d24a",m="M"+h,g="T"+h;var w=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))}) -/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:b,Map:v,SharedArrayBuffer:_,Uint16Array:A}=globalThis,{BYTES_PER_ELEMENT:E}=b,{BYTES_PER_ELEMENT:k}=A,{isArray:S}=Array,{notify:P,wait:R,waitAsync:x}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(x||w)(t,0):(R(t,0),{value:{then:e=>e()}}),M=new WeakSet,W=new WeakMap;let T=0;const O=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!W.has(e)){const s=(t,...r)=>e.postMessage({[h]:r},{transfer:t});let o=!1;W.set(e,new Proxy(new v,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=T++;let c=new b(new _(E)),l=[];M.has(r.at(-1)||l)&&M.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let p=0;return o&&u&&(p=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(p);const e=c[0];if(!e)return;const r=k*e;return c=new b(new _(r+r%E)),s([],i,c),$(u,c).value.then((()=>t(j(...new A(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new v;e.addEventListener("message",(async e=>{const s=e.data?.[h];if(S(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new A(i.buffer),r=0;r(M.add(e),e);const F="object",I="function",B="number",L="string",N="undefined",C="symbol",{defineProperty:J,getOwnPropertyDescriptor:H,getPrototypeOf:D,isExtensible:U,ownKeys:z,preventExtensions:q,set:Q,setPrototypeOf:Y}=Reflect,{assign:K,create:X}=Object,V=D(Int8Array),Z="isArray",G=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},ee=(e,t)=>[e,t],te=e=>t=>{const r=typeof t;switch(r){case F:if(null==t)return ee("null",t);if(t===globalThis)return ee(F,null);case I:return e(r,t);case"boolean":case B:case L:case N:case"bigint":return ee(r,t);case C:if(re.has(t))return ee(r,re.get(t))}throw new Error(`Unable to handle this ${r} type`)},re=new Map(z(Symbol).filter((e=>typeof Symbol[e]===C)).map((e=>[Symbol[e],e]))),ne=e=>{for(const[t,r]of re)if(r===e)return t};function se(){return this}const oe="apply",ae="construct",ie="defineProperty",ce="deleteProperty",le="get",ue="getOwnPropertyDescriptor",pe="getPrototypeOf",fe="has",de="isExtensible",ye="ownKeys",he="preventExtensions",me="set",ge="setPrototypeOf",we="delete";var be=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;J(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,p=a.length?K(X(globalThis),...a):globalThis,f=te(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return ee(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(we,ee(L,e))})),y=([e,r])=>{switch(e){case F:if(null==r)return p;if(typeof r===B)return l.get(r);if(!(r instanceof V))for(const e in r)r[e]=y(r[e]);return r;case I:if(typeof r===L){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(oe,ee(I,r),f(this),e.map(f))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case C:return ne(r)}return r},h={[oe]:(e,t,r)=>f(e.apply(t,r)),[ae]:(e,t)=>f(new e(...t)),[ie]:(e,t,r)=>f(J(e,t,r)),[ce]:(e,t)=>f(delete e[t]),[pe]:e=>f(D(e)),[le]:(e,t)=>f(e[t]),[ue]:(e,t)=>{const r=H(e,t);return r?ee(F,G(r,f)):ee(N,r)},[fe]:(e,t)=>f(t in e),[de]:e=>f(U(e)),[ye]:e=>ee(F,z(e).map(f)),[he]:e=>f(q(e)),[me]:(e,t,r)=>f(Q(e,t,r)),[ge]:(e,t)=>f(Y(e,t)),[we](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case oe:r[0]=y(r[0]),r[1]=r[1].map(y);break;case ae:r[0]=r[0].map(y);break;case ie:{const[e,t]=r;r[0]=y(e);const{get:n,set:s,value:o}=t;n&&(t.get=y(n)),s&&(t.set=y(s)),o&&(t.value=y(o));break}default:r=r.map(y)}return h[e](y(t),...r)},{proxy:r,[e.toLowerCase()]:p,[`is${e}Proxy`]:()=>!1}}})("Window",!0),ve=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===I?e():e,a=e=>typeof e===F&&!!e&&s in e,i=Array[Z],c=te(((e,a)=>{if(s in a)return o(a[s]);if(e===I){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return ee(e,r.get(a))}if(!(a instanceof V))for(const e in a)a[e]=c(a[e]);return ee(e,a)}));return(t,l,u)=>{const{[l]:p}=t,f=new Map,d=new FinalizationRegistry((e=>{f.delete(e),p(we,c(e))})),y=e=>{const[t,r]=e;if(!f.has(r)){const n=t===I?se.bind(e):e,s=new Proxy(n,g),o=new WeakRef(s);f.set(r,o),d.register(s,r,o)}return f.get(r).deref()},h=e=>{const[t,r]=e;switch(t){case F:return null===r?globalThis:typeof r===B?y(e):r;case I:return typeof r===L?n.get(r):y(e);case C:return ne(r)}return r},m=(e,t,...r)=>h(p(e,o(t),...r)),g={[oe]:(e,t,r)=>m(oe,e,c(t),r.map(c)),[ae]:(e,t)=>m(ae,e,t.map(c)),[ie]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===I&&(r.get=c(n)),typeof s===I&&(r.set=c(s)),typeof o===I&&(r.value=c(o)),m(ie,e,c(t),r)},[ce]:(e,t)=>m(ce,e,c(t)),[pe]:e=>m(pe,e),[le]:(e,t)=>t===s?e:m(le,e,c(t)),[ue]:(e,t)=>{const r=m(ue,e,c(t));return r&&G(r,h)},[fe]:(e,t)=>t===s||m(fe,e,c(t)),[de]:e=>m(de,e),[ye]:e=>m(ye,e).map(h),[he]:e=>m(he,e),[me]:(e,t,r)=>m(me,e,c(t),c(r)),[ge]:(e,t)=>m(ge,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case oe:return h(t).apply(h(s),o.map(h));case we:{const e=h(t);r.delete(n.get(e)),n.delete(e)}}};const w=new Proxy([F,null],g),b=w.Array[Z];return J(Array,Z,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:w,[`is${e}Proxy`]:a,proxy:t}}})("Window"),_e="function"==typeof Worker?Worker:class{};const Ae=new WeakMap,Ee=(e,...t)=>{const r=O(e,...t);if(!Ae.has(r)){const t=e instanceof _e?be:ve;Ae.set(r,t(r,m,g))}return Ae.get(r)};Ee.transfer=O.transfer;const{isArray:ke}=Array,{assign:Se,create:Pe,defineProperties:Re,defineProperty:xe,entries:je}=Object,{all:$e,resolve:Me}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),We=(e,t=location.href)=>new URL(e,t).href,Te=e=>e.arrayBuffer(),Oe=e=>e.json(),Fe=e=>e.text(),Ie=[["beforeRun","codeBeforeRunWorker"],["beforeRunAsync","codeBeforeRunWorkerAsync"],["afterRun","codeAfterRunWorker"],["afterRunAsync","codeAfterRunWorkerAsync"]];class Be{constructor(e,t){this.interpreter=e,this.onWorkerReady=t.onWorkerReady;for(const[e,r]of Ie)this[e]=t[r]?.()}get stringHooks(){const e={};for(const[t]of Ie)this[t]&&(e[t]=this[t]);return e}}var Le=(...e)=>function(t,r){const n=new Worker(URL.createObjectURL(new Blob(['const e="object"==typeof self?self:globalThis,t=t=>((t,r)=>{const n=(e,r)=>(t.set(r,e),e),s=o=>{if(t.has(o))return t.get(o);const[a,i]=r[o];switch(a){case 0:case-1:return n(i,o);case 1:{const e=n([],o);for(const t of i)e.push(s(t));return e}case 2:{const e=n({},o);for(const[t,r]of i)e[s(t)]=s(r);return e}case 3:return n(new Date(i),o);case 4:{const{source:e,flags:t}=i;return n(new RegExp(e,t),o)}case 5:{const e=n(new Map,o);for(const[t,r]of i)e.set(s(t),s(r));return e}case 6:{const e=n(new Set,o);for(const t of i)e.add(s(t));return e}case 7:{const{name:t,message:r}=i;return n(new e[t](r),o)}case 8:return n(BigInt(i),o);case"BigInt":return n(Object(BigInt(i)),o)}return n(new e[a](i),o)};return s})(new Map,t)(0),r="",{toString:n}={},{keys:s}=Object,o=e=>{const t=typeof e;if("object"!==t||!e)return[0,t];const s=n.call(e).slice(8,-1);switch(s){case"Array":return[1,r];case"Object":return[2,r];case"Date":return[3,r];case"RegExp":return[4,r];case"Map":return[5,r];case"Set":return[6,r]}return s.includes("Array")?[1,s]:s.includes("Error")?[7,s]:[2,s]},a=([e,t])=>0===e&&("function"===t||"symbol"===t),i=(e,{json:t,lossy:r}={})=>{const n=[];return((e,t,r,n)=>{const i=(e,t)=>{const s=n.push(e)-1;return r.set(t,s),s},c=n=>{if(r.has(n))return r.get(n);let[l,u]=o(n);switch(l){case 0:{let t=n;switch(u){case"bigint":l=8,t=n.toString();break;case"function":case"symbol":if(e)throw new TypeError("unable to serialize "+u);t=null;break;case"undefined":return i([-1],n)}return i([l,t],n)}case 1:{if(u)return i([u,[...n]],n);const e=[],t=i([l,e],n);for(const t of n)e.push(c(t));return t}case 2:{if(u)switch(u){case"BigInt":return i([u,n.toString()],n);case"Boolean":case"Number":case"String":return i([u,n.valueOf()],n)}if(t&&"toJSON"in n)return c(n.toJSON());const r=[],f=i([l,r],n);for(const t of s(n))!e&&a(o(n[t]))||r.push([c(t),c(n[t])]);return f}case 3:return i([l,n.toISOString()],n);case 4:{const{source:e,flags:t}=n;return i([l,{source:e,flags:t}],n)}case 5:{const t=[],r=i([l,t],n);for(const[r,s]of n)(e||!a(o(r))&&!a(o(s)))&&t.push([c(r),c(s)]);return r}case 6:{const t=[],r=i([l,t],n);for(const r of n)!e&&a(o(r))||t.push(c(r));return r}}const{message:f}=n;return i([l,{name:u,message:f}],n)};return c})(!(t||r),!!t,new Map,n)(e),n},{parse:c,stringify:l}=JSON,u={json:!0,lossy:!0};var f=Object.freeze({__proto__:null,parse:e=>t(c(e)),stringify:e=>l(i(e,u))});const p="891249cd-eb53-4bc8-ae48-b0a5a277d24a",d="M"+p,y="T"+p;var g=e=>({value:new Promise((t=>{let r=new Worker("data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))");r.onmessage=t,r.postMessage(e)}))})\n/*! (c) Andrea Giammarchi - ISC */;const{Int32Array:w,Map:h,SharedArrayBuffer:m,Uint16Array:b}=globalThis,{BYTES_PER_ELEMENT:v}=w,{BYTES_PER_ELEMENT:S}=b,{isArray:P}=Array,{notify:A,wait:E,waitAsync:M}=Atomics,{fromCharCode:j}=String,$=(e,t)=>e?(M||g)(t,0):(E(t,0),{value:{then:e=>e()}}),_=new WeakSet,k=new WeakMap;let x=0;const T=(e,{parse:t,stringify:r,transform:n}=JSON)=>{if(!k.has(e)){const s=(t,...r)=>e.postMessage({[p]:r},{transfer:t});let o=!1;k.set(e,new Proxy(new h,{has:(e,t)=>"string"==typeof t&&!t.startsWith("_"),get:(r,a)=>"then"===a?null:(...r)=>{const i=x++;let c=new w(new m(v)),l=[];_.has(r.at(-1)||l)&&_.delete(l=r.pop()),s(l,i,c,a,n?r.map(n):r);const u=e!==globalThis;let f=0;return o&&u&&(f=setTimeout(console.warn,1e3,`💀🔒 - Possible deadlock if proxy.${a}(...args) is awaited`)),$(u,c).value.then((()=>{clearTimeout(f);const e=c[0];if(!e)return;const r=S*e;return c=new w(new m(r+r%v)),s([],i,c),$(u,c).value.then((()=>t(j(...new b(c.buffer).slice(0,e)))))}))},set(t,n,s){if(!t.size){const n=new h;e.addEventListener("message",(async e=>{const s=e.data?.[p];if(P(s)){e.stopImmediatePropagation();const[a,i,...c]=s;if(c.length){const[e,s]=c;if(!t.has(e))throw new Error(`Unsupported action: ${e}`);o=!0;try{const o=await t.get(e)(...s);if(void 0!==o){const e=r(o);n.set(a,e),i[0]=e.length}}finally{o=!1}}else{const e=n.get(a);n.delete(a);for(let t=new b(i.buffer),r=0;r(_.add(e),e);const O="object",F="function",W="number",R="string",B="undefined",J="symbol",{defineProperty:L,getOwnPropertyDescriptor:I,getPrototypeOf:H,isExtensible:C,ownKeys:D,preventExtensions:N,set:U,setPrototypeOf:z}=Reflect,{assign:q,create:K}=Object,Y=H(Int8Array),G="isArray",V=(e,t)=>{const{get:r,set:n,value:s}=e;return r&&(e.get=t(r)),n&&(e.set=t(n)),s&&(e.value=t(s)),e},Q=(e,t)=>[e,t],X=e=>t=>{const r=typeof t;switch(r){case O:if(null==t)return Q("null",t);if(t===globalThis)return Q(O,null);case F:return e(r,t);case"boolean":case W:case R:case B:case"bigint":return Q(r,t);case J:if(Z.has(t))return Q(r,Z.get(t))}throw new Error(`Unable to handle this ${r} type`)},Z=new Map(D(Symbol).filter((e=>typeof Symbol[e]===J)).map((e=>[Symbol[e],e]))),ee=e=>{for(const[t,r]of Z)if(r===e)return t};function te(){return this}const re="apply",ne="construct",se="defineProperty",oe="deleteProperty",ae="get",ie="getOwnPropertyDescriptor",ce="getPrototypeOf",le="has",ue="isExtensible",fe="ownKeys",pe="preventExtensions",de="set",ye="setPrototypeOf",ge="delete";var we=((e,t)=>{const r=t&&new WeakMap;if(t){const{addEventListener:e}=EventTarget.prototype;L(EventTarget.prototype,"addEventListener",{value(t,n,...s){return s.at(0)?.invoke&&(r.has(this)||r.set(this,new Map),r.get(this).set(t,[].concat(s[0].invoke)),delete s[0].invoke),e.call(this,t,n,...s)}})}const n=t&&(e=>{const{currentTarget:t,target:n,type:s}=e;for(const o of r.get(t||n)?.get(s)||[])e[o]()});return(r,s,o,...a)=>{let i=0;const c=new Map,l=new Map,{[o]:u}=r,f=a.length?q(K(globalThis),...a):globalThis,p=X(((e,t)=>{if(!c.has(t)){let e;for(;l.has(e=i++););c.set(t,e),l.set(e,t)}return Q(e,c.get(t))})),d=new FinalizationRegistry((e=>{u(ge,Q(R,e))})),y=([e,r])=>{switch(e){case O:if(null==r)return f;if(typeof r===W)return l.get(r);if(!(r instanceof Y))for(const e in r)r[e]=y(r[e]);return r;case F:if(typeof r===R){if(!l.has(r)){const e=function(...e){return t&&e.at(0)instanceof Event&&n(...e),u(re,Q(F,r),p(this),e.map(p))},s=new WeakRef(e);l.set(r,s),d.register(e,r,s)}return l.get(r).deref()}return l.get(r);case J:return ee(r)}return r},g={[re]:(e,t,r)=>p(e.apply(t,r)),[ne]:(e,t)=>p(new e(...t)),[se]:(e,t,r)=>p(L(e,t,r)),[oe]:(e,t)=>p(delete e[t]),[ce]:e=>p(H(e)),[ae]:(e,t)=>p(e[t]),[ie]:(e,t)=>{const r=I(e,t);return r?Q(O,V(r,p)):Q(B,r)},[le]:(e,t)=>p(t in e),[ue]:e=>p(C(e)),[fe]:e=>Q(O,D(e).map(p)),[pe]:e=>p(N(e)),[de]:(e,t,r)=>p(U(e,t,r)),[ye]:(e,t)=>p(z(e,t)),[ge](e){c.delete(l.get(e)),l.delete(e)}};return r[s]=(e,t,...r)=>{switch(e){case re:r[0]=y(r[0]),r[1]=r[1].map(y);break;case ne:r[0]=r[0].map(y);break;case se:{const[e,t]=r;r[0]=y(e);const{get:n,set:s,value:o}=t;n&&(t.get=y(n)),s&&(t.set=y(s)),o&&(t.value=y(o));break}default:r=r.map(y)}return g[e](y(t),...r)},{proxy:r,[e.toLowerCase()]:f,[`is${e}Proxy`]:()=>!1}}})("Window",!0),he=(e=>{let t=0;const r=new Map,n=new Map,s=Symbol(),o=e=>typeof e===F?e():e,a=e=>typeof e===O&&!!e&&s in e,i=Array[G],c=X(((e,a)=>{if(s in a)return o(a[s]);if(e===F){if(!n.has(a)){let e;for(;n.has(e=String(t++)););r.set(a,e),n.set(e,a)}return Q(e,r.get(a))}if(!(a instanceof Y))for(const e in a)a[e]=c(a[e]);return Q(e,a)}));return(t,l,u)=>{const{[l]:f}=t,p=new Map,d=new FinalizationRegistry((e=>{p.delete(e),f(ge,c(e))})),y=e=>{const[t,r]=e;if(!p.has(r)){const n=t===F?te.bind(e):e,s=new Proxy(n,h),o=new WeakRef(s);p.set(r,o),d.register(s,r,o)}return p.get(r).deref()},g=e=>{const[t,r]=e;switch(t){case O:return null===r?globalThis:typeof r===W?y(e):r;case F:return typeof r===R?n.get(r):y(e);case J:return ee(r)}return r},w=(e,t,...r)=>g(f(e,o(t),...r)),h={[re]:(e,t,r)=>w(re,e,c(t),r.map(c)),[ne]:(e,t)=>w(ne,e,t.map(c)),[se]:(e,t,r)=>{const{get:n,set:s,value:o}=r;return typeof n===F&&(r.get=c(n)),typeof s===F&&(r.set=c(s)),typeof o===F&&(r.value=c(o)),w(se,e,c(t),r)},[oe]:(e,t)=>w(oe,e,c(t)),[ce]:e=>w(ce,e),[ae]:(e,t)=>t===s?e:w(ae,e,c(t)),[ie]:(e,t)=>{const r=w(ie,e,c(t));return r&&V(r,g)},[le]:(e,t)=>t===s||w(le,e,c(t)),[ue]:e=>w(ue,e),[fe]:e=>w(fe,e).map(g),[pe]:e=>w(pe,e),[de]:(e,t,r)=>w(de,e,c(t),c(r)),[ye]:(e,t)=>w(ye,e,c(t))};t[u]=(e,t,s,o)=>{switch(e){case re:return g(t).apply(g(s),o.map(g));case ge:{const e=g(t);r.delete(n.get(e)),n.delete(e)}}};const m=new Proxy([O,null],h),b=m.Array[G];return L(Array,G,{value:e=>a(e)?b(e):i(e)}),{[e.toLowerCase()]:m,[`is${e}Proxy`]:a,proxy:t}}})("Window"),me="function"==typeof Worker?Worker:class{};const be=new WeakMap,ve=(e,...t)=>{const r=T(e,...t);if(!be.has(r)){const t=e instanceof me?we:he;be.set(r,t(r,d,y))}return be.get(r)};ve.transfer=T.transfer;const{isArray:Se}=Array,{assign:Pe,create:Ae,defineProperties:Ee,defineProperty:Me,entries:je}=Object,{all:$e,resolve:_e}=new Proxy(Promise,{get:(e,t)=>e[t].bind(e)}),ke=(e,t=location.href)=>new URL(e,t).href;Promise.withResolvers||(Promise.withResolvers=function(){var e,t,r=new this((function(r,n){e=r,t=n}));return{resolve:e,reject:t,promise:r}});const xe=e=>e.arrayBuffer(),Te=e=>e.json(),Oe=e=>e.text(),Fe=e=>e.replace(/^[^\\r\\n]+$/,(e=>e.trim())),We=new WeakMap,Re=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return We.set(t,r),t}}},Be=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},Je=e=>{const t=e.split("/");return t.pop(),t.join("/")},Le=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},Ie=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\\/+/,"/")},He=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Ce=new WeakMap,De=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use \'to_file\' and \'files\' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn\'t determine the filename from the path ${n}, please supply \'to_file\' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(Se(n))return n.map((r=>({url:He([e,r]),path:He([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:He([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(ke(t,Ce.get(e))))(r,n).then(xe).then((r=>e.writeFile(t,s,r)))))),Ne=(e,t,r)=>{e.registerJsModule(t,r)},Ue=(e,t,...r)=>{try{return e.runPython(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},ze=async(e,t,...r)=>{try{return await e.runPythonAsync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},qe=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}};var Ke={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Re();r=r.replace(/\\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await De(this,a,t.fetch),a},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ye={dict_converter:Object.fromEntries};var Ge={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Re(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await De(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Ne,run:Ue,runAsync:ze,runEvent:qe,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(Ye):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>Be({FS:e,PATH:t,PATH_FS:r},n,s)};const Ve="ruby-wasm-wasi",Qe=Ve.replace(/\\W+/g,"_");var Xe={type:Ve,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await De(this,o,t.fetch),o},registerJSModule(e,t,r){const n=[\'require "js"\'];for(const[e,t]of je(r)){const r=`__module_${Qe}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Fe(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Fe(t),...r),async runEvent(e,t,r){if(/^xworker\\.(on\\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${Qe}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${Ve}`)}};var Ze={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Re(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await De(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of je(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Fe(t),...r)}catch(t){We.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){We.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Le(e,Je(t)),t=Ie(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const et=new Map,tt=new Map,rt=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=et.get(r),o=/^https?:\\/\\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{tt.set(t,e);const a=e?.fetch;return a&&Ce.set(a,o),s(n,e,r)}))}}),nt=e=>{for(const t of[].concat(e.type))et.set(t,e)};for(const e of[Ke,Ge,Xe,Ze])nt(e);const st=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e);try{new SharedArrayBuffer(4)}catch(e){throw new Error(["Unable to use SharedArrayBuffer due insecure environment.","Please read requirements in MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements"].join("\\n"))}let ot,at,it;const ct=(e,t)=>{addEventListener(e,t||(async t=>{try{await ot,at(`xworker.on${e}`,t)}catch(e){postMessage(e)}}),!!t&&{once:!0})},{parse:lt,stringify:ut}=f,{proxy:ft,window:pt,isWindowProxy:dt}=ve(self,{parse:lt,stringify:ut,transform:e=>it?it(e):e}),yt={sync:ft,window:pt,isWindowProxy:dt,onmessage:console.info,onerror:console.error,onmessageerror:console.warn,postMessage:postMessage.bind(self)};ct("message",(({data:{options:e,config:t,code:r,hooks:n}})=>{ot=(async()=>{try{const{type:s,version:o,config:a,async:i}=e,c=await((e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Te),t=ke(t);else if(t.endsWith(".toml"))r=fetch(t).then(Oe).then(st),t=ke(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=st(t)}t=ke("./config.txt")}return _e(r).then((r=>rt[e](r,t)))})(((e,t="")=>`${e}@${t}`.replace(/@$/,""))(s,o),t,a),l=Ae(et.get(s)),u="run"+(i?"Async":"");if(n){const{beforeRun:e,beforeRunAsync:t,afterRun:r,afterRunAsync:s}=n,o=r||s,a=e||t;if(o){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${r}\\n${o}`,...n)}if(a){const e=l[u].bind(l);l[u]=(t,r,...n)=>e(t,`${a}\\n${r}`,...n)}}return l.registerJSModule(c,"polyscript",{xworker:yt}),at=l.runEvent.bind(l,c),it=l.transform.bind(l,c),await l[u](c,r),c}catch(e){postMessage(e)}})(),ct("error"),ct("message"),ct("messageerror")}));\n'],{type:"application/javascript"})),{type:"module"}),{postMessage:s}=n,o=this instanceof Be;if(e.length){const[t,n]=e;(r=Se({},r||{type:t,version:n})).type||(r.type=t)}const{config:a}=r,i=We(a&&"string"==typeof a?a:"./config.txt"),c=fetch(t).then(Fe).then((e=>{const t=o?this.stringHooks:void 0;s.call(n,{options:r,config:i,code:e,hooks:t})}));return Re(n,{postMessage:{value:(e,...t)=>c.then((()=>s.call(n,e,...t)))},sync:{value:Ee(n,y).proxy},onerror:{writable:!0,configurable:!0,value:console.error}}),o&&this.onWorkerReady?.(this.interpreter,n),n.addEventListener("message",(e=>{const{data:t}=e;t instanceof Error&&(e.stopImmediatePropagation(),n.onerror(Object.create(e,{type:{value:"error"},error:{value:t}})))})),n};const Ne=e=>e.replace(/^[^\r\n]+$/,(e=>e.trim())),Ce=new WeakMap,Je=e=>{const t=e||console,r={stderr:(t.stderr||console.error).bind(t),stdout:(t.stdout||console.log).bind(t)};return{stderr:(...e)=>r.stderr(...e),stdout:(...e)=>r.stdout(...e),async get(e){const t=await e;return Ce.set(t,r),t}}},He=({FS:e,PATH:t,PATH_FS:r},n,s)=>{const o=r.resolve(n);return e.mkdirTree(t.dirname(o)),e.writeFile(o,new Uint8Array(s),{canOwn:!0})},De=e=>{const t=e.split("/");return t.pop(),t.join("/")},Ue=(e,t)=>{const r=[];for(const n of t.split("/"))"."!==n&&(r.push(n),n&&e.mkdir(r.join("/")))},ze=(e,t)=>{const r=[];for(const e of t.split("/"))switch(e){case"":case".":break;case"..":r.pop();break;default:r.push(e)}return[e.cwd()].concat(r).join("/").replace(/^\/+/,"/")},qe=e=>{const t=e.map((e=>e.trim().replace(/(^[/]*|[/]*$)/g,""))).filter((e=>""!==e&&"."!==e)).join("/");return e[0].startsWith("/")?`/${t}`:t},Qe=new WeakMap,Ye=(e,t,r)=>$e((e=>{for(const{files:t,to_file:r,from:n=""}of e){if(void 0!==t&&void 0!==r)throw new Error("Cannot use 'to_file' and 'files' parameters together!");if(void 0===t&&void 0===r&&n.endsWith("/"))throw new Error(`Couldn't determine the filename from the path ${n}, please supply 'to_file' parameter.`)}return e.flatMap((({from:e="",to_folder:t=".",to_file:r,files:n})=>{if(ke(n))return n.map((r=>({url:qe([e,r]),path:qe([t,r])})));const s=r||e.slice(1+e.lastIndexOf("/"));return[{url:e,path:qe([t,s])}]}))})(r).map((({url:n,path:s})=>((e,t)=>fetch(We(t,Qe.get(e))))(r,n).then(Te).then((r=>e.writeFile(t,s,r)))))),Ke=(e,t,r)=>{e.registerJsModule(t,r)},Xe=(e,t,...r)=>{try{return e.runPython(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ve=async(e,t,...r)=>{try{return await e.runPythonAsync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},Ze=async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.globals.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}};var Ge={type:"micropython",module:(e="1.20.0-297")=>`https://cdn.jsdelivr.net/npm/@micropython/micropython-webassembly-pyscript@${e}/micropython.mjs`,async engine({loadMicroPython:e},t,r){const{stderr:n,stdout:s,get:o}=Je();r=r.replace(/\.m?js$/,".wasm");const a=await o(e({stderr:n,stdout:s,url:r}));return t.fetch&&await Ye(this,a,t.fetch),a},registerJSModule:Ke,run:Xe,runAsync:Ve,runEvent:Ze,transform:(e,t)=>t,writeFile:({FS:e,_module:{PATH:t,PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const et={dict_converter:Object.fromEntries};var tt={type:"pyodide",module:(e="0.23.4")=>`https://cdn.jsdelivr.net/pyodide/v${e}/full/pyodide.mjs`,async engine({loadPyodide:e},t,r){const{stderr:n,stdout:s,get:o}=Je(),a=r.slice(0,r.lastIndexOf("/")),i=await o(e({stderr:n,stdout:s,indexURL:a}));if(t.fetch&&await Ye(this,i,t.fetch),t.packages){await i.loadPackage("micropip");const e=await i.pyimport("micropip");await e.install(t.packages),e.destroy()}return i},registerJSModule:Ke,run:Xe,runAsync:Ve,runEvent:Ze,transform:(e,t)=>t instanceof e.ffi.PyProxy?t.toJs(et):t,writeFile:({FS:e,PATH:t,_module:{PATH_FS:r}},n,s)=>He({FS:e,PATH:t,PATH_FS:r},n,s)};const rt="ruby-wasm-wasi",nt=rt.replace(/\W+/g,"_");var st={type:rt,experimental:!0,module:(e="2.0.0")=>`https://cdn.jsdelivr.net/npm/ruby-3_2-wasm-wasi@${e}/dist/browser.esm.js`,async engine({DefaultRubyVM:e},t,r){const n=await fetch(`${r.slice(0,r.lastIndexOf("/"))}/ruby.wasm`),s=await WebAssembly.compile(await n.arrayBuffer()),{vm:o}=await e(s);return t.fetch&&await Ye(this,o,t.fetch),o},registerJSModule(e,t,r){const n=['require "js"'];for(const[e,t]of je(r)){const r=`__module_${nt}_${e}`;globalThis[r]=t,n.push(`$${e}=JS.global[:${r}]`)}this.run(e,n.join(";"))},run:(e,t,...r)=>e.eval(Ne(t),...r),runAsync:(e,t,...r)=>e.evalAsync(Ne(t),...r),async runEvent(e,t,r){if(/^xworker\.(on\w+)$/.test(t)){const{$1:t}=RegExp,n=`__module_${nt}_event`;globalThis[n]=r,this.run(e,`require "js";$xworker.call("${t}",JS.global[:${n}])`),delete globalThis[n]}else{const n=this.run(e,`method(:${t})`);await n.call(t,e.wrap(r))}},transform:(e,t)=>t,writeFile:()=>{throw new Error(`writeFile is not supported in ${rt}`)}};var ot={type:"wasmoon",module:(e="1.15.0")=>`https://cdn.jsdelivr.net/npm/wasmoon@${e}/+esm`,async engine({LuaFactory:e,LuaLibraries:t},r){const{stderr:n,stdout:s,get:o}=Je(),a=await o((new e).createEngine());return a.global.getTable(t.Base,(e=>{a.global.setField(e,"print",s),a.global.setField(e,"printErr",n)})),r.fetch&&await Ye(this,a,r.fetch),a},registerJSModule:(e,t,r)=>{for(const[t,n]of je(r))e.global.set(t,n)},run:(e,t,...r)=>{try{return e.doStringSync(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runAsync:async(e,t,...r)=>{try{return await e.doString(Ne(t),...r)}catch(t){Ce.get(e).stderr(t)}},runEvent:async(e,t,r)=>{const[n,...s]=t.split(".");let o,a=e.global.get(n);for(const e of s)[o,a]=[a,a[e]];try{await a.call(o,r)}catch(t){Ce.get(e).stderr(t)}},transform:(e,t)=>t,writeFile:({cmodule:{module:{FS:e}}},t,r)=>((e,t,r)=>(Ue(e,De(t)),t=ze(e,t),e.writeFile(t,new Uint8Array(r),{canOwn:!0})))(e,t,r)};const at=new Map,it=new Map,ct=[],lt=[],ut=new Proxy(new Map,{get(e,t){if(!e.has(t)){const[r,...n]=t.split("@"),s=at.get(r),o=/^https?:\/\//i.test(n)?n.join("@"):s.module(...n);e.set(t,{url:o,module:import(o),engine:s.engine.bind(s)})}const{url:r,module:n,engine:s}=e.get(t);return(e,o)=>n.then((n=>{it.set(t,e);const a=e?.fetch;return a&&Qe.set(a,o),s(n,e,r)}))}}),pt=e=>{for(const t of[].concat(e.type))at.set(t,e),ct.push(`script[type="${t}"]`),lt.push(`${t}-`)};for(const e of[Ge,tt,st,ot])pt(e);const ft=async e=>(await import("https://cdn.jsdelivr.net/npm/basic-toml@0.3.1/es.js")).parse(e),dt=(e,t,r={})=>{if(t)if(t.endsWith(".json"))r=fetch(t).then(Oe),t=We(t);else if(t.endsWith(".toml"))r=fetch(t).then(Fe).then(ft),t=We(t);else if(!t.endsWith(".txt")){try{r=JSON.parse(t)}catch(e){r=ft(t)}t=We("./config.txt")}return Me(r).then((r=>ut[e](r,t)))},yt=(e,t="")=>`${e}@${t}`.replace(/@$/,""),ht=(t,r)=>{const n=(e=>{let t=e;for(;t.parentNode;)t=t.parentNode;return t})(t);return n.getElementById(r)||e(r,n)},mt=new WeakMap,gt={get(){let e=mt.get(this);return e||(e=document.createElement(`${this.type}-script`),mt.set(this,e),At(this)),e},set(e){"string"==typeof e?mt.set(this,ht(this,e)):(mt.set(this,e),At(this))}},wt=new WeakMap,bt=new Map,vt=(e,t)=>{const r=e?.value;return r?t+r:""},_t=(e,t,r,n,s,o=e)=>{if(!bt.has(t)){const a={interpreter:dt(r,s),queue:Me(),XWorker:Le(e,n)};bt.set(t,a),bt.has(e)||bt.set(e,a),bt.has(o)||bt.set(o,a)}return bt.get(t)},At=async e=>{if(wt.has(e)){const{target:t}=e;t&&(e.closest("head")?document.body.append(t):e.after(t))}else{const{attributes:{async:t,config:r,env:n,target:s,version:o,worker:a},src:i,type:c}=e,l=o?.value,u=yt(c,l);let p=vt(r,"|");const f=vt(n,"")||`${u}${p}`;p=p.slice(1);const d=a?.value;if(d){const r=new(Le(c,l))(d,{async:!!t,config:p});return void wt.set(xe(e,"xworker",{value:r}),{xworker:r})}const y=vt(s,""),h=_t(c,f,u,l,p);wt.set(xe(e,"target",gt),h),y&&mt.set(e,ht(e,y));const m=i?fetch(i).then(Fe):e.textContent;h.queue=h.queue.then((()=>(async(e,t,r,n)=>{const s=at.get(e.type);s.experimental&&console.warn(`The ${e.type} interpreter is experimental`);const[o,a]=await $e([wt.get(e).interpreter,t]);try{return xe(document,"currentScript",{configurable:!0,get:()=>e}),s.registerJSModule(o,"polyscript",{XWorker:r}),s[n?"runAsync":"run"](o,a)}finally{delete document.currentScript}})(e,m,h.XWorker,!!t)))}};new Proxy(Pe(null),{get:(e,t)=>Et(t)});const Et=async e=>{if(bt.has(e)){const{interpreter:t,queue:r}=bt.get(e);return(await $e([t,r]))[0]}const t=bt.size?`Available interpreters are: ${[...bt.keys()].map((e=>`"${e}"`)).join(", ")}.`:"There are no interpreters in this page.";throw new Error(`The interpreter "${e}" was not found. ${t}`)},kt=async e=>{const{type:t,currentTarget:n}=e;for(let{name:s,value:o,ownerElement:a}of r(`./@*[${lt.map((e=>`name()="${e}${t}"`)).join(" or ")}]`,n)){s=s.slice(0,-(t.length+1));const r=await Et(a.getAttribute(`${s}-env`)||s);at.get(s).runEvent(r,o,e)}},St=e=>{for(let{name:t,ownerElement:n}of r(`.//@*[${lt.map((e=>`starts-with(name(),"${e}")`)).join(" or ")}]`,e))t=t.slice(t.lastIndexOf("-")+1),"env"!==t&&n.addEventListener(t,kt)},Pt=[],Rt=new Map,xt=new Map,jt=e=>{for(const t of Pt)if(e.matches(t)){const r=Rt.get(t),{resolve:n}=xt.get(r),{options:s,known:o}=$t.get(r);if(!o.has(e)){o.add(e);const{interpreter:t,config:a,version:i,env:c,onInterpreterReady:l}=s,u=e.attributes.worker?.value||"";if(u){const o=Wt.call(new Be(null,s),u,{version:i,type:t,config:a||{},async:e.hasAttribute("async")});return xe(e,"xworker",{value:o}),void n({type:r,xworker:o})}const p=yt(t,i),f=c||`${p}${a?`|${a}`:""}`,{interpreter:d,XWorker:y}=_t(r,f,p,i,a,t);d.then((o=>{const a=Pe(at.get(t)),{onBeforeRun:i,onBeforeRunAsync:c,onAfterRun:u,onAfterRunAsync:f}=s,d=new Be(o,s),h=function(...e){return y.apply(d,e)};for(const[t,[r,n]]of[["run",[i,u]]]){const s=a[t];a[t]=function(t,o,...a){r&&r.call(this,m,e);const i=s.call(this,t,o,...a);return n&&n.call(this,m,e),i}}for(const[t,[r,n]]of[["runAsync",[c,f]]]){const s=a[t];a[t]=async function(t,o,...a){r&&await r.call(this,m,e);const i=await s.call(this,t,o,...a);return n&&await n.call(this,m,e),i}}a.registerJSModule(o,"polyscript",{XWorker:h});const m={type:r,interpreter:o,XWorker:h,io:Ce.get(o),config:structuredClone(it.get(p)),run:a.run.bind(a,o),runAsync:a.runAsync.bind(a,o),runEvent:a.runEvent.bind(a,o)};n(m),l?.(m,e)}))}}},$t=new Map,Mt=e=>(xt.has(e)||xt.set(e,Promise.withResolvers()),xt.get(e).promise),Wt=Le(),Tt=ct.join(","),Ot=new MutationObserver((e=>{for(const{type:r,target:n,attributeName:s,addedNodes:o}of e)if("attributes"!==r){for(const e of o)if(1===e.nodeType)if(St(e),e.matches(Tt))At(e);else{if(t(Tt,e).forEach(At),!Pt.length)continue;jt(e),t(Pt.join(","),e).forEach(jt)}}else{const e=s.lastIndexOf("-")+1;if(e){const t=s.slice(0,e);for(const r of lt)if(t===r){const t=s.slice(e);if("env"!==t){const e=n.hasAttribute(s)?"add":"remove";n[`${e}EventListener`](t,kt)}break}}}})),Ft=e=>(Ot.observe(e,{childList:!0,subtree:!0,attributes:!0}),e),{attachShadow:It}=Element.prototype;Se(Element.prototype,{attachShadow(e){return Ft(It.call(this,e))}}),St(Ft(document)),t(Tt,document).forEach(At);const Bt={"<":"<",">":">"},Lt=e=>{return(new DOMParser).parseFromString((t=e,t.replace(/[<>]/g,(e=>Bt[e]))),"text/html").documentElement.textContent;var t};var Nt={sleep:e=>new Promise((t=>setTimeout(t,1e3*e)))};const{entries:Ct}=Object,Jt=["from pathlib import Path as _Path"],Ht=(e,t)=>{for(const[r,n]of Ct(t)){const t=`_Path("${e}/${r}")`;if("string"==typeof n){const e=JSON.stringify(n);Jt.push(`${t}.write_text(${e})`)}else Jt.push(`${t}.mkdir(parents=True, exist_ok=True)`),Ht(`${e}/${r}`,n)}};Ht(".",{_pyscript:{"__init__.py":'import js as window\n\nIS_WORKER = not hasattr(window, "document")\n\nif IS_WORKER:\n from polyscript import xworker as _xworker\n\n window = _xworker.window\n document = window.document\n sync = _xworker.sync\nelse:\n document = window.document\n',"display.py":'import base64\nimport html\nimport io\nimport re\n\nfrom . import document, window\n\n_MIME_METHODS = {\n "__repr__": "text/plain",\n "_repr_html_": "text/html",\n "_repr_markdown_": "text/markdown",\n "_repr_svg_": "image/svg+xml",\n "_repr_png_": "image/png",\n "_repr_pdf_": "application/pdf",\n "_repr_jpeg_": "image/jpeg",\n "_repr_latex": "text/latex",\n "_repr_json_": "application/json",\n "_repr_javascript_": "application/javascript",\n "savefig": "image/png",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode("utf-8")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$"\n )\n # If value doesn\'t match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode("utf-8")).decode("utf-8")\n\n data = f"data:{mime};charset=utf-8;base64,{value}"\n attrs = " ".join([\'{k}="{v}"\' for k, v in meta.items()])\n return f\'\'\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n "text/plain": html.escape,\n "text/html": _identity,\n "image/png": lambda value, meta: _render_image("image/png", value, meta),\n "image/jpeg": lambda value, meta: _render_image("image/jpeg", value, meta),\n "image/svg+xml": _identity,\n "application/json": _identity,\n "application/javascript": lambda value, meta: f" - - + + + + + @pyscript/core + + + + + + import pyscript + from pyscript import display + display("Hello", append=True) + pyscript.display("same", append=True) + + + display("World", append=True) # first has another DIV with World + + + from pyscript import display + display("A part", append=True) + + + display("!", target="first", append=True) + + + from pyscript import display + display("worker", append=True) + + From 37d4cb7c48c68537cc95fc2b830d564308b1656f Mon Sep 17 00:00:00 2001 From: Jeff Glass Date: Wed, 6 Sep 2023 03:20:16 -0500 Subject: [PATCH 013/105] Adjust Comments in `target.html` test (#1674) * Adjust comments * Remove unnecessary styling --- pyscript.core/test/target.html | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pyscript.core/test/target.html b/pyscript.core/test/target.html index 790b8129..49a614d1 100644 --- a/pyscript.core/test/target.html +++ b/pyscript.core/test/target.html @@ -11,20 +11,25 @@ import pyscript from pyscript import display - display("Hello", append=True) - pyscript.display("same", append=True) + display("Hello", append=True) # Appears in a DIV that is a child of this py-script tag + pyscript.display("same", append=True) # Appears in another DIV that is a child of this py-script tag - display("World", append=True) # first has another DIV with World + # Appears in a DIV that is a child of this py-script tag, no need to re-import + display("World", append=True) + # Appears in a DIV that is a child of this py-script tag + # Re-importing has no effect in the essential behavior from pyscript import display display("A part", append=True) + # Use the 'target' element to specify the ID of an element in the DOM to write the content to display("!", target="first", append=True) - + \ + # Appears in a DIV that is a child of this py-script tag, even with the code running in a worker from pyscript import display display("worker", append=True) From 264675d0c3b6472c2877f948fbb310b502f718c4 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Wed, 6 Sep 2023 11:28:58 +0200 Subject: [PATCH 014/105] [next] Fix #1675 - use `async` runner in py-script too (#1676) --- pyscript.core/package-lock.json | 16 ++++++++-------- pyscript.core/package.json | 4 ++-- pyscript.core/src/core.js | 5 +++-- pyscript.core/test/async.html | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 pyscript.core/test/async.html diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 1f2747b3..3ff84dfd 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -11,12 +11,12 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.2.5" + "polyscript": "^0.3.0" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-terser": "^0.4.3", - "rollup": "^3.28.1", + "rollup": "^3.29.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.2", @@ -935,9 +935,9 @@ } }, "node_modules/polyscript": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.2.5.tgz", - "integrity": "sha512-c2q4EyvMMdmIH0e85rF7I+fefX0YfEq2g9hzzMeLMOiYcGap04SobVlGO5oDP1KW/k0rFHBR6wN68kzRKOcixA==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.3.0.tgz", + "integrity": "sha512-kdB6yXuYFh86XqHaA28gSIgeNqVVIBq/8fyuPBwlXuF339fNrzFmXAi8KadC7LIdllO4p0WgQKPMnBqRd9wmdg==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", @@ -1550,9 +1550,9 @@ } }, "node_modules/rollup": { - "version": "3.28.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz", - "integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.0.tgz", + "integrity": "sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w==", "dev": true, "bin": { "rollup": "dist/bin/rollup" diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 31a5cfae..1dddce45 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -33,12 +33,12 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.2.5" + "polyscript": "^0.3.0" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-terser": "^0.4.3", - "rollup": "^3.28.1", + "rollup": "^3.29.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.2", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 8242d271..6b9d6834 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -215,10 +215,11 @@ class PyScriptElement extends HTMLElement { async connectedCallback() { if (!this.executed) { this.executed = true; - const { io, run } = await this._pyodide.promise; + const { io, run, runAsync } = await this._pyodide.promise; + const runner = this.hasAttribute("async") ? runAsync : run; this.srcCode = await fetchSource(this, io, !this.childElementCount); this.replaceChildren(); - run(this.srcCode); + runner(this.srcCode); this.style.display = "block"; } } diff --git a/pyscript.core/test/async.html b/pyscript.core/test/async.html new file mode 100644 index 00000000..b1ad516f --- /dev/null +++ b/pyscript.core/test/async.html @@ -0,0 +1,14 @@ + + + + + + + + import asyncio + print('foo') + await asyncio.sleep(1) + print('bar') + + + From 1d015c753418283ffcf7669a34151e2436636d93 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Wed, 6 Sep 2023 16:49:43 +0200 Subject: [PATCH 015/105] [next] Include most basic error plugin (#1677) --- .gitignore | 1 + .pre-commit-config.yaml | 6 +-- pyscript.core/README.md | 41 ++++++++++++++ pyscript.core/package.json | 16 +++--- pyscript.core/rollup/core-css.config.js | 20 ------- pyscript.core/rollup/core.config.js | 39 ++++++++++---- pyscript.core/rollup/plugins.cjs | 24 +++++++++ pyscript.core/src/core.js | 13 ++++- pyscript.core/src/plugins.js | 4 ++ pyscript.core/src/plugins/error.js | 40 ++++++++++++++ pyscript.core/test/async.html | 3 +- pyscript.core/test/create-element.html | 4 +- pyscript.core/test/error.html | 18 +++++++ pyscript.core/test/error.js | 39 ++++++++++++++ pyscript.core/test/html-decode.html | 4 +- pyscript.core/test/index.html | 4 +- pyscript.core/test/no-error.html | 19 +++++++ pyscript.core/test/target.html | 6 +-- pyscript.core/test/worker.html | 4 +- pyscript.core/types/coincident/window.d.ts | 10 ---- pyscript.core/types/plugins.d.ts | 4 ++ pyscript.core/types/plugins/error.d.ts | 1 + .../types/polyscript/esm/custom.d.ts | 54 ------------------- .../types/polyscript/esm/fetch-utils.d.ts | 3 -- pyscript.core/types/polyscript/esm/index.d.ts | 3 -- .../polyscript/esm/interpreter/_python.d.ts | 4 -- .../polyscript/esm/interpreter/_utils.d.ts | 15 ------ .../esm/interpreter/micropython.d.ts | 25 --------- .../polyscript/esm/interpreter/pyodide.d.ts | 25 --------- .../esm/interpreter/ruby-wasm-wasi.d.ts | 16 ------ .../polyscript/esm/interpreter/wasmoon.d.ts | 22 -------- .../types/polyscript/esm/interpreters.d.ts | 9 ---- .../types/polyscript/esm/listeners.d.ts | 3 -- .../types/polyscript/esm/loader.d.ts | 2 - .../types/polyscript/esm/script-handler.d.ts | 4 -- pyscript.core/types/polyscript/esm/toml.d.ts | 1 - pyscript.core/types/polyscript/esm/utils.d.ts | 29 ---------- .../types/polyscript/esm/worker/class.d.ts | 19 ------- .../types/polyscript/esm/worker/hooks.d.ts | 6 --- .../types/polyscript/esm/worker/xworker.d.ts | 2 - .../pyscript/pyscript.core/src/core.d.ts | 25 --------- .../pyscript.core/src/exceptions.d.ts | 27 ---------- .../pyscript/pyscript.core/src/fetch.d.ts | 10 ---- 43 files changed, 255 insertions(+), 369 deletions(-) delete mode 100644 pyscript.core/rollup/core-css.config.js create mode 100644 pyscript.core/rollup/plugins.cjs create mode 100644 pyscript.core/src/plugins.js create mode 100644 pyscript.core/src/plugins/error.js create mode 100644 pyscript.core/test/error.html create mode 100644 pyscript.core/test/error.js create mode 100644 pyscript.core/test/no-error.html delete mode 100644 pyscript.core/types/coincident/window.d.ts create mode 100644 pyscript.core/types/plugins.d.ts create mode 100644 pyscript.core/types/plugins/error.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/custom.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/fetch-utils.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/index.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/_python.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/_utils.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/micropython.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/pyodide.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/ruby-wasm-wasi.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreter/wasmoon.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/interpreters.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/listeners.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/loader.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/script-handler.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/toml.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/utils.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/worker/class.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/worker/hooks.d.ts delete mode 100644 pyscript.core/types/polyscript/esm/worker/xworker.d.ts delete mode 100644 pyscript.core/types/pyscript/pyscript.core/src/core.d.ts delete mode 100644 pyscript.core/types/pyscript/pyscript.core/src/exceptions.d.ts delete mode 100644 pyscript.core/types/pyscript/pyscript.core/src/fetch.d.ts diff --git a/.gitignore b/.gitignore index 4d5828f4..2aa902e0 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,4 @@ test_results # @pyscript/core npm artifacts pyscript.core/core.* +pyscript.core/dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa01299f..6f6eafe2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,14 +20,14 @@ repos: - id: check-yaml - id: detect-private-key - id: end-of-file-fixer - exclude: pyscript\.core/core.*|\.min\.js$ + exclude: pyscript\.core/dist|\.min\.js$ - id: trailing-whitespace - repo: https://github.com/charliermarsh/ruff-pre-commit rev: v0.0.257 hooks: - id: ruff - exclude: pyscript\.core/test|pyscript.core/src/stdlib/pyscript.py + exclude: pyscript\.core/test|pyscript\.core/dist|pyscript.core/src/stdlib/pyscript.py args: [--fix] - repo: https://github.com/psf/black @@ -47,7 +47,7 @@ repos: rev: "v3.0.0-alpha.6" hooks: - id: prettier - exclude: pyscript\.core/test|pyscript\.core/core.*|pyscript\.core/types/|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/ + exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/ args: [--tab-width, "4"] - repo: https://github.com/pre-commit/mirrors-eslint diff --git a/pyscript.core/README.md b/pyscript.core/README.md index e35e428f..960e7b9f 100644 --- a/pyscript.core/README.md +++ b/pyscript.core/README.md @@ -1,3 +1,44 @@ # @pyscript/core We have moved and renamed previous _core_ module as [polyscript](https://github.com/pyscript/polyscript/#readme), which is the base module used in here to build up _PyScript Next_, now hosted in this folder. + +## Documentation + +Please read [core documentation](./docs/README.md) to know more about this project. + +## Development + +Clone this repository then run `npm install` within its folder. + +Use `npm run build` to create all artifacts and _dist_ files. + +Use `npm run server` to test locally, via the `http://localhost:8080/test/` url, smoke tests or to test manually anything you'd like to check. + +### Artifacts + +There are two main artifacts in this project: + +- **stdlib** and its content, where `src/stdlib/pyscript.js` exposes as object literal all the _Python_ content within the folder (recursively) +- **plugins** and its content, where `src/plugins.js` exposes all available _dynamic imports_, able to instrument the bundler to create files a part within the _dist/_ folder, so that by default _core_ remains as small as possible + +Accordingly, whenever a file contains this warning at its first line, please do not change such file directly before submitting a merge request, as that file will be overwritten at the next `npm run build` command, either here or in _CI_: + +```js +// ⚠️ This file is an artifact: DO NOT MODIFY +``` + +## Python stdlib + +The `pyscript` module available in _Python_ defines its exported utilities via `src/stdlib/pyscript.py`. Any file that would like to provide an export should be placed into `src/stdlib/_pyscript` folder (see the `display.py` as example) and its public functionalities should be explicit in the `src/stdlib/pyscript.py` file. + +All _Python_ files will be embedded automatically whenever `npm run build` happens and reflected into the `src/stdlib/pyscript.js` file. + +It is _core_ responsibility to ensure those files will be available through the Filesystem in either the _main_ thread, or any _worker_. + +## JS plugins + +While community or third party plugins don't need to be part of this repository and can be added just importing `@pyscript/core` as module, there are a few plugins that we would like to make available by default and these are considered _core plugins_. + +To add a _core plugin_ to this project you can define your plugin entry-point and name in the `src/plugins` folder (see the `error.js` example) and create, if necessary, a folder with the same name where extra files or dependencies can be added. + +The _build_ command will bring plugins by name as artifact so that the bundler can create ad-hoc files within the `dist/` folder. diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 1dddce45..cf5cc781 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -3,25 +3,21 @@ "version": "0.1.7", "type": "module", "description": "PyScript", - "main": "./core.js", - "module": "./core.js", - "unpkg": "./core.js", + "module": "./dist/core.js", + "unpkg": "./dist/core.js", "exports": { ".": { - "types": "./types/esm/core.d.ts", - "import": "./esm/core.js" - }, - "./js": { - "import": "./core.js" + "types": "./types/core.d.ts", + "import": "./src/core.js" }, "./css": { - "import": "./core.css" + "import": "./dist/core.css" }, "./package.json": "./package.json" }, "scripts": { "server": "npx static-handler --cors --coep --coop --corp .", - "build": "node rollup/stdlib.cjs && rollup --config rollup/core.config.js && rollup --config rollup/core-css.config.js && npm run ts", + "build": "node rollup/stdlib.cjs && node rollup/plugins.cjs && rollup --config rollup/core.config.js && npm run ts", "ts": "tsc -p ." }, "keywords": [ diff --git a/pyscript.core/rollup/core-css.config.js b/pyscript.core/rollup/core-css.config.js deleted file mode 100644 index 370dd49b..00000000 --- a/pyscript.core/rollup/core-css.config.js +++ /dev/null @@ -1,20 +0,0 @@ -import postcss from "rollup-plugin-postcss"; - -export default { - input: "./src/core.css", - plugins: [ - postcss({ - extract: true, - sourceMap: false, - minimize: !process.env.NO_MIN, - plugins: [], - }), - ], - output: { - file: "./core.css", - }, - onwarn(warning, warn) { - if (warning.code === "FILE_NAME_CONFLICT") return; - warn(warning); - }, -}; diff --git a/pyscript.core/rollup/core.config.js b/pyscript.core/rollup/core.config.js index 530e84c7..e6a2da21 100644 --- a/pyscript.core/rollup/core.config.js +++ b/pyscript.core/rollup/core.config.js @@ -3,16 +3,37 @@ import { nodeResolve } from "@rollup/plugin-node-resolve"; import terser from "@rollup/plugin-terser"; +import postcss from "rollup-plugin-postcss"; const plugins = []; -export default { - input: "./src/core.js", - plugins: plugins.concat( - process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()], - ), - output: { - esModule: true, - file: "./core.js", +export default [ + { + input: "./src/core.js", + plugins: plugins.concat( + process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()], + ), + output: { + esModule: true, + dir: "./dist", + }, }, -}; + { + input: "./src/core.css", + plugins: [ + postcss({ + extract: true, + sourceMap: false, + minimize: !process.env.NO_MIN, + plugins: [], + }), + ], + output: { + file: "./dist/core.css", + }, + onwarn(warning, warn) { + if (warning.code === "FILE_NAME_CONFLICT") return; + warn(warning); + }, + }, +]; diff --git a/pyscript.core/rollup/plugins.cjs b/pyscript.core/rollup/plugins.cjs new file mode 100644 index 00000000..07f94a69 --- /dev/null +++ b/pyscript.core/rollup/plugins.cjs @@ -0,0 +1,24 @@ +const { readdirSync, writeFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const plugins = [""]; + +for (const file of readdirSync(join(__dirname, "..", "src", "plugins"))) { + if (/\.js$/.test(file)) { + const name = file.slice(0, -3); + const key = /^[a-zA-Z0-9$_]+$/.test(name) + ? name + : `[${JSON.stringify(name)}]`; + const value = JSON.stringify(`./plugins/${file}`); + plugins.push(` ${key}: () => import(${value}),`); + } +} + +plugins.push(""); + +writeFileSync( + join(__dirname, "..", "src", "plugins.js"), + `// ⚠️ This file is an artifact: DO NOT MODIFY\nexport default {${plugins.join( + "\n", + )}};\n`, +); diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 6b9d6834..9313f485 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -5,6 +5,7 @@ import { htmlDecode } from "./utils.js"; import sync from "./sync.js"; import stdlib from "./stdlib.js"; +import plugins from "./plugins.js"; // TODO: this is not strictly polyscript related but handy ... not sure // we should factor this utility out a part but this works anyway. @@ -13,7 +14,7 @@ import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; import { robustFetch as fetch } from "./fetch.js"; -const { assign, defineProperty } = Object; +const { assign, defineProperty, entries } = Object; const getText = (body) => body.text(); @@ -163,6 +164,16 @@ define("py", { shouldRegister = false; registerModule(pyodide); } + + // load plugins unless specified otherwise + const toBeAwaited = []; + for (const [key, value] of entries(plugins)) { + if (!pyodide.config?.plugins?.includes(`!${key}`)) + toBeAwaited.push(value()); + } + + if (toBeAwaited.length) await Promise.all(toBeAwaited); + // allows plugins to do whatever they want with the element // before regular stuff happens in here for (const callback of hooks.onInterpreterReady) diff --git a/pyscript.core/src/plugins.js b/pyscript.core/src/plugins.js new file mode 100644 index 00000000..0e1966dd --- /dev/null +++ b/pyscript.core/src/plugins.js @@ -0,0 +1,4 @@ +// ⚠️ This file is an artifact: DO NOT MODIFY +export default { + error: () => import("./plugins/error.js"), +}; diff --git a/pyscript.core/src/plugins/error.js b/pyscript.core/src/plugins/error.js new file mode 100644 index 00000000..f6eb9c37 --- /dev/null +++ b/pyscript.core/src/plugins/error.js @@ -0,0 +1,40 @@ +// PyScript Error Plugin +import { hooks } from "../core.js"; + +hooks.onBeforeRun.add(function override(pyScript) { + // be sure this override happens only once + hooks.onBeforeRun.delete(override); + + // trap generic `stderr` to propagate to it regardless + const { stderr } = pyScript.io; + + // override it with our own logic + pyScript.io.stderr = (...args) => { + // grab the message of the first argument (Error) + const [{ message }] = args; + // show it + notify(message); + // still let other plugins or PyScript itself do the rest + return stderr(...args); + }; +}); + +// Error hook utilities + +// Custom function to show notifications +function notify(message) { + const div = document.createElement("div"); + div.className = "py-error"; + div.textContent = message; + div.style.cssText = ` + border: 1px solid red; + background: #ffdddd; + color: black; + font-family: courier, monospace; + white-space: pre; + overflow-x: auto; + padding: 8px; + margin-top: 8px; + `; + document.body.append(div); +} diff --git a/pyscript.core/test/async.html b/pyscript.core/test/async.html index b1ad516f..0e9801d1 100644 --- a/pyscript.core/test/async.html +++ b/pyscript.core/test/async.html @@ -1,7 +1,8 @@ - + + diff --git a/pyscript.core/test/create-element.html b/pyscript.core/test/create-element.html index cff34e20..f8543606 100644 --- a/pyscript.core/test/create-element.html +++ b/pyscript.core/test/create-element.html @@ -1,8 +1,8 @@ - - + + + + + print(4, 5, 6) + second() + + + diff --git a/pyscript.core/test/error.js b/pyscript.core/test/error.js new file mode 100644 index 00000000..46a99a9d --- /dev/null +++ b/pyscript.core/test/error.js @@ -0,0 +1,39 @@ +// PyScript Error Plugin +import { hooks } from '@pyscript/core'; + +hooks.onBeforeRun.add(function override(pyScript) { + // be sure this override happens only once + hooks.onBeforeRun.delete(override); + + // trap generic `stderr` to propagate to it regardless + const { stderr } = pyScript.io; + + // override it with our own logic + pyScript.io.stderr = (...args) => { + // grab the message of the first argument (Error) + const [ { message } ] = args; + // show it + notify(message); + // still let other plugins or PyScript itself do the rest + return stderr(...args); + }; +}); + +// Error hook utilities + +// Custom function to show notifications +function notify(message) { + const div = document.createElement('div'); + div.textContent = message; + div.style.cssText = ` + border: 1px solid red; + background: #ffdddd; + color: black; + font-family: courier, monospace; + white-space: pre; + overflow-x: auto; + padding: 8px; + margin-top: 8px; + `; + document.body.append(div); +} diff --git a/pyscript.core/test/html-decode.html b/pyscript.core/test/html-decode.html index 55a08fb9..f096c9b3 100644 --- a/pyscript.core/test/html-decode.html +++ b/pyscript.core/test/html-decode.html @@ -1,8 +1,8 @@ - - + + diff --git a/pyscript.core/test/index.html b/pyscript.core/test/index.html index 40b56441..0f43dc36 100644 --- a/pyscript.core/test/index.html +++ b/pyscript.core/test/index.html @@ -4,8 +4,8 @@ PyScript Next - - + + + plugins = ['!error'] + + + print(4, 5, 6) + second() + + + diff --git a/pyscript.core/test/target.html b/pyscript.core/test/target.html index 49a614d1..90703d60 100644 --- a/pyscript.core/test/target.html +++ b/pyscript.core/test/target.html @@ -4,8 +4,8 @@ @pyscript/core - - + + @@ -28,7 +28,7 @@ # Use the 'target' element to specify the ID of an element in the DOM to write the content to display("!", target="first", append=True) - \ + # Appears in a DIV that is a child of this py-script tag, even with the code running in a worker from pyscript import display display("worker", append=True) diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 6b8e6cb9..99cc8bc7 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -4,11 +4,11 @@ PyScript Next - + + + + + + + +
+ + From fd60b4789a76d4747fa6caf3325783519936ef6c Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 8 Sep 2023 09:55:27 +0200 Subject: [PATCH 018/105] [next] Follow up on stderr (#1683) --- pyscript.core/package-lock.json | 4 ++-- pyscript.core/package.json | 2 +- pyscript.core/src/plugins/error.js | 11 ++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 65c5b26b..faa58fe9 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.1.9", + "version": "0.1.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.9", + "version": "0.1.10", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 89440d9e..0acbc005 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.1.9", + "version": "0.1.10", "type": "module", "description": "PyScript", "module": "./dist/core.js", diff --git a/pyscript.core/src/plugins/error.js b/pyscript.core/src/plugins/error.js index d9e81bd1..58484df5 100644 --- a/pyscript.core/src/plugins/error.js +++ b/pyscript.core/src/plugins/error.js @@ -9,13 +9,10 @@ hooks.onBeforeRun.add(function override(pyScript) { const { stderr } = pyScript.io; // override it with our own logic - pyScript.io.stderr = (...args) => { - // grab the message of the first argument (Error) - const [{ message }] = args; - // show it - notify(message); - // still let other plugins or PyScript itself do the rest - return stderr(...args); + pyScript.io.stderr = (error, ...rest) => { + notify(error.message || error); + // let other plugins or stderr hook, if any, do the rest + return stderr(error, ...rest); }; // be sure uncaught Python errors are also visible From 59db56feecc1e4b715d0e08117760b03d95aaab7 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 8 Sep 2023 17:43:54 +0200 Subject: [PATCH 019/105] [next] Add PyScript Developers Team copy (#1685) --- pyscript.core/rollup/core.config.js | 1 + pyscript.core/src/core.js | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pyscript.core/rollup/core.config.js b/pyscript.core/rollup/core.config.js index e6a2da21..bb5a10ec 100644 --- a/pyscript.core/rollup/core.config.js +++ b/pyscript.core/rollup/core.config.js @@ -16,6 +16,7 @@ export default [ output: { esModule: true, dir: "./dist", + sourcemap: true, }, }, { diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 6c60170a..2cd1130c 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -1,3 +1,5 @@ +/*! (c) PyScript Development Team */ + import "@ungap/with-resolvers"; import { $ } from "basic-devtools"; import { define, XWorker } from "polyscript"; From 7d2df4895e5eebad4842254228ab436215117a44 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 8 Sep 2023 17:59:50 +0200 Subject: [PATCH 020/105] [next] improve integration tests (#1684) --- Makefile | 2 +- pyscript.core/package-lock.json | 4 +- pyscript.core/package.json | 2 +- pyscript.core/src/core.js | 9 +- pyscript.core/types/core.d.ts | 2 +- pyscriptjs/tests/integration/support.py | 3 +- pyscriptjs/tests/integration/test_01_basic.py | 85 +++++++------------ .../tests/integration/test_02_display.py | 65 ++++---------- .../tests/integration/test_03_element.py | 28 +++--- pyscriptjs/tests/integration/test_async.py | 16 +--- .../tests/integration/test_py_config.py | 59 +++---------- .../tests/integration/test_script_type.py | 39 ++++----- .../tests/integration/test_shadow_root.py | 2 +- 13 files changed, 107 insertions(+), 209 deletions(-) diff --git a/Makefile b/Makefile index e0a15d72..e7b3e498 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ run-examples: setup build examples make dev test: - cd pyscript.core && npm run build && cp core.js ../pyscriptjs/build/core.js + cd pyscript.core && npm run build && cp -R dist ../pyscriptjs/build/ make test-integration make test-examples diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index faa58fe9..efb004e5 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.1.10", + "version": "0.1.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.10", + "version": "0.1.11", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 0acbc005..4a3a1f9f 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.1.10", + "version": "0.1.11", "type": "module", "description": "PyScript", "module": "./dist/core.js", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 2cd1130c..0a2e1563 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -79,7 +79,8 @@ const fetchSource = async (tag, io, asText) => { // common life-cycle handlers for any node const bootstrapNodeAndPlugins = (pyodide, element, callback, hook) => { - if (isScript(element)) callback(element); + // make it possible to reach the current target node via Python + callback(element); for (const fn of hooks[hook]) fn(pyodide, element); }; @@ -110,7 +111,7 @@ export const hooks = { /** @type {Set} */ onBeforeRun: new Set(), /** @type {Set} */ - onBeforeRunAync: new Set(), + onBeforeRunAsync: new Set(), /** @type {Set} */ onAfterRun: new Set(), /** @type {Set} */ @@ -156,9 +157,9 @@ define("py", { currentElement = element; bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRun"); }, - onBeforeRunAync(pyodide, element) { + onBeforeRunAsync(pyodide, element) { currentElement = element; - bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRunAync"); + bootstrapNodeAndPlugins(pyodide, element, before, "onBeforeRunAsync"); }, onAfterRun(pyodide, element) { bootstrapNodeAndPlugins(pyodide, element, after, "onAfterRun"); diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index ed89927b..76fb79ef 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -12,7 +12,7 @@ export function PyWorker(file: string, options?: { }; export namespace hooks { let onBeforeRun: Set; - let onBeforeRunAync: Set; + let onBeforeRunAsync: Set; let onAfterRun: Set; let onAfterRunAsync: Set; let onInterpreterReady: Set; diff --git a/pyscriptjs/tests/integration/support.py b/pyscriptjs/tests/integration/support.py index f807f21e..92b04caf 100644 --- a/pyscriptjs/tests/integration/support.py +++ b/pyscriptjs/tests/integration/support.py @@ -504,9 +504,10 @@ class PyScriptTest: doc = f""" + {extra_head} diff --git a/pyscriptjs/tests/integration/test_01_basic.py b/pyscriptjs/tests/integration/test_01_basic.py index b53d8cbd..3222d9d2 100644 --- a/pyscriptjs/tests/integration/test_01_basic.py +++ b/pyscriptjs/tests/integration/test_01_basic.py @@ -17,26 +17,23 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines == ["hello pyscript"] - # TODO: I think this test actually should test that we don't load anything if there aren't - # any pyscrpt related tags or features. Meaning that the Platform is not invasive. - @pytest.mark.skip( - reason="DIFFERENT BEHAVIOUR: We don't print anything in the console once loaded" - ) def test_execution_thread(self): self.pyscript_run( """ - """ + pyscript does not bootstrap --> + """, + wait_for_pyscript=False, ) assert self.execution_thread in ("main", "worker") if self.execution_thread == "main": pass elif self.execution_thread == "worker": pass - expected = ("[pyscript/main] PyScript Ready",) - assert expected in self.console.info.lines + assert self.console.log.lines == [] + # TODO: if there's no py-script there are surely no plugins neither + # this test must be discussed or rewritten to make sense now @pytest.mark.skip( reason="FIXME: No banner and should also add a WARNING about CORS" ) @@ -74,7 +71,6 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello pyscript" - @pytest.mark.skip("FIXME: No banner") def test_python_exception(self): self.pyscript_run( """ @@ -89,19 +85,17 @@ class TestBasic(PyScriptTest): # # check that we sent the traceback to the console tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "Python Error: Traceback (most recent call last):" - assert tb_lines[-1] == "Exception: this is an error" + assert tb_lines[0] == "PythonError: Traceback (most recent call last):" # # check that we show the traceback in the page. Note that here we # display the "raw" python traceback, without the "[pyexec] Python # exception:" line (which is useful in the console, but not for the # user) - pre = self.page.locator("py-script > pre") - tb_lines = pre.inner_text().splitlines() + banner = self.page.locator(".py-error") + tb_lines = banner.inner_text().splitlines() assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error" - @pytest.mark.skip(reason="FIX TEST: Works on CHROME") def test_python_exception_in_event_handler(self): self.pyscript_run( """ @@ -122,9 +116,7 @@ class TestBasic(PyScriptTest): ## error in console tb_lines = self.console.error.lines[-1].splitlines() - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" - assert tb_lines[-1] == "Exception: this is an error inside handler" + assert tb_lines[0] == "PythonError: Traceback (most recent call last):" ## error in DOM tb_lines = self.page.locator(".py-error").inner_text().splitlines() @@ -151,7 +143,6 @@ class TestBasic(PyScriptTest): "four", ] - @pytest.mark.skip(reason="FIXME: log('
') now logs an empty string.") def test_escaping_of_angle_brackets(self): """ Check that py-script tags escape angle brackets @@ -186,6 +177,8 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] + # TODO: if there's no py-script there are surely no plugins neither + # this test must be discussed or rewritten to make sense now @pytest.mark.skip("FIXME: No banner") def test_non_existent_package(self): self.pyscript_run( @@ -207,6 +200,8 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") + # TODO: if there's no py-script there are surely no plugins neither + # this test must be discussed or rewritten to make sense now @pytest.mark.skip("FIXME: No banner") def test_no_python_wheel(self): self.pyscript_run( @@ -227,7 +222,6 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't find a pure Python 3 wheel for 'opsdroid'") - @pytest.mark.skip("""FIXME: Dynamically adding a py-script tag fails""") def test_dynamically_add_py_script_tag(self): self.pyscript_run( """ @@ -237,14 +231,13 @@ class TestBasic(PyScriptTest): tag.innerHTML = "print('hello world')"; document.body.appendChild(tag); } + addPyScriptTag() - """, timeout=20000, ) - self.page.locator("button").click() + self.page.locator("py-script") - self.page.wait_for_selector("py-terminal") assert self.console.log.lines[-1] == "hello world" def test_py_script_src_attribute(self): @@ -256,7 +249,6 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello from foo" - @pytest.mark.skip("FIXME: No banner") def test_py_script_src_not_found(self): self.pyscript_run( """ @@ -266,16 +258,18 @@ class TestBasic(PyScriptTest): ) assert "Failed to load resource" in self.console.error.lines[0] - expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404" - assert any((expected_msg in line) for line in self.console.js_error.lines) - assert self.assert_banner_message(expected_msg) + # TODO: we need to be sure errors make sense from both main and worker worlds + # expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404" + # assert any((expected_msg in line) for line in self.console.js_error.lines) + # assert self.assert_banner_message(expected_msg) - pyscript_tag = self.page.locator("py-script") - assert pyscript_tag.inner_html() == "" + # pyscript_tag = self.page.locator("py-script") + # assert pyscript_tag.inner_html() == "" - self.check_js_errors(expected_msg) + # self.check_js_errors(expected_msg) - @pytest.mark.skip("DIFFERENT BEHAVIOUR?: we don't expose pyscript on window") + # TODO: ... and we shouldn't: it's a module and we better don't leak in global + @pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window") def test_js_version(self): self.pyscript_run( """ @@ -290,7 +284,8 @@ class TestBasic(PyScriptTest): is not None ) - @pytest.mark.skip("DIFFERENT BEHAVIOUR?: we don't expose pyscript on window") + # TODO: ... and we shouldn't: it's a module and we better don't leak in global + @pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window") def test_python_version(self): self.pyscript_run( """ @@ -314,7 +309,6 @@ class TestBasic(PyScriptTest): is not None ) - @pytest.mark.skip("FIXME: No banner") def test_assert_no_banners(self): """ Test that the DOM doesn't contain error/warning banners @@ -322,16 +316,13 @@ class TestBasic(PyScriptTest): self.pyscript_run( """ - from _pyscript_js import showWarning - showWarning("hello") - showWarning("world") + import sys + print("hello world", file=sys.stderr) """ ) - # check that we have 2 banners - with pytest.raises(AssertionError, match="Found 2 alert banners"): - self.assert_no_banners() + assert self.page.locator(".py-error").inner_text() == "hello world" def test_getPySrc_returns_source_code(self): self.pyscript_run( @@ -360,19 +351,3 @@ class TestBasic(PyScriptTest): self.wait_for_console("hello world!") assert self.console.log.lines[-1] == "hello world!" assert self.console.error.lines == [] - - # TODO: THis can actually be removed since we are removing `py-mount` - @pytest.mark.skip("REMOVE TEST: No py-mount anymore") - def test_py_mount_shows_deprecation_warning(self): - # last non-deprecated version: 2023.03.1 - self.pyscript_run( - """ -
- """ - ) - banner = self.page.locator(".alert-banner") - expected_message = ( - 'The "py-mount" attribute is deprecated. ' - + "Please add references to HTML Elements manually in your script." - ) - assert banner.inner_text() == expected_message diff --git a/pyscriptjs/tests/integration/test_02_display.py b/pyscriptjs/tests/integration/test_02_display.py index ee1d941d..da07a11d 100644 --- a/pyscriptjs/tests/integration/test_02_display.py +++ b/pyscriptjs/tests/integration/test_02_display.py @@ -18,9 +18,6 @@ DISPLAY_OUTPUT_ID_PATTERN = r'[id^="py-"]' class TestDisplay(PyScriptTest): - @pytest.mark.skip( - "DIFFERENT BEHAVIOUR!: display w/o target renders as TXT without
tag" - ) def test_simple_display(self): self.pyscript_run( """ @@ -93,7 +90,6 @@ class TestDisplay(PyScriptTest): lines = [line for line in filter_page_content(lines)] # remove empty lines assert lines == ["hello 1", "hello in between 1 and 2", "hello 2", "hello 3"] - @pytest.mark.skip("DIFFERENT BEHAVIOUR!: display is not appending by default") def test_multiple_display_calls_same_tag(self): self.pyscript_run( """ @@ -106,7 +102,6 @@ class TestDisplay(PyScriptTest): ) tag = self.page.locator("py-script") lines = tag.inner_text().splitlines() - # TODO: Did the default change to append=False? assert lines == ["hello", "world"] def test_implicit_target_from_a_different_tag(self): @@ -129,37 +124,21 @@ class TestDisplay(PyScriptTest): assert py1.inner_text() == "" assert py2.inner_text() == "hello" - @pytest.mark.skip( - "DIFFERENT BEHAVIOUR!: display is not raising Implicit target exception" - ) - def test_no_implicit_target(self): + def test_no_explicit_target(self): self.pyscript_run( """ - - from pyscript import display - def display_hello(): - # this fails because we don't have any implicit target - # from event handlers - display('hello world') - - - """ + + from pyscript import display + def display_hello(error): + display('hello world') + + + """ ) - self.page.locator("text=Click me").click() - self.check_py_errors("Implicit target not allowed here") - ## error in console - tb_lines = self.console.error.lines[-1].splitlines() + self.page.locator("button").click() - # TODO: This does seem like a regression - assert tb_lines[0] == "[pyexec] Python exception:" - assert tb_lines[1] == "Traceback (most recent call last):" - assert ( - tb_lines[-1] - == "Exception: Implicit target not allowed here. Please use display(..., target=...)" - ) - - text = self.page.text_content("body") - assert "hello world" not in text + text = self.page.locator("py-script").text_content() + assert "hello world" in text def test_explicit_target_pyscript_tag(self): self.pyscript_run( @@ -177,16 +156,12 @@ class TestDisplay(PyScriptTest): text = self.page.locator("id=second-pyscript-tag").inner_text() assert text == "hello" - @pytest.mark.skip( - "FIXME: in Chrome fails with the error:" - ' The interpreter "py" was not found. Available interpreters are: "py-script", "pyodide".' - ) def test_explicit_target_on_button_tag(self): self.pyscript_run( """ from pyscript import display - def display_hello(): + def display_hello(error): display('hello', target='my-button') @@ -194,7 +169,6 @@ class TestDisplay(PyScriptTest): ) self.page.locator("text=Click me").click() text = self.page.locator("id=my-button").inner_text() - # TODO: This does seem like a regression that assert "hello" in text def test_explicit_different_target_from_call(self): @@ -244,7 +218,6 @@ class TestDisplay(PyScriptTest): pattern = r'hello world' assert re.search(pattern, inner_html) - @pytest.mark.skip("FIXME: display doesn't seem to have append=True as default") def test_display_multiple_values(self): self.pyscript_run( """ @@ -273,12 +246,14 @@ class TestDisplay(PyScriptTest): pattern = r'world' assert re.search(pattern, inner_html) - @pytest.mark.skip("WEIRDLY BROKEN not because of Display?") + # TODO: this is a display.py issue to fix when append=False is used + # do not use the first element, just clean up and then append + # remove the # display comment once that's done def test_display_multiple_append_false_with_target(self): self.pyscript_run( """
- + @@ -304,7 +279,6 @@ class TestDisplay(PyScriptTest): ) assert self.console.error.lines == [] - @pytest.mark.skip("FIXME: display doesn't seem to have append=True as default") def test_display_list_dict_tuple(self): self.pyscript_run( """ @@ -325,9 +299,6 @@ class TestDisplay(PyScriptTest): == "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')" ) - @pytest.mark.skip( - "DIFFERENT BEHAVIOUR!: display w/o target renders as TXT without
tag" - ) def test_display_should_escape(self): self.pyscript_run( """ @@ -393,7 +364,6 @@ class TestDisplay(PyScriptTest): assert deviation == 0.0 self.assert_no_banners() - # @pytest.mark.skip("FIXME: display() without target is broken") def test_empty_HTML_and_console_output(self): self.pyscript_run( """ @@ -413,7 +383,6 @@ class TestDisplay(PyScriptTest): assert "print from js" in console_text assert "error from js" in console_text - # @pytest.mark.skip("FIXME: display() without target is broken") def test_text_HTML_and_console_output(self): self.pyscript_run( """ diff --git a/pyscriptjs/tests/integration/test_03_element.py b/pyscriptjs/tests/integration/test_03_element.py index 63367803..4f0594b4 100644 --- a/pyscriptjs/tests/integration/test_03_element.py +++ b/pyscriptjs/tests/integration/test_03_element.py @@ -6,7 +6,7 @@ from .support import PyScriptTest class TestElement(PyScriptTest): """Test the Element api""" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_id(self): """Test the element id""" self.pyscript_run( @@ -24,7 +24,7 @@ class TestElement(PyScriptTest): py_terminal = self.page.wait_for_selector("py-terminal") assert "foo" in py_terminal.inner_text() - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_value(self): """Test the element value""" self.pyscript_run( @@ -42,7 +42,7 @@ class TestElement(PyScriptTest): py_terminal = self.page.wait_for_selector("py-terminal") assert "bar" in py_terminal.inner_text() - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_innerHtml(self): """Test the element innerHtml""" self.pyscript_run( @@ -60,7 +60,7 @@ class TestElement(PyScriptTest): py_terminal = self.page.wait_for_selector("py-terminal") assert "bar" in py_terminal.inner_text() - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_write_no_append(self): """Test the element write""" self.pyscript_run( @@ -77,7 +77,7 @@ class TestElement(PyScriptTest): div = self.page.wait_for_selector("#foo") assert "World!" in div.inner_text() - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_write_append(self): """Test the element write""" self.pyscript_run( @@ -97,7 +97,7 @@ class TestElement(PyScriptTest): # confirm that the second write was appended assert "Hello!
World!
" in parent_div.inner_html() - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_clear_div(self): """Test the element clear""" self.pyscript_run( @@ -113,7 +113,7 @@ class TestElement(PyScriptTest): div = self.page.locator("#foo") assert div.inner_text() == "" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_clear_input(self): """Test the element clear""" self.pyscript_run( @@ -129,7 +129,7 @@ class TestElement(PyScriptTest): input = self.page.wait_for_selector("#foo") assert input.input_value() == "" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_select(self): """Test the element select""" self.pyscript_run( @@ -146,7 +146,7 @@ class TestElement(PyScriptTest): ) assert self.console.log.lines[-1] == "bar" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_select_content(self): """Test the element select""" self.pyscript_run( @@ -163,7 +163,7 @@ class TestElement(PyScriptTest): ) assert self.console.log.lines[-1] == "Bar" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_clone_no_id(self): """Test the element clone""" self.pyscript_run( @@ -181,7 +181,7 @@ class TestElement(PyScriptTest): assert divs.first.inner_text() == "Hello!" assert divs.last.inner_text() == "Hello!" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_clone_with_id(self): """Test the element clone""" self.pyscript_run( @@ -201,7 +201,7 @@ class TestElement(PyScriptTest): clone = self.page.locator("#bar") assert clone.inner_text() == "Hello!" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_clone_to_other_element(self): """Test the element clone""" self.pyscript_run( @@ -236,7 +236,7 @@ class TestElement(PyScriptTest): # Make sure that the clones are rendered in the right order assert container_div.inner_text() == "Bond\nJames\nBond" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_remove_single_class(self): """Test the element remove_class""" self.pyscript_run( @@ -252,7 +252,7 @@ class TestElement(PyScriptTest): div = self.page.locator("#foo") assert div.get_attribute("class") == "baz" - @pytest.mark.skip("FIXME: Element missing from PyScript") + @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") def test_element_remove_multiple_classes(self): """Test the element remove_class""" self.pyscript_run( diff --git a/pyscriptjs/tests/integration/test_async.py b/pyscriptjs/tests/integration/test_async.py index 7d5f098f..4d196023 100644 --- a/pyscriptjs/tests/integration/test_async.py +++ b/pyscriptjs/tests/integration/test_async.py @@ -1,5 +1,3 @@ -import pytest - from .support import PyScriptTest, filter_inner_text @@ -123,21 +121,16 @@ class TestAsync(PyScriptTest): inner_text = self.page.inner_text("html") assert "A0\nA1\nB0\nB1" in filter_inner_text(inner_text) - @pytest.mark.skip("FIXME: display in implicit target WAS not allowed") def test_async_display_untargeted(self): self.pyscript_run( """ - + from pyscript import display import asyncio import js async def a_func(): - try: - display('A') - await asyncio.sleep(0.1) - except Exception as err: - js.console.error(str(err)) + display('A') await asyncio.sleep(1) js.console.log("DONE") @@ -146,10 +139,7 @@ class TestAsync(PyScriptTest): """ ) self.wait_for_console("DONE") - assert ( - self.console.error.lines[-1] - == "Implicit target not allowed here. Please use display(..., target=...)" - ) + assert self.page.locator("py-script").inner_text() == "A" def test_sync_and_async_order(self): """ diff --git a/pyscriptjs/tests/integration/test_py_config.py b/pyscriptjs/tests/integration/test_py_config.py index 26d7fde0..597dd799 100644 --- a/pyscriptjs/tests/integration/test_py_config.py +++ b/pyscriptjs/tests/integration/test_py_config.py @@ -50,28 +50,22 @@ def unzip(location, extract_to="."): # of config @with_execution_thread(None) class TestConfig(PyScriptTest): - @pytest.mark.skip( - "FIXME: API has changed and there's no pyscript_get_config anymore" - ) def test_py_config_inline(self): self.pyscript_run( """ - + name = "foobar" - - import js - config = js.pyscript_get_config() - js.console.log("config name:", config.name) + + from pyscript import window, document + promise = await document.currentScript._pyodide.promise + window.console.log("config name:", promise.config.name) """ ) assert self.console.log.lines[-1] == "config name: foobar" - @pytest.mark.skip( - "FIXME: API has changed and there's no pyscript_get_config anymore" - ) def test_py_config_external(self): pyconfig_toml = """ name = "app with external config" @@ -79,13 +73,12 @@ class TestConfig(PyScriptTest): self.writefile("pyconfig.toml", pyconfig_toml) self.pyscript_run( """ - - + - - import js - config = js.pyscript_get_config() - js.console.log("config name:", config.name) + + from pyscript import window, document + promise = await document.currentScript._pyodide.promise + window.console.log("config name:", promise.config.name) """ ) @@ -122,38 +115,6 @@ class TestConfig(PyScriptTest): assert self.console.log.lines[-1] == f"version {PYODIDE_VERSION}" - @pytest.mark.skip("FIXME: We need to restore the banner.") - def test_runtime_still_works_but_shows_deprecation_warning(self, pyodide_tar): - unzip(pyodide_tar, extract_to=self.tmpdir) - self.pyscript_run( - """ - - { - "runtimes": [{ - "src": "/pyodide/pyodide.js", - "name": "my-own-pyodide", - "lang": "python" - }] - } - - - - import sys, js - pyodide_version = sys.modules["pyodide"].__version__ - js.console.log("version", pyodide_version) - - """, - ) - - assert self.console.log.lines[-1] == f"version {PYODIDE_VERSION}" - - deprecation_banner = self.page.wait_for_selector(".alert-banner") - expected_message = ( - "The configuration option `config.runtimes` is deprecated. " - "Please use `config.interpreters` instead." - ) - assert deprecation_banner.inner_text() == expected_message - @pytest.mark.skip("FIXME: We need to restore the banner.") def test_invalid_json_config(self): # we need wait_for_pyscript=False because we bail out very soon, diff --git a/pyscriptjs/tests/integration/test_script_type.py b/pyscriptjs/tests/integration/test_script_type.py index 3b2c6af1..e41ff456 100644 --- a/pyscriptjs/tests/integration/test_script_type.py +++ b/pyscriptjs/tests/integration/test_script_type.py @@ -4,72 +4,72 @@ from .support import PyScriptTest class TestScriptTypePyScript(PyScriptTest): - @pytest.mark.skip("FIXME: display() without target is broken") def test_display_line_break(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "hello\nworld" == text_content - @pytest.mark.skip("FIXME: display() without target is broken") def test_amp(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "a & b" == text_content - @pytest.mark.skip("FIXME: display() without target is broken") def test_quot(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "a " b" == text_content - @pytest.mark.skip("FIXME: display() without target is broken") def test_lt_gt(self): self.pyscript_run( r""" - """ ) - text_content = self.page.locator("py-script-tag").text_content() + text_content = self.page.locator("script-py").text_content() assert "< < > >" == text_content - @pytest.mark.skip("FIXME: display() without target is broken") def test_dynamically_add_script_type_py_tag(self): self.pyscript_run( """ - """ ) - self.page.locator("button").click() + # please note the test here was on timeout + # incapable of finding a + + + diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts index 0a049182..34511c07 100644 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -2,6 +2,7 @@ declare const _default: { _pyscript: { "__init__.py": string; "display.py": string; + "event_handling.py": string; }; "pyscript.py": string; }; From f376097a15225305fe6f313b4aed68b3cf3aec02 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Wed, 13 Sep 2023 11:59:52 +0200 Subject: [PATCH 024/105] [next] Update CDN links to avoid breaking (#1693) --- pyscript.core/docs/README.md | 38 ++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/pyscript.core/docs/README.md b/pyscript.core/docs/README.md index 7b2d8afc..09dddc57 100644 --- a/pyscript.core/docs/README.md +++ b/pyscript.core/docs/README.md @@ -14,7 +14,7 @@ Accordingly, this is the bare minimum required output to bootstrap *PyScript Nex ```html - + @@ -28,22 +28,24 @@ If no ` ``` +Alternatively, it is possible to specify a `worker` attribute to either run embedded code or the provided `src` file. + #### CSS If you are planning to use either `` or `` tags on the page, where latter case is usually better off with ` ``` +#### HTML Example + +This is a complete reference to bootstrap *PyScript* in a HTML document. + +```html + + + + PyScript Next + + + + + + + + + +``` + ## Tag attributes API @@ -81,7 +107,7 @@ The module itself is currently exporting the following utilities: * **hooks**, which allows plugins to define *ASAP* callbacks or strings that should be executed either in the main thread or the worker before, or after, the code has been executed. ```js -import { hooks } from "https://unpkg.com/@pyscript/core"; +import { hooks } from "https://cdn.jsdelivr.net/npm/@pyscript/core"; // example hooks.onInterpreterReady.add((utils, element) => { @@ -146,7 +172,7 @@ The commonly shared utilities are: ```html From 3aef5a99dceb0ecb2125a2ac9023ecc885fef50f Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 14 Sep 2023 11:11:44 +0200 Subject: [PATCH 026/105] [next] Bootstrap plugins directly (#1698) --- pyscript.core/rollup/plugins.cjs | 6 +++- pyscript.core/src/config.js | 44 +++++++++++++++++++++++++ pyscript.core/src/core.js | 56 ++++++++------------------------ pyscript.core/src/fetch.js | 3 ++ pyscript.core/src/plugins.js | 2 +- pyscript.core/types/config.d.ts | 2 ++ pyscript.core/types/core.d.ts | 3 +- pyscript.core/types/fetch.d.ts | 1 + 8 files changed, 70 insertions(+), 47 deletions(-) create mode 100644 pyscript.core/src/config.js create mode 100644 pyscript.core/types/config.d.ts diff --git a/pyscript.core/rollup/plugins.cjs b/pyscript.core/rollup/plugins.cjs index 07f94a69..22572b08 100644 --- a/pyscript.core/rollup/plugins.cjs +++ b/pyscript.core/rollup/plugins.cjs @@ -10,7 +10,11 @@ for (const file of readdirSync(join(__dirname, "..", "src", "plugins"))) { ? name : `[${JSON.stringify(name)}]`; const value = JSON.stringify(`./plugins/${file}`); - plugins.push(` ${key}: () => import(${value}),`); + plugins.push( + // this comment is needed to avoid bundlers eagerly embedding lazy + // dependencies, causing all sort of issues once in production + ` ${key}: () => import(/* webpackIgnore: true */ ${value}),`, + ); } } diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js new file mode 100644 index 00000000..23a52c63 --- /dev/null +++ b/pyscript.core/src/config.js @@ -0,0 +1,44 @@ +/** + * This file parses a generic or config attribute + * to use as base config for all py-script elements, importing + * also a queue of plugins *before* the interpreter (if any) resolves. + */ +import { $ } from "basic-devtools"; + +import allPlugins from "./plugins.js"; +import { robustFetch as fetch, getText } from "./fetch.js"; + +// TODO: this is not strictly polyscript related but handy ... not sure +// we should factor this utility out a part but this works anyway. +import { parse } from "../node_modules/polyscript/esm/toml.js"; + +// find the shared config for all py-script elements +let config, plugins, parsed; +let pyConfig = $("py-config"); +if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent; +else { + pyConfig = $('script[type="py"][config]'); + if (pyConfig) config = pyConfig.getAttribute("config"); +} + +// load its content if remote +if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText); + +// parse config only if not empty +if (config?.trim()) { + try { + parsed = JSON.parse(config); + } catch (_) { + parsed = await parse(config); + } +} + +// parse all plugins and optionally ignore only +// those flagged as "undesired" via `!` prefix +const toBeAwaited = []; +for (const [key, value] of Object.entries(allPlugins)) { + if (!parsed?.plugins?.includes(`!${key}`)) toBeAwaited.push(value()); +} +if (toBeAwaited.length) plugins = Promise.all(toBeAwaited); + +export { config, plugins }; diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 717815e0..56c81c14 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -1,12 +1,7 @@ /*! (c) PyScript Development Team */ import "@ungap/with-resolvers"; -import { $ } from "basic-devtools"; import { define, XWorker } from "polyscript"; -import sync from "./sync.js"; - -import stdlib from "./stdlib.js"; -import plugins from "./plugins.js"; // TODO: this is not strictly polyscript related but handy ... not sure // we should factor this utility out a part but this works anyway. @@ -14,29 +9,21 @@ import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js"; import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; -import { robustFetch as fetch } from "./fetch.js"; +import sync from "./sync.js"; +import stdlib from "./stdlib.js"; +import { config, plugins } from "./config.js"; +import { robustFetch as fetch, getText } from "./fetch.js"; const { assign, defineProperty, entries } = Object; -const getText = (body) => body.text(); +const TYPE = "py"; // allows lazy element features on code evaluation let currentElement; // create a unique identifier when/if needed let id = 0; -const getID = (prefix = "py") => `${prefix}-${id++}`; - -// find the shared config for all py-script elements -let config; -let pyConfig = $("py-config"); -if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent; -else { - pyConfig = $('script[type="py"]'); - config = pyConfig?.getAttribute("config"); -} - -if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText); +const getID = (prefix = TYPE) => `${prefix}-${id++}`; // generic helper to disambiguate between custom element and script const isScript = ({ tagName }) => tagName === "SCRIPT"; @@ -70,7 +57,7 @@ const fetchSource = async (tag, io, asText) => { if (asText) return dedent(tag.textContent); console.warn( - 'Deprecated: use + + +
+ + diff --git a/pyscript.core/test/terminal.py b/pyscript.core/test/terminal.py new file mode 100644 index 00000000..7919f593 --- /dev/null +++ b/pyscript.core/test/terminal.py @@ -0,0 +1,22 @@ +###### magic monkey patching ###### +import sys +import builtins +import js +from pyscript import sync +from pyodide.code import eval_code + +sys.stdout = sync +builtins.input = sync.readline + +globals = {"js": js} + +####### main code ###### +while True: + code = input(f"> ") + if len(code): + try: + result = eval_code(f"{code}", globals=globals) + if result is not None: + print(result) + except: + print(f"Unable to evaluate: {code}") From 4d89cbde015bf22d26e40f08e20353d31f58a0a4 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 14 Sep 2023 18:11:10 +0200 Subject: [PATCH 028/105] [next] Terminal smoke-test follow up (#1702) --- pyscript.core/test/terminal.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/pyscript.core/test/terminal.py b/pyscript.core/test/terminal.py index 7919f593..7ec20067 100644 --- a/pyscript.core/test/terminal.py +++ b/pyscript.core/test/terminal.py @@ -1,22 +1,13 @@ ###### magic monkey patching ###### import sys import builtins -import js from pyscript import sync from pyodide.code import eval_code sys.stdout = sync builtins.input = sync.readline -globals = {"js": js} - ####### main code ###### -while True: - code = input(f"> ") - if len(code): - try: - result = eval_code(f"{code}", globals=globals) - if result is not None: - print(result) - except: - print(f"Unable to evaluate: {code}") +import code + +code.interact() From e2a2292a6f225750a668424e18146f89f48826bc Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Thu, 14 Sep 2023 12:45:22 -0500 Subject: [PATCH 029/105] Add release html template (#1705) --- public/index.html | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 public/index.html diff --git a/public/index.html b/public/index.html new file mode 100644 index 00000000..e232906e --- /dev/null +++ b/public/index.html @@ -0,0 +1,53 @@ + + + + + + + + + + PyScript + + + +
+

<py-script>

+ +
+ + from pyscript import display + import sys + display(sys.version) + + +

Example

+
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+    <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width,initial-scale=1" />
+    <title>PyScript Hello World</title>
+    <link rel="stylesheet" href="[[PATH]]core.css" />
+    <script defer src="[[PATH]]core.js"></script>
+    </head>
+
+    <body>
+    Hello world! <br>
+    This is the current date and time, as computed by Python:
+    <py-script>
+from pyscript import display
+from datetime import datetime
+now = datetime.now()
+display(now.strftime("%m/%d/%Y, %H:%M:%S"))
+    </py-script>
+    </body>
+</html>
+
+ + \ No newline at end of file From 7f666dc6a09ca22107ff252c9b545d251262c772 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Thu, 14 Sep 2023 13:35:57 -0500 Subject: [PATCH 030/105] Fix HTML template (#1709) --- public/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/index.html b/public/index.html index e232906e..6d5452d8 100644 --- a/public/index.html +++ b/public/index.html @@ -5,8 +5,8 @@ - - + + PyScript @@ -33,8 +33,8 @@ <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>PyScript Hello World</title> - <link rel="stylesheet" href="[[PATH]]core.css" /> - <script defer src="[[PATH]]core.js"></script> + <link rel="stylesheet" href="_PATH_core.css" /> + <script defer src="_PATH_core.js"></script> </head> <body> From 9660976d1d96e029ec27d6e60bcfe741bdf72dec Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Thu, 14 Sep 2023 13:40:57 -0500 Subject: [PATCH 031/105] Fix to HTML template logic (#1711) --- public/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/index.html b/public/index.html index 6d5452d8..857cabfd 100644 --- a/public/index.html +++ b/public/index.html @@ -34,7 +34,7 @@ <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>PyScript Hello World</title> <link rel="stylesheet" href="_PATH_core.css" /> - <script defer src="_PATH_core.js"></script> + <script type="module" src="_PATH_core.js"></script> </head> <body> From 00fdc73015d2f3231da14bd48cb5b2a36479433b Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Thu, 14 Sep 2023 13:31:23 -0700 Subject: [PATCH 032/105] [NEXT] Pydom (#1681) * add pyweb * build * add test file * fix pydom example code * remove old reference to js * temporarily comment out query functions on BaseElement while rearranging code to reuse the same underlying logic accross PyDom and other elements * add temp TODO comment to content as it breaks with template elements * update pydom example to define code on external file * fix name type while renaming document -> dom * add real pydom test files * add classes to dom scope * __len__ to ElementCollection * fix some of the old tests * rename test from test_query_by_class to test_getitem_by_class * change test for read and write multiple elements * add find method to BaseElement * fix remaining tests * add Collection Tests * add equality to Collection * add test for collection style manipulation * fix getter for style property and rename style related attribute from pop to remove * add single element creation test * remove append on BaseElement and add body and head to dom * add test_create_element_child to verify child creation * add children getter property to Element * remove old code * remove more old code, change style attribute from visibility to visible and now default getters on collection to return a list with the value of an attribute for every element in the collection * remove more old code and add possibility to customize test flags via url * add support to pass Js and pydom.Element elements to when decorator * remove methods related to input type of elements until we have a better design for it * rename _element to _js * add test_when decorator with a ElementCollection input * when decorator now supporte pydom.ElementCollection as input * update pyscript.js * remove useless variable from when decorator * remove base.py from pyweb * add nodes for append collection test and add better feedback on successes vs failure * add tests and fix code for support of append Element and ElementCollection * manage access to content attribute when tagname is template * fix comment --------- Co-authored-by: Fabio Pliger --- .../src/stdlib/_pyscript/event_handling.py | 18 +- pyscript.core/src/stdlib/pyscript.js | 7 +- pyscript.core/src/stdlib/pyweb/pydom.py | 314 ++++++++++++++++++ pyscript.core/test/pydom.html | 19 ++ pyscript.core/test/pydom.py | 26 ++ pyscript.core/test/pyscript_dom/index.html | 111 +++++++ pyscript.core/test/pyscript_dom/run_tests.py | 7 + pyscript.core/test/pyscript_dom/tests.toml | 8 + .../test/pyscript_dom/tests/__init__.py | 0 .../test/pyscript_dom/tests/conftest.py | 15 + .../test/pyscript_dom/tests/test_dom.py | 246 ++++++++++++++ pyscript.core/types/stdlib/pyscript.d.ts | 3 + 12 files changed, 771 insertions(+), 3 deletions(-) create mode 100644 pyscript.core/src/stdlib/pyweb/pydom.py create mode 100644 pyscript.core/test/pydom.html create mode 100644 pyscript.core/test/pydom.py create mode 100644 pyscript.core/test/pyscript_dom/index.html create mode 100644 pyscript.core/test/pyscript_dom/run_tests.py create mode 100644 pyscript.core/test/pyscript_dom/tests.toml create mode 100644 pyscript.core/test/pyscript_dom/tests/__init__.py create mode 100644 pyscript.core/test/pyscript_dom/tests/conftest.py create mode 100644 pyscript.core/test/pyscript_dom/tests/test_dom.py diff --git a/pyscript.core/src/stdlib/_pyscript/event_handling.py b/pyscript.core/src/stdlib/_pyscript/event_handling.py index 01b9ade3..ea6af0ef 100644 --- a/pyscript.core/src/stdlib/_pyscript/event_handling.py +++ b/pyscript.core/src/stdlib/_pyscript/event_handling.py @@ -11,7 +11,23 @@ def when(event_type=None, selector=None): """ def decorator(func): - elements = document.querySelectorAll(selector) + if isinstance(selector, str): + elements = document.querySelectorAll(selector) + else: + # TODO: This is a hack that will be removed when pyscript becomes a package + # and we can better manage the imports without circular dependencies + from pyweb import pydom + + if isinstance(selector, pydom.Element): + elements = [selector._js] + elif isinstance(selector, pydom.ElementCollection): + elements = [el._js for el in selector] + else: + raise ValueError( + f"Invalid selector: {selector}. Selector must" + " be a string, a pydom.Element or a pydom.ElementCollection." + ) + sig = inspect.signature(func) # Function doesn't receive events if not sig.parameters: diff --git a/pyscript.core/src/stdlib/pyscript.js b/pyscript.core/src/stdlib/pyscript.js index 45862798..df7de4bf 100644 --- a/pyscript.core/src/stdlib/pyscript.js +++ b/pyscript.core/src/stdlib/pyscript.js @@ -3,7 +3,10 @@ export default { "_pyscript": { "__init__.py": "import js as window\n\nIS_WORKER = not hasattr(window, \"document\")\n\nif IS_WORKER:\n from polyscript import xworker as _xworker\n\n window = _xworker.window\n document = window.document\n sync = _xworker.sync\nelse:\n document = window.document\n", "display.py": "import base64\nimport html\nimport io\nimport re\n\nfrom . import document, window\n\n_MIME_METHODS = {\n \"__repr__\": \"text/plain\",\n \"_repr_html_\": \"text/html\",\n \"_repr_markdown_\": \"text/markdown\",\n \"_repr_svg_\": \"image/svg+xml\",\n \"_repr_png_\": \"image/png\",\n \"_repr_pdf_\": \"application/pdf\",\n \"_repr_jpeg_\": \"image/jpeg\",\n \"_repr_latex\": \"text/latex\",\n \"_repr_json_\": \"application/json\",\n \"_repr_javascript_\": \"application/javascript\",\n \"savefig\": \"image/png\",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode(\"utf-8\")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r\"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$\"\n )\n # If value doesn't match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode(\"utf-8\")).decode(\"utf-8\")\n\n data = f\"data:{mime};charset=utf-8;base64,{value}\"\n attrs = \" \".join(['{k}=\"{v}\"' for k, v in meta.items()])\n return f''\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n \"text/plain\": html.escape,\n \"text/html\": _identity,\n \"image/png\": lambda value, meta: _render_image(\"image/png\", value, meta),\n \"image/jpeg\": lambda value, meta: _render_image(\"image/jpeg\", value, meta),\n \"image/svg+xml\": _identity,\n \"application/json\": _identity,\n \"application/javascript\": lambda value, meta: f\" + + + + + + + + +
+ + diff --git a/pyscript.core/test/pydom.py b/pyscript.core/test/pydom.py new file mode 100644 index 00000000..a5ec8b13 --- /dev/null +++ b/pyscript.core/test/pydom.py @@ -0,0 +1,26 @@ +import random +from pyscript import display +from pyweb import pydom +from pyweb.base import when +from datetime import datetime as dt + + +@when("click", "#just-a-button") +def on_click(event): + print(f"Hello from Python! {dt.now()}") + display(f"Hello from Python! {dt.now()}", append=False, target="result") + + +@when("click", "#color-button") +def on_color_click(event): + print("1") + btn = pydom["#result"] + print("2") + btn.style["background-color"] = f"#{random.randrange(0x1000000):06x}" + + +def reset_color(): + pydom["#result"].style["background-color"] = "white" + + +# btn_reset = pydom["#color-reset-button"][0].when('click', reset_color) diff --git a/pyscript.core/test/pyscript_dom/index.html b/pyscript.core/test/pyscript_dom/index.html new file mode 100644 index 00000000..450d99f2 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/index.html @@ -0,0 +1,111 @@ + + + PyperCard PyTest Suite + + + + + + + + + + +

pyscript.dom Tests

+

You can pass test parameters to this test suite by passing them as query params on the url. + For instance, to pass "-v -s --pdb" to pytest, you would use the following url: + +

+
+ + + + + + + +
+ +
+

Test Read and Write

+
Content test_rr_div
+

Content test_rr_h3

+ +
Content multi-elem-div
+

Content multi-elem-p

+

Content multi-elem-h2

+ +
+ + + + +
+ +
+ + + + + +
+

+
+

+
+ + + + + diff --git a/pyscript.core/test/pyscript_dom/run_tests.py b/pyscript.core/test/pyscript_dom/run_tests.py new file mode 100644 index 00000000..128abccc --- /dev/null +++ b/pyscript.core/test/pyscript_dom/run_tests.py @@ -0,0 +1,7 @@ +print("tests starting") +import pytest +from pyscript import window + +args = window.location.search.replace("?", "").split("&") + +pytest.main(args) diff --git a/pyscript.core/test/pyscript_dom/tests.toml b/pyscript.core/test/pyscript_dom/tests.toml new file mode 100644 index 00000000..6bcee173 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests.toml @@ -0,0 +1,8 @@ +packages = [ + "pytest" +] + +[[fetch]] +from = "tests/" +files = ["__init__.py", "conftest.py", "test_dom.py"] +to_folder = "tests" diff --git a/pyscript.core/test/pyscript_dom/tests/__init__.py b/pyscript.core/test/pyscript_dom/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pyscript.core/test/pyscript_dom/tests/conftest.py b/pyscript.core/test/pyscript_dom/tests/conftest.py new file mode 100644 index 00000000..4ba26c05 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests/conftest.py @@ -0,0 +1,15 @@ +import pytest +from js import document, localStorage + + +@pytest.fixture(autouse=True) +def before_tests(): + """ + Ensure browser storage is always reset to empty. Remove the app + placeholder. Reset the page title. + """ + localStorage.clear() + # app_placeholder = document.querySelector("pyper-app") + # if app_placeholder: + # app_placeholder.remove() + document.querySelector("title").innerText = "Web API PyTest Suite" diff --git a/pyscript.core/test/pyscript_dom/tests/test_dom.py b/pyscript.core/test/pyscript_dom/tests/test_dom.py new file mode 100644 index 00000000..fa2531b8 --- /dev/null +++ b/pyscript.core/test/pyscript_dom/tests/test_dom.py @@ -0,0 +1,246 @@ +import pytest +from pyscript import document, when +from unittest import mock + +from pyweb import pydom + + +class TestDocument: + def test__element(self): + assert pydom._js == document + + def test_no_parent(self): + assert pydom.parent is None + + def test_create_element(self): + new_el = pydom.create("div") + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "DIV" + # EXPECT the new element to be associated with the document + assert new_el.parent == None + + +def test_getitem_by_id(): + # GIVEN an existing element on the page with a known text content + id_ = "test_id_selector" + txt = "You found test_id_selector" + selector = f"#{id_}" + # EXPECT the element to be found by id + result = pydom[selector] + div = result[0] + # EXPECT the element text value to match what we expect and what + # the JS document.querySelector API would return + assert document.querySelector(selector).innerHTML == div.html == txt + # EXPECT the results to be of the right types + assert isinstance(div, pydom.BaseElement) + assert isinstance(result, pydom.ElementCollection) + + +def test_getitem_by_class(): + ids = [ + "test_class_selector", + "test_selector_w_children", + "test_selector_w_children_child_1", + ] + expected_class = "a-test-class" + result = pydom[f".{expected_class}"] + div = result[0] + + # EXPECT to find exact number of elements with the class in the page (== 3) + assert len(result) == 3 + + # EXPECT that all element ids are in the expected list + assert [el.id for el in result] == ids + + +def test_read_n_write_collection_elements(): + elements = pydom[".multi-elems"] + + for element in elements: + assert element.html == f"Content {element.id.replace('#', '')}" + + new_content = "New Content" + elements.html = new_content + for element in elements: + assert element.html == new_content + + +class TestElement: + def test_query(self): + # GIVEN an existing element on the page, with at least 1 child element + id_ = "test_selector_w_children" + parent_div = pydom[f"#{id_}"][0] + + # EXPECT it to be able to query for the first child element + div = parent_div.find("div")[0] + + # EXPECT the new element to be associated with the parent + assert div.parent == parent_div + # EXPECT the new element to be a BaseElement + assert isinstance(div, pydom.BaseElement) + # EXPECT the div attributes to be == to how they are configured in the page + assert div.html == "Child 1" + assert div.id == "test_selector_w_children_child_1" + + def test_equality(self): + # GIVEN 2 different Elements pointing to the same underlying element + id_ = "test_id_selector" + selector = f"#{id_}" + div = pydom[selector][0] + div2 = pydom[selector][0] + + # EXPECT them to be equal + assert div == div2 + # EXPECT them to be different objects + assert div is not div2 + + # EXPECT their value to always be equal + assert div.html == div2.html + div.html = "some value" + + assert div.html == div2.html == "some value" + + def test_append_element(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + new_el = div.create("p") + div.append(new_el) + assert len(div.children) == len_children_before + 1 + assert div.children[-1] == new_el + + def test_append_js_element(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + new_el = div.create("p") + div.append(new_el._js) + assert len(div.children) == len_children_before + 1 + assert div.children[-1] == new_el + + def test_append_collection(self): + id_ = "element-append-tests" + div = pydom[f"#{id_}"][0] + len_children_before = len(div.children) + collection = pydom[".collection"] + div.append(collection) + assert len(div.children) == len_children_before + len(collection) + + for i in range(len(collection)): + assert div.children[-1 - i] == collection[-1 - i] + + def test_read_classes(self): + id_ = "test_class_selector" + expected_class = "a-test-class" + div = pydom[f"#{id_}"][0] + assert div.classes == [expected_class] + + def test_add_remove_class(self): + id_ = "div-no-classes" + classname = "tester-class" + div = pydom[f"#{id_}"][0] + assert not div.classes + div.add_class(classname) + same_div = pydom[f"#{id_}"][0] + assert div.classes == [classname] == same_div.classes + div.remove_class(classname) + assert div.classes == [] == same_div.classes + + def test_when_decorator(self): + called = False + + just_a_button = pydom["#a-test-button"][0] + + @when("click", just_a_button) + def on_click(event): + nonlocal called + called = True + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk pydom getting in the way + assert not called + just_a_button._js.click() + + assert called + + +class TestCollection: + def test_iter_eq_children(self): + elements = pydom[".multi-elems"] + assert [el for el in elements] == [el for el in elements.children] + assert len(elements) == 3 + + def test_slices(self): + elements = pydom[".multi-elems"] + assert elements[0] + _slice = elements[:2] + assert len(_slice) == 2 + for i, el in enumerate(_slice): + assert el == elements[i] + assert elements[:] == elements + + def test_style_rule(self): + selector = ".multi-elems" + elements = pydom[selector] + for el in elements: + assert el.style["background-color"] != "red" + + elements.style["background-color"] = "red" + + for i, el in enumerate(pydom[selector]): + assert elements[i].style["background-color"] == "red" + assert el.style["background-color"] == "red" + + elements.style.remove("background-color") + + for i, el in enumerate(pydom[selector]): + assert el.style["background-color"] != "red" + assert elements[i].style["background-color"] != "red" + + def test_when_decorator(self): + called = False + + buttons_collection = pydom["button"] + + @when("click", buttons_collection) + def on_click(event): + nonlocal called + called = True + + # Now let's simulate a click on the button (using the low level JS API) + # so we don't risk pydom getting in the way + assert not called + for button in buttons_collection: + button._js.click() + assert called + called = False + + +class TestCreation: + def test_create_document_element(self): + new_el = pydom.create("div") + new_el.id = "new_el_id" + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "DIV" + # EXPECT the new element to be associated with the document + assert new_el.parent == None + pydom.body.append(new_el) + + assert pydom["#new_el_id"][0].parent == pydom.body + + def test_create_element_child(self): + selector = "#element-creation-test" + parent_div = pydom[selector][0] + + # Creating an element from another element automatically creates that element + # as a child of the original element + new_el = parent_div.create( + "p", classes=["code-description"], html="Ciao PyScripters!" + ) + + assert isinstance(new_el, pydom.BaseElement) + assert new_el._js.tagName == "P" + # EXPECT the new element to be associated with the document + assert new_el.parent == parent_div + + assert pydom[selector][0].children[0] == new_el diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts index 34511c07..9244d1f2 100644 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -5,5 +5,8 @@ declare const _default: { "event_handling.py": string; }; "pyscript.py": string; + pyweb: { + "pydom.py": string; + }; }; export default _default; From 840bc803b7b182bafc6770badecbee27cb652d1a Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 15 Sep 2023 12:50:52 +0200 Subject: [PATCH 033/105] [next] Improve config parsing on bootstrap (#1704) --- .pre-commit-config.yaml | 1 + pyscript.core/package-lock.json | 10 +- pyscript.core/package.json | 3 +- pyscript.core/src/config.js | 88 ++++++++++++--- pyscript.core/src/core.js | 146 +++++++++++++------------ pyscript.core/src/plugins/error.js | 2 +- pyscript.core/test/bad.toml | 1 + pyscript.core/test/config-url.html | 11 ++ pyscript.core/test/config.html | 13 +++ pyscript.core/types/config.d.ts | 1 + pyscript.core/types/plugins/error.d.ts | 2 +- 11 files changed, 186 insertions(+), 92 deletions(-) create mode 100644 pyscript.core/test/bad.toml create mode 100644 pyscript.core/test/config-url.html create mode 100644 pyscript.core/test/config.html diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6f6eafe2..5f2dcae7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,6 +16,7 @@ repos: - id: check-json exclude: tsconfig\.json - id: check-toml + exclude: bad\.toml - id: check-xml - id: check-yaml - id: detect-private-key diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index fe2777b1..74698014 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.1.18", + "version": "0.1.19", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.18", + "version": "0.1.19", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", @@ -597,9 +597,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.519", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.519.tgz", - "integrity": "sha512-kqs9oGYL4UFVkLKhqCTgBCYZv+wZ374yABDMqlDda9HvlkQxvSr7kgf4hfWVjMieDbX+1MwPHFBsOGCMIBaFKg==", + "version": "1.4.520", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.520.tgz", + "integrity": "sha512-Frfus2VpYADsrh1lB3v/ft/WVFlVzOIm+Q0p7U7VqHI6qr7NWHYKe+Wif3W50n7JAFoBsWVsoU0+qDks6WQ60g==", "dev": true }, "node_modules/entities": { diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 91a378aa..14d68636 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.1.18", + "version": "0.1.19", "type": "module", "description": "PyScript", "module": "./index.js", @@ -21,6 +21,7 @@ "scripts": { "server": "npx static-handler --cors --coep --coop --corp .", "build": "node rollup/stdlib.cjs && node rollup/plugins.cjs && rm -rf dist && rollup --config rollup/core.config.js && npm run ts", + "size": "echo -e \"\\033[1mdist/*.js file size\\033[0m\"; for js in $(ls dist/*.js); do echo -e \"\\033[2m$js:\\033[0m $(cat $js | brotli | wc -c) bytes\"; done", "ts": "tsc -p ." }, "keywords": [ diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js index 23a52c63..79625ee9 100644 --- a/pyscript.core/src/config.js +++ b/pyscript.core/src/config.js @@ -7,38 +7,96 @@ import { $ } from "basic-devtools"; import allPlugins from "./plugins.js"; import { robustFetch as fetch, getText } from "./fetch.js"; +import { ErrorCode } from "./exceptions.js"; -// TODO: this is not strictly polyscript related but handy ... not sure -// we should factor this utility out a part but this works anyway. -import { parse } from "../node_modules/polyscript/esm/toml.js"; +const badURL = (url, expected = "") => { + let message = `(${ErrorCode.BAD_CONFIG}): Invalid URL: ${url}`; + if (expected) message += `\nexpected ${expected} content`; + throw new Error(message); +}; + +/** + * Given a string, returns its trimmed content as text, + * fetching it from a file if the content is a URL. + * @param {string} config either JSON, TOML, or a file to fetch + * @returns {{json: boolean, toml: boolean, text: string}} + */ +const configDetails = async (config) => { + let text = config?.trim(); + // we only support an object as root config + let url = "", + toml = false, + json = /^{/.test(text) && /}$/.test(text); + // handle files by extension (relaxing urls parts after) + if (!json && /\.(\w+)(?:\?\S*)?$/.test(text)) { + const ext = RegExp.$1; + if (ext === "json" && type !== "toml") json = true; + else if (ext === "toml" && type !== "json") toml = true; + else badURL(text, type); + url = text; + text = (await fetch(url).then(getText)).trim(); + } + return { json, toml: toml || (!json && !!text), text, url }; +}; + +const syntaxError = (type, url, { message }) => { + let str = `(${ErrorCode.BAD_CONFIG}): Invalid ${type}`; + if (url) str += ` @ ${url}`; + return new SyntaxError(`${str}\n${message}`); +}; // find the shared config for all py-script elements -let config, plugins, parsed; +let config, plugins, parsed, error, type; let pyConfig = $("py-config"); if (pyConfig) config = pyConfig.getAttribute("src") || pyConfig.textContent; else { pyConfig = $('script[type="py"][config]'); if (pyConfig) config = pyConfig.getAttribute("config"); } +if (pyConfig) type = pyConfig.getAttribute("type"); -// load its content if remote -if (/^https?:\/\//.test(config)) config = await fetch(config).then(getText); - -// parse config only if not empty -if (config?.trim()) { - try { - parsed = JSON.parse(config); - } catch (_) { - parsed = await parse(config); +// catch possible fetch errors +try { + const { json, toml, text, url } = await configDetails(config); + config = text; + if (json || type === "json") { + try { + parsed = JSON.parse(text); + } catch (e) { + error = syntaxError("JSON", url, e); + } + } else if (toml || type === "toml") { + try { + const { parse } = await import( + /* webpackIgnore: true */ + "https://cdn.jsdelivr.net/npm/@webreflection/toml-j0.4/toml.js" + ); + parsed = parse(text); + } catch (e) { + error = syntaxError("TOML", url, e); + } } +} catch (e) { + error = e; } // parse all plugins and optionally ignore only // those flagged as "undesired" via `!` prefix const toBeAwaited = []; for (const [key, value] of Object.entries(allPlugins)) { - if (!parsed?.plugins?.includes(`!${key}`)) toBeAwaited.push(value()); + if (error) { + if (key === "error") { + // show on page the config is broken, meaning that + // it was not possible to disable error plugin neither + // as that part wasn't correctly parsed anyway + value().then(({ notify }) => notify(error.message)); + } + } else if (!parsed?.plugins?.includes(`!${key}`)) { + toBeAwaited.push(value()); + } } + +// assign plugins as Promise.all only if needed if (toBeAwaited.length) plugins = Promise.all(toBeAwaited); -export { config, plugins }; +export { config, plugins, error }; diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 56c81c14..d1403394 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -11,7 +11,7 @@ import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; import sync from "./sync.js"; import stdlib from "./stdlib.js"; -import { config, plugins } from "./config.js"; +import { config, plugins, error } from "./config.js"; import { robustFetch as fetch, getText } from "./fetch.js"; const { assign, defineProperty, entries } = Object; @@ -128,74 +128,81 @@ const workerHooks = { }; // define the module as both ` + + + diff --git a/pyscript.core/test/config.html b/pyscript.core/test/config.html new file mode 100644 index 00000000..e9f0af02 --- /dev/null +++ b/pyscript.core/test/config.html @@ -0,0 +1,13 @@ + + + + + + PyScript Next Plugin + + + + files = [ + + + diff --git a/pyscript.core/types/config.d.ts b/pyscript.core/types/config.d.ts index 6507150f..2d5eceee 100644 --- a/pyscript.core/types/config.d.ts +++ b/pyscript.core/types/config.d.ts @@ -1,2 +1,3 @@ export let config: any; export let plugins: any; +export let error: any; diff --git a/pyscript.core/types/plugins/error.d.ts b/pyscript.core/types/plugins/error.d.ts index cb0ff5c3..5c76300b 100644 --- a/pyscript.core/types/plugins/error.d.ts +++ b/pyscript.core/types/plugins/error.d.ts @@ -1 +1 @@ -export {}; +export function notify(message: any): void; From 5191c45113d17144fb5036fb176097ac27ffdcd9 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Fri, 15 Sep 2023 11:57:06 +0000 Subject: [PATCH 034/105] Refactor the pyscript python package. (#1713) --- pyscript.core/README.md | 4 +-- pyscript.core/docs/README.md | 15 ++------ pyscript.core/src/core.js | 2 +- .../src/stdlib/_pyscript/__init__.py | 12 ------- pyscript.core/src/stdlib/pyscript.js | 10 +++--- pyscript.core/src/stdlib/pyscript.py | 34 ------------------- .../stdlib/{_pyscript => pyscript}/display.py | 5 ++- .../{_pyscript => pyscript}/event_handling.py | 2 +- pyscript.core/src/stdlib/pyscript/magic_js.py | 33 ++++++++++++++++++ pyscript.core/types/stdlib/pyscript.d.ts | 10 +++--- 10 files changed, 54 insertions(+), 73 deletions(-) delete mode 100644 pyscript.core/src/stdlib/_pyscript/__init__.py delete mode 100644 pyscript.core/src/stdlib/pyscript.py rename pyscript.core/src/stdlib/{_pyscript => pyscript}/display.py (97%) rename pyscript.core/src/stdlib/{_pyscript => pyscript}/event_handling.py (97%) create mode 100644 pyscript.core/src/stdlib/pyscript/magic_js.py diff --git a/pyscript.core/README.md b/pyscript.core/README.md index 960e7b9f..9899819e 100644 --- a/pyscript.core/README.md +++ b/pyscript.core/README.md @@ -27,9 +27,9 @@ Accordingly, whenever a file contains this warning at its first line, please do // ⚠️ This file is an artifact: DO NOT MODIFY ``` -## Python stdlib +## `pyscript` python package -The `pyscript` module available in _Python_ defines its exported utilities via `src/stdlib/pyscript.py`. Any file that would like to provide an export should be placed into `src/stdlib/_pyscript` folder (see the `display.py` as example) and its public functionalities should be explicit in the `src/stdlib/pyscript.py` file. +The `pyscript` package available in _Python_ lives in the folder `src/stdlib/pyscript/`. All _Python_ files will be embedded automatically whenever `npm run build` happens and reflected into the `src/stdlib/pyscript.js` file. diff --git a/pyscript.core/docs/README.md b/pyscript.core/docs/README.md index 09dddc57..ca4a4d9f 100644 --- a/pyscript.core/docs/README.md +++ b/pyscript.core/docs/README.md @@ -111,7 +111,7 @@ import { hooks } from "https://cdn.jsdelivr.net/npm/@pyscript/core"; // example hooks.onInterpreterReady.add((utils, element) => { - console.lot(element, 'found', 'pyscript is ready'); + console.log(element, 'found', 'pyscript is ready'); }); // the hooks namespace @@ -148,9 +148,9 @@ Please note that a *worker* is a completely different environment and it's not p However, each worker string can use `from pyscript import x, y, z` as that will be available out of the box. -## PyScript Module API +## PyScript Python API -The python module offers various utilities in either the main thread or the worker. +The `pyscript` python package offers various utilities in either the main thread or the worker. The commonly shared utilities are: @@ -257,15 +257,6 @@ We might decide to allow TOML too in the future, but the direct config as attrib
-
- why worker attribute needs an external file? -
- -It would create confusion to have worker code embedded directly in the page and let *PyScript* forward the content to be executed as worker, but the separation of concerns felt more aligned with the meaning of bootstrapping a worker: it inevitably happens elsewhere and with little caveats or features here and there, so it's OK for now to keep that separation explicit. - -
-
-
what are the worker's caveats?
diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index d1403394..b17a830f 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -82,7 +82,7 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => { } // enrich the Python env with some JS utility for main - interpreter.registerJsModule("_pyscript_js", { + interpreter.registerJsModule("_pyscript", { PyWorker, get target() { return isScript(currentElement) diff --git a/pyscript.core/src/stdlib/_pyscript/__init__.py b/pyscript.core/src/stdlib/_pyscript/__init__.py deleted file mode 100644 index 20718253..00000000 --- a/pyscript.core/src/stdlib/_pyscript/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import js as window - -IS_WORKER = not hasattr(window, "document") - -if IS_WORKER: - from polyscript import xworker as _xworker - - window = _xworker.window - document = window.document - sync = _xworker.sync -else: - document = window.document diff --git a/pyscript.core/src/stdlib/pyscript.js b/pyscript.core/src/stdlib/pyscript.js index df7de4bf..6bc74670 100644 --- a/pyscript.core/src/stdlib/pyscript.js +++ b/pyscript.core/src/stdlib/pyscript.js @@ -1,11 +1,11 @@ // ⚠️ This file is an artifact: DO NOT MODIFY export default { - "_pyscript": { - "__init__.py": "import js as window\n\nIS_WORKER = not hasattr(window, \"document\")\n\nif IS_WORKER:\n from polyscript import xworker as _xworker\n\n window = _xworker.window\n document = window.document\n sync = _xworker.sync\nelse:\n document = window.document\n", - "display.py": "import base64\nimport html\nimport io\nimport re\n\nfrom . import document, window\n\n_MIME_METHODS = {\n \"__repr__\": \"text/plain\",\n \"_repr_html_\": \"text/html\",\n \"_repr_markdown_\": \"text/markdown\",\n \"_repr_svg_\": \"image/svg+xml\",\n \"_repr_png_\": \"image/png\",\n \"_repr_pdf_\": \"application/pdf\",\n \"_repr_jpeg_\": \"image/jpeg\",\n \"_repr_latex\": \"text/latex\",\n \"_repr_json_\": \"application/json\",\n \"_repr_javascript_\": \"application/javascript\",\n \"savefig\": \"image/png\",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode(\"utf-8\")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r\"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$\"\n )\n # If value doesn't match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode(\"utf-8\")).decode(\"utf-8\")\n\n data = f\"data:{mime};charset=utf-8;base64,{value}\"\n attrs = \" \".join(['{k}=\"{v}\"' for k, v in meta.items()])\n return f''\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n \"text/plain\": html.escape,\n \"text/html\": _identity,\n \"image/png\": lambda value, meta: _render_image(\"image/png\", value, meta),\n \"image/jpeg\": lambda value, meta: _render_image(\"image/jpeg\", value, meta),\n \"image/svg+xml\": _identity,\n \"application/json\": _identity,\n \"application/javascript\": lambda value, meta: f\" {extra_head} diff --git a/pyscriptjs/tests/integration/test_00_support.py b/pyscript.core/tests/integration/test_00_support.py similarity index 100% rename from pyscriptjs/tests/integration/test_00_support.py rename to pyscript.core/tests/integration/test_00_support.py diff --git a/pyscriptjs/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py similarity index 100% rename from pyscriptjs/tests/integration/test_01_basic.py rename to pyscript.core/tests/integration/test_01_basic.py diff --git a/pyscriptjs/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py similarity index 100% rename from pyscriptjs/tests/integration/test_02_display.py rename to pyscript.core/tests/integration/test_02_display.py diff --git a/pyscriptjs/tests/integration/test_03_element.py b/pyscript.core/tests/integration/test_03_element.py similarity index 100% rename from pyscriptjs/tests/integration/test_03_element.py rename to pyscript.core/tests/integration/test_03_element.py diff --git a/pyscriptjs/tests/integration/test_assets/line_plot.png b/pyscript.core/tests/integration/test_assets/line_plot.png similarity index 100% rename from pyscriptjs/tests/integration/test_assets/line_plot.png rename to pyscript.core/tests/integration/test_assets/line_plot.png diff --git a/pyscriptjs/tests/integration/test_assets/tripcolor.png b/pyscript.core/tests/integration/test_assets/tripcolor.png similarity index 100% rename from pyscriptjs/tests/integration/test_assets/tripcolor.png rename to pyscript.core/tests/integration/test_assets/tripcolor.png diff --git a/pyscriptjs/tests/integration/test_async.py b/pyscript.core/tests/integration/test_async.py similarity index 100% rename from pyscriptjs/tests/integration/test_async.py rename to pyscript.core/tests/integration/test_async.py diff --git a/pyscriptjs/tests/integration/test_event_handling.py b/pyscript.core/tests/integration/test_event_handling.py similarity index 100% rename from pyscriptjs/tests/integration/test_event_handling.py rename to pyscript.core/tests/integration/test_event_handling.py diff --git a/pyscriptjs/tests/integration/test_importmap.py b/pyscript.core/tests/integration/test_importmap.py similarity index 100% rename from pyscriptjs/tests/integration/test_importmap.py rename to pyscript.core/tests/integration/test_importmap.py diff --git a/pyscriptjs/tests/integration/test_interpreter.py b/pyscript.core/tests/integration/test_interpreter.py similarity index 100% rename from pyscriptjs/tests/integration/test_interpreter.py rename to pyscript.core/tests/integration/test_interpreter.py diff --git a/pyscriptjs/tests/integration/test_plugins.py b/pyscript.core/tests/integration/test_plugins.py similarity index 100% rename from pyscriptjs/tests/integration/test_plugins.py rename to pyscript.core/tests/integration/test_plugins.py diff --git a/pyscriptjs/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py similarity index 100% rename from pyscriptjs/tests/integration/test_py_config.py rename to pyscript.core/tests/integration/test_py_config.py diff --git a/pyscriptjs/tests/integration/test_py_repl.py b/pyscript.core/tests/integration/test_py_repl.py similarity index 100% rename from pyscriptjs/tests/integration/test_py_repl.py rename to pyscript.core/tests/integration/test_py_repl.py diff --git a/pyscriptjs/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py similarity index 100% rename from pyscriptjs/tests/integration/test_py_terminal.py rename to pyscript.core/tests/integration/test_py_terminal.py diff --git a/pyscriptjs/tests/integration/test_runtime_attributes.py b/pyscript.core/tests/integration/test_runtime_attributes.py similarity index 100% rename from pyscriptjs/tests/integration/test_runtime_attributes.py rename to pyscript.core/tests/integration/test_runtime_attributes.py diff --git a/pyscriptjs/tests/integration/test_script_type.py b/pyscript.core/tests/integration/test_script_type.py similarity index 100% rename from pyscriptjs/tests/integration/test_script_type.py rename to pyscript.core/tests/integration/test_script_type.py diff --git a/pyscriptjs/tests/integration/test_shadow_root.py b/pyscript.core/tests/integration/test_shadow_root.py similarity index 100% rename from pyscriptjs/tests/integration/test_shadow_root.py rename to pyscript.core/tests/integration/test_shadow_root.py diff --git a/pyscriptjs/tests/integration/test_splashscreen.py b/pyscript.core/tests/integration/test_splashscreen.py similarity index 100% rename from pyscriptjs/tests/integration/test_splashscreen.py rename to pyscript.core/tests/integration/test_splashscreen.py diff --git a/pyscriptjs/tests/integration/test_stdio_handling.py b/pyscript.core/tests/integration/test_stdio_handling.py similarity index 100% rename from pyscriptjs/tests/integration/test_stdio_handling.py rename to pyscript.core/tests/integration/test_stdio_handling.py diff --git a/pyscriptjs/tests/integration/test_style.py b/pyscript.core/tests/integration/test_style.py similarity index 100% rename from pyscriptjs/tests/integration/test_style.py rename to pyscript.core/tests/integration/test_style.py diff --git a/pyscriptjs/tests/integration/test_warnings_and_banners.py b/pyscript.core/tests/integration/test_warnings_and_banners.py similarity index 100% rename from pyscriptjs/tests/integration/test_warnings_and_banners.py rename to pyscript.core/tests/integration/test_warnings_and_banners.py diff --git a/pyscriptjs/tests/integration/test_zz_examples.py b/pyscript.core/tests/integration/test_zz_examples.py similarity index 100% rename from pyscriptjs/tests/integration/test_zz_examples.py rename to pyscript.core/tests/integration/test_zz_examples.py diff --git a/pyscriptjs/tests/integration/test_zzz_docs_snippets.py b/pyscript.core/tests/integration/test_zzz_docs_snippets.py similarity index 100% rename from pyscriptjs/tests/integration/test_zzz_docs_snippets.py rename to pyscript.core/tests/integration/test_zzz_docs_snippets.py From c330a623b2458ce303e79e0333790dd85e049677 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Mon, 18 Sep 2023 14:07:03 +0200 Subject: [PATCH 037/105] [next] Remove artifacts from GitHub (#1721) --- .gitignore | 3 +++ pyscript.core/src/plugins.js | 4 ---- pyscript.core/src/stdlib/pyscript.js | 13 ------------- 3 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 pyscript.core/src/plugins.js delete mode 100644 pyscript.core/src/stdlib/pyscript.js diff --git a/.gitignore b/.gitignore index 2aa902e0..3e952354 100644 --- a/.gitignore +++ b/.gitignore @@ -145,3 +145,6 @@ test_results # @pyscript/core npm artifacts pyscript.core/core.* pyscript.core/dist +pyscript.core/dist +pyscript.core/src/plugins.js +pyscript.core/src/stdlib/pyscript.js diff --git a/pyscript.core/src/plugins.js b/pyscript.core/src/plugins.js deleted file mode 100644 index bc45e825..00000000 --- a/pyscript.core/src/plugins.js +++ /dev/null @@ -1,4 +0,0 @@ -// ⚠️ This file is an artifact: DO NOT MODIFY -export default { - error: () => import(/* webpackIgnore: true */ "./plugins/error.js"), -}; diff --git a/pyscript.core/src/stdlib/pyscript.js b/pyscript.core/src/stdlib/pyscript.js deleted file mode 100644 index b3069bdb..00000000 --- a/pyscript.core/src/stdlib/pyscript.js +++ /dev/null @@ -1,13 +0,0 @@ -// ⚠️ This file is an artifact: DO NOT MODIFY -export default { - "pyscript": { - "__init__.py": "# Some notes about the naming conventions and the relationship between various\n# similar-but-different names.\n#\n# import pyscript\n# this package contains the main user-facing API offered by pyscript. All\n# the names which are supposed be used by end users should be made\n# available in pyscript/__init__.py (i.e., this file)\n#\n# import _pyscript\n# this is an internal module implemented in JS. It is used internally by\n# the pyscript package, end users should not use it directly. For its\n# implementation, grep for `interpreter.registerJsModule(\"_pyscript\",\n# ...)` in core.js\n#\n# import js\n# this is the JS globalThis, as exported by pyodide and/or micropython's\n# FFIs. As such, it contains different things in the main thread or in a\n# worker.\n#\n# import pyscript.magic_js\n# this submodule abstracts away some of the differences between the main\n# thread and the worker. In particular, it defines `window` and `document`\n# in such a way that these names work in both cases: in the main thread,\n# they are the \"real\" objects, in the worker they are proxies which work\n# thanks to coincident.\n#\n# from pyscript import window, document\n# these are just the window and document objects as defined by\n# pyscript.magic_js. This is the blessed way to access them from pyscript,\n# as it works transparently in both the main thread and worker cases.\n", - "display.py": "import base64\nimport html\nimport io\nimport re\n\nfrom pyscript.magic_js import document, window, current_target\n\n_MIME_METHODS = {\n \"__repr__\": \"text/plain\",\n \"_repr_html_\": \"text/html\",\n \"_repr_markdown_\": \"text/markdown\",\n \"_repr_svg_\": \"image/svg+xml\",\n \"_repr_png_\": \"image/png\",\n \"_repr_pdf_\": \"application/pdf\",\n \"_repr_jpeg_\": \"image/jpeg\",\n \"_repr_latex\": \"text/latex\",\n \"_repr_json_\": \"application/json\",\n \"_repr_javascript_\": \"application/javascript\",\n \"savefig\": \"image/png\",\n}\n\n\ndef _render_image(mime, value, meta):\n # If the image value is using bytes we should convert it to base64\n # otherwise it will return raw bytes and the browser will not be able to\n # render it.\n if isinstance(value, bytes):\n value = base64.b64encode(value).decode(\"utf-8\")\n\n # This is the pattern of base64 strings\n base64_pattern = re.compile(\n r\"^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$\"\n )\n # If value doesn't match the base64 pattern we should encode it to base64\n if len(value) > 0 and not base64_pattern.match(value):\n value = base64.b64encode(value.encode(\"utf-8\")).decode(\"utf-8\")\n\n data = f\"data:{mime};charset=utf-8;base64,{value}\"\n attrs = \" \".join(['{k}=\"{v}\"' for k, v in meta.items()])\n return f''\n\n\ndef _identity(value, meta):\n return value\n\n\n_MIME_RENDERERS = {\n \"text/plain\": html.escape,\n \"text/html\": _identity,\n \"image/png\": lambda value, meta: _render_image(\"image/png\", value, meta),\n \"image/jpeg\": lambda value, meta: _render_image(\"image/jpeg\", value, meta),\n \"image/svg+xml\": _identity,\n \"application/json\": _identity,\n \"application/javascript\": lambda value, meta: f\" + + + [[fetch]] + files = ["a.py"] + + + + diff --git a/pyscript.core/types/config.d.ts b/pyscript.core/types/config.d.ts index 2d5eceee..6c3055f8 100644 --- a/pyscript.core/types/config.d.ts +++ b/pyscript.core/types/config.d.ts @@ -1,3 +1,4 @@ -export let config: any; +declare let parsed: any; export let plugins: any; export let error: any; +export { parsed as config }; From f6decfd93d20064813946c78fb9668624ecd34ed Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 19 Sep 2023 18:10:46 +0200 Subject: [PATCH 041/105] [next] Errors on ambiguous/conflicting code intents (#1724) --- pyscript.core/package-lock.json | 4 ++-- pyscript.core/package.json | 2 +- pyscript.core/src/core.js | 33 +++++++++++++++++++++++++++++ pyscript.core/src/exceptions.js | 17 ++++++++------- pyscript.core/test/error.html | 4 ++++ pyscript.core/test/no-error.html | 4 ++++ pyscript.core/types/exceptions.d.ts | 11 +++++----- 7 files changed, 59 insertions(+), 16 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 32dd2b90..d7ebb76e 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.1.21", + "version": "0.1.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.21", + "version": "0.1.22", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 7963e501..e46b7954 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.1.21", + "version": "0.1.22", "type": "module", "description": "PyScript", "module": "./index.js", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index b17a830f..a35f677d 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -9,6 +9,7 @@ import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js"; import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; +import { ErrorCode } from "./exceptions.js"; import sync from "./sync.js"; import stdlib from "./stdlib.js"; import { config, plugins, error } from "./config.js"; @@ -40,6 +41,36 @@ const after = () => { delete document.currentScript; }; +/** + * Some content that might contain Python/JS comments only. + * @param {string} text some content to evaluate + * @returns {boolean} + */ +const hasCommentsOnly = (text) => + !text + .replace(/\/\*[\s\S]*?\*\//g, "") + .replace(/^\s*(?:\/\/|#).*/gm, "") + .trim(); + +/** + * + * @param {Element} scriptOrPyScript the element with possible `src` or `worker` content + * @returns {boolean} + */ +const hasAmbiguousContent = ( + io, + { localName, textContent, attributes: { src, worker } }, +) => { + // any `src` or a non-empty `worker` attribute + not just comments + if ((src || worker?.value) && !hasCommentsOnly(textContent)) { + io.stderr( + `(${ErrorCode.CONFLICTING_CODE}) a ${localName} tag has content shadowed by attributes`, + ); + return true; + } + return false; +}; + /** * Given a generic DOM Element, tries to fetch the 'src' attribute, if present. * It either throws an error if the 'src' can't be fetched or it returns a fallback @@ -172,6 +203,7 @@ error || callback(pyodide, element); if (isScript(element)) { + if (hasAmbiguousContent(pyodide.io, element)) return; const { attributes: { async: isAsync, target }, } = element; @@ -222,6 +254,7 @@ class PyScriptElement extends HTMLElement { if (!this.executed) { this.executed = true; const { io, run, runAsync } = await this._pyodide.promise; + if (hasAmbiguousContent(io, this)) return; const runner = this.hasAttribute("async") ? runAsync : run; this.srcCode = await fetchSource(this, io, !this.childElementCount); this.replaceChildren(); diff --git a/pyscript.core/src/exceptions.js b/pyscript.core/src/exceptions.js index 56132dfc..1c5b0a3b 100644 --- a/pyscript.core/src/exceptions.js +++ b/pyscript.core/src/exceptions.js @@ -7,19 +7,20 @@ const CLOSEBUTTON = */ export const ErrorCode = { GENERIC: "PY0000", // Use this only for development then change to a more specific error code - FETCH_ERROR: "PY0001", - FETCH_NAME_ERROR: "PY0002", - // Currently these are created depending on error code received from fetching - FETCH_UNAUTHORIZED_ERROR: "PY0401", - FETCH_FORBIDDEN_ERROR: "PY0403", - FETCH_NOT_FOUND_ERROR: "PY0404", - FETCH_SERVER_ERROR: "PY0500", - FETCH_UNAVAILABLE_ERROR: "PY0503", + CONFLICTING_CODE: "PY0409", BAD_CONFIG: "PY1000", MICROPIP_INSTALL_ERROR: "PY1001", BAD_PLUGIN_FILE_EXTENSION: "PY2000", NO_DEFAULT_EXPORT: "PY2001", TOP_LEVEL_AWAIT: "PY9000", + // Currently these are created depending on error code received from fetching + FETCH_ERROR: "PY0001", + FETCH_NAME_ERROR: "PY0002", + FETCH_UNAUTHORIZED_ERROR: "PY0401", + FETCH_FORBIDDEN_ERROR: "PY0403", + FETCH_NOT_FOUND_ERROR: "PY0404", + FETCH_SERVER_ERROR: "PY0500", + FETCH_UNAVAILABLE_ERROR: "PY0503", }; export class UserError extends Error { diff --git a/pyscript.core/test/error.html b/pyscript.core/test/error.html index 15416049..374a3003 100644 --- a/pyscript.core/test/error.html +++ b/pyscript.core/test/error.html @@ -14,5 +14,9 @@ print(4, 5, 6) second() + + print(4, 5, 6) + second() + diff --git a/pyscript.core/test/no-error.html b/pyscript.core/test/no-error.html index aebae5bb..92e06f13 100644 --- a/pyscript.core/test/no-error.html +++ b/pyscript.core/test/no-error.html @@ -15,5 +15,9 @@ print(4, 5, 6) second() + + print(4, 5, 6) + second() + diff --git a/pyscript.core/types/exceptions.d.ts b/pyscript.core/types/exceptions.d.ts index 138ddfdd..5fe7f315 100644 --- a/pyscript.core/types/exceptions.d.ts +++ b/pyscript.core/types/exceptions.d.ts @@ -1,6 +1,12 @@ export function _createAlertBanner(message: any, level: any, messageType?: string, logMessage?: boolean): void; export namespace ErrorCode { let GENERIC: string; + let CONFLICTING_CODE: string; + let BAD_CONFIG: string; + let MICROPIP_INSTALL_ERROR: string; + let BAD_PLUGIN_FILE_EXTENSION: string; + let NO_DEFAULT_EXPORT: string; + let TOP_LEVEL_AWAIT: string; let FETCH_ERROR: string; let FETCH_NAME_ERROR: string; let FETCH_UNAUTHORIZED_ERROR: string; @@ -8,11 +14,6 @@ export namespace ErrorCode { let FETCH_NOT_FOUND_ERROR: string; let FETCH_SERVER_ERROR: string; let FETCH_UNAVAILABLE_ERROR: string; - let BAD_CONFIG: string; - let MICROPIP_INSTALL_ERROR: string; - let BAD_PLUGIN_FILE_EXTENSION: string; - let NO_DEFAULT_EXPORT: string; - let TOP_LEVEL_AWAIT: string; } export class UserError extends Error { constructor(errorCode: any, message?: string, messageType?: string); From 77b40aa34817b0cb209ccf9d138d39eed8297136 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Tue, 19 Sep 2023 16:35:15 +0000 Subject: [PATCH 042/105] Use ` + + + import js + js.console.log('hello from py-script') + """ ) - assert self.console.log.lines == ["hello pyscript"] + assert self.console.log.lines == ["hello from script py", + "hello from py-script"] def test_execution_thread(self): self.pyscript_run( @@ -64,9 +70,9 @@ class TestBasic(PyScriptTest): def test_print(self): self.pyscript_run( """ - + """ ) assert self.console.log.lines[-1] == "hello pyscript" @@ -74,10 +80,10 @@ class TestBasic(PyScriptTest): def test_python_exception(self): self.pyscript_run( """ - + """ ) assert "hello pyscript" in self.console.log.lines @@ -100,10 +106,10 @@ class TestBasic(PyScriptTest): self.pyscript_run( """ - + """ ) @@ -125,15 +131,15 @@ class TestBasic(PyScriptTest): def test_execution_in_order(self): """ - Check that they py-script tags are executed in the same order they are + Check that they script py tags are executed in the same order they are defined """ self.pyscript_run( """ - import js; js.console.log('one') - js.console.log('two') - js.console.log('three') - js.console.log('four') + + + + """ ) assert self.console.log.lines[-4:] == [ @@ -145,16 +151,21 @@ class TestBasic(PyScriptTest): def test_escaping_of_angle_brackets(self): """ - Check that py-script tags escape angle brackets + Check that script tags escape angle brackets """ self.pyscript_run( """ - import js; js.console.log(1<2, 1>2) - js.console.log("
")
+ + + import js; js.console.log("C", 1<2, 1>2) + js.console.log("D
")
+ """ ) - - assert self.console.log.lines[-2:] == ["true false", "
"] + assert self.console.log.lines[-4:] == ["A true false", + "B
", + "C true false", + "D
"] @pytest.mark.skip(reason="FIX TEST: Works on CHROME") def test_packages(self): @@ -163,11 +174,11 @@ class TestBasic(PyScriptTest): packages = ["asciitree"] - + """ ) @@ -177,7 +188,7 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] - # TODO: if there's no py-script there are surely no plugins neither + # TODO: if there's no """ ) assert self.console.log.lines[-1] == "hello from foo" @@ -252,7 +263,7 @@ class TestBasic(PyScriptTest): def test_py_script_src_not_found(self): self.pyscript_run( """ - + """, check_js_errors=False, ) @@ -263,7 +274,7 @@ class TestBasic(PyScriptTest): # assert any((expected_msg in line) for line in self.console.js_error.lines) # assert self.assert_banner_message(expected_msg) - # pyscript_tag = self.page.locator("py-script") + # pyscript_tag = self.page.locator("script-py") # assert pyscript_tag.inner_html() == "" # self.check_js_errors(expected_msg) @@ -273,8 +284,8 @@ class TestBasic(PyScriptTest): def test_js_version(self): self.pyscript_run( """ - - + """ ) self.page.add_script_tag(content="console.log(pyscript.version)") @@ -289,11 +300,11 @@ class TestBasic(PyScriptTest): def test_python_version(self): self.pyscript_run( """ - + """ ) assert ( @@ -315,35 +326,39 @@ class TestBasic(PyScriptTest): """ self.pyscript_run( """ - + """ ) assert self.page.locator(".py-error").inner_text() == "hello world" + @pytest.mark.skip("ERROR_SCRIPT: works with not with """ ) - pyscript_tag = self.page.locator("py-script") assert pyscript_tag.inner_html() == "" - assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello world!")' + assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello from py-script")' + script_py_tag = self.page.locator('script[type="py"]') + assert script_py_tag.evaluate("node => node.srcCode") == 'print("hello from script py")' + @pytest.mark.skip(reason="FIX TEST: works in chrome!") def test_py_attribute_without_id(self): self.pyscript_run( """ - + """ ) btn = self.page.wait_for_selector("button") diff --git a/pyscript.core/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py index da07a11d..3d46e72b 100644 --- a/pyscript.core/tests/integration/test_02_display.py +++ b/pyscript.core/tests/integration/test_02_display.py @@ -21,11 +21,11 @@ class TestDisplay(PyScriptTest): def test_simple_display(self): self.pyscript_run( """ - + """, timeout=20000, ) @@ -37,15 +37,15 @@ class TestDisplay(PyScriptTest): def test_consecutive_display(self): self.pyscript_run( """ - +

hello 2

- + """ ) inner_text = self.page.inner_text("body") @@ -57,32 +57,50 @@ class TestDisplay(PyScriptTest): def test_target_attribute(self): self.pyscript_run( """ - +
""" ) mydiv = self.page.locator("#mydiv") assert mydiv.inner_text() == "hello world" + def test_target_script_py(self): + self.pyscript_run( + """ +
ONE
+ +
THREE
+ + + """ + ) + text = self.page.inner_text("body") + assert text == 'ONE\nTWO\nTHREE' + def test_consecutive_display_target(self): self.pyscript_run( """ - +

hello in between 1 and 2

- + + """ ) inner_text = self.page.inner_text("body") @@ -93,77 +111,78 @@ class TestDisplay(PyScriptTest): def test_multiple_display_calls_same_tag(self): self.pyscript_run( """ - + """ ) - tag = self.page.locator("py-script") + tag = self.page.locator("script-py") lines = tag.inner_text().splitlines() assert lines == ["hello", "world"] def test_implicit_target_from_a_different_tag(self): self.pyscript_run( """ - + - + """ ) - py1 = self.page.locator("#py1") - py2 = self.page.locator("#py2") - assert py1.inner_text() == "" - assert py2.inner_text() == "hello" + elems = self.page.locator("script-py") + py0 = elems.nth(0) + py1 = elems.nth(1) + assert py0.inner_text() == "" + assert py1.inner_text() == "hello" def test_no_explicit_target(self): self.pyscript_run( """ - + """ ) self.page.locator("button").click() - text = self.page.locator("py-script").text_content() + text = self.page.locator("script-py").text_content() assert "hello world" in text def test_explicit_target_pyscript_tag(self): self.pyscript_run( """ - + + """ ) - text = self.page.locator("id=second-pyscript-tag").inner_text() + text = self.page.locator("script-py").nth(1).inner_text() assert text == "hello" def test_explicit_target_on_button_tag(self): self.pyscript_run( """ - + """ ) @@ -171,80 +190,58 @@ class TestDisplay(PyScriptTest): text = self.page.locator("id=my-button").inner_text() assert "hello" in text - def test_explicit_different_target_from_call(self): - self.pyscript_run( - """ - - from pyscript import display - def display_hello(): - display('hello', target='second-pyscript-tag') - - - print('nothing to see here') - - - display_hello() - - """ - ) - text = self.page.locator("id=second-pyscript-tag").all_inner_texts() - assert "hello" in text - def test_append_true(self): self.pyscript_run( """ - + """ ) - node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) - pattern = r"
hello world
" - - assert node_list[0].inner_html() == pattern - assert len(node_list) == 1 + output = self.page.locator('script-py') + assert output.inner_text() == 'AAA\nBBB' def test_append_false(self): self.pyscript_run( """ - + """ ) - inner_html = self.page.content() - pattern = r'hello world' - assert re.search(pattern, inner_html) + output = self.page.locator('script-py') + assert output.inner_text() == 'BBB' def test_display_multiple_values(self): self.pyscript_run( """ - + """ ) - inner_text = self.page.inner_text("html") - assert inner_text == "hello\nworld" + output = self.page.locator('script-py') + assert output.inner_text() == "hello\nworld" def test_display_multiple_append_false(self): self.pyscript_run( """ - + """ ) - inner_html = self.page.content() - pattern = r'world' - assert re.search(pattern, inner_html) + output = self.page.locator('script-py') + assert output.inner_text() == "world" # TODO: this is a display.py issue to fix when append=False is used # do not use the first element, just clean up and then append @@ -282,13 +279,13 @@ class TestDisplay(PyScriptTest): def test_display_list_dict_tuple(self): self.pyscript_run( """ - + """ ) inner_text = self.page.inner_text("html") @@ -299,32 +296,33 @@ class TestDisplay(PyScriptTest): == "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')" ) + @pytest.mark.skip("The asserts are commented out. Investigate") def test_display_should_escape(self): self.pyscript_run( """ - + """ ) - # out = self.page.locator("py-script > div") + # out = self.page.locator("script-py > div") node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) node_list[0] # assert out.inner_html() == html.escape("

hello world

") # assert out.inner_text() == "

hello world

" - @pytest.mark.skip("FIXME: HTML has been removed from pyscript") + @pytest.mark.skip("The asserts are commented out. Investigate") def test_display_HTML(self): self.pyscript_run( """ - + """ ) - # out = self.page.locator("py-script > div") + # out = self.page.locator("script-py > div") node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) node_list[0] # assert out.inner_html() == "

hello world

" @@ -339,14 +337,14 @@ class TestDisplay(PyScriptTest): self.pyscript_run( """ packages = ["matplotlib"] - + """ ) wait_for_render(self.page, "*", " + """ ) inner_html = self.page.content() @@ -386,17 +384,17 @@ class TestDisplay(PyScriptTest): def test_text_HTML_and_console_output(self): self.pyscript_run( """ - + """ ) - inner_text = self.page.inner_text("py-script") + inner_text = self.page.inner_text("script-py") assert inner_text == "this goes to the DOM" assert self.console.log.lines[-2:] == [ "print from python", @@ -408,10 +406,10 @@ class TestDisplay(PyScriptTest): def test_console_line_break(self): self.pyscript_run( """ - + """ ) console_text = self.console.all.lines @@ -439,12 +437,12 @@ class TestDisplay(PyScriptTest):
- + """ ) diff --git a/pyscript.core/tests/integration/test_03_element.py b/pyscript.core/tests/integration/test_03_element.py index 4f0594b4..bf082f1f 100644 --- a/pyscript.core/tests/integration/test_03_element.py +++ b/pyscript.core/tests/integration/test_03_element.py @@ -12,11 +12,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
- + """ ) assert self.console.log.lines[-1] == "foo" @@ -30,11 +30,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """ - + """ ) assert self.console.log.lines[-1] == "bar" @@ -48,11 +48,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
bar
- + """ ) assert self.console.log.lines[-1] == "bar" @@ -66,12 +66,12 @@ class TestElement(PyScriptTest): self.pyscript_run( """
- + """ ) div = self.page.wait_for_selector("#foo") @@ -83,12 +83,12 @@ class TestElement(PyScriptTest): self.pyscript_run( """
- + """ ) parent_div = self.page.wait_for_selector("#foo") @@ -103,11 +103,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
Hello!
- + """ ) div = self.page.locator("#foo") @@ -119,11 +119,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """ - + """ ) input = self.page.wait_for_selector("#foo") @@ -137,11 +137,11 @@ class TestElement(PyScriptTest): - + """ ) assert self.console.log.lines[-1] == "bar" @@ -154,11 +154,11 @@ class TestElement(PyScriptTest): - + """ ) assert self.console.log.lines[-1] == "Bar" @@ -169,11 +169,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
Hello!
- + """ ) divs = self.page.locator("#foo") @@ -187,11 +187,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
Hello!
- + """ ) divs = self.page.locator("#foo") @@ -214,14 +214,14 @@ class TestElement(PyScriptTest): James
- + """ ) bond_divs = self.page.locator("#bond") @@ -242,11 +242,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
- + """ ) div = self.page.locator("#foo") @@ -258,11 +258,11 @@ class TestElement(PyScriptTest): self.pyscript_run( """
- + """ ) div = self.page.locator("#foo") @@ -275,11 +275,11 @@ class TestElement(PyScriptTest): """
Hi!
- + """ ) div = self.page.locator("#foo") @@ -292,11 +292,11 @@ class TestElement(PyScriptTest): """
Hi!
- + """ ) div = self.page.locator("#foo") diff --git a/pyscript.core/tests/integration/test_async.py b/pyscript.core/tests/integration/test_async.py index 4d196023..3bac8b70 100644 --- a/pyscript.core/tests/integration/test_async.py +++ b/pyscript.core/tests/integration/test_async.py @@ -1,3 +1,4 @@ +import pytest from .support import PyScriptTest, filter_inner_text @@ -5,7 +6,7 @@ class TestAsync(PyScriptTest): # ensure_future() and create_task() should behave similarly; # we'll use the same source code to test both coroutine_script = """ - + """ def test_asyncio_ensure_future(self): @@ -30,7 +31,7 @@ class TestAsync(PyScriptTest): def test_asyncio_gather(self): self.pyscript_run( """ - + """ ) self.wait_for_console("DONE") @@ -54,7 +55,7 @@ class TestAsync(PyScriptTest): def test_multiple_async(self): self.pyscript_run( """ - + - + """ ) self.wait_for_console("b func done") @@ -90,7 +91,7 @@ class TestAsync(PyScriptTest): def test_multiple_async_multiple_display_targeted(self): self.pyscript_run( """ - + + + """ ) self.wait_for_console("B DONE") @@ -124,7 +128,7 @@ class TestAsync(PyScriptTest): def test_async_display_untargeted(self): self.pyscript_run( """ - + """ ) self.wait_for_console("DONE") - assert self.page.locator("py-script").inner_text() == "A" + assert self.page.locator("script-py").inner_text() == "A" def test_sync_and_async_order(self): """ The order of execution is defined as follows: - 1. first, we execute all the py-script tag in order + 1. first, we execute all the script tags in order 2. then, we start all the tasks which were scheduled with create_task Note that tasks are started *AFTER* all py-script tags have been @@ -152,12 +156,12 @@ class TestAsync(PyScriptTest): executed after e.g. js.console.log("6"). """ src = """ - + - + - + - + """ self.pyscript_run(src, wait_for_pyscript=False) self.wait_for_console("DONE") diff --git a/pyscript.core/tests/integration/test_event_handling.py b/pyscript.core/tests/integration/test_event_handling.py index 0ecf3ad9..a0a15e7b 100644 --- a/pyscript.core/tests/integration/test_event_handling.py +++ b/pyscript.core/tests/integration/test_event_handling.py @@ -15,12 +15,12 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() @@ -36,12 +36,12 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() @@ -54,7 +54,7 @@ class TestEventHandler(PyScriptTest): """ - + """ ) self.page.locator("text=foo_button").click() @@ -82,13 +82,13 @@ class TestEventHandler(PyScriptTest): """ - + """ ) self.page.locator("text=bar_button").hover() @@ -103,13 +103,13 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").hover() @@ -127,12 +127,12 @@ class TestEventHandler(PyScriptTest): """ - + """ ) self.page.locator("text=button1").click() @@ -147,13 +147,13 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() @@ -170,12 +170,12 @@ class TestEventHandler(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.locator("text=foo_button").click() diff --git a/pyscript.core/tests/integration/test_importmap.py b/pyscript.core/tests/integration/test_importmap.py index 9ef3e9dd..17ba21aa 100644 --- a/pyscript.core/tests/integration/test_importmap.py +++ b/pyscript.core/tests/integration/test_importmap.py @@ -28,10 +28,10 @@ class TestImportmap(PyScriptTest): say_hello("JS"); - + """ ) assert self.console.log.lines == [ @@ -46,9 +46,9 @@ class TestImportmap(PyScriptTest): this is not valid JSON - + """, wait_for_pyscript=False, ) diff --git a/pyscript.core/tests/integration/test_interpreter.py b/pyscript.core/tests/integration/test_interpreter.py index e906fa29..9a7fcb5e 100644 --- a/pyscript.core/tests/integration/test_interpreter.py +++ b/pyscript.core/tests/integration/test_interpreter.py @@ -14,11 +14,11 @@ class TestInterpreterAccess(PyScriptTest): def test_interpreter_python_access(self): self.pyscript_run( """ - + """ ) @@ -74,11 +74,11 @@ class TestInterpreterAccess(PyScriptTest): """Test accessing Python objects from JS via pyscript.runtime""" self.pyscript_run( """ - + """ ) diff --git a/pyscript.core/tests/integration/test_plugins.py b/pyscript.core/tests/integration/test_plugins.py index 518b4062..53ded193 100644 --- a/pyscript.core/tests/integration/test_plugins.py +++ b/pyscript.core/tests/integration/test_plugins.py @@ -250,11 +250,11 @@ class TestPlugin(PyScriptTest): @prepare_test( "exec_test_logger", PYSCRIPT_HOOKS_PLUGIN_CODE, - template=HTML_TEMPLATE_NO_TAG + "\nx=2; x", + template=HTML_TEMPLATE_NO_TAG + "\n", ) def test_pyscript_exec_hooks(self): """Test that the beforePyScriptExec and afterPyScriptExec hooks work as intended""" - assert self.page.locator("py-script") is not None + assert self.page.locator("script") is not None log_lines: list[str] = self.console.log.lines diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py index 597dd799..34d24555 100644 --- a/pyscript.core/tests/integration/test_py_config.py +++ b/pyscript.core/tests/integration/test_py_config.py @@ -50,7 +50,7 @@ def unzip(location, extract_to="."): # of config @with_execution_thread(None) class TestConfig(PyScriptTest): - def test_py_config_inline(self): + def test_py_config_inline_pyscript(self): self.pyscript_run( """ @@ -66,6 +66,25 @@ class TestConfig(PyScriptTest): ) assert self.console.log.lines[-1] == "config name: foobar" + @pytest.mark.skip("ERROR_SCRIPT: works with not with + """ + ) + assert self.console.log.lines[-1] == "config name: foobar" + + + @pytest.mark.skip("ERROR_SCRIPT: works with not with """ ) assert self.console.log.lines[-1] == "config name: app with external config" @@ -105,11 +124,11 @@ class TestConfig(PyScriptTest): } - + """, ) @@ -168,11 +187,11 @@ class TestConfig(PyScriptTest): this is ignored and won't even be parsed - + """ ) banner = self.page.wait_for_selector(".py-warning") @@ -217,10 +236,10 @@ class TestConfig(PyScriptTest): } - + """ self.pyscript_run(snippet) banner = self.page.wait_for_selector(".py-warning") @@ -240,12 +259,12 @@ class TestConfig(PyScriptTest): files = ["./a.py", "./b.py"] - + """ ) assert self.console.log.lines[-2:] == [ @@ -284,11 +303,11 @@ class TestConfig(PyScriptTest): files = ["__init__.py", "a.py"] - + """ ) assert self.console.log.lines[-1] == "hello from A" diff --git a/pyscript.core/tests/integration/test_py_repl.py b/pyscript.core/tests/integration/test_py_repl.py index 44263895..949c517b 100644 --- a/pyscript.core/tests/integration/test_py_repl.py +++ b/pyscript.core/tests/integration/test_py_repl.py @@ -386,7 +386,7 @@ class TestPyRepl(PyScriptTest): self.pyscript_run( """
- + asyncio.ensure_future(print_it()); @@ -544,7 +544,7 @@ class TestPyRepl(PyScriptTest): this_tag.setAttribute("output", "third") print("three.") - + """ ) diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py index 816a3506..470e1fe6 100644 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -22,12 +22,12 @@ class TestPyTerminal(PyScriptTest): """ - + """ ) term = self.page.locator("py-terminal") @@ -54,7 +54,7 @@ class TestPyTerminal(PyScriptTest): """ - + """ ) term1 = self.page.locator("#term1") @@ -115,9 +115,9 @@ class TestPyTerminal(PyScriptTest): terminal = true - + """ ) term = self.page.locator("py-terminal") @@ -167,13 +167,13 @@ class TestPyTerminal(PyScriptTest): xterm = true - + """ ) @@ -242,10 +242,10 @@ class TestPyTerminal(PyScriptTest): xterm = true - + """ diff --git a/pyscript.core/tests/integration/test_runtime_attributes.py b/pyscript.core/tests/integration/test_runtime_attributes.py index 59aea814..621b43a1 100644 --- a/pyscript.core/tests/integration/test_runtime_attributes.py +++ b/pyscript.core/tests/integration/test_runtime_attributes.py @@ -9,7 +9,7 @@ class TestPyScriptRuntimeAttributes(PyScriptTest): self.pyscript_run( r"""
- + """ ) self.page.locator("button").click() @@ -28,7 +28,7 @@ class TestPyScriptRuntimeAttributes(PyScriptTest): self.pyscript_run( r""" - + """ ) self.page.locator("button").click() @@ -47,7 +47,7 @@ class TestPyScriptRuntimeAttributes(PyScriptTest): self.pyscript_run( r""" - + """ ) self.page.locator("button").click() diff --git a/pyscript.core/tests/integration/test_script_type.py b/pyscript.core/tests/integration/test_script_type.py index e41ff456..8173f1b3 100644 --- a/pyscript.core/tests/integration/test_script_type.py +++ b/pyscript.core/tests/integration/test_script_type.py @@ -110,11 +110,11 @@ class TestScriptTypePyScript(PyScriptTest): """
- + """ ) assert self.page.locator("#stdout-div").text_content() == "one.two." diff --git a/pyscript.core/tests/integration/test_shadow_root.py b/pyscript.core/tests/integration/test_shadow_root.py index ebc0a324..d02b2c43 100644 --- a/pyscript.core/tests/integration/test_shadow_root.py +++ b/pyscript.core/tests/integration/test_shadow_root.py @@ -24,10 +24,10 @@ class TestShadowRoot(PyScriptTest): }); - + """ ) assert self.console.log.lines[-1] == "OK" diff --git a/pyscript.core/tests/integration/test_splashscreen.py b/pyscript.core/tests/integration/test_splashscreen.py index 72fe9215..74d7a604 100644 --- a/pyscript.core/tests/integration/test_splashscreen.py +++ b/pyscript.core/tests/integration/test_splashscreen.py @@ -22,9 +22,9 @@ class TestSplashscreen(PyScriptTest): """ self.pyscript_run( """ - + """, wait_for_pyscript=False, ) @@ -49,9 +49,9 @@ class TestSplashscreen(PyScriptTest): [splashscreen] autoclose = false - + """, ) div = self.page.locator("py-splashscreen > div") @@ -66,9 +66,9 @@ class TestSplashscreen(PyScriptTest): autoclose_loader = false - + """, ) warning = self.page.locator(".py-warning") @@ -89,11 +89,11 @@ class TestSplashscreen(PyScriptTest): enabled = false - + """, ) assert self.page.locator("py-splashscreen").count() == 0 @@ -110,12 +110,12 @@ class TestSplashscreen(PyScriptTest): autoclose = false - + """, ) diff --git a/pyscript.core/tests/integration/test_stdio_handling.py b/pyscript.core/tests/integration/test_stdio_handling.py index 6bc1dddd..73b231fd 100644 --- a/pyscript.core/tests/integration/test_stdio_handling.py +++ b/pyscript.core/tests/integration/test_stdio_handling.py @@ -20,11 +20,11 @@ class TestOutputHandling(PyScriptTest):
- print("first 1.") - print("second.") - print("third.") - print("first 2.") - print("no output.") + + + + + """ ) @@ -63,10 +63,10 @@ class TestOutputHandling(PyScriptTest): self.pyscript_run( """
- + """ ) @@ -81,16 +81,16 @@ class TestOutputHandling(PyScriptTest): self.pyscript_run( """
- +
- + """ ) @@ -106,7 +106,7 @@ class TestOutputHandling(PyScriptTest): # Test the behavior of stdio capture in async contexts self.pyscript_run( """ - +
- +
- +
- + - + """ ) self.wait_for_console("DONE DONE") - # py-script tags without output parameter should not send + # script tags without output parameter should not send # stdout to element assert self.page.locator("#first").text_content() == "" - # py-script tags with output parameter not expected to send + # script tags with output parameter not expected to send # std to element in coroutine assert self.page.locator("#second").text_content() == "" assert self.page.locator("#third").text_content() == "" @@ -157,7 +157,7 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -196,7 +196,7 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -224,18 +224,18 @@ class TestOutputHandling(PyScriptTest): # Attribute creates exactly 1 warning banner per missing id self.pyscript_run( """ - +
- + - + """ ) @@ -253,19 +253,19 @@ class TestOutputHandling(PyScriptTest): # attribute creates exactly 1 warning banner per missing id self.pyscript_run( """ - +
- + - + """ ) @@ -285,11 +285,11 @@ class TestOutputHandling(PyScriptTest): """
- + """ ) @@ -299,14 +299,14 @@ class TestOutputHandling(PyScriptTest): @skip_worker("FIXME: js.document") def test_stdio_output_attribute_change(self): - # If the user changes the 'output' attribute of a tag mid-execution, + # If the user changes the 'output' attribute of a """ ) @@ -340,7 +340,7 @@ class TestOutputHandling(PyScriptTest):
- + """ ) diff --git a/pyscript.core/tests/integration/test_style.py b/pyscript.core/tests/integration/test_style.py index e544a8b1..6eb6e851 100644 --- a/pyscript.core/tests/integration/test_style.py +++ b/pyscript.core/tests/integration/test_style.py @@ -19,7 +19,7 @@ class TestStyle(PyScriptTest): hello - hello + hello @@ -38,7 +38,7 @@ class TestStyle(PyScriptTest): name = "foo" - display("hello") + display("hello") """ ) diff --git a/pyscript.core/tests/integration/test_warnings_and_banners.py b/pyscript.core/tests/integration/test_warnings_and_banners.py index 933e8ea8..e809b04a 100644 --- a/pyscript.core/tests/integration/test_warnings_and_banners.py +++ b/pyscript.core/tests/integration/test_warnings_and_banners.py @@ -12,13 +12,13 @@ class TestWarningsAndBanners(PyScriptTest): # Use a script tag with an invalid output attribute to generate a warning, but only one self.pyscript_run( """ - + + """ ) diff --git a/pyscript.core/tests/integration/test_zzz_docs_snippets.py b/pyscript.core/tests/integration/test_zzz_docs_snippets.py index cf2c6379..92b7ee57 100644 --- a/pyscript.core/tests/integration/test_zzz_docs_snippets.py +++ b/pyscript.core/tests/integration/test_zzz_docs_snippets.py @@ -19,7 +19,7 @@ class TestDocsSnippets(PyScriptTest):

- + """ ) @@ -51,7 +51,7 @@ class TestDocsSnippets(PyScriptTest): packages = ["requests", "pyodide-http"] - + """ ) @@ -83,9 +83,9 @@ class TestDocsSnippets(PyScriptTest): from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" files = ["todo.py"] - +

@@ -143,10 +143,10 @@ class TestDocsSnippets(PyScriptTest): name = "pyodide-0.23.0" lang = "python" - + """ ) @@ -167,7 +167,7 @@ class TestDocsSnippets(PyScriptTest):

- + """ ) btn_manual = self.page.wait_for_selector("#manual") @@ -200,7 +200,7 @@ class TestDocsSnippets(PyScriptTest): def test_guides_asyncio(self): self.pyscript_run( """ - + """ ) py_terminal = self.page.wait_for_selector("py-terminal") @@ -222,7 +222,7 @@ class TestDocsSnippets(PyScriptTest): xterm = true - + """ ) self.page.get_by_text("test-done").wait_for() @@ -249,12 +249,12 @@ class TestDocsSnippets(PyScriptTest): self.pyscript_run( """ - + """ ) self.page.get_by_text("Click Me to Say Hi").click() @@ -270,7 +270,7 @@ class TestDocsSnippets(PyScriptTest):
- + """ ) From 23e1ab81b34974da66bf63d8306610edb8f95a32 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 08:02:19 -0500 Subject: [PATCH 043/105] Docs to the docs repo (#1731) --- .github/workflows/docs-release.yml | 62 --- .github/workflows/docs-review.yml | 53 --- .github/workflows/docs-unstable.yml | 58 --- docs/Makefile | 46 -- docs/README.md | 54 --- docs/_static/examples/what-is-pyscript.html | 52 --- docs/_static/fonts/Hack-Bold.woff | Bin 166044 -> 0 bytes docs/_static/fonts/Hack-BoldItalic.woff | Bin 172708 -> 0 bytes docs/_static/fonts/Hack-Italic.woff | Bin 168384 -> 0 bytes docs/_static/fonts/Hack-Regular.woff | Bin 160716 -> 0 bytes docs/_static/images/pyscript.svg | 16 - docs/_static/redirect.html | 1 - docs/_static/s3_error.html | 4 - docs/changelog.md | 94 ---- docs/concepts/governance/maintainers.md | 1 - docs/concepts/governance/policy.md | 1 - docs/concepts/index.md | 12 - docs/concepts/what-is-pyscript.md | 33 -- docs/conf.py | 108 ----- docs/development/deprecation-cycle.md | 38 -- docs/development/developing.md | 222 --------- docs/development/index.md | 12 - docs/development/setting-up-environment.md | 285 ----------- docs/environment.yml | 19 - docs/error.md | 3 - docs/guides/asyncio.md | 35 -- docs/guides/custom-plugins.md | 225 --------- docs/guides/event-handlers.md | 179 ------- docs/guides/http-requests.md | 224 --------- docs/guides/index.md | 22 - docs/guides/passing-objects.md | 295 ------------ docs/img/diataxis.png | Bin 110191 -> 0 bytes docs/img/pyodide-pyscript.png | Bin 24872 -> 0 bytes docs/index.md | 58 --- docs/make.bat | 35 -- docs/reference/API/__version__.md | 8 - docs/reference/API/attr_to_event.md | 85 ---- docs/reference/API/display.md | 87 ---- docs/reference/API/element.md | 309 ------------ docs/reference/API/version_info.md | 16 - docs/reference/API/when.md | 51 -- docs/reference/elements/py-config.md | 493 -------------------- docs/reference/elements/py-repl.md | 62 --- docs/reference/elements/py-script.md | 126 ----- docs/reference/exceptions.md | 52 --- docs/reference/faq.md | 160 ------- docs/reference/index.md | 54 --- docs/reference/modules/pyscript.md | 77 --- docs/reference/plugins/py-splashscreen.md | 65 --- docs/reference/plugins/py-terminal.md | 82 ---- docs/robots.txt | 5 - docs/tutorials/getting-started.md | 275 ----------- docs/tutorials/index.md | 38 -- docs/tutorials/py-click.md | 127 ----- docs/tutorials/py-config-fetch.md | 188 -------- docs/tutorials/py-config-interpreter.md | 88 ---- docs/tutorials/requests.md | 123 ----- docs/tutorials/writing-to-page.md | 212 --------- 58 files changed, 5030 deletions(-) delete mode 100644 .github/workflows/docs-release.yml delete mode 100644 .github/workflows/docs-review.yml delete mode 100644 .github/workflows/docs-unstable.yml delete mode 100644 docs/Makefile delete mode 100644 docs/README.md delete mode 100644 docs/_static/examples/what-is-pyscript.html delete mode 100644 docs/_static/fonts/Hack-Bold.woff delete mode 100644 docs/_static/fonts/Hack-BoldItalic.woff delete mode 100644 docs/_static/fonts/Hack-Italic.woff delete mode 100644 docs/_static/fonts/Hack-Regular.woff delete mode 100644 docs/_static/images/pyscript.svg delete mode 100644 docs/_static/redirect.html delete mode 100644 docs/_static/s3_error.html delete mode 100644 docs/changelog.md delete mode 120000 docs/concepts/governance/maintainers.md delete mode 120000 docs/concepts/governance/policy.md delete mode 100644 docs/concepts/index.md delete mode 100644 docs/concepts/what-is-pyscript.md delete mode 100644 docs/conf.py delete mode 100644 docs/development/deprecation-cycle.md delete mode 100644 docs/development/developing.md delete mode 100644 docs/development/index.md delete mode 100644 docs/development/setting-up-environment.md delete mode 100644 docs/environment.yml delete mode 100644 docs/error.md delete mode 100644 docs/guides/asyncio.md delete mode 100644 docs/guides/custom-plugins.md delete mode 100644 docs/guides/event-handlers.md delete mode 100644 docs/guides/http-requests.md delete mode 100644 docs/guides/index.md delete mode 100644 docs/guides/passing-objects.md delete mode 100644 docs/img/diataxis.png delete mode 100644 docs/img/pyodide-pyscript.png delete mode 100644 docs/index.md delete mode 100644 docs/make.bat delete mode 100644 docs/reference/API/__version__.md delete mode 100644 docs/reference/API/attr_to_event.md delete mode 100644 docs/reference/API/display.md delete mode 100644 docs/reference/API/element.md delete mode 100644 docs/reference/API/version_info.md delete mode 100644 docs/reference/API/when.md delete mode 100644 docs/reference/elements/py-config.md delete mode 100644 docs/reference/elements/py-repl.md delete mode 100644 docs/reference/elements/py-script.md delete mode 100644 docs/reference/exceptions.md delete mode 100644 docs/reference/faq.md delete mode 100644 docs/reference/index.md delete mode 100644 docs/reference/modules/pyscript.md delete mode 100644 docs/reference/plugins/py-splashscreen.md delete mode 100644 docs/reference/plugins/py-terminal.md delete mode 100644 docs/robots.txt delete mode 100644 docs/tutorials/getting-started.md delete mode 100644 docs/tutorials/index.md delete mode 100644 docs/tutorials/py-click.md delete mode 100644 docs/tutorials/py-config-fetch.md delete mode 100644 docs/tutorials/py-config-interpreter.md delete mode 100644 docs/tutorials/requests.md delete mode 100644 docs/tutorials/writing-to-page.md diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml deleted file mode 100644 index 2978d7a9..00000000 --- a/.github/workflows/docs-release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: "[Docs] Build Release" - -on: - release: - types: [published] - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-${{ github.ref_name }} - path: docs/_build/html/ - - # Deploy to S3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - - name: Copy redirect file - run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html - - - name: Sync to S3 - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/ - - # Make sure to remove the latest folder so we sync the full docs upon release - - name: Delete latest directory - run: aws s3 rm --recursive s3://docs.pyscript.net/latest/ - - # Note that the files are the same as above, but we want to have folders with - # // AND /latest/ which latest will always point to the latest release - - name: Sync to /latest - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/ diff --git a/.github/workflows/docs-review.yml b/.github/workflows/docs-review.yml deleted file mode 100644 index 37ba5b13..00000000 --- a/.github/workflows/docs-review.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: "[Docs] Build Review" - -on: - pull_request: - branches: - - "*" - paths: - - docs/** - -concurrency: - # Concurrency group that uses the workflow name and PR number if available - # or commit SHA as a fallback. If a new build is triggered under that - # concurrency group while a previous build is running it will be canceled. - # Repeated pushes to a PR will cancel all previous builds, while multiple - # merges to main will not cancel. - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} - cancel-in-progress: true - -jobs: - build: - if: github.repository_owner == 'pyscript' - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-review-${{ github.event.number }} - path: docs/_build/html/ diff --git a/.github/workflows/docs-unstable.yml b/.github/workflows/docs-unstable.yml deleted file mode 100644 index 0d093db5..00000000 --- a/.github/workflows/docs-unstable.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: "[Docs] Build Latest" - -on: - push: - branches: - - main - paths: - - docs/** - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - env: - SPHINX_HTML_BASE_URL: https://docs.pyscript.net/ - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token. - fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository. - - - name: Setup - uses: conda-incubator/setup-miniconda@v2 - with: - auto-update-conda: true - activate-environment: docs - environment-file: docs/environment.yml - python-version: "3.9" - - - name: Build - shell: bash -l {0} - run: | - cd docs/ - make html - - - name: Upload artifacts - uses: actions/upload-artifact@v3 - with: - name: pyscript-docs-latest - path: docs/_build/html/ - - # Deploy to S3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - # Sync will only copy changed files - - name: Sync Error - run: aws s3 cp --quiet ./docs/_static/s3_error.html s3://docs.pyscript.net/error.html - - # Sync will only copy changed files - - name: Sync to S3 - run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/ diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index af47bc08..00000000 --- a/docs/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build -CONDA_ENV ?= _env - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -env := $(CONDA_ENV) -conda_run := conda run -p $(env) - -setup: - @if [ -z "$${CONDA_SHLVL:+x}" ]; then echo "Conda is not installed." && exit 1; fi - $(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml - -clean: - rm -rf $(BUILDDIR) - -clean-all: clean - rm -rf $(env) *.egg-info - -shell: - @export CONDA_ENV_PROMPT='<{name}>' - @echo 'conda activate $(env)' - -htmlserve: html - @echo 'visit docs at http://localhost:8080' - python -m http.server -d "$(BUILDDIR)/html/" 8080 - -livehtml: - sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - - -.PHONY: help Makefile setup clean clean-all shell - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 59dd0d2a..00000000 --- a/docs/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# PyScript documentation - -Welcome to the PyScript documentation directory, where you can find -and contribute to discussions around PyScript and related topics. - -## Getting started - -Before you start contributing to the documentation, it's worthwhile to -take a look at the general contributing guidelines for the PyScript project. You can find these guidelines here -[Contributing Guidelines](https://github.com/pyscript/pyscript/blob/main/CONTRIBUTING.md) - -## Documentation Principles - -The PyScript documentation is based on a documentation framework called [Diátaxis](https://diataxis.fr/). This framework helps to solve the problem of structure in technical documentation and identifies four modes of documentation - **tutorials, how-to guides, technical reference and explanation**. Each one of these modes answers to a different user need, fulfills a different purpose and requires a different approach to its creation. - -The picture below gives a good visual representation of that separation of concerns: - -![pyodide-pyscript](./img/diataxis.png) - -So, please keep that in mind when contributing to the project documentation. For more information on, make sure to check [their website](https://diataxis.fr/). - -### Setup - -The `docs` directory in the pyscript repository contains a -[Sphinx](https://www.sphinx-doc.org/) documentation project. Sphinx is a system -that takes plaintext files containing documentation written in Markdown, along with -static files like templates and themes, to build the static end result. - -### Build - -To learn how to build the docs, head over the [CONTRIBUTING](../CONTRIBUTING.md) page. - - -## Cross-referencing - -You can link to other pages in the documentation by using the `{doc}` role. For example, to link to the `docs/README.md` file, you would use: - -```markdown -{doc}`docs/README.md` -``` - -You can also cross-reference the python glossary by using the `{term}` role. For example, to link to the `iterable` term, you would use: - -```markdown -{term}`iterable` -``` - -You can also cross-reference functions, methods or data attributes by using the `{attr}` for example: - -```markdown -{py:func}`repr` -``` - -This would link to the `repr` function in the python builtins. diff --git a/docs/_static/examples/what-is-pyscript.html b/docs/_static/examples/what-is-pyscript.html deleted file mode 100644 index ee639cf6..00000000 --- a/docs/_static/examples/what-is-pyscript.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - -

Let's plot random numbers

-
-
-

❰py❱

-
-
- - - packages = [ - "numpy", - "matplotlib" - ] - - - -import matplotlib.pyplot as plt -import numpy as np - -x = np.random.randn(1000) -y = np.random.randn(1000) - -fig, ax = plt.subplots() -ax.scatter(x, y) -pyscript.write('plot', fig) - - - diff --git a/docs/_static/fonts/Hack-Bold.woff b/docs/_static/fonts/Hack-Bold.woff deleted file mode 100644 index 35feb8f859d5f39d8ba7ef1d4fc3f1bd03370206..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166044 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 Rjz^6o;=6U8hGdEztz16VU~;MG}(gM&_ZaB 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 z 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�^(NL2!MI5t_QPz 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 ALI3~& diff --git a/docs/_static/fonts/Hack-Italic.woff b/docs/_static/fonts/Hack-Italic.woff deleted file mode 100644 index 037a0b3ef62b282e18762ad216197dc59afa1ee8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168384 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 z 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 z∋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 S`{i_R5 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 diff --git a/docs/_static/images/pyscript.svg b/docs/_static/images/pyscript.svg deleted file mode 100644 index 8d32dcac..00000000 --- a/docs/_static/images/pyscript.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - diff --git a/docs/_static/redirect.html b/docs/_static/redirect.html deleted file mode 100644 index 3c3a36bc..00000000 --- a/docs/_static/redirect.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/docs/_static/s3_error.html b/docs/_static/s3_error.html deleted file mode 100644 index a3b97055..00000000 --- a/docs/_static/s3_error.html +++ /dev/null @@ -1,4 +0,0 @@ - -

404 - File not found

-

You will be redirected to the latest documentation in 5 seconds.

- diff --git a/docs/changelog.md b/docs/changelog.md deleted file mode 100644 index efc26b67..00000000 --- a/docs/changelog.md +++ /dev/null @@ -1,94 +0,0 @@ -# Release Notes - -2023.XX.X -========= - - -Features --------- - -- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal. -- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes. -- Added the `@when` decorator for attaching Python functions as event handlers -- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release. - - -### Runtime py- attributes - -- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435)) - -### <script type="py"> -- Added the ability to optionally use ` - - - - - plugins = ["./hello-world.py"] - - - -``` - -Now we need to start a live server to serve our page. You can use Python's `http.server` module for this. - -```bash -python -m http.server -``` - -Now you can open your browser and go to `http://localhost:8000` to see the page. You might be surprised that the text "Hello World" is not on the page. This is because we need to do a few more things to make our plugin work. - -First, we must create a custom element that our plugin will use. We can use a decorator in our `PyHelloWorld` class. - -```python -from pyscript import Plugin, js - -plugin = Plugin("PyHelloWorld") - -@plugin.register_custom_element("py-hello-world") -class PyHelloWorld: - def __init__(self, element): - self.element = element - - def connect(self): - self.element.innerHTML = "
Hello World!
" -``` - -Now that we have registered our custom element, we can use the custom tag `` to add our plugin to the page. - -```html - - - - - - - Python Plugin - - - - - - - - plugins = ["./hello-world.py"] - - - - - -``` - -Now, if you go to `http://localhost:8000` you should see the text "Hello World" on the page. - -Writing plugins in Python is an excellent way if you want to use PyScript's API's. However, if you want to write plugins in Javascript, you can do that too. - -## Javascript plugins - -Javascript plugins need to have a specific structure to be loaded by PyScript. The plugin export a default class with the following method, which may implement any, all, or none of the [Plugin lifecycle methods](https://github.com/pyscript/pyscript/blob/main/pyscriptjs/src/plugin.ts#L9-L65). These method will be called at the corresponding points in lifecycle of PyScript as it loads, configures itself and its Python interpreter, and executes `` and `` tags. - -```{note} -You need to specify the file extension `.js` when adding your custom plugin to the `` tag. -``` - -### Creating a Hello World plugin - -Let's create a simple plugin that will add the text "Hello World" to the page. We will create a `hello-world.js` file and write the plugin class. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - // Code goes here - } -} -``` - -Now we need to add the code that will add the text to the page. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - const elem = document.createElement("h1"); - elem.innerText = "Hello World"; - document.body.appendChild(elem); - } -} -``` - -Finally, we need to add the plugin to our page's `` tag. - -```html - - - - - - - Javascript Plugin - - - - - - - - plugins = ["./hello-world.js"] - - - -``` - -Now we need to start a live server to serve our page. You can use Python's `http.server` module for this. - -```bash -python -m http.server -``` - -Now you can open your browser and go to `http://localhost:8000` to see the page. You should see the text "Hello World" on the page. - -```{note} -Because we are using a local file, you must start a live server. Otherwise, Pyscript will not be able to fetch the file. -``` - -### Expanding the Hello World plugin - -As you can see, we could build all our plugin logic inside the `afterStartup` method. You may also want to create a custom html element for your plugin. Let's see how we can do that. - -First, we need to create a custom html element. Let's start by creating our `PyHelloWorld` class that extends the `HTMLElement` class. - - -```js -class PyHelloWorld extends HTMLElement { - constructor() { - super(); - } - - connectedCallback() { - this.innerHTML = `

Hello, world!

`; - this.mount_name = this.id; - } -} -``` - -We can now register our custom element in the `afterStartup` method of our `HelloWorldPlugin` class. We will also add the custom tag `py-hello-world` to the page. - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - // Create a custom element called - customElements.define("py-hello-world", PyHelloWorld); - - // Add the custom element to the page so we can see it - const elem = document.createElement('py-hello-world'); - document.body.append(elem); - } -} -``` - -Now we can open our page and see the custom element on the page. - -By now, you should have a good idea for creating a custom plugin. Also, how powerful it can be to create custom elements that other users could use in their PyScript pages. diff --git a/docs/guides/event-handlers.md b/docs/guides/event-handlers.md deleted file mode 100644 index 7546ccc4..00000000 --- a/docs/guides/event-handlers.md +++ /dev/null @@ -1,179 +0,0 @@ -# Event handlers in PyScript - -PyScript offer two ways to subscribe to Javascript event handlers: - -## Subscribe to event with `py-*` attributes - -The value of the attribute contains python code which will be executed when the event is fired. A very common pattern is to call a function which does further work, for example: - -```html - - -``` - -```python - - def say_hello_no_param(): - print("Hello!") - - def say_hello_with_param(name): - print("Hello " + name + "!") - -``` - -Note that py-\* attributes need a _function call_ - -Supported py-\* attributes can be seen in the [PyScript API reference](<[../api-reference.md](https://github.com/pyscript/pyscript/blob/66b57bf812dcc472ed6ffee075ace5ced89bbc7c/pyscriptjs/src/components/pyscript.ts#L119-L260)>). - -## Subscribe to event with `addEventListener` - -You can also subscribe to an event using the `addEventListener` method of the DOM element. This is useful if you want to pass event object to the event handler. - -```html - -``` - -```python - - from js import console, document - from pyodide.ffi.wrappers import add_event_listener - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - add_event_listener(document.getElementById("two"), "click", hello_args) - -``` - -or using the `addEventListener` method of the DOM element: - -```html - -``` - -```python - - from js import console, document - from pyodide.ffi import create_proxy - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - document.getElementById("three").addEventListener("click", create_proxy(hello_args)) - -``` - -or using the PyScript Element class: - -```html - -``` - -```python - - from js import console - from pyodide.ffi import create_proxy - - def hello_args(*args): - console.log(f"Hi! I got some args! {args}") - - Element("four").element.addEventListener("click", create_proxy(hello_args)) - -``` - -## JavaScript to PyScript and From PyScript to JavaScript - -If you're wondering about how to pass objects from JavaScript to PyScript and/or the other way around head over to the [Passing Objects](passing-objects.md) page. - - -### Exporting all Global Python Objects - -We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: - -```python - - from js import createObject - from pyodide.ffi import create_proxy - createObject(create_proxy(globals()), "pyodideGlobals") - -``` - -This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. - -(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a ` -``` - -### Exporting Individual Python Objects - -We can also export individual Python objects to the JavaScript global scope if we wish. - -(As above, the following example uses a button to delay the execution of the ` -``` diff --git a/docs/guides/http-requests.md b/docs/guides/http-requests.md deleted file mode 100644 index bdcd0564..00000000 --- a/docs/guides/http-requests.md +++ /dev/null @@ -1,224 +0,0 @@ -# How to make HTTP requests using `PyScript`, in pure Python - -[Pyodide](https://pyodide.org), the interpreter that underlies `PyScript`, does not have the `requests` module -(or other similar modules) available by default, which are traditionally used to make HTTP requests in Python. -However, it is possible to make HTTP requests in Pyodide using the modern `JavaScript` `fetch` API -([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch)). This example shows how to make common HTTP request -(GET, POST, PUT, DELETE) to an API, using only Python code! We will use asynchronous functions with -async/await syntax, as concurrent code is preferred for HTTP requests. - -The purpose of this guide is not to teach the basics of HTTP requests, but to show how to make them -from `PyScript` using Python, since currently, the common tools such as `requests` and `httpx` are not available. - -## Fetch - -The `fetch` API is a modern way to make HTTP requests. It is available in all modern browsers, and in Pyodide. - -Although there are two ways to use `fetch`: -1) using `JavaScript` from `PyScript` -2) using Pyodide's Python wrapper, -`pyodide.http.pyfetch` - -This example will only show how to use the Python wrapper. Still, the -[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) is a useful reference, as its -parameters can be called from Python using the `pyfetch` wrapper. - -## Pyodide.http, pyfetch, and FetchResponse - -The [pyodide.http module](https://pyodide.org/en/stable/usage/api/python-api/http.html#module-pyodide.http) is a Python API -for dealing with HTTP requests. It provides the `pyfetch` function as a wrapper for the `fetch` API, -which returns a `FetchResponse` object whenever a request is made. Extra keyword arguments can be passed to `pyfetch` -which will be passed to the `fetch` API. - -The returned object `FetchResponse` has familiar methods and properties -for dealing with the response, such as `json()` or `status`. See the -[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse) -for more information. - -## Example - -We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`. -First we write a helper function in pure Python that makes a request and returns the response. This function -makes it easier to make specific types of requests with the most common parameters. - -## Python convenience function - -```python -from pyodide.http import pyfetch, FetchResponse -from typing import Optional, Any - -async def request(url: str, method: str = "GET", body: Optional[str] = None, - headers: Optional[dict[str, str]] = None, **fetch_kwargs: Any) -> FetchResponse: - """ - Async request function. Pass in Method and make sure to await! - Parameters: - url: str = URL to make request to - method: str = {"GET", "POST", "PUT", "DELETE"} from `JavaScript` global fetch()) - body: str = body as json string. Example, body=json.dumps(my_dict) - headers: dict[str, str] = header as dict, will be converted to string... - Example, headers=json.dumps({"Content-Type": "application/json"}) - fetch_kwargs: Any = any other keyword arguments to pass to `pyfetch` (will be passed to `fetch`) - Return: - response: pyodide.http.FetchResponse = use with .status or await.json(), etc. - """ - kwargs = {"method": method, "mode": "cors"} # CORS: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing - if body and method not in ["GET", "HEAD"]: - kwargs["body"] = body - if headers: - kwargs["headers"] = headers - kwargs.update(fetch_kwargs) - - response = await pyfetch(url, **kwargs) - return response -``` - -This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function, -so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools. -The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore, -the script containing this function must be importable by `PyScript`. - -For this example, we will name the file containing the Python code `request.py` and place it in the same directory as the file -containing the html code, which is described below. - -## `PyScript` HTML code - -In this How-to, the HTML code is split into separate code blocks to enable context highlighting (coloring of the Python -code inside the html code block), but in reality it is all in the same file. The first part is a bare bones `PyScript` -html page, using the [community examples](https://github.com/pyscript/pyscript-collective/) set-up. The second part is -the actual Python code for HTTP requests, which is wrapped in `` tags, while the third block has the -concluding html code. - -```html - - - - - - - GET, POST, PUT, DELETE example - - - - - - - [[fetch]] - files = ["/request.py"] - - - -

- Hello world request example!
- Here is the output of your request: -

- - import asyncio - import json - from request import request # import our request function. - - async def main(): - baseurl = "https://jsonplaceholder.typicode.com" - - # GET - headers = {"Content-type": "application/json"} - response = await request(f"{baseurl}/posts/2", method="GET", headers=headers) - print(f"GET request=> status:{response.status}, json:{await response.json()}") - - # POST - body = json.dumps({"title": "test_title", "body": "test body", "userId": 1}) - new_post = await request(f"{baseurl}/posts", body=body, method="POST", headers=headers) - print(f"POST request=> status:{new_post.status}, json:{await new_post.json()}") - - # PUT - body = json.dumps({"id": 1, "title": "test_title", "body": "test body", "userId": 2}) - new_post = await request(f"{baseurl}/posts/1", body=body, method="PUT", headers=headers) - print(f"PUT request=> status:{new_post.status}, json:{await new_post.json()}") - - # DELETE - new_post = await request(f"{baseurl}/posts/1", method="DELETE", headers=headers) - print(f"DELETE request=> status:{new_post.status}, json:{await new_post.json()}") - - asyncio.ensure_future(main()) - - -
-

- You can also use other methods. See fetch documentation:
- https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters -

-
-
-

- See pyodide documentation for what to do with a FetchResponse object:
- https://pyodide.org/en/stable/usage/api/python-api.html#pyodide.http.FetchResponse -

-
- - -``` - -## Explanation -### `py-config` tag for importing our Python code -The very first thing to notice is the `py-config` tag. This tag is used to import Python files into the `PyScript`. -In this case, we are importing the `request.py` file, which contains the `request` function we wrote above. - -### `py-script` tag for making async HTTP requests - -Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`, -which are required or helpful for the `request` function. -The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic -HTTP requests. The `await` keyword is required not only for the `request` function, but also for certain methods of the -`FetchResponse` object, such as `json()`, meaning that the code is asynchronous and slower requests will not block the -faster ones. - -### HTTP Requests - -HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from -a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the -local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also -through HTTP requests. - -In our example, we show how to pass in a request `body`, `headers`, and specify the request `method`, in order to make -`GET`, `POST`, `PUT`, and `DELETE` requests, although methods such as `PATCH` are also available. Additional -parameters for the `fetch` API are also available, which can be specified as keyword arguments passed to our helper -function or to `pyfetch`. See the -[fetch documentation](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) for more information. -HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and -[RFC 9110](https://www.rfc-editor.org/info/rfc9110). - -## Conclusion - -This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python -code/files into the `PyScript` using the `py-config` tag is also covered. - -Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`, -or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing! - -## API Quick Reference - -## pyodide.http.pyfetch - -### pyfetch Usage - -```python -await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse -``` - -Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`. - -- [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch) - -## pyodide.http.FetchResponse - -### FetchResponse Usage - -```python -response: pyodide.http.FetchResponse = await -status = response.status -json = await response.json() -``` - -Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async) -methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc. - -- [`FetchResponse` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse) diff --git a/docs/guides/index.md b/docs/guides/index.md deleted file mode 100644 index b39f2341..00000000 --- a/docs/guides/index.md +++ /dev/null @@ -1,22 +0,0 @@ -# Guides - -Welcome to the how-to documentation section for PyScript. If you've already -gained some experience with PyScript before and just need practical guides -to get your ideas realized, you can learn step by step how to use PyScript here. - -```{note} -Please head over to the [tutorials](../tutorials/index.md) section if you're only getting started. -``` - -```{toctree} ---- -maxdepth: 2 -glob: -caption: 'Contents:' ---- -passing-objects -http-requests -asyncio -custom-plugins -event-handlers -``` diff --git a/docs/guides/passing-objects.md b/docs/guides/passing-objects.md deleted file mode 100644 index f7ef966c..00000000 --- a/docs/guides/passing-objects.md +++ /dev/null @@ -1,295 +0,0 @@ -# How to Pass Objects from PyScript to Javascript (and Vice Versa) - -[Pyodide](https://pyodide.org), the interpreter that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other. - -This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html). - -For our purposes, an 'object' is anything that can be bound to a variable (a number, string, object, [function](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), etc). - -## JavaScript to PyScript - -We can use the syntax `from js import ...` to import JavaScript objects directly into PyScript. Simple JavaScript objects are converted to equivalent Python types; these are called [implicit conversions](https://pyodide.org/en/stable/usage/type-conversions.html#implicit-conversions). More complicated objects are wrapped in [JSProxy](https://pyodide.org/en/stable/usage/type-conversions.html) objects to make them behave like Python objects. - -`import js` and `from js import ...` [in Pyodide](https://pyodide.org/en/stable/usage/type-conversions.html#type-translations-using-js-obj-from-py) get objects from the [JavaScript globalThis scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis), so keep the[ rules of JavaScript variable scoping](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/) in mind. - -```html - -``` -```python - - # Import and use JS function and variable into Python - from js import name, addTwoNumbers - - print(f"Hello {name}") - print("Adding 1 and 2 in Javascript: " + str(addTwoNumbers(1, 2))) - -``` - -## PyScript to JavaScript - -### Using Pyodide's globals access - -The [PyScript JavaScript module](../reference/modules/pyscript.md) exposes its underlying Pyodide interpreter as `PyScript.interpreter`, and maintains a reference to the [globals()](https://docs.python.org/3/library/functions.html#globals) dictionary of the Python namespace. Thus, any global variables in python are accessible in JavaScript at `PyScript.interpreter.globals.get('my_variable_name')` - -```html - - x = 42 - - - - -``` - -Since [everything is an object](https://docs.python.org/3/reference/datamodel.html) in Python, this applies not only to user created variables, but also to classes, functions, built-ins, etc. If we want, we can even apply Python functions to JavaScript data and variables: - -```html - - - - - -``` - -### Using JavaScript's eval() - -There may be some situations where it isn't possible or ideal to use `PyScript.interpreter.globals.get()` to retrieve a variable from the Pyodide global dictionary. For example, some JavaScript frameworks may take a function/Callable as an html attribute in a context where code execution isn't allowed (i.e. `get()` fails). In these cases, you can create JavaScript proxies of Python objects more or less "manually" using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval). - -First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace. - -Include the following script tag anywhere in your html document: - -```html - -``` - -This function takes a Python Object and creates a variable pointing to it in the JavaScript global scope. - -### Exporting all Global Python Objects - -We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object: - -```python - - from js import createObject - from pyodide.ffi import create_proxy - createObject(create_proxy(globals()), "pyodideGlobals") - -``` -This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`. - -(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a ` -``` - -#### Full example - -```html - - - - - - - Exporting all Global Python Objects - - - - - - - - - - - from js import createObject - from pyodide.ffi import create_proxy - - createObject(create_proxy(globals()), "pyodideGlobals") - - # create some Python objects: - symbols = {'pi': 3.1415926, 'e': 2.7182818} - - def rough_exponential(x): - return symbols['e']**x - - class Circle(): - def __init__(self, radius): - self.radius = radius - - @property - def area(self): - return symbols['pi'] * self.radius**2 - - - - -``` - - -### Exporting Individual Python Objects - -We can also export individual Python objects to the JavaScript global scope if we wish. - -(As above, the following example uses a button to delay the execution of the ` -``` - -#### Full example - -```html - - - - - - - Exporting Individual Python Objects - - - - - - - - - - import js - from pyodide.ffi import create_proxy - - # Create 3 python objects - language = "Python 3" - animals = ['dog', 'cat', 'bird'] - multiply3 = lambda a, b, c: a * b * c - - # js object can be named the same as Python objects... - js.createObject(language, "language") - - # ...but don't have to be - js.createObject(create_proxy(animals), "animals_from_py") - - # functions are objects too, in both Python and Javascript - js.createObject(create_proxy(multiply3), "multiply") - - - - - - -``` diff --git a/docs/img/diataxis.png b/docs/img/diataxis.png deleted file mode 100644 index a9518ce5da727d7d908cd2d524627e70baab9541..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110191 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�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 z%0D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 diff --git a/docs/img/pyodide-pyscript.png b/docs/img/pyodide-pyscript.png deleted file mode 100644 index 300d8a7cc70974abfeedf9d0f82f3cb19d157525..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24872 zcmce8Ra9JC&?Y3oH35P{2*KSQ5;VBGySp};1oz+$!P2<9ySrQC?$Ef-$^F-?nb&z4 z9%yJzuOoX`)hAViD#%HoArm0Oz`&qMeiv1Ofr0G>ett!S2fqJMAAN*@F*uVH{ifoP zegbjz&{2KpxHxO*flOOWe{prshQ~$@+^qQbHL%&#&Y_X0>#b>{X<+y>FsE1R@bomM z&e1(W)oq`vlAoRl{hlj}W>7>o<>rWGS1D~S5x42~b5XbJrBdh-fNi)cA zMf%&vX~so1_eDN6{aOu?4e=$LBTxOHOw%sc6bbU*b+cOgwe&`i|Axg&`X*PYh`NC8 zIGfr_t%4=Q${9_hWvkKaPFK`Z^vd%k6oWA;3D>2?|yG|M8%#Mf(OOJz= z2VVY3F=EQzRs?~j^`?v&r{+1mi+R+37BF!@= z<>rf(Jh0>y@zi|w6sVJY#+%#^=YHwrJTwC`158u9c3cc{{3EWTFi!~Ph0-j41*n_E_ zYHcXw$Hu>>65vJ}`;=U%^C1TlT*$6|xfUCtK`B4=%gAC?zj6JZgS8|ZR_r`?t41V@ikA?nnimhQ(>62TunQxU@}$XW ztE4rT)eoL1k3=RKtd4u>2|HE=PS;Z2{hrZ^jfPW;kj9ewa8x4z4-=JE;J)_6om0A4 z<}BahLC#H94*1|1Tr(W>Za?_`bQ{BlX<>1G0};0-1^Z+{ky@n{KOFO|u%XZUk7@Z3 z*4nuxy|BM$3l-O{h;M~|u>5!wUl}DtcohSQfb@gOc|ZBz24dy}Q#_y>8qSD$r#=Ah ze&+oosfbAC*_m*m?(pa86BVu8jVpByaV$1)Xp+tcSC--`^;=iG|NV{(TE@u3Q)B~k zO!7W?M(SftImP1_CEGHxV$SArkpne?{Gd-FpLl8;1>8_urTP)qHVWc}+%v6eIARs! zBpq9iL=akP^$Oypr1O#kFJKO|P5J9aX|m%V;|IghQ59)%Hn(z~PzXvtrpv-< z6PF*T@@}>mg`3q)<9+cAP8tjE)Vm;J6zEcT-EKpds4@CV(YuEF$ic(W z_~bec^&yt3Z(=)8*ZJs0GhcoOCzkPD0mj#pbVwFwfw$qZh2N8`o&qB5=u^4H;U38+ z9vPF}3hZBV-TKR$Dt=3Ju|eWO~z?rKN!D zUMCN(nT@GMys^@Q{B$_?Kb+#Z5%MNPAuGe361bPR(LILULXS`P3Tx9JTa6x@-<`dS zQqTOIw;+#JkXN8qphyR=GQg;rdhvE~mIr%2$<0bAU$`^ad3A5rr@Znr_<0W-J|Xk4 z&#Fux6h8eDx+-#~I#tRqbYHG>J&iWwQt@VpPhwT1c*YGcO{-9xLd3HvP^wVa*8bjI zh}?zNa_0b>Q-6OY;fk&-qWu@sbo*}qNY+5fpm4qdOP}8tjL4=eFx69Lf1RLM?h40E zA@i*QdXk$rEbT)Ozw$9cl~vUpC6w>j<&?)?DO(skWu$`N?4pwf8QZwb^>#QGVW&ki zev)u&7$4h&*f6dv8S+d*DTC$Aq+d8;K10YG`EOX&Ov*M#yU%`W#=-rVwKJ8tusdD8 z!VDD@Y4FrwyPosU{MV$3v*Ksv-U%`EyH=R^^xmGQ9mK6ctK1bQHWw`Sq+npyR?jxL0y~ z&UoYf!Qz~%lP|OV#25AloiXEExE81LtkOiL5;`N(8>>F}$kS0~*zYv*JKq--{|3lV zPT;NAj2cx}}vfDl<)k*%57WDsa`GUj%8>^7J-WQQ#jk9@$^M1cWS*DdT_)n zN(k?wM6|&b(Jt?scr~<@r%puGMV>xv#7J>(!fH?COZekH#u;(q5qj&x#B<_hyJBP( zAiLFSOxmClEnc`gTgbFo2sKgPuq)xDtN#KS5cA)?m`Lo0MP!A)te5ob)ZH38%@NSB zRU^TNezJC+gGT$?J1EWs;;DF+5qjfv+L74|Ek}&n89SYSu_N^?CZ~}@B^YOlv+I-H z8rxnEC1T_gZgJ;tmwA9=I(bGAGGm}xz>^8^nof0V^CX1_i5k_VP8QT;NQG_K8LqHy zQ(ju5a4WbCTs)wOlu`6BBrnEPQ(IHJk3c*$uP7R=<;NH$woh}GgynHUd?JAxpivhG$EQvbW80O ze&bw4>n}-$)$sY0m1OBjBRo6}I(zlo(nQTXMt7NgRx3b)yO9HwoW|s!<=k*gjVqxW z0-lSbbyh9!0g8Grgzyw$J$y_5Vshn`o1!kCs%>ku`}Iv~qF$5zHbm}Gs2W;+%(#fq zF}?NLk@p*kaUPO|Gc&yA=*RIVZgVmW+fLgVtXw{Nv{|;h+d~L?9B2o2(o^yU);y}- z2x0K+PQ&yB5FFv@-Rk{GO*-RvuaiBXey8Cg{h0Zdfy<-dHOd~$&4ste)sN)WZza=(&~NqHCU_4dnEZh? zrF2vl3`5q3sWha#1OflKKjWOF>pXB@ieoKeC3;Gqm?LB_;B+6gxa`zd7#vKNj_JFjm(2+E#ql21{3y>-ZknAvO!hq9lKAc zwC=W$a*js4%V3y*u5u0NV!_kv*ic6ORe2 zW?F8l(h(w;1#KMA-jl7;|9k}HG4Xkc4)0}X~b`kC9{!$Wo+V85n%w3A?$eN74uF(Kj#OA__ zD?Ua(z<}v56`j?I0n;jl@ink9_PUX3twX1i|Spw;3S*h~w zpzQ!9pyA;oPvruEW@2mCL9IQT-=`rT%-76kN@ag=1?Sn`PFGYsiEVuwbG<@@)mwbk z6o$GJnpKHd`<$&km|US?ZT!p1W(%$)QT^>ZP>B5-SaCnW)W_~>Q_5MF{DAxR-1OP>a9pFyDBCL~f8E`>8pqq>idBRqzwf?V zt0XfgXFB!^%nABz<3{MH$6`aju(He3u+*-St$?{BSkOCk!dn|PWT)4{nM)Z50B;$z zlJ48&+eZexmkWn3)q_Utwv#h~&Vw4ZW9NolkN)+Jk9M}EtjcadsP zP!=Za-yj)7>D7%e72kElF!h1%AjcI%(F) zD0(LQ8jC6BPQW}0CLwVDEbw_i;6%TQ%RZ-|p*;}r$5F2QNR>DC zIW}F7Ps=yLBa2%&;#<_boWQaGB&LcSk3&3Xg}jhco$vX`rhLgcrnxU;1GanN_nG%b zZMFd$#dZElg11+=nZu7_<1z!4_3wh*H;VRwv^_s&&f;>^@=fDk5i<#%@!SlwH^xO^ zmFTAM50gfce<)JpAP3!3I*YCBl+IOO_0-FtrF9(-XnH$uYJ+XdX8ti9_b;nb4$vge z-z>jFJF%$ksh#;rpVs&NLNCHLb^{16rXSbyueX;PiW_)$!x%Fj5nl}>F!22K@{RM> z95M-R@d|e=j{&Si9jBBzG&3~zpg_F^)ylu{-GwYHn$wNFkr%!DO zX+t2Vqci-?w2oqBeG}h1qD=wg6fDkg2?@atTM@s(zLn9Z_|~fE&$vbg`?sUuTa4!5 z#+YgzJLR9H(ntM0rnnc;YkcFSxn0}!zQd!+ zMOz!*T+noaCwe^5c4CkI`9`{X4`;6+H3bvX3)^6WK)@AWY zwN#v$W|F*0_zG=EVpDq6Ju-le0et(toO`T0jl?-sySlD2 zsHpGod)2A+RPaM zMO+bnYb;D3pKANFsx+R@f+yMVe0tr;y@mhO`ov9|33lfJR!yS% z0$6*SQF|XE3vpS>XnRnYbS|z#_wOS_SCmex>R8>l?xV-G&E*kNPc|De_%DI2kq1ko zYHaEZ?b+jdQYthm`zpLZiLye+?t(afx}nQ523O$kLG z#b#)vr^SjQb-dhGrwTHTRAA2Ro{?4l();;Y7IlZmiRI+SlQ$B&XlilFtTrbe085Gu z8k5DDPpn%NfkVbdhU4@aR-N~85scC+K*qLENp9U%I0XyzEp546%h#uVR4YfVsB-xP*u(#5{!85+T+(jg_4K2HtCsMIop^1GJ+Aj8 zxog&NR08;1^APvRuuIv8ILtzv96&du(XA->zO9Fk+mt-(ie27`maGs!|3 zkwOJlG6Qu-PM>LGkZKrzJ0^hRtgE^h(jIr$mOOB&CygZwz})-LDkcA0@b~dydKoKqDgJTDj>x>!o88$^6#&t@ssX{6Dzl_zjrZPxLOSp34zUB(HT>Cy@^|0_%r#A zU<{J?-U!u9Z6P8GB}@(NTDmJJ5&+zfyx5LGZgHDpiqMN0j~g|5;VZ97lF1d$?L_q9 z(dhJWJu$jZEq!iz=J`6pRHHdOdv zT42^{(o_&D=dLYTJ!4Y8xIoX!z@lyx{+~Z}KcbZdO_TLmq41+8Gi_>V3D#;W?-uTD zRwWAJ8E|#>OXMiTfL#qa`+lI9xeWc>{=K0M61uzWOiLpu@Nz5Xo}t#9K&bu_yZP|J zHvX2Iif1=t;yI zePr`-dNF-bUAjP}i$KB~E$Da;KgU{9let-DUN$q;6vO3p-3+7wUS3tTl7z{1f$ZC(l*lXL< z*s5*GPB*`KLW6S{T`vy3iGcs}r|fsqP0LXJBuWSr*vJ;Ge!E`5uidXxLj7aok<2d30E%+f+x0bx)h&-}$q_Xy zX*ut}H*jvp^gJ&V;kmeud*{pd?9a|_xM!|JN7Gm1u*r%Xs(shlr;jl zznR2Xm+lsN$7xrqcWm3c1mRxeToNOt{dYw&vw)D%b^arpT`O(wmu-!vM&dJ8JD&I3 z>F&QDc6dUrc?e9u8JN>r3W6cDL}sjC0`@jWuH(K_53xm=HnL_qteIW-m}3nPa7*zFE(h53&6gEvC1`hm`ppW=-0X6qJ=0^RI8LjRD^=qbL}Iemsx6b*l+f+!;_9E0QCUX}*D!Ynsi&CoS#E2qvM5}`Q;Ir5eE-3fSEXpI~QvuJy5ZC^=4^_C=e6pWEZ) zNa_Riy!m~c^sZy~mn~3rh)l=bde#!VY&Fuu6|%Cu8shZj0BL5o(DxwKgA)!y9nOMg`l&L^7OrFDUmR25a7PY)xr zKI>|V@HnnkQe!{+;g`?fwg=AI?W9Qh9oHK7c}TEL*>gWiVZbovu;h3|AmVxVw4o1hw`2qd#Q)n&@jSh5L7RdET9e|y{&-0)N z@73>)7oC%^GgoEh)Bu_-PbOha@S%8=Ea&}J!7@>)5h$E(5Wj}ViEFnr-kfPF+`$ci zrszme!En2KQru?Ph^n{qrM48IROofYhUoPmBeBDuY3kY;&BJpAF9*YIosWHbQ~3vh zbvVZcl1sShC3dNt^5EFo1J7TzpzHpX?cthfkDm-WuNCofDmSg_%o zp#@z|tS#Db9xtTeaYsq#FqvrxWkl`)MAQI)9)LP$t|}kv{#iS`4hz)h+;AgL zqfMmI{thB%%uP!24D(l)@+R@v+_=;1SL8RwEI(`B^vOOGj*H+E`F|RvlJcS^@v+V} z7`h{m^%6}ch{SjXJ>7V%AhU=5$V71dgv|PGv&?NPv@-g`&Z5)0qqg1>l-5i7Hb!54 z!GAI|bG!W37zord$%dkG5yvW8YqTRLE|+2A9AZAoVx(57vrED8Gf+xamAaGbal#7A z6~L!bO3Y|wae!*%ecfgorOKb*Q1*_iG);MrL>kKczP4%yE`QNVym*S&x6O3+WP4`! zG6~7gMEKl8Mh#1?xfVkBTilvF|F6=UD_C=mVY%RO?AOXOS2vuqn1F>KC1rfS)qDD0 zR|>|2*Rx7_jg)Gw4@RWaB}|(@5y@P=R|m5wo`3*;2B;#RksN=}SyJy5$E}^8gq{Hy zGkEHO^~LAP$4KH*hG8~FAqh)=GTt3AFUPyaqdv^dLroolF zRLDd;sFist&U7n-RBI_AH6ZjqB?zNVUW26d@WA6vfa?H7nY^)?CsiZ`kGOHlE6Ox?EhA zf$8hrvD0|f3?TGO_3qNE?VOJ7z?(?y4V)m5yA>A=qrg3J|M;|da7OKCa~zJylX9Xe z7JD`dG^c*Z{N*9?ouIR3@Xp+xZO+$I%yAmP*BTuazdUv8DHxv3&`$b_{hIQO4wU9r-(vuRJ2pzYqyTETiK%$A>CMNpqXZ4netJ$6 z{DhNow5ECwKPEA9PiaLT76j=>UzTNCIKE_J&f?`cm}BHX;cpS{?5VyBgX0C9n5QIj zRQ+~rG^wR#n=PB3Y>BY4%PVxX0)}?kt=N(KA&R#9=eIb=n@!F}28y%~c7?ghH`pg9 zGb4;Sw>5rX4GLLsSydx*ny}|=s9uO@!{$st_le|DXJMY`8ch+?;Snacl4HcXwN4-6 zAdA2e3-SQW)`Gk?Z23ruEY6IuI!PsL;SfC))1of*c>xr}@KdV)EKo%)Q{DtK{M~8& z|2cqtfGrlr-%mf7Y-z$8i`&yuK=MW|0G-mZ)UssbtLB<}%4sxwe9;H=wXlwl(N`jK4r3k3GAB_|Ky$zy?{y}Fo-%qIMFLi!2 zHLMg4%~Csc+ISg^%&w-V$X22h%p8H%L~JI+j6quwd&g8HUGS7)t!Cu{L)5(02!~Gl z<;Q*}vaUsu+%t1PJbeM}mwsHHk>VJac_Kf+=?9q{#g(4=y@q%d0@o?u{PLz_jY=R~ z(RjU2^+cYd7Lb>W{ren-50}SZzG!WfIrbY_=XF{g#yof}m&f`_=1F{M*K_B>*&X`0 zyv1*P2f3sAu9-rsJb*MAeWj)J#Ji>4Hg-36P)o{mA2dGQzWHoSdZUK-b~Wmkt_(^> z7vQV)ML~5=|*X#bd+9(2Z&mBoPw zNf0SdEw8fH!K=8k;o;@&7f&i?fMKH}^CkkR1z-2TaBc>J(J8BCt}WjsF@G~=o} zD`N+GIxbMJW&1>qsgJx0Y^?3)c|`< zs>Pj1D?eyUl}aP7dDU_^V;DhqDEqQ|M$0ONgcZlWluH|>-ucflre{JF($6itQ=#;g zLmjo@;d(Lv1I${gQo3rg5ys7}*%04sQM4usrU(A=ZeonUPZNe6n6VQG69~ zNjeBPcq6~Q;X3+samekgre4UKiH-aztNd3%{W8xH>?9j1ndDAN7LVOHckPUv21Mh* zu3D)itZ2ofL%Y8iO2%}hbL`)I3xest`DFYFu=O=ETIUMehI5!Uitgx$g}jbhK*oJ^ zPqg=HD>LH%TtdL>G*IAK>um&9>xuV*^M&<5KA8K9|Mx?IYFC}Em%lX)B6X6UlJ&4y0i?x$T`1$Sp74>EdyO>Z(haF}MvQw|)B0qKOep}g z_pn@A!zW};HK!6B{pXzOpY;=W+ifvzz3$hH$QQ6A`;B|Y4I6({n%9tsm%uI`^#~pO zhDB_;8!)<=aKQBYI88LaF^v06jh8&=fWJFd!gXglH3}%2j`Ix{1IY-D_6znpQNU`>0IT^5I+sNz3}e<# z`@5+`8}IEiX+9F3-0jsb2(zBK;ci%|-RS)6qmoSf<8O1!yjjcf9sYXPKqJ6qSDG(i zZAOo1+I{zJQLS{#GnL)75~_oSjhIYJUjKo4`1M~E_%?%U;<=+;ZLx3T=aN|YY(8e? zF~J(REzlRqsM;{C?x-Zap$MBUiv%wDla$JnCqy91Jl6QFICN#(e4zaK9(ir{*3Y*` zhcUD@dCkrv8EbSJ-Z%XP-+uH70fij*Tz1#}n0ob}Q!K2g`+oe`cdW8p(bnYKjM$U$ ztI$2m5mo10>_aGfV@#%D20XkC}0Ac!AqZK85v}>m_sglLLS~=yD2u#9m(QYo6ZU{q2({H{x z$ccxK)B3v?{sWAE3J$aj-FaT@B7!44tObBRoc~#=YHMdA(k~XN z>Q~4TJ(?gwT#MOr0p)4i|?~@?%CVctCzol6M2r)Ol({!j2kQ4 z6o}8_G|6Qi^@n!nZJ+T`+Q zPjpCaNGs_MB56BvDj6v+S|zmwO=1 zK}CzFfY3FQ-w=fPh1yB2@LM--+Gwq{_c0k?5OM*%JjMZzyF5Lv=g|bklJE3ucy2bs z-u8O_MdKmV#Pne)dZuMW%#ciI4AZ6XB3ho`E-_X-HWh6M%>DYU#2wY1$g>&3+r1*p zQiNurQmdn6DSsgt>y7nuto7Bubqk3d{`WptPhooWSnw9kiF|`?rKZQxI^RmF3tKfg z)2Dp?gwcC#&6sM>4hR{LzoAPn^B|Keeatka?r{xwWDQah8=Z#M(SAPITq&bG2UFeRas!R=23BoYK7~`PB7z@ z?4J|GusS{!aaPF70Q-jFMcl@X?=c+X!xsLDM``Z3V*v|xzOba6EMuu7$A6DeIt&no z+|61CJEufi+|JREk5CF(=g<2c<+Byp(TE31hr5lcS!bA1BH_kRf--rO|79wnWA9W2 zV`lPa304*lqSvN%G`*!qWI89c+a-`|Jr0j`1Lp>?Zc)Z&cP@ag=*EuGJ?J$@}@Qs3Wxv@iMs=1l_MKGpVK9BNCVGK@QOSYOVu4cWizehP9j z?z*OrYW}r6x3YMMYwB0WYK}(!6a>9Xmhb?b38mMeT}%E;rWIeVQ3Pe~laZa_Y7=?e zTF(6#=&W4D5^vVRt9JRG_uPc!`|z=l0h%e%pAW>=O6`UqAY0+>rj10LALy`ou(azr zmrp|uK1Cze;hwn^Nt911FY;4PCyYBPioEA+j^r-K3wl+~t>haq732iKbrvuO8OIUTFkpVFa>Gt0ZH2*$>j{ zMCc>2d^Lw3A(VXY=C1K7uOyW|N%>xk4Vvie<6(_c^`33xU_M9B~eb|oq?=O5gp-p8qdnTP zx@+ZyZgqg7W69U4(DiAriKGC&P@ zx^4piPbVNWexBrm%@_U&T=xBY=Zd9L0DHM_5FdGgGnoj+G&uJyG?94|60MDJ0o?$J z6aHeNV9lt?t>rYAu4r`DJK+Tl#rPvLxd|iPb$^~aW(u8GjWe%`^K>h-(n5VU5Dn*(ZKvG0?cy@m3oP7PTh0{HX z#I*^&?F61)t)sf5>j(~GFF$6&Owy+L`N_W)vxl1ds~Od`1HfH;@_oz#8EpH|r@R7v ztbwNZLY2H;41!>W`dB^JU%{LLeQ+Dq$waK7TM7LDoR$W<7KC%J_xOJ6iZwU-p4UE^ z^^{xIa4MP6nwxJhuJT@<>G6$cRk|i6x1?Y$9C{PHzwsOizFCXak+^@mze0C+>gPgKBlnea@ z#l4oWHnJ8xtKA)1gbIED)@mj>!)r_HMD4KjT7~1~>E081&Nst3cQKrocAv3~MU9Od zb{KZQd#6M@k^r@X&BMIBbPRN?UnB6t^H5moEu#CNB84- zf!JP`=gTB(t~=nVF3#GDgwytLJR7EuYW+p{p-ik$!Kr2QT{)@uaDFmEPQ;;1jzI3e zW=;4&2++f57_exyTeQPzU>gbGUKM1DNaC8_cAjU_WE;xU zwX2ZnBXAjO_>puI#SI(W{&S;WkAMs!$(mWpvfA3>?z>4{Q-!0#diI(|-BOj@ADnAk z|D55#=|4xxa#^%;Ki@=3ZOx=raM-rK!T{ZqFd{HO7l!T4uUYEZyQ617>v7^ISN-#; zV_hPlv1xf%{CW-q-E(}Eh}AbrGcD6_vkgb5ESsX9)i|kBTbozbdW2-~&Tl>_9WP84 z)ySPSiWg>2&Mj0iCPY23t)|WC@%2_W-j|g^`DRGFa!2=BsJU0^!xeC9t^K1Hj zgpJDxT^*w>R!W&dy!L&hQg<{}5>&Nsstx@to$BoM{$M81#{YVyx#JkExO(2{+d>K8 z*9x*3#BF9*k@HvFzXwv&=vD@{iHbSe!XE0|$d=bVFc3(mI$jw4%O2tkONn~E>5yKp zMjwmE;hNAk4&b9S6lkVzJ>61&%B{XaXS=HvriKfq|f5`*%z2ISOj(re@+8x`$x`?BTn-wn(hKN>#cjLFsWjmc;v_IE&| zka#(%wu@YvC}{LB}Z^W`Rfk^oF-~Z7fHa6K7j_ zL18U_tEq5S1|1m~o)HD#@M)?J9<~ro6&E$Rto(Y=VhqLWNnp94Zc-6B8!jz1G?nAD zRK?La$yj?eapeeyN87yI=e}Zm$(Yfk_s#;vzGlc!bxt==_q(VUBXJUFV&aR1Opfk6 zE78$vBxQ+w^U(!IBPpy*biidB(uakeOug8G+|C%iU3ovR@PEI$AnThh);_}Z5izV^ z=6m{XJ2Jl0NxVG3F}nqxbSh}F))(w@&E;=Zq{eRHwtK@S(yhA$9y8hqQypH=SN--) zWS&V2n;LQQ$b;UI`WB7wU`jCBer*T={{TCA?9_;6$-<<_?-S`*`j*nY{IqhTbN@#f zH$F5q>!fIFl|sDD(?Q(oT};S$`%2p||KM!eT(%l@L8V5MPPAP9=ROOQ!3ZAI>uc-! zc-)I6*|?1!gz09Q%YQM^uvm$M;Zwan={6+@y%qI82GpT5#os> zsqz(*9%`-`my%k@rhnn()aEOSOYn*zW2PJa4Xl)EAGTrU43(b9*!=bFmcLdW9KTSD z%?IpXw+PyO2+!eb8}czYqI?1IqlK3q4Q{x+hkr{dmojOn^l~Z6dwaSf-d32c9Yy$O z_R?g^;gnRc3gTpmgA<`&7a!KwXUD_X(e+y)ajdmr`S8dN&egTYuX?*Ab|dBQ{e7ij zXO7!&gx&+37ad*GNwTjNgJqI_WV9Yoo_#2K={2BOAT$Wn9nL}BhTmQ$WzzOKQOiY<1@BbhGhUDF4%@{*G#b}%U=2XVqDlf}_NcanH6mbgi zJ?53}cQ@oUozK**qnfhlS^75YE2T=ImR71AU93h;eX`56dFs;A6g$*+`Ybc2SsGsl zC2FY1j(V_byDPA(ak+~)w=f0OlVEies43f>F0Pf!GasKbQCD$=Lr4;jkNQc2BR6~fA0K$JCt?3hHBO?~5ytjphdH_7;{IPlV^6fc zh*>1^X8_FS`$B_ECd$-kqQIVIlF_p=DxxELdoZ&CHkZy;U|#8tV`=mCuwW-DE;4Yo zMB+%ydi~1JZnX>lj?eYdvO-(3xNKKL7L9R4YA@CxBWlnW);l3-n&BFWOjLruR%`bi ze06Ta@50V(AL1wrv2u!Dls9iY%!g!*_**L$Y-ThFF6IuYEerN~-#&VrE*Qd)5Ty5< z^+$kfUiLbBPPG_36T;%doK7KiF$rQ~8N6`F@+l} zBC>>nhomTIZj@VNvCGlJ*W)yu7gcpea{1~jbEvZp#Zflk-$qkXLhlAxyc2z5<7!>; zRICmeKE4rrU8rma*1u|9frOMLRo-mObYY4~C)2~z&fpUrqt3t|CP7E32&?=z3Bp>@ zftamyebeD+aQFYLE0Jg_v0A0UwLbZ66IUFRxfjs`%WBBp%)IkjrtV6;xq7o}a*0~v zwwWHBhpH(Zglkpm$KSW?$-uzEP_;7J(=KPlAMc=?TQILn@ zsMTJ;0?sfpv|{Nb03VV}j5$C}Dx_y&DmSs#(-)_w+Y9_Ee*ehT%ISfaPl*M(u5HQ8 z+@&s7pl)FQ62Q}$&8}ffKRjw?OBYA3PyDenzT*?%lv<-)-d8fOSr+Edb$?c%!=`5% zF;>)gr~Jl$u%ysTQVqV4gTvf)HOH^OioN=38|fD+yjif=A0^&;b`v%AN_xIHU@=P> zduvK7e)yYG=x|a8b+9Ee9TwO*o=z0TTkPB}+h2Pq$y{B*8fb$KH0NEFO|WSLf7KMx zia*?4tON|wj}B9w)Z}61%wJsg6!NzjqadxWiZ*b_#uA@wgtlkD=c4FvU#Uos@XZ!qVtEw(pSibldZc;Gb>5NQsk|@Os1TfEC-v~%l`L>`d+H_ zvdQzWmxxbSyy)=>PO`@ar*Z^++osYynsmy$XfC(5iya7~&J(`umIPcqRNQqbC2D=o zcag?oDJyj48;yy(_Q#0E3`1V zkz6a4!a*JH)~&TZI6$@DcW_I>cDy(=1@o0rJk}<;v%<0*yNCZN3kmzy2KTd1%ow3*=#H)3&zUuHB-E%8FJ~ zk5g5a&8aUR-eY_yrwWSd(9SiiXy)VUL33OBcyiF2!Qu$eV@6bDvmtx|6sE`svtQ9n zTKQpXR2a@uA;hx`0s8_1zTgHx7+MZSH4OmcKI-T+Hjh~u?sG{K38j_Pso@g(?Ccxb z$$sD59iUzv=I-R!cppFj@o2o4D<$V_&e#bYQ)a}OpEp*qCK8hH@&J5;(2tL0W5XL& z1$bR(@J^}0(L~fVwlNXXhewXnSBDM?lOlE@^6Nv%+%-}ZLu!ndtLeOPxKy&e1y=Wu z=?2jmwu<;L-Jc{TWu5065iS5_BIX@sBTuU zC&<0XgR2Hj+6WbIA%e_k&rc8!D`2caq;^HoHe) zUVyYJLm>J*Zpog~EdMdSvEn{$lN-mE8TE2eKal+fP4Y>&5PAqiVG8!9mD+H=;HvtqNWAqEP++%dz#0TcV_o5F>wG40tKQ^wTo6V%Y+08nbB z(URfJJl!R}m^p2r(0b8E+mch!khl3F1z-i966M!0gZ9ikW@Rizs&|$(CiC^_vm5p_ z66u}}O`pHp|H;eFtY1#vF|*WTly1KZ_?{c16&|QmosxmG^Td~HijcZS%DbK%d>wyH zK_T;Wz;{K9(?%d$JkD*uQir5X7nh*lU^i>osvU?ad}Z!4#ZWb7ls`6g!!A*V4u)}1 zFK!SN{COKqeB!{9$ks1ar`lG!#idcYU0WGl8`(o8-GfNh)4{U7N6^Gd|E5)HbeM*f zTMu#al?Dfyp7Wq^RUhpR)+KAlr24kGT+22LM>yoAPr5jNX61pIZSofWDZ|KrcFE|0 z6Tlkf!YeD1rG=;eO_F;5>$UhPTCNncebB3zvQ?)K487CBMvjzC+Osd6Q18r>_3#*) zDIlgHU;fjT!Z`oU&U{v}-yhWw<$J2pYN=^zLl;4uMB5D%J2zDm2SAF}q#g7CO|kNe zr^l5VeGV}fYS=-A%&%szdQz^%WpFoZ+|yI@b3^spH+=M4<@4^3j;%GRQ7G4B8A`K` z*>Xj0hKMSywYU9C;x3Mf#W#0H5B-5V`#-+6%xI~ZnFB~>6BYRX0{WC+l$f@TAJUV= zyGuo4ml(Fnxg1ImNLGsv8b<4i5O)1WOA5tizd?PHCrf)j$e0)Rn0&sgspWr6v%tXc zZsu|HDxM8!s`dGXW9D*nV+_Av15{q%UjzKszSaK?RB^0=Gt&08<_~cm7XzKZJ*HtT`K*`}%=~L?>CqsxYE_A_Q{cHer7D z_oV8;57_c8&Ron5u~<<|$*k|74uz~@ru5rxT2b;5A)z{ld6zv+KSrsvjZFz>Qh6?l z{HRN<%#M|%xYVRmAgyYds(F9AEH23pZ6VM9sPe7Aa?m*c71)CwH~ z#=iY7SF=n#G?-C)W@gCDg#G~se20f-)~^*w=JstUhOpR%Iz8Gsdp8V$*h;f@@Fn$KGz2#Wg7YS zuS9Rl@|sK8w2pE2%o*pLw1w;5-sna;1Lw#F_-l0(RSgr<^YJOPm`j;%&+*UOs>fG- zU0Nz5DJE9eo_lsmg?#HR{I)vsSVxoYI)3CL_{-Odgz@_6l`;RVE5v6{9~!B2fWX4J zdZ%UmJ=oD(8!_8hpOt3;bgL0+w(BZ*JsS%yj(s0Nm-QKPt`nl4IV1OUiPc4Rf~iic zG~RIcZ33zuQoP(umMy*>4eKs0SsqN2Q@easn!(=O)5l--l|n2w;|VoOz!bx{#s7^n ze(&DtIrBTar)ek@I@d%NtJ})csp)i-(36&L^}V1njNsUB)B3rPJGw$IRg?GZjBS`K z`+>?4I}c;~@$E^1XoE&$t?cf?LQ{yjRa1@-YB}({F1W`6^}Evj;)-9#+)g)brb2_+ zhv6yS0G;y=YYz{_952#Z4^x;|utKc>f553Yvnt?3Rxt4#7cNydkH!mLjE(OSdwjRK zk4JJFL23n@M)H`IptafU!hA=;=xobHuE@&o-O3Fzs(^Q)QU!cr$GAMfZUT zr{X&n-FWZZ9~n>V^MkT-dKG%wD8XCbhP6jg39K*}^V6;?|Kc`eAp6_izUM+Inp9M_ zrk<>djt76rq%uuXk~&s@U14Z!th+B!JZ`)Idl>dOA3IY=-sL(C?62+~tTmD?=}LGV zD3=&a8fTDPC9afuj>~Vad+BZOD;zGr-agL#Uy4RY&Jo+FWGBOu$7$cXi8E&se+PUX zR@`EJ*Y$7T$&^;tNa#0KTaQfGAOU|sK&-ZqBj2avjx^+_BPLjIBJKSuunudKkmN;#Q0*yt$2`^f)6e{2kKzfBGG6s4Q{sFk1^kJryOi`o;P z&XE6UKdHYD_h(isE*XAcAp9-{=pYiH{ex?YNrHg=b5T{(W<^>hbQU~Z(Oky>cFtM$ zZ8h@UeakFRdaLMqF$;2_MUViDO7J~5caXFz_eG!rffL-HbnWnA z$N12kAjYN2rqXn{MBlv1ohg5{lex=SM}NJV5SOd`ZN4%A5fC6_ju32BmEFU;r0=xJ zo(0bG(^~p7&4|WieW-^4+A5#C^jy=JIeQyFc>1bewR+*W>!;0Z zn_*Y84YVI&42x04HZ`8;`GhSPTB_UlIMx~r=uMpmA0Q$Tr%UCsJICD>D*hmfIw0<7 zN@0R?FZ&94R{RkpTvaWyos?7Gv+YIp6vgoLy!sA7_xGER$aYL zTt0GAK#O;Jl2E!C^uqHlZzdS(VxSHnc+f+l-{zMP%!e;Qsh=<$MO}50NV!WWnBwR8 zb?CbO18u2tRmS4U<3&5K^^wEMBl4#>CU6kepM1A4NbDl7&vxK#DhB$_hmR& zuZVKU<-SBZw7m4*MK$e{lmX23S*!=h7ZIa(H)FY8UN}rGGS(L$$`}0zx^ris;2(=0 z(g>HFjf$S~9aeUC(N+Pdi_dp{e)#(Pw$Ehg=k6D)acRa^ZfI%ch+8g@%N~Kw1;Kq4 zi+>wA)dymofF^&bMK*2c?dSUzhfuZpUq9rVF&MaPBmySZH5OaOwd|WjmPxU*COszJ zkNH&b`f*(7Z})93?OW5#^?E>PrRcx*)sK9G*a+GUQ;c2CsB48(2e6C}a9M9d;Qe`5 z5YGLGZ;O=)Kx+5G*^uJ5sw|MN(EhAyQBOyBll*|kmFuz3H&oZe#W-Cv5A?=mSmmdeH}B$QGI z?DIJ-5Lcfx&gL|K7x`~a=oD&#sYwGBLfOF;v-q4ZVcvG`fYkBd&}n_tJT%- zx8)*U@T~E7GM2EXfbmTA9qvg~ zZn~amozY_zn(F-bDI#SsXbx+T#MC@jKngodYZOvT7tadFup|V)@+$7hW&*a#l0)`= z3UazJ7+Z&WH~~C-V=fx$y=E8!pvo!Lj3l`+s+MfhA6qTC%6CRHw6*pRpEyvQ_C`5Z zPj?fr$)>;@a{zWnlZMJx*V?mSm2O*$P{3(#@mQ3nKW&tkIQu#-vhM2jd{^idkN=>bA(7`jSy1M2G**#vnPW^@5jXs(ws*AA|cQqQ&r@%7+Vk!K+YFir2|ZDh7P0(BsJ7&clXbsypqE{>>a=O=KMp>ITXIhcG42rOFPA48QyWAWO|EEq2=# z-VGYr{t!c_8xK`xRL+tdadk0HNgDTR<*or>9uAbpDu*VarK)B-d_}L_XDYHV!K%TLUM8agpQw6|uw#p{hNUs@BX zy$*ps)Ijv##^9j`5pn@U;-slNoaQ%0cwgH+6+)u(0#Kx3Nl9m?oTyc*fgN!D=NO|8 zQUlRh1o{kK|K_)d=L*M>to`KcWL{h<8LVK489lf?!E>X~dAhZAL}7jbJx-YVH& ztn*S?PD>tav@$L2Xb^{=~yZc_V5U}2X$$UbZVkfNg3t;g%WdHRMs6TA8k z2AwLK0P6;Q{TShl{v#%YBQ84w9wssn;cbE-$8dvx@wK)JQ%0}MALt(%8tiqg*gygf z=%ty3NaE?B4hE08ku*f}o7_E~JXSS~EPGn+v`n$FQd_U_oV}v-;qP)A=z@t zP^F+Jfp8I$OLnD%5?icEcBYoQ77Y;F?f?x2?V(K(x>am|*j8n_&%bo1ILj@HW3yh? znKj@Bl>elm+?bWSH3`*u(+#v&(*6aAxbiw(Y?2FDV6p67Uvrf|vM`hUcOyg~NLDzJ z*WMneyqyKl-Q(tPw;ieU*d20W#o}ViE#Ima`IgG%=uIZ~Ge985vX{CNB_-45X=;h_ zVjPKTo?V@2VQ2TRO(Ke<0kM(S64jOpCcQqFCcD~R^9dLM@r#-D_L#ES@weBjCt{J- zfljPN)GW1#;NZuiwS*}uDXm~>MbNvKHKl9B11XY=hYp-abUZykT~E2?jEBD@g);ng zX^Hz%M)!RHzXMsaOV{4eUU?1Asf{tmRCHvYxM9>Lhcd@KlZ)h=Ta ztw*AY&X9w77a|_3)BfMVd&7Mk02QhXx!%4pkdR6fWuxU@!~33eYRlh0 z+v`kLm$tq-jR=GR1wXtuIi`|7btNwi`5$rMa8IiXSf~xf0s_ysZWTemAq=Rd#%UeP z317>Ps+Qm!?0ui=9~q??E?r3KJA+!lwk3NgEq%r-f^PE`WU?QVR%#%-FD^^+y)194 z$h^KM;tNv3E_$HzRzuBR*YI*ZzXRx{depHDIJ_3d*#&^H^tj)xvTTEX)vIsAuA~mG z8QUYHCk=6{ASGLRQhAXMexH(4E$SQOO9k~TqceqFx0@DrFUk1wwFy@rL4y_C*-yIP zRoS6ub#6zC92o6gXQ74De5myUd0tov#O+&lLPcq59ZVmAU@@$1!BF03$A=m}wYA|Q zJ&Ih5HudrlrG?Rg4p(<}X&OVJ{M8zk4$(qaQ>v|rSl4MQgWuI;Uu4J*iwMhb0Kw*N_l1J6aeYkd!a_ft%MZy}Gt>UMpSK&O=l7q2M5L-a zqHv>OPac|Du0C6ON<%#6xIw;N9Vg+cK~+J<5)q;6CILPNR~3}fEAZ9Ud<3B?%G>DS zAMy~~I}^_7zX^-jMLEL90P}1=FHg{ACM4TABm|&00br2(``9j*Dj@M^_(`ost7{{% zySu`6gSgXfQHEs+&pr0Uj)`(r+i50Zfz9F>pW z+q5PooVgvkGUy`TDVd6W%m0v($s6A(ou_X^rj@NPYIS}K6QBJv?v0V{^P>BuCCg%` z{-n#2h`WD+V6jVEBT4%M~Ok)>-_>CZfA$r zNcKK>=P&u(Ndmq8*;~F${b`~0T3xgoL5{>Fe`MI^+UGwRnTVq)8}8|rYfkKO33`h| zwk@N}?0>dZ9fF%s*R}*-|M&`SlUxe{eBsoeLuROHiLQ;a*MjZmbf5@T9L;>#QxU+( zyx0GFJ_vk-ReadIo;D{)^?7Shs*JB#GD+iBgGM+YQsNpNF*V^uQV=nfad^vC&m2CW zJUXGWJ|Pq5>`rWa<2f%Npj$60UjrrP1E;R^Z9({EU812 zU*7q5XXmm$U%fa`5ZH7*mA`REerw~r0ckr`2!L|Fj}n2Cv<60irlzv*j2^f~VgmCi z`r1<>ppr?p#s75ep#Tsq_)aVyZGHLtB`2W33b^Ng3Y{sBP)+CBw91s?Lv=@3`OKC@ zbnKrQ(}fKAs>wLPLG4T~IDi~KnS%sMG6S%wm)+Uf%QMz%>Kew4n*yc&U;-vBb~}bG zP33YNz&rhPDw4l);Z(|e-RPBX1clGfr{7{9wj&nkC+~X&QfX9Got$^;n6q(B+5r`A z)O;QS|3PIz6Fgy70fY$gUPdMLw?S#p*4BAltH%~x1`d+b=y6U_A$toO(i0+aj)9}A z=1nxHFpp>X(b#H?Oo5w_@KPdL$W)Wa7eP<<=96KcCrk{W4p7p?)+}?GgEktB#BNvwe6`E}_2N$&EQGU?XX_Y+nuc*&sO&U;tUw^Y|Yi(MgTHRTUMfsp? zv?YlIfUkk#7JvgD(P^*jCfGd}vTtS>R!mLA3T~t@aS99Nt8cTvp+7e_gi9}zg|V{G zzbjuDn*9BaG*|Cmw_b!?D%30t5ZWEq{D%|#e;oR8&U1Lp*q|1HH`!hLI)Y4`V#VvN z-y`U;fAnS3(m&DWt*dNsU_Z3REQS%dGQ zX`TO!2hl18kQv3q;94J|>fOz+JP8XjO=e?ZYnNkj5Y#EwpOdnA_7(>S%ZNdvat)xQ z3qjtPyWhAa>&CZ|P~j(M7eYwyi#o$vS1Fffz1$HzH+NZcmdR_D%J z4gSOvtcCE&mMynAC?SAQmy8O%lvYysp4M({rB+{1p4A&bXEE;{MuAuzfd(CC_OWrU z&$~ao(|)3nnCmqDx{*Pf`J>NPd%I!nrETwX5@wiF@F^O#>^bUsVhih=ezM)<3F-2V zu6OSR0rOL~eTjE&J8r|KH(rct-w0@Yc1-4B-MIYJLE+rWmtFeE95kY1n6H0xWvi1Q z%D%XIa$L`WupI_^l=mFPBAl{=!0%*&(aWs+kzKjt@{6wp8L31$WFz8bwgto?uXKKs ziX1jM*xsGht?Cgi_YVx#Rwn1Y8(#nSlZIe<+1l%Al&QiYjb3CWUPUxM7@g3msxcbv z55|x9q@NtY>Q9q^el}P3{yA_cq}e^v5P!P=3p$q0VWHp$0Fmmzh)1uP(Jp_T^xkq> z;~%0oCWa&V8f*P|YOO%* z_Cn!BWKDC0MY0W?c)FLm4|U83M^m+2Dnv#m!_CB42S%;jJ?j;L&kOzcu+~NfS_dX? zB3rheds=dTr=1C-!Q}4vp`9@MTI2awuj@d8RdFh$e}h;@;;|YZvqm&%AVK&ISO(3} zoK>dq&kP7oYr>+ilcSMe^o!(U#@%c8#~kr>#IRwNzkzb_mxoc#Zi*i}e%MWmX4leV z&-kD^)%fTwwR8nxW|Sqh6miKM`$zq*(N7nE7VQLPO>0D9XlBI) zLM|L$^bqp0L#oU5$&<6XKyL|{u*o7(_A#Z`!iT*3GsM=9yiVf}+*xPGsENf173*Uz zigUx&VZFm)5{Hh=-cNjP6_;neW`l+wFS2PBs5X7X7tk&*x*q*<#+$bMu$ARSg{3RV z%@qY1G`)W)CTw$d*@S5^B&Ze`?k^Q9E{KmdG){dOdyJyHHr)|-O!JIbFg+%mq(vZFh zv(jW$Zkqme=?^}VKi?|7iD2~|OJ}e5^9F=WbPL5|4Tb2;$Nmn*Wt+T#5Cpeb>+G+U>tBm|8Ae zJ>K!w2EKLfX2sd2)gl;vX^p>mff(0Z<&W?gZ&&%arEyx{bziH=fRH80{OTIBrkhSE zs-rV(_E$;!gQe!;DINn_5rhk05scU()W!gwiZP?~x=3)0`o%~1wirK8OZcWVw0U^xrl4++ z{r(cJ_-fw4r*YePNc@gs7E8$7g8O;-w}t2dcgNpDPMcZ|stQC=aQxcd`Y%D@muG>r z=Ue`Uib!6)w<_LU;KlvkjHbBYl1=tPMLSK@xGfF=%^!8e`SF*^fSHJ22XmU~v5+s{ zYbO-1N=cdSG#v4a`Pq`7`rlI?jY+v zVBZXpQR-#C+-vQsW=!3Dq*c8x(%5)9XBOwjfS#KW^$ggXK6!OFI3I@*gY8RPuM1wV zq|C#oWg^38_AcNRhq;{s2^~Omn z6RLyK6_@I+m9@JGaMol+W%8Dlv5o)2C#|H!cZWxtW&d2H+S5~{M5wVFP)hz=0g$KR zRca`sfX1ICfXfZYq2QucYX^ynmX<%cd2ZYQ9WET->9I&BzE(HCF8=Y!kw<(}T7f+eppfN$`%>@o zIoH_+PcKWxN2EF1&b;(60|E*3skX{DW$Up20U6%j AK>z>% diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 72aa2342..00000000 --- a/docs/index.md +++ /dev/null @@ -1,58 +0,0 @@ -# PyScript - -Welcome to the PyScript documentation! - -PyScript provides a way for you to run Python code directly in your browser, giving -anyone the ability to program without infrastructure barriers. Add an interactive -Python REPL directly to your website, share an interactive dashboard with a colleague -as an HTML file, or create a client-side Python-powered web application. This documentation -will show you how. - -::::{grid} 2 -:gutter: 3 - -:::{grid-item-card} [Tutorials](tutorials/index.md) - -Just getting started with PyScript? - -Check out our [getting started guide](tutorials/getting-started.md)! -::: -:::{grid-item-card} [Guides](guides/index.md) - -You already know the basics and want to learn specifics! - -[Passing Objects between JavaScript and Python](guides/passing-objects.md) - -[Making async HTTP requests in pure Python](guides/http-requests.md) - -[Async/Await and Asyncio](guides/asyncio.md) - -::: -:::{grid-item-card} [Concepts](concepts/index.md) - -[What is PyScript?](concepts/what-is-pyscript.md) - -::: -:::{grid-item-card} [Reference](reference/index.md) - -[Frequently asked questions](reference/faq.md) - -[The PyScript JS Module](reference/modules/pyscript.md) - -:::{toctree} -:maxdepth: 1 - -::: -:::: - -```{toctree} ---- -maxdepth: 1 -hidden: ---- -tutorials/index -guides/index -concepts/index -reference/index -changelog -``` diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 32bb2452..00000000 --- a/docs/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -if "%1" == "" goto help - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/docs/reference/API/__version__.md b/docs/reference/API/__version__.md deleted file mode 100644 index aa649480..00000000 --- a/docs/reference/API/__version__.md +++ /dev/null @@ -1,8 +0,0 @@ -# `__version__` - -`PyScript.__version__` is a `str` representing the current version of PyScript in a human-readable form. For a structured version more suitable to comparisons, and for details of what each part of the version number represents, see [`version_info`](version_info.md) - -```shell ->>> pyscript.__version__ -'2023.02.1.dev' -``` diff --git a/docs/reference/API/attr_to_event.md b/docs/reference/API/attr_to_event.md deleted file mode 100644 index 194583e8..00000000 --- a/docs/reference/API/attr_to_event.md +++ /dev/null @@ -1,85 +0,0 @@ -# List of PyScript Attributes to Events: - -PyScript provides a convenient syntax for mapping JavaScript events to PyScript events, making it easy to connect events to HTML tags. - -For example, you can use the following code to connect the click event to a button: - -``` - -``` - -Here is a list of all the available event mappings: - -| PyScript Event Name | DOM Event Name | -|-------------------|----------------| -| 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-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-keydown | keydown | -| py-keypress | keypress | -| py-keyup | keyup | -| 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-drag | drag | -| py-dragend | dragend | -| py-dragenter | dragenter | -| py-dragleave | dragleave | -| py-dragover | dragover | -| py-dragstart | dragstart | -| py-drop | drop | -| py-scroll | scroll | -| py-copy | copy | -| py-cut | cut | -| py-paste | paste | -| 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-toggle | toggle | diff --git a/docs/reference/API/display.md b/docs/reference/API/display.md deleted file mode 100644 index 1034559f..00000000 --- a/docs/reference/API/display.md +++ /dev/null @@ -1,87 +0,0 @@ -# `display(*values, target=None, append=True)` - -## Parameters - -`*values` - the objects to be displayed. String objects are output as-written. For non-string objects, the default content to display is the the object's {py:func}`repr`. Objects may implement the following methods to indicate that they should be displayed as a different MIME type. MIME types with a * indicate that the content will be wrapped in the appropriate html tags and attributes before output: - - -| Method | Inferred MIME type | -|---------------------|------------------------| -| `__repr__` | text/plain | -| `_repr_html_` | text/html | -| `_repr_svg_` | image/svg+xml | -| `_repr_png_` | image/png* | -| `_repr_pdf_` | application/pdf | -| `_repr_jpeg_` | image/jpeg* | -| `_repr_json_` | application/json | -| `_repr_javascript_` | application/javascript*| -| `savefig` | image/png | -| | | - -`target` - Element's ID. The default value for `target` is the current `py-script` tag ID, it's possible to specify different IDs for this parameter - -`append` - `boolean` if the output is going to be appended or not to the `target`ed element. It creates a `
` tag if `True` and a `` tag with a random ID if `False`. The default value for `append` is `True`. - -### Description - -Display is the default function to display objects on the screen. Functions like the Python `print()` or JavaScript `console.log()` are now defaulted to only appear on the terminal. - -Display will throw an exception if the target is not clear. E.g. the following code is invalid: - -```html - - def display_hello(): - # this fails because we don't have any implicit target - # from event handlers - display('hello') - - -``` - -Because it's considered unclear if the `hello` string should be displayed underneath the `` tag or the ` -``` - -#### Using matplotlib with display - -`matplotlib` has two ways of plotting things as mentioned [here](https://matplotlib.org/matplotblog/posts/pyplot-vs-object-oriented-interface/) - -- In case of using the `pyplot` interface, the graph can be shown using `display(plt)`. - -```python -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -t = np.arange(0.0, 2.0, 0.01) -s = 1 + np.sin(2 * np.pi * t) -plt.plot(t,s) - -display(plt) -``` - -- In case of using the `object oriented` interface, the graph can be shown using `display(fig)` or `display(plt)` both. - -```python -import matplotlib.pyplot as plt -import numpy as np - -# Data for plotting -t = np.arange(0.0, 2.0, 0.01) -s = 1 + np.sin(2 * np.pi * t) - -fig, ax = plt.subplots() -ax.plot(t, s) - -display(fig) # but even display(plt) would have worked! -``` diff --git a/docs/reference/API/element.md b/docs/reference/API/element.md deleted file mode 100644 index 1d8e89e5..00000000 --- a/docs/reference/API/element.md +++ /dev/null @@ -1,309 +0,0 @@ -# `Element` - -The `Element` API is a helpful way to create and manipulate elements in the DOM. It is a wrapper around the native DOM API, and is designed to be as intuitive as possible. - -## Methods and Properties - -| Property | Description | -|----------|-----------------------------------------| -| `element` | Returns the element with the given ID. | -| `id` | Returns the element's ID. | -| `value` | Returns the element's value. | -| `innerHtml` | Returns the element's inner HTML. | - - - -| Method | Description | -|----------------------|--------------------------------------------------------------| -| `write` | Writes `value` to element and handles various mime types. `append` defaults to `False`, if set to true, it will create a child element. | -| `clear` | Clears the element's value or content. | -| `select` | Select element from `query` which uses [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). | -| `clone` | Clones the with `new_id` if provided and `to` element if provided. | -| `remove_class` | Removes one or more class name from the element. | -| `add_class` | Adds one or more class name to the element. | - -## Element.element - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -The `element` property returns the DOM element with the given ID. - -```html - from pyscript import Element - - my_div = Element('my-div') - print(my_div.element) -``` - -## Element.id - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's ID. - -```html - -
- - - from pyscript import Element - - my_div = Element('my-div') - print(my_div.id) # prints 'my-div' - -``` - -## Element.value - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's value. - -```html - - - - from pyscript import Element - - my_input = Element('my-input') - print(my_input.value) # prints 'hello world' - -``` - -## Element.innerHtml - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Return the element's inner HTML. - -```html -
- hello world -
- - - from pyscript import Element - - my_innerHtml = Element('my-innerHtml') - print(my_innerHtml.innerHtml) # prints hello world - -``` - -## Element.write - -| Parameter | Default | Type | -|-------------|---------|-----------------------------| -| `value` | | `str` or `__mime_type__` | -| `append` | False | `bool` | - -Writes `value` to element and handles various mime types. This method also contains a `append` parameter, which defaults to `False`. - -Currently, these are the MIME types that are supported when rendering content using this method - -| Method | Inferred MIME type | -|---------------------|------------------------| -| `__repr__` | text/plain | -| `_repr_html_` | text/html | -| `_repr_svg_` | image/svg+xml | -| `_repr_png_` | image/png* | -| `_repr_pdf_` | application/pdf | -| `_repr_jpeg_` | image/jpeg* | -| `_repr_json_` | application/json | -| `_repr_javascript_` | application/javascript*| -| `savefig` | image/png | - -```html -
- - - from pyscript import Element - el = Element("foo") - el.write("Hello!") - el.write("World!") # will replace the previous content - -``` - -If we set `append` to `True`, it will create a child element using a `div`. - -```html -
- - - from pyscript import Element - el = Element("foo") - el.write("Hello!", append=True) - - # This will create a child div with the id "foo-1" - el.write("World!", append=True) - -``` - -## Element.clear - -| Parameter | Default | Type | -|-----------|---------|------| -| | | | - -Clears the element's value or content. For example, we can clear the value of an input element. - -```html - - - - from pyscript import Element - el = Element("foo") - el.clear() # Removes value from input - -``` - -Or we can clear the content of a div element. - -```html -
Hello!
- - - from pyscript import Element - el = Element("foo") - el.clear() # Removes Hello from div content - -``` - -## Element.select - -Select element from `query`, it will look into the main Element if `from_content` is `True`. This method is a wrapper of [Document.querySelector()](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector). - -```html -
-
-
- - - from pyscript import Element - el = Element("foo") - bar = el.select("#bar") - print(bar.id) # prints 'bar' - -``` - -## Element.clone - -| Parameter | Default | Type | -|-------------|---------|-----------| -| `new_id` | None | `str` | -| `to` | None | `Element` | - -Clones the element to a new element. You can provide `new_id` to set a different id to the cloned element. You can also use a `to` element to append the cloned element to. - -```html -
- HI! -
- - - from pyscript import Element - - el = Element("foo") - # Creates two divs with the id "foo" and content "HI!" - el.clone() - -``` - -It's always a good idea to pass a new id to the element you are cloning to avoid confusion if you need to reference the element by id again. - -```html -
Hello!
- - - from pyscript import Element - el = Element("foo") - # Clones foo and its contents, but uses the id 'bar' - el.clone(new_id="bar") - -``` - -You can also clone an element into another element. - -```html -
- Bond -
-
- James -
- - from pyscript import Element - - bond_div = Element("bond") - james_div = Element("james") - - bond_div.clone(new_id="bond-2", to=james_div) - -``` - -## Element.remove_class - -| Parameter | Default | Type | -|-------------|---------|-----------------------| -| `classname` | None | `str` or `List[str]` | - -Removes one or more class names from the element. - -```html -
- - from pyscript import Element - - el = Element("foo") - el.remove_class("bar") - -``` - -You can also remove multiple classes by passing a list of strings. - -```html -
- - from pyscript import Element - - el = Element("foo") - el.remove_class(["bar", "baz"]) # Remove all classes from element - -``` - -## Element.add_class - -| Parameter | Default | Type | -|-------------|---------|-----------------------| -| `classname` | None | `str` or `List[str]` | - -Adds one or more class names to the element. - -```html - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class("red") - -``` - -You can also add multiple classes at once by passing a list of strings. - -```html - -
Hi!
- - from pyscript import Element - el = Element("foo") - el.add_class(["red", "bold"]) - -``` diff --git a/docs/reference/API/version_info.md b/docs/reference/API/version_info.md deleted file mode 100644 index dfba3c20..00000000 --- a/docs/reference/API/version_info.md +++ /dev/null @@ -1,16 +0,0 @@ -# `version_info` - -`PyScript.version_info` is a `namedtuple` representing the current version of PyScript. It can be used to compare whether current version precedes or follows a desired version. For a human-readable version of the same info, see [`__version__`](__version__.md) - -```sh ->>> pyscript.version_info -version_info(year=2023, month=2, minor=1, releaselevel='dev') -``` - -## Version Fields -| **parameter** | **CalVer equivalent field** | **example value** | **description** | -|-----------------|-----------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------| -| `year` | Full year (YYYY) | 2023 | The year of the release; when printed or represented as a string, always written with 4 digits | -| `month` | Short Month (MM) | 2 | The month of the release; when printed or represented as a string, written with 1 or 2 digits as necessary | -| `minor` | | 1 | The incremental number of the release for this month; when printed or represented as a string, written with 1 or two digits as necessary | -| `releaselevel` | | 'dev' | A string representing the qualifications of this build | diff --git a/docs/reference/API/when.md b/docs/reference/API/when.md deleted file mode 100644 index aaf4f761..00000000 --- a/docs/reference/API/when.md +++ /dev/null @@ -1,51 +0,0 @@ -# `@when` - -`@when(event_type:str = None, selector:str = None)` - -The `@when` decorator attaches the decorated function or Callable as an event handler for selected objects on the page. That is, when the named event is emitted by the selected DOM elements, the decorated Python function will be called. - -If the decorated function takes a single (non-self) argument, it will be passed the [Event object](https://developer.mozilla.org/en-US/docs/Web/API/Event) corresponding to the triggered event. If the function takes no (non-self) argument, it will be called with no arguments. - -## Parameters - -`event_type` - A string representing the event type to match against. This can be any of the [https://developer.mozilla.org/en-US/docs/Web/Events#event_listing](https://developer.mozilla.org/en-US/docs/Web/Events) that HTML elements may emit, as appropriate to their element type. - -`selector` = A string containing one or more [CSS selectors](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). The selected DOM elements will have the decorated function attacehed as an event handler. - -## Examples: - -The following example prints "Hello, world!" whenever the button is clicked. It demonstrates using the `@when` decorator on a Callable which takes no arguments: - -```html - - - from pyscript import when - @when("click", selector="#my_btn") - def say_hello(): - print(f"Hello, world!") - -``` - -The following example includes three buttons - when any of the buttons is clicked, that button turns green, and the remaining two buttons turn red. This demonstrates using the `@when` decorator on a Callable which takes one argument, which is then passed the Event object from the associated event. When combined with the ability to look at other elements in on the page, this is quite a powerful feature. - -```html -
- - - -
- - from pyscript import when - import js - - @when("click", selector="#container button") - def highlight(evt): - #Set the clicked button's background to green - evt.target.style.backgroundColor = 'green' - - #Set the background of all buttons to red - other_buttons = (button for button in js.document.querySelectorAll('button') if button != evt.target) - for button in other_buttons: - button.style.backgroundColor = 'red' - -``` diff --git a/docs/reference/elements/py-config.md b/docs/reference/elements/py-config.md deleted file mode 100644 index 3d1058a1..00000000 --- a/docs/reference/elements/py-config.md +++ /dev/null @@ -1,493 +0,0 @@ -# <py-config> - -Use the `` tag to set and configure general metadata along with declaring dependencies for your PyScript application. The configuration has to be set in either [TOML](https://toml.io/)(default) or [JSON](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/JSON) format. - -If you are unfamiliar with TOML, consider [reading about it](https://learnxinyminutes.com/docs/toml/) or if you are unfamiliar with JSON, consider reading [freecodecamp's JSON for beginners](https://www.freecodecamp.org/news/what-is-json-a-json-file-example/) guide for more information. - -The `` element should be placed within the `` element. - -## Attributes - -| attribute | type | default | description | -|-----------|--------|---------|----------------------------------------------------------------------------------------------------------| -| **type** | string | "toml" | Syntax type of the ``. Value can be `json` or `toml`. Default: "toml" if type is unspecified. | -| **src** | url | | Source url to an external configuration file. | - -## Examples - -### Defining an inline config - -- `` using TOML (default) - -```{note} -Reminder: when using TOML, any Arrays of Tables defined with double-brackets (like `[[interpreters]]` and `[[fetch]]` must come after individual keys (like `plugins = ...` and `packages=...`) -``` - -```html - - [splashscreen] - autoclose = true - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js" - name = "pyodide-0.21.2" - lang = "python" - -``` - -- `` using JSON via `type` attribute - -```html - - { - "splashscreen": { - "autoclose": true - }, - "interpreters": [{ - "src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js", - "name": "pyodide-0.21.2", - "lang": "python" - }] - } - -``` - -### Defining a file based config - -- Use of the `src` attribute - -```html - -``` -where `custom.toml` contains - -```toml -[splashscreen] -autoclose = true - -[[interpreters]] -src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js" -name = "pyodide-0.21.2" -lang = "python" -``` - -- JSON using the `type` and `src` attribute - -```html - -``` -where `custom.json` contains - -```json -{ - "splashscreen": { - "autoclose": true, - }, - "interpreters": [{ - "src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js", - "name": "pyodide-0.21.2", - "lang": "python" - }] -} -``` - -### Mixing inline and file based configs - -One can also use both i.e pass the config from `src` attribute as well as specify it as `inline`. So the following snippet is also valid: - -```html - - [[fetch]] - files = ["./utils.py"] - -``` - -This can also be done via JSON using the `type` attribute. - -```html - - { - "fetch": [{ - "files": ["./utils.py"] - }] - } - -``` - -Note: While the `` tag supports both TOML and JSON, one cannot mix the type of config passed from 2 different sources i.e. the case when inline config is in TOML format while config from src is in JSON format is NOT allowed. Similarly for the opposite case. - ---- - -This is helpful in cases where a number of applications share a common configuration (which can be supplied via `src`), but their specific keys need to be customised and overridden. - -The keys supplied through `inline` override the values present in config supplied via `src`. - -## Dependencies and Packages - -One can also declare dependencies so as to get access to many 3rd party OSS packages that are supported by PyScript. -You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html). - -Package dependencies in the `` can be declared by using the direct link to the package URL (whl or any other format supported by the chosen interpreter) or by just providing the package name [and version]. If only the name [and version] are provided, packages will be installed directly from what's provided by your interpreter or from PyPI. - -NOTICE that only pure python packages from PyPI will work and packages with C dependencies will not. These need to be built specifically for WASM (please, consult the Pyodide project for more information about what's supported and on how to build packages with C dependencies) - -```html - - packages = ["./static/wheels/travertino-0.1.3-py3-none-any.whl"] - -``` - -OR in JSON like - -```html - - { - "packages": ["./static/wheels/travertino-0.1.3-py3-none-any.whl"] - } - -``` - -If your `.whl` is not a pure Python wheel, then open a PR or issue with [pyodide](https://github.com/pyodide/pyodide) to get it added [here](https://github.com/pyodide/pyodide/tree/main/packages). - -If there's enough popular demand, the pyodide team will likely work on supporting your package. Regardless, things will likely move faster if you make the PR and consult with the team to get unblocked. - -For example, NumPy and Matplotlib are available. Notice here we're using `display(fig, target="plot")`, which takes the graph and displays it in the element with the id `plot`. - - -```html - - - - - - - -

Let's plot random numbers

-
- - { - "packages": ["numpy", "matplotlib"] - } - - - import matplotlib.pyplot as plt - import numpy as np - x = np.random.randn(1000) - y = np.random.randn(1000) - fig, ax = plt.subplots() - ax.scatter(x, y) - display(fig, target="plot") - - - -``` - -## Local modules - -In addition to packages, you can declare local Python modules that will -be imported in the `` tag. For example, we can place the random -number generation steps in a function in the file `data.py`. - -```python -# data.py -import numpy as np -def make_x_and_y(n): - x = np.random.randn(n) - y = np.random.randn(n) - return x, y -``` - -In the HTML tag ``, paths to local modules are provided in the -`files` key within the `fetch` section. Refer to the [fetch](#fetch) section for -more details. - -```html - - - - - - - -

Let's plot random numbers

-
- - packages = ["numpy", "matplotlib"] - - [[fetch]] - files = ["./data.py"] - - - import matplotlib.pyplot as plt - from data import make_x_and_y - x, y = make_x_and_y(n=1000) - fig, ax = plt.subplots() - ax.scatter(x, y) - display(fig, target="plot") - - - -``` - -## Supported configuration values - -The following optional values are supported by ``: -| Value | Type | Description | -| ------ | ---- | ----------- | -| `name` | string | Name of the user application. This field can be any string and is to be used by the application author for their own customization purposes. | -| `description` | string | Description of the user application. This field can be any string and is to be used by the application author for their own customization purposes. | -| `version` | string | Version of the user application. This field can be any string and is to be used by the application author for their own customization purposes. It is not related to the PyScript version. | -| `schema_version` | number | The version of the config schema which determines what all keys are supported. This can be supplied by the user so PyScript knows what to expect in the config. If not supplied, the latest version for the schema is automatically used. | -| `type` | string | Type of the project. The default is an "app" i.e. a user application | -| `author_name` | string | Name of the author. | -| `author_email` | string | Email of the author. | -| `license` | string | License to be used for the user application. | -| `autoclose_loader` | boolean | If false, PyScript will not close the loading splash screen when the startup operations finish. | -| `packages` | List of Packages | Dependencies on 3rd party OSS packages are specified here. The default value is an empty list. | -| `fetch` | List of Stuff to fetch | Local Python modules OR resources from the internet are to be specified here using a Fetch Configuration, described below. The default value is an empty list. | -| `plugins` | List of Plugins | List of Plugins are to be specified here. The default value is an empty list. | -| `interpreters` | List of Interpreters| List of Interpreter configurations, described below. The default value contains a single Pyodide based interpreter. **Note:** Currently, only a single interpreter is supported. | -| `runtimes` {bdg-warning-line}`Deprecated` | List of Runtimes | This value is deprecated, please use `interpreters`. List of runtime configurations, described below. The default value contains a single Pyodide based interpreter. | - -###
Fetch - -A fetch configuration consists of the following: - -| Value | Type | Description | -|--------------|-----------------|-------------------------------------------------| -| `from` | string | Base URL for the resource to be fetched. | -| `to_folder` | string | Name of the folder to create in the filesystem. | -| `to_file` | string | Name of the target to create in the filesystem. | -| `files` | List of strings | List of files to be downloaded. | - -The parameters `to_file` and `files` shouldn't be supplied together. - -#### Mechanism - -The `fetch` mechanism works in the following manner: - -- If both `files` and `to_file` parameters are supplied: Error! -- `from` defaults to an empty string i.e. `""` to denote relative URLs of the serving directory -- `to_folder` defaults to `.` i.e. the current working directory of the filesystem -- If `files` is specified - - for each `file` present in the `files` array - - the `sourcePath` is calculated as `from + file` - - the `destination` is calculated as `to_folder + file` - - thus, the object is downloaded from `sourcePath` to `destination` -- Else i.e. `files` is NOT specified - - If `to_file` is specified - - the object is downloaded from `from` to `to_folder + to_file` - - Otherwise, calculate the `filename` at the end of `from` i.e. the part after last `/` - - the object is downloaded from `from` to `to_folder + filename at the end of 'from'` - -Learn more about `fetch` on PyScript [here](https://jeff.glass/post/whats-new-pyscript-2022-12-1) - -#### Use-Cases - -Assumptions: - -The directory being served has the following tree structure: - -``` -content/ - ├─ index.html <<< File with - ├─ info.txt - ├─ data/ - │ ├─ sensordata.csv - ├─ packages/ - │ ├─ my_package/ - │ │ ├─ __init__.py - │ │ ├─ helloworld/ - │ │ │ ├─ __init__.py - │ │ │ ├─ greetings.py -``` - -1. Fetching a single file - -```html - - [[fetch]] - files = ['info.txt'] - -``` - -```html - - with open('info.txt', 'r') as fp: - print(fp.read()) - -``` - -2. Single File with Renaming - -```html - - [[fetch]] - from = 'info.txt' - to_file = 'info_loaded_from_web.txt' - -``` - -```html - - with open('info_loaded_from_web.txt', 'r') as fp: - print(fp.read()) - -``` - -3. Single File to another Directory - -```html - - [[fetch]] - files = ['info.txt'] - to_folder = 'infofiles/loaded_info' - -``` - -```html - - with open('infofiles/loaded_info/info.txt', 'r') as fp: - print(fp.read()) - -``` - -4. Single File to another Directory with Renaming - -```html - - [[fetch]] - from = 'info.txt' - to_folder = 'infofiles/loaded_info' - to_file = 'info_loaded_from_web.txt' - -``` - -```html - - with open('infofiles/loaded_info/info_loaded_from_web.txt', 'r') as fp: - print(fp.read()) - -``` - -5. Single file from a folder to the current working directory - -```html - - [[fetch]] - from = 'data/' - files = ['sensordata.csv'] - -``` - -```html - - with open('./sensordata.csv', 'r') as fp: - print(fp.read()) - -``` - -6. Single file from a folder to another folder (i.e. not the current working directory) - -```html - - [[fetch]] - from = 'data/' - to_folder = './local_data' - files = ['sensordata.csv'] - -``` - -```html - - with open('./local_data/sensordata.csv', 'r') as fp: - print(fp.read()) - -``` - -7. Multiple files preserving directory structure - -```html - - [[fetch]] - from = 'packages/my_package/' - files = ['__init__.py', 'helloworld/greetings.py', 'helloworld/__init__.py'] - to_folder = 'custom_pkg' - -``` - -```html - - from custom_pkg.helloworld.greetings import say_hi - print(say_hi()) - -``` - -8. From an API endpoint which doesn't end in a filename - -```html - - [[fetch]] - from = 'https://catfact.ninja/fact' - to_file = './cat_fact.json' - -``` - -```html - - import json - with open("cat_fact.json", "r") as fp: - data = json.load(fp) - -``` - -### Interpreter - -An interpreter configuration consists of the following: - -| Value | Type | Description | -|--------|-------------------|-------------| -| `src` | string (Required) | URL to the interpreter source. | -| `name` | string | Name of the interpreter. This field can be any string and is to be used by the application author for their own customization purposes | -| `lang` | string | Programming language supported by the interpreter. This field can be used by the application author to provide clarification. It currently has no implications on how PyScript behaves. | - -#### Example - -- The default interpreter is `pyodide`, another version of which can be specified as following - -```html - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js" - name = "pyodide-0.20.0" - lang = "python" - -``` - -```{note} -Currently, PyScript supports a single interpreter, this may change in the future. -``` - -## Supplying extra information (or metadata) - -Besides the above schema, a user can also supply any extra keys and values that are relevant as metadata information or perhaps are being used within the application. - -For example, a valid config could also be with the snippet below: - -```html - - magic = "unicorn" - -``` - -OR in JSON like - -```html - - { - "magic": "unicorn" - } - -``` - -If this `"magic"` key is present in config supplied via `src` and also present in config supplied via `inline`, then the value in the inline config is given priority i.e. the overriding process also works for custom keys. diff --git a/docs/reference/elements/py-repl.md b/docs/reference/elements/py-repl.md deleted file mode 100644 index 32d95021..00000000 --- a/docs/reference/elements/py-repl.md +++ /dev/null @@ -1,62 +0,0 @@ -# <py-repl> - -The `` element provides a REPL(Read Eval Print Loop) to evaluate multi-line Python and display output. - -## Attributes - -| attribute | type | default | description | -|-------------------|---------|---------|--------------------------------------| -| **auto-generate** | boolean | | Auto-generates REPL after evaluation | -| **output-mode** | string | "" | Determines whether the output element is cleared prior to writing output | -| **output** | string | | The id of the element to write `stdout` and `stderr` to | -| **stderr** | string | | The id of the element to write `stderr` to | -| **src** | string | | Resource to be preloaded into the REPL | - - -### `auto-generate` -If a \ tag has the `auto-generate` attribute, upon execution, another \ tag will be created and added to the DOM as a sibling of the current tag. - -### `output-mode` -By default, the element which displays the output from a REPL is cleared (`innerHTML` set to "") prior to each new execution of the REPL. If `output-mode` == "append", that element is not cleared, and the output is appended instead. - -### `output` -The ID of an element in the DOM that `stdout` (e.g. `print()`), `stderr`, and the results of executing the repl are written to. Defaults to an automatically-generated \ as the next sibling of the REPL itself. - -### `stderr` -The ID of an element in the DOM that `stderr` will be written to. Defaults to None, though writes to `stderr` will still appear in the location specified by `output`. - -### `src` -If a \ tag has the `src` attribute, during page initialization, resource in the `src` will be preloaded into the REPL. Please note that this will not run in advance. If there is content in the \ tag, it will be cleared and replaced with preloaded resource. - -## Examples - -### `` element set to auto-generate - -```html - -``` - -### `` element with output - -The following will write "Hello! World!" to the div with id `replOutput`. - -```html -
- - print("Hello!") - hello = "World!" - hello - -``` - -Note that if we `print` from the REPL (or otherwise write to `sys.stdout`), the output will be printed in the [`py-terminal`](../plugins/py-terminal.md) if is enabled. - -### `` element with src -Preload resource from src into the REPL -```html - - If a py-repl tag has the src attribute, - the content here will be cleared and replaced. - -
-``` diff --git a/docs/reference/elements/py-script.md b/docs/reference/elements/py-script.md deleted file mode 100644 index 85a9a0fd..00000000 --- a/docs/reference/elements/py-script.md +++ /dev/null @@ -1,126 +0,0 @@ -# <py-script> - -The `` element, also available as ` - - - - print("Let's compute π:") - def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - - pi = compute_pi(100000) - s = f"π is approximately {pi:.3f}" - print(s) - - - -``` - -### Using `` element with `src` attribute - -we can also move our python code to its own file and reference it via the `src` attribute. - - -```python -# compute_pi.py -print("Let's compute π:") -def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - -pi = compute_pi(100000) -s = f"π is approximately {pi:.3f}" -print(s) -``` - -Since both compute_pi.py and index.html are in the same directory, we can reference the python file with a relative path. - -```html - - - - - - - - - -``` - -### Writing into labeled elements - -In the example above, we had a single `` tag printing -one or more lines onto the page in order. Within the ``, you can -use the `Element` class to create a python object for interacting with -page elements. Objects created from the `Element` class provide the `.write()` method -which enables you to send strings into the page elements referenced by those objects. - -For example, we'll add some style elements and provide placeholders for -the `` tag to write to. - -```html - - - - - - - - -

Today is

-
-
- - import datetime as dt - Element('today').write(dt.date.today().strftime('%A %B %d, %Y')) - - def compute_pi(n): - pi = 2 - for i in range(1,n): - pi *= 4 * i ** 2 / (4 * i ** 2 - 1) - return pi - - pi = compute_pi(100000) - Element('pi').write(f'π is approximately {pi:.3f}') - - - -``` diff --git a/docs/reference/exceptions.md b/docs/reference/exceptions.md deleted file mode 100644 index a298e8af..00000000 --- a/docs/reference/exceptions.md +++ /dev/null @@ -1,52 +0,0 @@ -# Exceptions and error codes - -When creating pages with PyScript, you may encounter exceptions. Each handled exception will contain a specific code which will give you more information about it. -This reference guide contains the error codes you might find and a description of each of them. - -## User Errors - -| Error code | Description | Recommendation | -|------------|--------------------------------|--------------------| -| PY1000 | Invalid configuration supplied | Confirm that your `py-config` tag is using a valid `TOML` or `JSON` syntax and is using the correct configuration type. | -| PY1001 | Unable to install package(s) | Confirm that the package contains a pure Python 3 wheel or the name of the package is correct. | -| PY2000 | Invalid plugin file extension | Only `.js` and `.py` files can be used when loading user plugins. Please confirm your path contains the file extension. | -| PY2001 | Plugin doesn't contain a default export | Please add `export default` to the main plugin class. | -| PY9000 | Top level await is deprecated | Create a coroutine with your code and schedule it with `asyncio.ensure_future` or similar | - - - -## Fetch Errors - -These error codes are related to any exception raised when trying to fetch a resource. If, while trying to fetch a resource, we encounter a status code that is not 200, the error code will contain the HTTP status code and the `PY0` prefix. For example, if we encounter a 404 error, the error code will be `P02404`. - - -| Error Code | Description | -|------------|--------------------------------------------------------------| -| PY0001 | Generic fetch error, failed to fetch page from the server | -| PY0002 | Name supplied when trying to fetch resource is invalid | -| PY0401 | You are not authorized to access this resource. | -| PY0403 | You are not allowed to access this resource. | -| PY0404 | The page you are trying to fetch does not exist. | -| PY0500 | The server encountered an internal error. | -| PY0503 | The server is currently unavailable. | - -## PY1001 - -Pyscript cannot install the package(s) you specified in your `py-config` tag. This can happen for a few reasons: - -- The package does not exist -- The package does not contain a pure Python 3 wheel -- An error occurred while trying to install the package - -An error banner should appear on your page with the error code and a description of the error or a traceback. You can also check the developer console for more information. - -## PY2001 - -Javascript plugins must export a default class. This is required for PyScript to be able to load the plugin. Please add `export default` to the main plugin class. For example: - -```js -export default class HelloWorldPlugin { - afterStartup(runtime) { - console.log("Hello World from the plugin!"); - } -``` diff --git a/docs/reference/faq.md b/docs/reference/faq.md deleted file mode 100644 index bd459949..00000000 --- a/docs/reference/faq.md +++ /dev/null @@ -1,160 +0,0 @@ -# Frequently asked questions - -As the world’s most popular programming language, Python is powerful in its capabilities and comparatively easy to learn, yet the limitations cannot be ignored: it’s hard to install Python and all necessary dependencies; it’s glued to the backend without the ability to make apps or websites; and it’s difficult to share your work. - -What if we could remove those limitations, making the power of Python accessible to the masses? The makers of PyScript set out to do just that by enabling Python in the browser for frontend web and application development. No more complicated installs. Projects can be shared with anyone, anywhere—all you need is a browser. - -We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable OS on top to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration. - -> “This is the exciting beginning for supporting new ways of programming, building, sharing, and deploying applications. Ultimately, we should be spending our time thinking and writing applications to solve the real problems we have, not dealing with mundane, hardware-induced challenges. Let's make programming more fun and simple.” - Fabio Pliger - -## Why PyScript? - -Exponentially expand accessibility and use cases for Python by enabling Python in the browser for building UIs. Reproduce environments without having to download Python or conda or install other packages. Projects can be shared with anyone and deployed anywhere—all you need is a browser and a web-accessible device (computer, tablet, or mobile). - -We are fully leaning into the idea that the browser is the most ubiquitous VM by using Python to build a graphical, programmable operating system on top of the browser to make and share applications. Harness the full power of canvas, webGL, WASI, and even in-browser support for P2P and CRDTs for serverless data sharing and collaboration. - -- [PyCon US 2022 Keynote with Peter Wang](https://anaconda.cloud/pyscript-pycon2022-peter-wang-keynote) -- [Example demos from Keynote](https://pyscript.net/examples/index.html) - -## What is PyScript? - -PyScript is a framework that allows users to create rich Python applications in the browser using HTML's interface and the power of [Pyodide — Version 0.20.0](https://pyodide.org/en/stable/), [WebAssembly](https://webassembly.org/), and modern web technologies. The PyScript framework provides users at every experience level with access to an expressive, easy-to-learn programming language with countless applications. - -What is PyScript? Well, here are some of the core components: - -- Python in the browser: Enable drop-in content, external file hosting, and application hosting without the reliance on server-side configuration - -- Python ecosystem: Run many popular packages of Python and the scientific stack (such as numpy, pandas, scikit-learn, and more) - -- Python with JavaScript: Bi-directional communication between Python and Javascript objects and namespaces - -- Environment management: Allow users to define what packages and files to include for the page code to run - -- Visual application development: Use readily available curated UI components, such as buttons, containers, text boxes, and more - -- Flexible framework: A flexible framework that can be leveraged to create and share new pluggable and extensible components directly in Python - -All that to say... PyScript is just HTML, only a bit (okay, maybe a lot) more powerful, thanks to the rich and accessible ecosystem of Python libraries. - -In short, our mission is to enable programming for the 99%. - -## How can a user get started? - -Leveraging Python in HTML is literally as simple as adding a few lines of code to your page. The best place to learn more, get started, and stay updated on all things PyScript is [Pyscript.net](http://pyscript.net/). Additional shareable resources below: - -- [PyScript Repo](https://github.com/pyscript/pyscript) -- [PyScript Announcement Blog](https://www.anaconda.com/blog/pyscript-python-in-the-browser) -- [PyScript Technical Blog](https://engineering.anaconda.com/2022/04/welcome-pyscript.html) -- [PyScript Nucleus Project](https://anaconda.cloud/s/pyscript) -- [PyScript Documentation](https://docs.pyscript.net/) - -## Why isn't this going to be as terrible as PHP? - -This comparison is based on both PHP and PyScript having a similar way of declaring things: put a tag on the page and the interpreter handles it. PHP works on the server side and is itself a whole different programming language that has its own directives and semantics. - -The choice of using tags to allow people to execute Python is explicit; even if this functionality is similar to PHP, it works differently. First of all, everything runs in the browser itself rather than going to the server side. Secondly, PyScript lives close to the text and allows changes to be made to the visual elements. The PyScript REPL can generate output, plus it provides additional visual elements like buttons, titles, and input boxes. PyScript functions as a framework that generates UIs that makes sense as a tag in the html code. - -Currently, both PHP and PyScript operate with only one namespace. However, PyScript will soon support multiple namespaces and different types of isolation of code (scope), along with support for languages beyond Python. - -## Why not just learn JavaScript? - -JavaScript is not only a different language from python, but a challenging language at that. With PyScript, you now have two languages to choose from, with even more on the roadmap. PyScript allows you to use both libraries and makes JavaScript and Python compatible with one another. - -Python is incredibly powerful, super intuitive, and easy to learn. By adding Python to your toolkit, you can use Numpy, SciPy, Pandas, and more, seamlessly. One tradeoff is longer download times, so it isn’t the right tool for everything—but where it is the right tool, it’s almost irreplaceable. - -Ultimately, PyScript will enable the use of a variety of languages, offer a standard set of components that is well linked to the REPLs, and allow you to do an introspection on the code base—you can have, for example, a *modifiable* chart as a python object. - -## Will PyScript replace JavaScript? - -No. PyScript allows Python to leverage HTML, CSS, and JavaScript conventions to build elegant UIs and address general web application building, packaging, distribution, and deployment challenges (a huge pain). We expect the popularity and adoption of HTML, CSS, and JavaScript to rise alongside Python, ultimately making the web a more friendly and hackable place for everyone. That said, we do believe: - -- PyScript will displace some use cases that people have to rely on Javascript for now -- PyScript will heavily leverage and interface with existing powerful, feature-full JS libraries, as appropriate -- PyScript will open up web programming to tens of millions of people who would otherwise not have touched JavaScript; so in this way, it will outpace JavaScript - -But none of these above scenarios lead to a situation where "PyScript replaces all existing JavaScript." Just as Python itself didn't replace C, C++, or Java. But, it did take a LOT of market share for new use cases where those languages would otherwise have been used. - -## What is the difference between PyScript and Pyodide? - -![pyodide-pyscript](../img/pyodide-pyscript.png) - -PyScript provides HTML tags for embedding and executing Python code in your browser. As a ‘glue’ framework, it sits on top of a variety of tools and provides users access to Pyodide, the WebAssembly port of CPython, which is compiled using Emscripten. In other words, Pyodide enables PyScript users to take advantage of real CPython on the browser. - -Together, PyScript and Pyodide allow users to author applications by turning the browser into a code deployment tool that anyone can learn to use. - -With respect to the UI, PyScript is opinionated and purposeful, while Pyodide is agnostic, unopinionated, and intended for more general use. - -## What packages can I use? Can I use anything from PyPI? - -You can use anything within the Pyodide library, and pure python packages from PyPi that do not contain C dependencies should be supported by Pyodide. - -There is a list of packages built in Pyodide in [Packages built in Pyodide — Version 0.20.0](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) (these are mostly packages with C extensions). You can also install pure Python packages from PyPI or custom URLs, assuming they have a wheel. - -In general, Pyodide doesn’t support all Python features—not because of Pyodide itself, but because some concepts just work differently on the browser (think of sockets/websockets, IO, threading, etc.). If it’s a pure python package that doesn’t have any non-supported features, you should expect it to work. If it has C dependencies, etc., don’t expect it to work unless someone builds/ports them. A lot of the features that don’t work can be made to work, but it will take human power to fix. For example, the PyTorch community wanted those features to work, so they rallied around it to make it happen. Expect the set of libraries that work to grow quickly given the volume of package builds coming from the community. - -## This package XXX is not supported because it has C dependencies. How can I make it work? - -See [Creating a Pyodide package — Version 0.20.0](https://pyodide.org/en/stable/development/new-packages.html). - -## Why is PyScript loading so slowly? Why can’t we put things behind a CDN? - -Packages are already served from the JsDelivr CDN. This is not a downloading speed problem—it's WASM assembly time. PyScript loads slowly because the Python standard library and packages are large and WebAssembly code needs to be compiled and run by the browser after they are loaded for the first time. - -Currently, there are efforts to mitigate the problem, and Pyodide is currently working on a bundler, for instance. - -## Is PyScript owned by Anaconda? - -Anaconda doesn’t own PyScript. It is an open source project developed by Anaconda internally, and Anaconda team members are currently the main contributors, but the repo itself is public. We are working on a steering council to ensure the project stays public and owned by the community. - -See [Maintainers](../concepts/governance/maintainers.md). - -See [Governance Policy](../concepts/governance/policy.md). - -## What is the governing model for PyScript? - -See [Governance Policy](../concepts/governance/policy.md). - -## What is the license? - -PyScript uses the Apache-2.0 license. - -Pyodide uses MPL-2.0 license. Various packages are distributed under their corresponding license. - -## Is Pyodide a replacement for CPython? How does PyScript and Pyodide compare to CPython on WASM? - -No. They have different elements that do different things, both of which are additive. - -PyScript sits on top of everything. Pyodide came before the work on CPython and WASM. Patches were created in order for it to work, but now that CPython/WASM are progressing, Pyodide is able to remove a few of those patches. Additionally, CPython doesn’t deal with building Python packages for WASM. WASM related work on upstream CPython will integrate into Pyodide in the near future. - -For a list of differences from “standard” CPython, see [Pyodide Python compatibility — Version 0.20.0](https://pyodide.org/en/stable/usage/wasm-constraints.html). - -## Hasn’t this already been done before by Brython/skulpt? - -No. Brython and Skulpt accomplish different things than PyScript and Pyodide. - -Brython is client-side and functions as syntax on top of Javascript—it is a reimplementation of Python on top of Javascript, without support for packages or a file system. The extraction of a package in normal Python has been replaced completely by something else. You should be able to run code with minimal changes; however, that isn’t possible with Brython. - -Skulpt is a cross compiler from Python to Javascript, leveraged for compatibility with the Python ecosystem. If you want to do any more Python, you would have to send it over. - -Fairly similar syntax to normal Python, but not exactly the same. If Brython was an interpreter and a full Python implementation, it could be used with PyScript to leverage packages like Numpy, but that isn’t possible as it stands today. They do have the Python script tag, but it is a smaller API and not as feature rich—which is why PyScript is built on Pyodide, Emscripten, and WebAssembly. - -## How can I contribute/help? - -**PyScript** - we are currently working on building documentation and a contributing guide. In the meantime, just ask to help on the PyScript [discussions page](https://anaconda.cloud/s/pyscript) or in the [repo](http://github.com/pyscript/pyscript). - -**Pyodide** - refer to [Pyodide docs](https://pyodide.org/en/stable/development/contributing.html). - -## WebAssembly Security - -See [WebAssembly docs](https://webassembly.org/docs/security/). - -## Why don’t Requests and Black work? - -Requests and Black do not work out of the box because they weren’t meant for the browser. On the browser, sockets multiprocessing works differently, so there is work to be done to actually match things. - -For Black, it’s a design choice that can be patched. This is currently being addressed by the team at Pyodide. - -Requests do not work because of the sockets issue (sockets and websockets are two different things) and requests are blocking—which you don’t want in the browser. It’ll require putting the interpreter on a webworker and utilizing an assistant, but on the main thread it’s unlikely that it’ll work. - -There are options as a path forward. For example, Requests can be leveraged using javascript libraries, or building a python async version of Requests API or a python wrapper for fetch (pyfetch), etc. The websockets library has a client side that could be made to work—given that it has all asynchronous APIs, there’s nothing fundamentally difficult about getting it to work. diff --git a/docs/reference/index.md b/docs/reference/index.md deleted file mode 100644 index d52f247e..00000000 --- a/docs/reference/index.md +++ /dev/null @@ -1,54 +0,0 @@ -# Reference - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Elements ---- -elements/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Modules ---- -modules/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: Plugins ---- -plugins/* -``` - -```{toctree} ---- -maxdepth: 1 -glob: -caption: API ---- -API/* -``` - -```{toctree} ---- -maxdepth: 2 -glob: -caption: Exceptions ---- -exceptions -``` - -```{toctree} ---- -maxdepth: 1 -caption: Miscellaneous ---- -faq -``` diff --git a/docs/reference/modules/pyscript.md b/docs/reference/modules/pyscript.md deleted file mode 100644 index b4604c11..00000000 --- a/docs/reference/modules/pyscript.md +++ /dev/null @@ -1,77 +0,0 @@ -# pyscript - -The code underlying PyScript is a JavaScript module, which is loaded and executed by the browser. This is what loads when you include, for example, ` -``` -```js -//example result -Object { year: 2022, month: 11, patch: 1, releaselevel: "dev" } -``` - -## pyscript.interpreter - -The Interpreter object which is responsible for executing Python code in the Browser. Currently, all interpreters are assumed to be Pyodide interpreters, but there is flexibility to expand this to other web-based Python interpreters in future versions. - -The Interpreter object has the following attributes - -| attribute | type | description | -|---------------------|-----------------------|---------------------------------------------------------------------------------| -| **src** | string | The URL from which the current interpreter was fetched | -| **interface** | InterpreterInterface | A reference to the interpreter object itself | -| **globals** | any | The globals dictionary of the interpreter, if applicable/accessible | -| **name (optional)** | string | A user-designated name for the interpreter | -| **lang (optional)** | string | A user-designation for the language the interpreter runs ('Python', 'C++', etc) | - -### pyscript.interpreter.src - -The URL from which the current interpreter was fetched. - -### pyscript.interpreter.interface - -A reference to the Interpreter wrapper that PyScript uses to execute code. object itself. This allows other frameworks, modules etc to interact with the same [(Pyodide) interpreter instance](https://pyodide.org/en/stable/usage/api/js-api.html) that PyScript uses. - -For example, assuming we've loaded Pyodide, we can access the methods of the Pyodide interpreter as follows: - -```html - - -``` - -### pyscript.interpreter.globals - -A proxy for the interpreter's `globals()` dictionary. For example: - -```html - - x = 42 - - - - -``` -### pyscript.interpreter.name - -A user-supplied string for the interpreter given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript. - -### PyScript.interpreter.lang - -A user-supplied string for the language the interpreter uses given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript. diff --git a/docs/reference/plugins/py-splashscreen.md b/docs/reference/plugins/py-splashscreen.md deleted file mode 100644 index 3c3e84ce..00000000 --- a/docs/reference/plugins/py-splashscreen.md +++ /dev/null @@ -1,65 +0,0 @@ - -# <py-splashscreen> - -This is one of the core plugins in PyScript, which is active by default. The splashscreen is the first thing you see when you open a page with Pyscript while it is loading itself and all the necessary resources. - -## Configuration - -You can control how `` behaves by setting the value of the `splashscreen` configuration in your ``. - - -| parameter | default | description | -|-------------|-----------|-------------| -| `autoclose` | `true` | Whether to close the splashscreen automatically when the page is ready or not | -| `enabled` | `true` | Whether to show the splashscreen or not | - -### Examples - -#### Disabling the splashscreen - -If you don't want the splashscreen to show and log any loading messages, you can disable it by setting the splashscreen option `enabled` to `false`. - -```html - - [splashscreen] - enabled = false - -``` - -#### Disabling autoclose - -If you want to keep the splashscreen open even after the page is ready, you can disable autoclose by setting `autoclose` to `false`. - -```html - - [splashscreen] - autoclose = false - -``` - -## Adding custom messages - -You can add custom messages to the splashscreen. This is useful if you want to show the user that something is happening in the background for your PyScript app. - -There are two ways to add your custom messages to the splashscreen, either by dispatching a new custom event, `py-status-message` to the document: - - -```js -document.dispatchEvent(new CustomEvent("py-status-message", {detail: "Hello, world!"})) -``` - -Or by using the `log` method of the `py-splashscreen` tag directly: - -```js -const splashscreen = document.querySelector("py-splashscreen") -splashscreen.log("Hello, world!") -``` - -If you wish, you can also send messages directly to the splashscreen from your python code: - -```python -from js import document - -splashscreen = document.querySelector("py-splashscreen") -splashscreen.log("Hello, world!") -``` diff --git a/docs/reference/plugins/py-terminal.md b/docs/reference/plugins/py-terminal.md deleted file mode 100644 index 30001a50..00000000 --- a/docs/reference/plugins/py-terminal.md +++ /dev/null @@ -1,82 +0,0 @@ -# <py-terminal> - -This is one of the core plugins in PyScript, which is active by default. With it, you can print to `stdout` and `stderr` from your python code, and the output will be displayed on the page in ``. - -## Configuration - -You can control how `` behaves by setting the values of the `terminal`, `docked`, and `xterm` fields in your configuration in your ``. - -For the **terminal** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | Don't add `` to the page | -| `true` | Automatically add a `` to the page | -| `"auto"` | This is the default. Automatically add a ``, to the page. The terminal is initially hidden and automatically shown as soon as something writes to `stdout` and/or `stderr` | - -For the **docked** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | Don't dock `` to the page | -| `true` | Automatically dock a `` to the page | -| `"docked"` | This is the default. Automatically add a ``, to the page. The terminal, once visible, is automatically shown at the bottom of the page, covering the width of such page | - -Please note that **docked** mode is currently used as default only when `terminal="auto"`, or *terminal* default, is used. - -In all other cases it's up to the user decide if a terminal should be docked or not. - -For the **xterm** field, these are the values: - -| value | description | -|-------|-------------| -| `false` | This is the default. The `` is a simple `
` tag with some CSS styling. |
-| `true` or `xterm` | The [xtermjs](http://xtermjs.org/) library is loaded and its Terminal object is used as the ``. It's visibility and position are determined by the  `docked` and `auto` keys in the same way as the default `` |
-
-The xterm.js [Terminal object](http://xtermjs.org/docs/api/terminal/classes/terminal/) can be accessed directly if you want to adjust its properties, add [custom parser hooks](http://xtermjs.org/docs/guides/hooks/), introduce [xterm.js addons](http://xtermjs.org/docs/guides/using-addons/), etc. Access is best achieved by awaiting the `xtermReady` attribute of the `` HTML element itself:
-
-```python
-import js
-import asyncio
-
-async def adjust_term_size(columns, rows):
-    xterm = await js.document.querySelector('py-terminal').xtermReady
-    xterm.resize(columns, rows)
-
-asyncio.ensure_future(adjust_term_size(40,10))
-```
-
-Some terminal-formatting packages read from specific environment variables to determine whether they should emit formatted output; PyScript does not set these variables explicitly - you may need to set them yourself, or force your terminal-formatting package into a state where it outputs correctly formatted output.
-
-A couple of specific examples:
- - the [rich](https://github.com/Textualize/rich) will not, by default, output colorful text, but passing `256` or `truecolor` as an argument as the `color_system` parameter to the [Console constructor](https://rich.readthedocs.io/en/stable/reference/console.html#rich.console.Console) will force it to do so. (As of rich v13)
- - [termcolor](https://github.com/termcolor/termcolor) will not, by default, output colorful text, but setting `os.environ["FORCE_COLOR"] = "True"` or by passing `force_color=True` to the `colored()` function will force it to do so. (As of termcolor v2.3)
-
-### Examples
-
-```html
-
-    terminal = true
-    docked = false
-
-
-
-    print("Hello, world!")
-
-```
-
-This example will create a new ``, the value "Hello, world!" that was printed will show in it.
-
-You can also add one (or more) `` to the page manually.
-
-```html
-
-    print("Hello, world!")
-
-
-
-```
-
-```{note}
-If you include a `` in the page, you can skip `terminal` from your ``.
-```
diff --git a/docs/robots.txt b/docs/robots.txt
deleted file mode 100644
index 4fccf0cc..00000000
--- a/docs/robots.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-User-agent: *
-Disallow: /review/
-
-Sitemap: https://docs.pyscript.net/sitemap.xml
-Host: docs.pyscript.net
diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md
deleted file mode 100644
index d0e17da0..00000000
--- a/docs/tutorials/getting-started.md
+++ /dev/null
@@ -1,275 +0,0 @@
-# Getting started with PyScript
-
-This page will guide you through getting started with PyScript.
-
-## Development setup
-
-PyScript does not require any development environment other
-than a web browser (we recommend using [Chrome](https://www.google.com/chrome/)) and a text editor, even though using your [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) of choice might be convenient.
-
-If you're using [VSCode](https://code.visualstudio.com/), the
-[Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
-can be used to reload the page as you edit the HTML file.
-
-## Installation
-
-There is no installation required. In this document, we'll use
-the PyScript assets served on [https://pyscript.net](https://pyscript.net).
-
-If you want to download the source and build it yourself, follow
-the instructions in the [README.md](https://github.com/pyscript/pyscript/blob/main/README.md) file.
-
-## Your first PyScript HTML file
-
-Here's a "Hello, world!" example using PyScript.
-
-Using your favorite editor, create a new file called `hello.html` in
-the same directory as your PyScript, JavaScript, and CSS files with the
-following content, and open the file in your web browser. You can typically
-open an HTML by double-clicking it in your file explorer.
-
-```html
-
-  
-    
-    
-  
-  
-    
-        print('Hello, World!')
-    
-  
-
-```
-
-### Using a Local Server
-
-In some situations, your browser may forbid loading remote resources like `pyscript.js` and `pyscript.css` when you open an HTML file directly. When this is the case, you may see your Python code in the text of the webpage, and the [browser developer console](https://balsamiq.com/support/faqs/browserconsole/) may show an error like *"Cross origin requests are only supported for HTTP."* The fix for this is to use a [simple local server](https://developer.mozilla.org/en-US/docs/Learn/Common_questions/Tools_and_setup/set_up_a_local_testing_server) to make your html file available to the browser.
-
-If you have python installed on your system, you can use it's basic built-in server for this purpose via the command line. Change the current working directory of your terminal or command line to the folder where your HTML file is stored. From this folder, run `python -m http.server 8080 --bind 127.0.0.1` in your terminal or command line. With the server program running, point your browser to `http://localhost:8080` to view the contents of that folder. (If a file in that folder is called `index.html`, it will be displayed by default.)
-
-## A more complex example
-
-Now that we know how you can create a simple 'Hello, World!' example, let's see a more complex example. This example will use the Demo created by [Cheuk Ting Ho](https://github.com/Cheukting). In this example, we will use more features from PyScript.
-
-### Setting up the base index file
-
-Let's create a new file called `index.html` and add the following content:
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-  
-
-```
-
-In this first step, we have created the index file, imported `pyscript.css` and `pyscript.js`. We are ready to start adding the elements we need for our application.
-
-### Importing the needed libraries
-
-For this example, we will need to install `pandas` and `matplotlib`. We can install libraries using the `` tag so we can import them later. Please refer to the [``](../reference/elements/py-config.md) documentation for more information.
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-  
-
-```
-
-### Importing the data and exploring
-
-Now that we have installed the needed libraries, we can import and explore the data. In this step, we need to create a `` tag to import our dependencies, read the data with pandas and then use `py-repl` to explore the data.
-
-You may want to read the [``](../reference/elements/py-script.md) and [``](../reference/elements/py-repl.md) documentation for more information about these elements.
-
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-    
-      import pandas as pd
-
-      from pyodide.http import open_url
-
-      url = (
-          "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv"
-      )
-      ice_data = pd.read_csv(open_url(url))
-    
-
-    
-      ice_data
-    
-  
-
-```
-
-Note that we are adding `ice_data` to `py-repl` to pre-populate the REPL with this variable, so you don't have to type it yourself.
-
-### Creating the plot
-
-Now that we have the data, we can create the plot. We will use the `matplotlib` library to make the plot. We will use the `display` API to display the plot on the page. You may want to read the [`display`](../reference/API/display.md) documentation for more information.
-
-```html
-
-  
-    Ice Cream Picker
-    
-    
-    
-  
-  
-
-    
-      packages = ["matplotlib", "pandas"]
-    
-
-    
-      import pandas as pd
-      import matplotlib.pyplot as plt
-
-      from pyodide.http import open_url
-
-      url = (
-          "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv"
-      )
-      ice_data = pd.read_csv(open_url(url))
-
-      def plot(data):
-        plt.rcParams["figure.figsize"] = (22,20)
-        fig, ax = plt.subplots()
-        bars = ax.barh(data["name"], data["rating"], height=0.7)
-        ax.bar_label(bars)
-        plt.title("Rating of ice cream flavours of your choice")
-        display(fig, target="graph-area", append=False)
-
-      plot(ice_data)
-    
-
-    
-      ice_data
-    
-
-    
- - -``` - -### Select specific flavours - -Now that we have a way to explore the data using `py-repl` and a way to create the plot using all of the data, it's time for us to add a way to select specific flavours. - -```html - - - Ice Cream Picker - - - - - - - - packages = ["matplotlib", "pandas"] - - - - import js - import pandas as pd - import matplotlib.pyplot as plt - - from pyodide.http import open_url - from pyodide.ffi import create_proxy - - url = ( - "https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv" - ) - ice_data = pd.read_csv(open_url(url)) - - current_selected = [] - flavour_elements = js.document.getElementsByName("flavour") - - def plot(data): - plt.rcParams["figure.figsize"] = (22,20) - fig, ax = plt.subplots() - bars = ax.barh(data["name"], data["rating"], height=0.7) - ax.bar_label(bars) - plt.title("Rating of ice cream flavours of your choice") - display(fig, target="graph-area", append=False) - - def select_flavour(event): - for ele in flavour_elements: - if ele.checked: - current_selected = ele.value - break - if current_selected == "ALL": - plot(ice_data) - else: - filter = ice_data.apply(lambda x: ele.value in x["ingredients"], axis=1) - plot(ice_data[filter]) - - ele_proxy = create_proxy(select_flavour) - - for ele in flavour_elements: - if ele.value == "ALL": - ele.checked = True - current_selected = ele.value - ele.addEventListener("change", ele_proxy) - - plot(ice_data) - - - -
- Select your 🍨 flavour:
- - - - - - - - - - - - -
- - - ice_data - - -
- - -``` diff --git a/docs/tutorials/index.md b/docs/tutorials/index.md deleted file mode 100644 index 225d3e24..00000000 --- a/docs/tutorials/index.md +++ /dev/null @@ -1,38 +0,0 @@ -# Tutorials - -This section contains pyscript tutorials. Each tutorial is a self-contained document that will guide you through a specific topic. - -## Getting Started - -This tutorial will guide you through getting started with PyScript, from installation to writing your first PyScript application. The getting started will show you how to specify dependencies, read a csv file from the web, use `pandas` and `matplotlib` and how to handle user input. - -[Read the get started tutorial](getting-started.md) - - -## Basics - -This section contains tutorials about the basics of PyScript. - -```{toctree} ---- -maxdepth: 1 -glob: ---- -writing-to-page -py-click -requests -``` - -## PyScript Configuration - -This section contains tutorials about the PyScript configuration using the `` tag. - - -```{toctree} ---- -maxdepth: 1 -glob: ---- -py-config-fetch -py-config-interpreter -``` diff --git a/docs/tutorials/py-click.md b/docs/tutorials/py-click.md deleted file mode 100644 index 6cb52c2d..00000000 --- a/docs/tutorials/py-click.md +++ /dev/null @@ -1,127 +0,0 @@ -# Handling click events - -This tutorial will show you how to use the `py-click` attribute to handle mouse clicks on elements on your page. The `py-click` attribute is a special attribute that allows you to specify a Python function that will be called when the element is clicked. There are many other events such as py-mouseover, py-focus, py-input, py-keyress etc, which can be used as well. They are listed here [Attr-to-Event](../reference/API/attr_to_event.html) - -## Development setup - -Let's start by building the base HTML page. We will create an HTML page with a button and a paragraph. When the button is clicked, the paragraph will show the current time. - - -```html - - - - - - - Current Time - - - - - - - -``` - -## Adding elements to the page - -Let's add a button and a paragraph to the page. The button will have the `py-click` attribute, and the paragraph will have the `id` attribute. The `id` attribute is used to identify the element on the page, and the `py-click` attribute will be used to specify the function that will be called when the button is clicked. - -```html - - - - - - - Current Time - - - - - - - -

- - -``` - -There are two things to note here: - -- You must specify an id for an element that uses any `py-*` attribute -- We used the `py-button` class to style the button, this is optional, and these rules are coming from the pyscript.css that we added in the `` section. - -## Creating the Python function - -In this step, we will create the Python function that will be called when the button is clicked. This function will get the current time and update the paragraph with the current time. We will use a `` tag to specify the Python code that will be executed when the page is loaded. - - -```html - - - - - - - Current Time - - - - - - - -

- - - import datetime - - def current_time(): - now = datetime.datetime.now() - - - -``` - -## Writing the time to the page - -If you run the example, you will notice that nothing happened. This is because we still need to update the paragraph with the current time. We can do this by using the [`Element` API](../reference/API/element.md) to get the paragraph element and then update it with the current time with the `write` method. - - -```html - - - - - - - Current Time - - - - - - - -

- - - from pyscript import Element - import datetime - - def current_time(): - now = datetime.datetime.now() - - # Get paragraph element by id - paragraph = Element("current-time") - - # Add current time to the paragraph element - paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S")) - - - -``` - -Now, if you refresh the page and click the button, the paragraph will be updated with the current time. diff --git a/docs/tutorials/py-config-fetch.md b/docs/tutorials/py-config-fetch.md deleted file mode 100644 index 3831d8fa..00000000 --- a/docs/tutorials/py-config-fetch.md +++ /dev/null @@ -1,188 +0,0 @@ -# Using the fetch from py-config - -This tutorial shows how to use the fetch configuration from `py-config` to fetch two files from a remote server, store them in a local directory, and verify their contents. - -## Development setup - -We will create a todo list application similar to the one in the [examples](https://pyscript.net/examples/todo.html). To do this, we need three things: - - * An `index.html` file containing the HTML for the application. - * A `todo.py` file containing the Python code for the application. - * A `utils.py` file containing some utility functions for the application. - - -We will use the `fetch` configuration from `py-config` to fetch these files from a remote server and store them in a local directory. - -### Creating the html file - -In this first step, we will create the `index.html` file and import both `pyscript.css` and `pyscript.js`. These are needed to run our Python code in the browser and style the application. - -```html - - - - - - - My Todo - - - - - - - - - -``` - -## Fetching the files - -### Using `fetch` to get the python files - -Now we will use the `fetch` configuration from `py-config` to fetch the `todo.py` and `utils.py` files from a remote server and store them in a local directory called `todo`. Here we will fetch files from different URLs, using a `fetch` per item. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - - -``` - -## Creating a todo application - -### Creating the todo elements - -Now we will create the todo elements in the `body` of the `index.html` file. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - -
-
-

To Do List

-
-
- - -
-
- -
- - -``` - -Our todo application is starting to shape up, although if you try to add any tasks, you will notice that nothing happens. This is because we have not yet imported the `todo.py` file. - -### Importing the needed functions from `todo.py` - -This is where the magic happens. We can import the `todo.py` file by adding it as a source to the `py-script` tag. By specifying the file, pyscript will automatically import the file and run the code in it. - -```html - - - - - - - My Todo - - - - - - - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - - from todo import add_task, add_task_event - -
-
-

To Do List

-
-
- - -
-
- -
- - -``` - -You can now save the file and refresh the page. You should now be able to add tasks to your todo list. - -## That's it! - -You have now created a todo application using pyscript. You can add tasks and mark them as done. Let's take a recap of what we have achieved: - -* We have imported three separate files into our `index.html` file using the `py-config` tag. -* We have created the necessary HTML code to create our todo's -* We have imported functions from the `todo.py` file, using the `py-script` tag. - -For reference, the code from [the gist](https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/todo.py) is the same code that our [todo example](https://pyscript.net/examples/todo.html) uses with a slight change of importing `Element` from `pyscript`. diff --git a/docs/tutorials/py-config-interpreter.md b/docs/tutorials/py-config-interpreter.md deleted file mode 100644 index 9eea0e70..00000000 --- a/docs/tutorials/py-config-interpreter.md +++ /dev/null @@ -1,88 +0,0 @@ -# Setting a pyodide interpreter - -Pyscript will automatically set the interpreter for you, but you can also set it manually. This is useful if you want to use a different version than the one set by default. - -## Development setup - -To get started, let's create a new `index.html` file and import `pyscript.js`. - -```html - - - - - - - Interpreter - - - - - - - - - -``` - -We are using the pyodide CDN to setup our interpreter, but you can also download the files from [the pyodide GitHub releases](https://github.com/pyodide/pyodide/releases/), unzip them and use the `pyodide.js` file as your interpreter. - -## Setting the interpreter - -To set the interpreter, you can use the `interpreter` configuration in the `py-config` element. In this tutorial, we will use the default `TOML` format, but know that you can also use `json` if you prefer by changing the `type` attribute of the `py-config` element. - -```html - - - - - - - Interpreter - - - - - - - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - -``` - -## Confirming the interpreter version - -To confirm that the interpreter is set correctly, you can open the DevTools and check the version from the console. But for the sake of this tutorial, let's create a `py-script` tag and print pyodide's version. - -```html - - - - - - - Interpreter - - - - - - - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - import pyodide - print(pyodide.__version__) - - - -``` diff --git a/docs/tutorials/requests.md b/docs/tutorials/requests.md deleted file mode 100644 index 34a74905..00000000 --- a/docs/tutorials/requests.md +++ /dev/null @@ -1,123 +0,0 @@ -# Calling an API using Requests - -This tutorial will show you how to interact with an API using the [Requests](https://requests.readthedocs.io/en/master/) library. Requests is a popular library, but it doesn't work out of the box with Pyscript. We will use the [pyodide-http](https://github.com/koenvo/pyodide-http) library to patch the Requests library, so it works with Pyscript. - - We will use the [JSON Placeholder API](https://jsonplaceholder.typicode.com/), a free fake API that returns fake data. - -## Development Setup - -Let's build the base HTML page to add our `py-config` and `py-script` tags in the next steps. - -```html - - - - - - - Requests Tutorial - - - - - - - -``` - -## Installing the dependencies - -In this step, we will install the dependencies we need to use the Requests library. We will use the `py-config` tag to specify the dependencies we need to install. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - -``` - -## Patching the Requests library - -Now that we have installed the dependencies, we need to patch the Requests library to work with Pyscript. We will use the `py-script` tag to specify the code that will be executed when the page is loaded. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - - import pyodide_http - pyodide_http.patch_all() - - - -``` - -## Making a request - -Finally, let's make a request to the JSON Placeholder API to confirm that everything is working. - -```html - - - - - - - Requests Tutorial - - - - - - - packages = ["requests", "pyodide-http"] - - - - import requests - import pyodide_http - - # Patch the Requests library so it works with Pyscript - pyodide_http.patch_all() - - # Make a request to the JSON Placeholder API - response = requests.get("https://jsonplaceholder.typicode.com/todos") - print(response.json()) - - - -``` - -## Conclusion - -In this tutorial, we learned how to use the Requests library to make requests to an API. We also learned how to use the `py-config` and `py-script` tags to install dependencies and execute code when the page is loaded. - -Depending on the API you use, you may need to add additional headers to your request. You can read the [Requests documentation](https://requests.readthedocs.io/en/master/user/quickstart/#custom-headers) to learn more about how to do this. - -You may also be interested in creating your module to make requests. You can read the in-depth guide on [How to make HTTP requests using `PyScript`, in pure Python](../guides/http-requests.md) to learn more about how to do this. diff --git a/docs/tutorials/writing-to-page.md b/docs/tutorials/writing-to-page.md deleted file mode 100644 index d71fa5e8..00000000 --- a/docs/tutorials/writing-to-page.md +++ /dev/null @@ -1,212 +0,0 @@ -# How to write content to the page - -When creating your PyScript application, you will want to write content to the page. This tutorial will explore the different methods you can use to write content to the page and their differences. - -## Development setup - -To get started, we will create an `index.html` file, import PyScript and start building on top of it. - -```html - - - - - - - Writing to the page - - - - - - - - - -``` - -## Writing content to an element - -Let's first see how we can write content to an element on the page. We will start by creating a `div` element with an `id` of `manual-write`, then create a `py-script` tag that, upon a click of a button, will write 'Hello World' to the `div` element. - -```html - - - - - - - Writing to the page - - - - - - -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerText = "Hello World" - - - -``` - -```{note} -When using `py-click` you must supply an `id` to the element you want to use as the trigger. -``` - -We can now open our `index.html` file and click the button. You will see that "Hello World" will appear in the `div` element. You could also write HTML using `manual_div.element.innerHTML` instead of `innerText`. For example: - -```html - - - - - - - Writing to the page - - - - - - -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" -
- - -``` - -## Writing content with the `display` API - -The `display` API is a simple way to write content to the page. Not only does it allow you to write content to the page, but it also allows you to display a range of different content types such as images, markdown, svgs, json, etc. - -Using the' display' API, let's reuse our previous example and write "Hello World" to the page. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") -
- - -``` - -```{note} -When using the `display` API, you must specify the `target` parameter to tell PyScript where to write the content. If you do not use this parameter, an error will be thrown. -``` - -You may be interested in reading more about the `display` API in the [Display API](../reference/api/display) section of the documentation. - -## Printing to the page - -We couldn't have a tutorial on writing to the page without mentioning the `print` function. The `print` function is a simple way to write content to the page, that any Python developer will be familiar with. When you use the `print` function, the content will be written to the page in a `py-terminal` element. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- - - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") - - def print_to_page(): - print("I print things!") -
- - -``` - -You may be surprised to see that when you click the "Print Things!" button, the content is written below the rest of the elements on the page in a black canvas. This is because the `print` function writes content to the page in a `py-terminal` element. You can read more about the `py-terminal` element in the [Terminal Element](../reference/plugins/py-terminal) section of the documentation. - -PyScript comes with the `py-terminal` plugin by default and any `stdout` or `stderr` content will be shown in this element. We can be explicit about where we want the terminal to be shown by adding the `` tag to our HTML. - -```html - - - - - - - Writing to the page - - - - - - -
- -
- -
- -
- - - - def write_to_page(): - manual_div = Element("manual-write") - manual_div.element.innerHTML = "

Hello World

" - - def display_to_div(): - display("I display things!", target="display-write") - - def print_to_page(): - print("I print things!") -
- - -``` From 8f3c36deea53fa2a174f0e9b4329b1cfc6121fd3 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Wed, 20 Sep 2023 16:44:00 +0200 Subject: [PATCH 044/105] [next] Fix #1730 - Make `worker` an empty attribute only (#1732) --- pyscript.core/.npmignore | 1 + pyscript.core/package-lock.json | 12 +++---- pyscript.core/package.json | 4 +-- pyscript.core/src/core.js | 52 +++++++++++------------------- pyscript.core/src/plugins/error.js | 4 +-- pyscript.core/test/error.html | 1 + 6 files changed, 31 insertions(+), 43 deletions(-) diff --git a/pyscript.core/.npmignore b/pyscript.core/.npmignore index 8d1a31ae..7f6b3ed0 100644 --- a/pyscript.core/.npmignore +++ b/pyscript.core/.npmignore @@ -1,6 +1,7 @@ node_modules/ rollup/ test/ +tests/ src/stdlib/_pyscript src/stdlib/pyscript.py package-lock.json diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index d7ebb76e..a4b607d0 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,17 +1,17 @@ { "name": "@pyscript/core", - "version": "0.1.22", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.1.22", + "version": "0.2.0", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.3.10" + "polyscript": "^0.4.2" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", @@ -948,9 +948,9 @@ "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, "node_modules/polyscript": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.3.10.tgz", - "integrity": "sha512-uO9vg0oIbyjo2n7B3/PtOFSWGjpW9WfIVf02aWSkQ6eUrWDmfrB13R03oLofsQoDDfaMZ+odKh3HqoDWqXd99Q==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.2.tgz", + "integrity": "sha512-3mM5Y/DdpYND8/INAUmgF5VL4InVc04xADB+of129t8RjXi3eZK4xoGRPZdTYzW+wM56WNptnC8fC9Zt7jKLoA==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index e46b7954..b920fb2c 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.1.22", + "version": "0.2.0", "type": "module", "description": "PyScript", "module": "./index.js", @@ -33,7 +33,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.3.10" + "polyscript": "^0.4.2" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index a35f677d..8ad0c78e 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -1,7 +1,7 @@ /*! (c) PyScript Development Team */ import "@ungap/with-resolvers"; -import { define, XWorker } from "polyscript"; +import { INVALID_CONTENT, define, XWorker } from "polyscript"; // TODO: this is not strictly polyscript related but handy ... not sure // we should factor this utility out a part but this works anyway. @@ -41,36 +41,6 @@ const after = () => { delete document.currentScript; }; -/** - * Some content that might contain Python/JS comments only. - * @param {string} text some content to evaluate - * @returns {boolean} - */ -const hasCommentsOnly = (text) => - !text - .replace(/\/\*[\s\S]*?\*\//g, "") - .replace(/^\s*(?:\/\/|#).*/gm, "") - .trim(); - -/** - * - * @param {Element} scriptOrPyScript the element with possible `src` or `worker` content - * @returns {boolean} - */ -const hasAmbiguousContent = ( - io, - { localName, textContent, attributes: { src, worker } }, -) => { - // any `src` or a non-empty `worker` attribute + not just comments - if ((src || worker?.value) && !hasCommentsOnly(textContent)) { - io.stderr( - `(${ErrorCode.CONFLICTING_CODE}) a ${localName} tag has content shadowed by attributes`, - ); - return true; - } - return false; -}; - /** * Given a generic DOM Element, tries to fetch the 'src' attribute, if present. * It either throws an error if the 'src' can't be fetched or it returns a fallback @@ -158,6 +128,9 @@ const workerHooks = { [...hooks.codeAfterRunWorkerAsync].map(dedent).join("\n"), }; +// possible early errors sent by polyscript +const errors = new Map(); + // define the module as both ` + + + + + + + from pyscript import display + display("Hello", "M-PyScript Next Worker", append=False) + + + From 52da45bb9c6a66d4301d23537bdb46181a6ef847 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 13:01:08 -0500 Subject: [PATCH 046/105] Disable all workflows - mv to / from .github (#1733) --- {.github/workflows => workflows}/build-unstable.yml | 0 {.github/workflows => workflows}/prepare-release.yml | 0 {.github/workflows => workflows}/publish-release.yml | 0 {.github/workflows => workflows}/publish-snapshot.yml | 0 {.github/workflows => workflows}/sync-examples.yml | 0 {.github/workflows => workflows}/test-next.yml | 0 {.github/workflows => workflows}/test_report.yml | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {.github/workflows => workflows}/build-unstable.yml (100%) rename {.github/workflows => workflows}/prepare-release.yml (100%) rename {.github/workflows => workflows}/publish-release.yml (100%) rename {.github/workflows => workflows}/publish-snapshot.yml (100%) rename {.github/workflows => workflows}/sync-examples.yml (100%) rename {.github/workflows => workflows}/test-next.yml (100%) rename {.github/workflows => workflows}/test_report.yml (100%) diff --git a/.github/workflows/build-unstable.yml b/workflows/build-unstable.yml similarity index 100% rename from .github/workflows/build-unstable.yml rename to workflows/build-unstable.yml diff --git a/.github/workflows/prepare-release.yml b/workflows/prepare-release.yml similarity index 100% rename from .github/workflows/prepare-release.yml rename to workflows/prepare-release.yml diff --git a/.github/workflows/publish-release.yml b/workflows/publish-release.yml similarity index 100% rename from .github/workflows/publish-release.yml rename to workflows/publish-release.yml diff --git a/.github/workflows/publish-snapshot.yml b/workflows/publish-snapshot.yml similarity index 100% rename from .github/workflows/publish-snapshot.yml rename to workflows/publish-snapshot.yml diff --git a/.github/workflows/sync-examples.yml b/workflows/sync-examples.yml similarity index 100% rename from .github/workflows/sync-examples.yml rename to workflows/sync-examples.yml diff --git a/.github/workflows/test-next.yml b/workflows/test-next.yml similarity index 100% rename from .github/workflows/test-next.yml rename to workflows/test-next.yml diff --git a/.github/workflows/test_report.yml b/workflows/test_report.yml similarity index 100% rename from .github/workflows/test_report.yml rename to workflows/test_report.yml From a68967c773dbd833060a92c2c12994ce0e1a6524 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 13:37:02 -0500 Subject: [PATCH 047/105] Add publish snapshot GHA (#1734) --- .github/workflows/publish-snapshot.yml | 62 ++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/publish-snapshot.yml diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml new file mode 100644 index 00000000..20759b8d --- /dev/null +++ b/.github/workflows/publish-snapshot.yml @@ -0,0 +1,62 @@ +name: "Next Build Snapshot" + +on: + workflow_dispatch: + inputs: + snapshot_version: + description: "The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1" + type: string + required: true + +jobs: + next-build-snapshot: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 18.x + + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Install Dependencies + working-directory: ./pyscript.core + run: npm install + + - name: Build Pyscript.core + working-directory: ./pyscript.core + run: npm run build + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1.6.1 + with: + aws-region: ${{ secrets.AWS_REGION }} + role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} + + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html + + - name: Copy to Snapshot + working-directory: ./pyscript.core/dist + run: > + aws s3 sync . s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ \ No newline at end of file From fd307e52aec7771cfe01a3f9a63dd341b05b6750 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 13:40:24 -0500 Subject: [PATCH 048/105] Update publish snapshot (#1735) * Update publish snapshot * naming is hard --- .github/workflows/publish-snapshot.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 20759b8d..c72ad4da 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -1,4 +1,4 @@ -name: "Next Build Snapshot" +name: "Publish Snapshot" on: workflow_dispatch: @@ -9,7 +9,7 @@ on: required: true jobs: - next-build-snapshot: + publish-snapshot: runs-on: ubuntu-latest permissions: contents: read From 91ae242e49d9912dc3f75cff1028b00d48280f27 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 14:30:21 -0500 Subject: [PATCH 049/105] Build unstable (#1736) * Add build unstable * update publish snapshot * naming action and steps --- .github/workflows/publish-snapshot.yml | 13 ++-- .../workflows/publish-unstable.yml | 61 ++++++--------- workflows/prepare-release.yml | 27 +++---- workflows/publish-release.yml | 30 ++++---- workflows/publish-snapshot.yml | 26 ------- workflows/sync-examples.yml | 29 -------- workflows/test-next.yml | 74 ------------------- workflows/test_report.yml | 16 ---- 8 files changed, 53 insertions(+), 223 deletions(-) rename workflows/build-unstable.yml => .github/workflows/publish-unstable.yml (71%) delete mode 100644 workflows/publish-snapshot.yml delete mode 100644 workflows/sync-examples.yml delete mode 100644 workflows/test-next.yml delete mode 100644 workflows/test_report.yml diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index c72ad4da..b3019493 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -8,6 +8,10 @@ on: type: string required: true +defaults: + run: + working-directory: pyscript.core + jobs: publish-snapshot: runs-on: ubuntu-latest @@ -17,8 +21,6 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - with: - ref: main - name: Install node uses: actions/setup-node@v3 @@ -38,12 +40,10 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: Install Dependencies - working-directory: ./pyscript.core + - name: Install Dependencies run: npm install - name: Build Pyscript.core - working-directory: ./pyscript.core run: npm run build - name: Configure AWS credentials @@ -57,6 +57,5 @@ jobs: run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html - name: Copy to Snapshot - working-directory: ./pyscript.core/dist run: > - aws s3 sync . s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ \ No newline at end of file + aws s3 sync ./dist/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ \ No newline at end of file diff --git a/workflows/build-unstable.yml b/.github/workflows/publish-unstable.yml similarity index 71% rename from workflows/build-unstable.yml rename to .github/workflows/publish-unstable.yml index 73b0ba35..6bd1eae9 100644 --- a/workflows/build-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -1,11 +1,11 @@ -name: "[CI] Build Unstable" +name: "Publish Unstable" on: push: # Only run on merges into main that modify files under pyscriptjs/ and examples/ branches: - main paths: - - pyscriptjs/** + - pyscript.core/** - examples/** - .github/workflows/build-unstable.yml # Test that workflow works when changed @@ -19,17 +19,14 @@ on: workflow_dispatch: jobs: - BuildAndTest: + build-unstable: runs-on: ubuntu-latest defaults: run: - working-directory: pyscriptjs - env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 + working-directory: pyscript.core steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -49,49 +46,32 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 - - - name: Setup Environment - run: make setup + - name: NPM Install + run: npm install - name: Build - run: make build - - - name: TypeScript Tests - run: make test-ts - - - name: Python Tests - run: make test-py - - - name: Integration Tests - run: make test-integration-parallel - - - name: Examples Tests - run: make test-examples + run: npm run build + + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html - uses: actions/upload-artifact@v3 with: name: pyscript path: | - pyscriptjs/build/ + pyscript.core/dist/ if-no-files-found: error retention-days: 7 - - uses: actions/upload-artifact@v3 - if: success() || failure() - with: - name: test_results - path: pyscriptjs/test_results - if-no-files-found: error eslint: runs-on: ubuntu-latest defaults: run: - working-directory: pyscriptjs + working-directory: pyscript.core steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -117,9 +97,12 @@ jobs: - name: Eslint run: npx eslint src -c .eslintrc.js - Deploy: + publish-unstable: runs-on: ubuntu-latest - needs: BuildAndTest + defaults: + run: + working-directory: pyscript.core + needs: build-unstable if: github.ref == 'refs/heads/main' # Only deploy on merge into main permissions: contents: read @@ -129,7 +112,7 @@ jobs: - uses: actions/download-artifact@v3 with: name: pyscript - path: ./build/ + path: ./dist/ # Deploy to S3 - name: Configure AWS credentials @@ -139,4 +122,4 @@ jobs: role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - name: Sync to S3 - run: aws s3 sync --quiet ./build/ s3://pyscript.net/unstable/ + run: aws s3 sync --quiet ./dist/ s3://pyscript.net/unstable/ diff --git a/workflows/prepare-release.yml b/workflows/prepare-release.yml index 944eeef1..cd07810a 100644 --- a/workflows/prepare-release.yml +++ b/workflows/prepare-release.yml @@ -5,20 +5,16 @@ on: tags: - "[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+" # YYYY.MM.MICRO -env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 - defaults: run: - working-directory: pyscriptjs + working-directory: pyscript.core jobs: - build: + prepare-release: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -38,17 +34,18 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 + - name: NPM Install + run: npm install - - name: Setup Environment - run: make setup + - name: Build + run: npm run build - - name: Build and Test - run: make test + - name: Generate index.html + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html - - name: Zip build folder - run: zip -r -q ./build.zip ./build + - name: Zip dist folder + run: zip -r -q ./build.zip ./dist - name: Prepare Release uses: softprops/action-gh-release@v1 diff --git a/workflows/publish-release.yml b/workflows/publish-release.yml index 304fc759..54de4bf4 100644 --- a/workflows/publish-release.yml +++ b/workflows/publish-release.yml @@ -4,23 +4,19 @@ on: release: types: [published] -env: - MINICONDA_PYTHON_VERSION: py38 - MINICONDA_VERSION: 4.11.0 - defaults: run: - working-directory: pyscriptjs + working-directory: pyscript.core jobs: - build: + publish-release: runs-on: ubuntu-latest permissions: contents: read id-token: write steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install node uses: actions/setup-node@v3 @@ -40,16 +36,16 @@ jobs: ${{ runner.os }}-build- ${{ runner.os }}- - - name: setup Miniconda - uses: conda-incubator/setup-miniconda@v2 + - name: npm install + run: npm install - - name: Setup Environment - run: make setup + - name: build + run: npm run build + + - name: Generate index.html in snapshot + working-directory: . + run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html - - name: Build and Test - run: make test - - # Upload to S3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1.6.1 with: @@ -59,5 +55,5 @@ jobs: - name: Sync to S3 run: | # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/ - aws s3 sync --quiet ./build/ s3://pyscript.net/latest/ - aws s3 sync --quiet ./build/ s3://pyscript.net/releases/${{ github.ref_name }}/ + aws s3 sync --quiet ./dist/ s3://pyscript.net/latest/ + aws s3 sync --quiet ./dist/ s3://pyscript.net/releases/${{ github.ref_name }}/ diff --git a/workflows/publish-snapshot.yml b/workflows/publish-snapshot.yml deleted file mode 100644 index e2ef5c98..00000000 --- a/workflows/publish-snapshot.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: "[CI] Publish Snapshot" -# Copy /unstable/ to /snapshots/2022.09.1.RC1/ - -on: - workflow_dispatch: - inputs: - snapshot_version: - description: "The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1" - type: string - required: true - -jobs: - snapshot: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - steps: - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - name: Sync to S3 - run: > - aws s3 sync s3://pyscript.net/unstable/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/ diff --git a/workflows/sync-examples.yml b/workflows/sync-examples.yml deleted file mode 100644 index d8ed32b8..00000000 --- a/workflows/sync-examples.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: "[CI] Sync Examples" - -on: - release: - types: [published] - -jobs: - build: - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - defaults: - run: - working-directory: examples - - steps: - # Deploy to S3 - - name: Checkout - uses: actions/checkout@v3 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 - with: - aws-region: ${{ secrets.AWS_REGION }} - role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} - - name: - Sync to S3 - # Sync outdated or new files, delete ones no longer in source - run: aws s3 sync --quiet --delete . s3://pyscript.net/examples/ # Sync directory, delete what is not in source diff --git a/workflows/test-next.yml b/workflows/test-next.yml deleted file mode 100644 index 3764459f..00000000 --- a/workflows/test-next.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: "[CI] Test Next" - -on: - push: # Only run on merges into main that modify files under pyscriptjs/ and examples/ - branches: - - next - paths: - - pyscript.core/** - - .github/workflows/test-next.yml # Test that workflow works when changed - - pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/ - branches: - - next - paths: - - pyscript.core/** - - .github/workflows/test-next.yml # Test that workflow works when changed - workflow_dispatch: - -jobs: - TestNext: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscript.core - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Install node - uses: actions/setup-node@v3 - with: - node-version: 20.x - - - name: Cache node modules - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - # TODO: this will likely change soon to pyscript.next - # - name: install next deps - # working-directory: pyscript.core - # run: npm i; npx playwright install - - # - name: build next - # working-directory: pyscript.core - # run: npm run build - - # - name: Run next tests - # working-directory: pyscript.core - # run: npm run test - - # TODO: DO we want to upload next yet? - # - uses: actions/upload-artifact@v3 - # with: - # name: pyscript - # path: | - # pyscriptjs/build/ - # if-no-files-found: error - # retention-days: 7 - - # - uses: actions/upload-artifact@v3 - # if: success() || failure() - # with: - # name: test_results - # path: pyscriptjs/test_results - # if-no-files-found: error diff --git a/workflows/test_report.yml b/workflows/test_report.yml deleted file mode 100644 index dacbc8e7..00000000 --- a/workflows/test_report.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Test Report -on: - workflow_run: - workflows: ['\[CI\] Build Unstable'] - types: - - completed -jobs: - report: - runs-on: ubuntu-latest - steps: - - uses: dorny/test-reporter@v1.6.0 - with: - artifact: test_results - name: Test reports - path: "*.xml" - reporter: java-junit From ef8918f3a79b48900dfd2b9f4fe2b2c78dcef729 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 14:35:57 -0500 Subject: [PATCH 050/105] Update Build Unstable (#1737) --- .github/workflows/publish-unstable.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index 6bd1eae9..3cb8c5be 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -7,7 +7,6 @@ on: paths: - pyscript.core/** - examples/** - - .github/workflows/build-unstable.yml # Test that workflow works when changed pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/ branches: @@ -15,7 +14,7 @@ on: paths: - pyscriptjs/** - examples/** - - .github/workflows/build-unstable.yml # Test that workflow works when changed + workflow_dispatch: jobs: From 924e530096be43c31394ed8b9a2149c0dcf5ce99 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 14:42:49 -0500 Subject: [PATCH 051/105] Update pathing in publish-unstable (#1738) --- .github/workflows/publish-unstable.yml | 60 +------------------------- 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index 3cb8c5be..4b1b3bf4 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest defaults: run: - working-directory: pyscript.core + working-directory: ./pyscript.core steps: - name: Checkout uses: actions/checkout@v4 @@ -55,64 +55,6 @@ jobs: working-directory: . run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html - - uses: actions/upload-artifact@v3 - with: - name: pyscript - path: | - pyscript.core/dist/ - if-no-files-found: error - retention-days: 7 - - eslint: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscript.core - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - - name: Cache node modules - uses: actions/cache@v3 - env: - cache-name: cache-node-modules - with: - # npm cache files are stored in `~/.npm` on Linux/macOS - path: ~/.npm - key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - - - name: npm install - run: npm install - - - name: Eslint - run: npx eslint src -c .eslintrc.js - - publish-unstable: - runs-on: ubuntu-latest - defaults: - run: - working-directory: pyscript.core - needs: build-unstable - if: github.ref == 'refs/heads/main' # Only deploy on merge into main - permissions: - contents: read - id-token: write - - steps: - - uses: actions/download-artifact@v3 - with: - name: pyscript - path: ./dist/ - # Deploy to S3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1.6.1 From 312b6b07068b8a381e850e75bd071153ca0fda1b Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 14:53:19 -0500 Subject: [PATCH 052/105] Fix publish unstable (#1739) --- .github/workflows/publish-unstable.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index 4b1b3bf4..a7c2bde7 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -18,7 +18,7 @@ on: workflow_dispatch: jobs: - build-unstable: + publish-unstable: runs-on: ubuntu-latest defaults: run: @@ -55,7 +55,6 @@ jobs: working-directory: . run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html - # Deploy to S3 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1.6.1 with: From b78455c4c180443fd65e40b8dd91d3ac86973427 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 15:12:15 -0500 Subject: [PATCH 053/105] Add permissions section (#1740) --- .github/workflows/publish-unstable.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index a7c2bde7..ddddf22d 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -20,6 +20,9 @@ on: jobs: publish-unstable: runs-on: ubuntu-latest + permissions: + id-token: write + contents: read defaults: run: working-directory: ./pyscript.core From 287d0fa1afb2d395f9382147054c9fd7656a8e43 Mon Sep 17 00:00:00 2001 From: Ted Patrick Date: Wed, 20 Sep 2023 15:37:37 -0500 Subject: [PATCH 054/105] Prepare and Publish Release (#1741) * Prepare and Publish Release * Add prepare release and publish release * Update AWS Credentials config to v4 --- {workflows => .github/workflows}/prepare-release.yml | 6 +++--- {workflows => .github/workflows}/publish-release.yml | 10 +++++----- .github/workflows/publish-snapshot.yml | 4 ++-- .github/workflows/publish-unstable.yml | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) rename {workflows => .github/workflows}/prepare-release.yml (87%) rename {workflows => .github/workflows}/publish-release.yml (85%) diff --git a/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml similarity index 87% rename from workflows/prepare-release.yml rename to .github/workflows/prepare-release.yml index cd07810a..77fe8941 100644 --- a/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -1,4 +1,4 @@ -name: "[CI] Prepare Release" +name: "Prepare Release" on: push: @@ -7,7 +7,7 @@ on: defaults: run: - working-directory: pyscript.core + working-directory: ./pyscript.core jobs: prepare-release: @@ -42,7 +42,7 @@ jobs: - name: Generate index.html working-directory: . - run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html + run: sed 's#_PATH_#./#' ./public/index.html > ./pyscript.core/dist/index.html - name: Zip dist folder run: zip -r -q ./build.zip ./dist diff --git a/workflows/publish-release.yml b/.github/workflows/publish-release.yml similarity index 85% rename from workflows/publish-release.yml rename to .github/workflows/publish-release.yml index 54de4bf4..8fbd4852 100644 --- a/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -1,4 +1,4 @@ -name: "[CI] Publish Release" +name: "Publish Release" on: release: @@ -6,14 +6,14 @@ on: defaults: run: - working-directory: pyscript.core + working-directory: ./pyscript.core jobs: publish-release: runs-on: ubuntu-latest permissions: - contents: read id-token: write + contents: read steps: - name: Checkout uses: actions/checkout@v4 @@ -44,10 +44,10 @@ jobs: - name: Generate index.html in snapshot working-directory: . - run: sed 's#_PATH_#https://pyscript.net/snapshots/${{ inputs.snapshot_version }}/#' ./public/index.html > ./pyscript.core/dist/index.html + run: sed 's#_PATH_#https://pyscript.net/releases/${{ github.ref_name }}/#' ./public/index.html > ./pyscript.core/dist/index.html - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index b3019493..e5502831 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -10,7 +10,7 @@ on: defaults: run: - working-directory: pyscript.core + working-directory: ./pyscript.core jobs: publish-snapshot: @@ -47,7 +47,7 @@ jobs: run: npm run build - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index ddddf22d..a608e49c 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -59,7 +59,7 @@ jobs: run: sed 's#_PATH_#https://pyscript.net/unstable/#' ./public/index.html > ./pyscript.core/dist/index.html - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v1.6.1 + uses: aws-actions/configure-aws-credentials@v4 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }} From b4c686f411f1484852690478885508fd1fd56674 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 21 Sep 2023 19:20:02 +0200 Subject: [PATCH 055/105] [RC] Ensure dedicated configs per interpreter (#1743) --- integration.xml | 9 ++ pyscript.core/.npmignore | 1 + pyscript.core/package-lock.json | 4 +- pyscript.core/package.json | 2 +- pyscript.core/src/config.js | 119 ++++++++++++++------------- pyscript.core/src/core.js | 18 ++-- pyscript.core/src/types.js | 4 + pyscript.core/test/split-config.html | 20 +++++ pyscript.core/test/worker.html | 2 +- pyscript.core/types/config.d.ts | 6 +- pyscript.core/types/core.d.ts | 3 +- pyscript.core/types/types.d.ts | 2 + 12 files changed, 118 insertions(+), 72 deletions(-) create mode 100644 integration.xml create mode 100644 pyscript.core/src/types.js create mode 100644 pyscript.core/test/split-config.html create mode 100644 pyscript.core/types/types.d.ts diff --git a/integration.xml b/integration.xml new file mode 100644 index 00000000..d7e2f975 --- /dev/null +++ b/integration.xml @@ -0,0 +1,9 @@ +('/home/ag/git/pyscript/pyscript.core/tests/integration/test_event_handling.py', 5, 'Skipped: FIXME: @when decorator missing from pyscript')('/home/ag/git/pyscript/pyscript.core/tests/integration/test_interpreter.py', 5, "Skipped: FIXME: pyscript API changed doesn't expose pyscript to window anymore")('/home/ag/git/pyscript/pyscript.core/tests/integration/test_plugins.py', 5, "Skipped: FIX LATER: pyscript NEXT doesn't support plugins yet")('/home/ag/git/pyscript/pyscript.core/tests/integration/test_py_repl.py', 7, "Skipped: FIX LATER: pyscript NEXT doesn't support the REPL yet")('/home/ag/git/pyscript/pyscript.core/tests/integration/test_py_terminal.py', 8, "Skipped: FIX LATER: pyscript NEXT doesn't support the Terminal yet")('/home/ag/git/pyscript/pyscript.core/tests/integration/test_splashscreen.py', 6, 'Skipped: DECIDE: Should we remove the splashscreen?')('/home/ag/git/pyscript/pyscript.core/tests/integration/test_stdio_handling.py', 5, 'Skipped: FIXME: entire stdio should be reviewed')('/home/ag/git/pyscript/pyscript.core/tests/integration/test_style.py', 6, 'Skipped: FIX TESTS: These tests should reflect new PyScript and remove/change css')('/home/ag/git/pyscript/pyscript.core/tests/integration/test_warnings_and_banners.py', 5, 'Skipped: FIXME: Restore the banner')/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:43: FIXME: No banner and should also add a WARNING about CORS/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:170: FIX TEST: Works on CHROME/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:193: FIXME: No banner/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:216: FIXME: No banner/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:283: DIFFERENT BEHAVIOUR: we don't expose pyscript on window/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:299: DIFFERENT BEHAVIOUR: we don't expose pyscript on window/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:338: ERROR_SCRIPT: works with <py-script> not with <script>/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:353: FIX TEST: works in chrome!/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:299: The asserts are commented out. Investigate/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:315: The asserts are commented out. Investigate/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:331: FIX TEST: Works correctly in Chrome, but fails in TEST with the error: + +It's likely that the Test framework injections in config are causingthis error./home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:419: FIX TEST: Works correctly in Chrome, but fails in TEST with the error: + +It's likely that the Test framework injections in config are causingthis error./home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:9: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:27: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:45: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:63: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:80: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:100: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:116: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:132: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:149: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:166: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:184: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:204: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:239: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:255: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:271: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:288: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:69: ERROR_SCRIPT: works with <py-script> not with <script>/home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:87: ERROR_SCRIPT: works with <py-script> not with <script>/home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:137: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:157: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:178: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:204: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:219: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_py_config.py:275: FIXME: We need to restore the banner./home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:7: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:26: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:45: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:84: FIXME: test failure is unrelated/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:94: FIXME: output attribute is not implemented/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:107: FIXME: stderr attribute is not implemented/home/ag/git/pyscript/pyscript.core/tests/integration/test_shadow_root.py:8: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:34: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:44: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:63: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:82: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:106: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:115: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:124: flaky, see issue 759/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:141: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:165: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:177: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:205: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:253: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:272: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:281: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:292: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:301: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:322: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:339: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:368: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:394: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zz_examples.py:413: SKIPPING EXAMPLES: these should be moved elsewhere and updated/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:11: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:47: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:73: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:136: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:157: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:200: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:218: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:247: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:264: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:43: FIXME: No banner and should also add a WARNING about CORS/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:170: FIX TEST: Works on CHROME/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:193: FIXME: No banner/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:216: FIXME: No banner/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:283: DIFFERENT BEHAVIOUR: we don't expose pyscript on window/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:299: DIFFERENT BEHAVIOUR: we don't expose pyscript on window/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:338: ERROR_SCRIPT: works with <py-script> not with <script>/home/ag/git/pyscript/pyscript.core/tests/integration/test_01_basic.py:353: FIX TEST: works in chrome!/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:299: The asserts are commented out. Investigate/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:315: The asserts are commented out. Investigate/home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:331: FIX TEST: Works correctly in Chrome, but fails in TEST with the error: + +It's likely that the Test framework injections in config are causingthis error./home/ag/git/pyscript/pyscript.core/tests/integration/test_02_display.py:419: FIX TEST: Works correctly in Chrome, but fails in TEST with the error: + +It's likely that the Test framework injections in config are causingthis error./home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:9: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:27: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:45: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:63: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:80: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:100: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:116: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:132: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:149: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:166: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:184: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:204: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:239: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:255: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:271: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_03_element.py:288: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:7: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:26: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_runtime_attributes.py:45: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:84: FIXME: test failure is unrelated/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:94: FIXME: output attribute is not implemented/home/ag/git/pyscript/pyscript.core/tests/integration/test_script_type.py:107: FIXME: stderr attribute is not implemented/home/ag/git/pyscript/pyscript.core/tests/integration/test_shadow_root.py:8: FIXME: Element interface is gone. Replace with PyDom/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:11: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:47: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:73: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:136: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:157: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:200: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:218: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:247: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs/home/ag/git/pyscript/pyscript.core/tests/integration/test_zzz_docs_snippets.py:264: SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs diff --git a/pyscript.core/.npmignore b/pyscript.core/.npmignore index 7f6b3ed0..0fd1018a 100644 --- a/pyscript.core/.npmignore +++ b/pyscript.core/.npmignore @@ -1,3 +1,4 @@ +.pytest_cache/ node_modules/ rollup/ test/ diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index a4b607d0..beab5ad7 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.2.0", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.2.0", + "version": "0.2.2", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index b920fb2c..de424e8d 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.2.0", + "version": "0.2.2", "type": "module", "description": "PyScript", "module": "./index.js", diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js index 1943f5e2..bfd7a60b 100644 --- a/pyscript.core/src/config.js +++ b/pyscript.core/src/config.js @@ -5,6 +5,7 @@ */ import { $ } from "basic-devtools"; +import TYPES from "./types.js"; import allPlugins from "./plugins.js"; import { robustFetch as fetch, getText } from "./fetch.js"; import { ErrorCode } from "./exceptions.js"; @@ -45,66 +46,72 @@ const syntaxError = (type, url, { message }) => { return new SyntaxError(`${str}\n${message}`); }; -// find the shared config for all py-script elements -let config, plugins, parsed, error, type; -let pyConfig = $("py-config"); -if (pyConfig) { - config = pyConfig.getAttribute("src") || pyConfig.textContent; - type = pyConfig.getAttribute("type"); -} else { - pyConfig = $( - [ - 'script[type="py"][config]:not([worker])', - "py-script[config]:not([worker])", - ].join(","), - ); - if (pyConfig) config = pyConfig.getAttribute("config"); -} +const configs = new Map(); -// catch possible fetch errors -if (config) { - try { - const { json, toml, text, url } = await configDetails(config); - config = text; - if (json || type === "json") { - try { - parsed = JSON.parse(text); - } catch (e) { - error = syntaxError("JSON", url, e); - } - } else if (toml || type === "toml") { - try { - const { parse } = await import( - /* webpackIgnore: true */ - "https://cdn.jsdelivr.net/npm/@webreflection/toml-j0.4/toml.js" - ); - parsed = parse(text); - } catch (e) { - error = syntaxError("TOML", url, e); - } - } - } catch (e) { - error = e; +for (const [TYPE] of TYPES) { + // find the shared config for all py-script elements + let config, plugins, parsed, error, type; + let pyConfig = $(`${TYPE}-config`); + if (pyConfig) { + config = pyConfig.getAttribute("src") || pyConfig.textContent; + type = pyConfig.getAttribute("type"); + } else { + pyConfig = $( + [ + `script[type="${TYPE}"][config]:not([worker])`, + `${TYPE}-script[config]:not([worker])`, + ].join(","), + ); + if (pyConfig) config = pyConfig.getAttribute("config"); } -} -// parse all plugins and optionally ignore only -// those flagged as "undesired" via `!` prefix -const toBeAwaited = []; -for (const [key, value] of Object.entries(allPlugins)) { - if (error) { - if (key === "error") { - // show on page the config is broken, meaning that - // it was not possible to disable error plugin neither - // as that part wasn't correctly parsed anyway - value().then(({ notify }) => notify(error.message)); + // catch possible fetch errors + if (config) { + try { + const { json, toml, text, url } = await configDetails(config); + config = text; + if (json || type === "json") { + try { + parsed = JSON.parse(text); + } catch (e) { + error = syntaxError("JSON", url, e); + } + } else if (toml || type === "toml") { + try { + const { parse } = await import( + /* webpackIgnore: true */ + "https://cdn.jsdelivr.net/npm/@webreflection/toml-j0.4/toml.js" + ); + parsed = parse(text); + } catch (e) { + error = syntaxError("TOML", url, e); + } + } + } catch (e) { + error = e; } - } else if (!parsed?.plugins?.includes(`!${key}`)) { - toBeAwaited.push(value()); } + + // parse all plugins and optionally ignore only + // those flagged as "undesired" via `!` prefix + const toBeAwaited = []; + for (const [key, value] of Object.entries(allPlugins)) { + if (error) { + if (key === "error") { + // show on page the config is broken, meaning that + // it was not possible to disable error plugin neither + // as that part wasn't correctly parsed anyway + value().then(({ notify }) => notify(error.message)); + } + } else if (!parsed?.plugins?.includes(`!${key}`)) { + toBeAwaited.push(value()); + } + } + + // assign plugins as Promise.all only if needed + if (toBeAwaited.length) plugins = Promise.all(toBeAwaited); + + configs.set(TYPE, { config: parsed, plugins, error }); } -// assign plugins as Promise.all only if needed -if (toBeAwaited.length) plugins = Promise.all(toBeAwaited); - -export { parsed as config, plugins, error }; +export default configs; diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 64ca230e..aaa01441 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -9,10 +9,11 @@ import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js"; import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; -import { ErrorCode } from "./exceptions.js"; +import TYPES from "./types.js"; +import configs from "./config.js"; import sync from "./sync.js"; import stdlib from "./stdlib.js"; -import { config, plugins, error } from "./config.js"; +import { ErrorCode } from "./exceptions.js"; import { robustFetch as fetch, getText } from "./fetch.js"; const { assign, defineProperty } = Object; @@ -20,11 +21,6 @@ const { assign, defineProperty } = Object; // allows lazy element features on code evaluation let currentElement; -const TYPES = new Map([ - ["py", "pyodide"], - ["mpy", "micropython"], -]); - // generic helper to disambiguate between custom element and script const isScript = ({ tagName }) => tagName === "SCRIPT"; @@ -103,7 +99,12 @@ const workerHooks = { [...hooks.codeAfterRunWorkerAsync].map(dedent).join("\n"), }; +const exportedConfig = {}; +export { exportedConfig as config }; + for (const [TYPE, interpreter] of TYPES) { + const { config, plugins, error } = configs.get(TYPE); + // create a unique identifier when/if needed let id = 0; const getID = (prefix = TYPE) => `${prefix}-${id++}`; @@ -273,6 +274,9 @@ for (const [TYPE, interpreter] of TYPES) { // define py-script only if the config didn't throw an error if (!error) customElements.define(`${TYPE}-script`, PyScriptElement); + + // export the used config without allowing leaks through it + exportedConfig[TYPE] = structuredClone(config); } // TBD: I think manual worker cases are interesting in pyodide only diff --git a/pyscript.core/src/types.js b/pyscript.core/src/types.js new file mode 100644 index 00000000..06ad5496 --- /dev/null +++ b/pyscript.core/src/types.js @@ -0,0 +1,4 @@ +export default new Map([ + ["py", "pyodide"], + ["mpy", "micropython"], +]); diff --git a/pyscript.core/test/split-config.html b/pyscript.core/test/split-config.html new file mode 100644 index 00000000..434426bc --- /dev/null +++ b/pyscript.core/test/split-config.html @@ -0,0 +1,20 @@ + + + + + + PyScript Config + + + + [[fetch]] + files = ["a.py"] + + + + diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 99cc8bc7..2cbca689 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -15,7 +15,7 @@ - + - - - [[fetch]] - files = ["a.py"] - - - - diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 2cbca689..99cc8bc7 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -15,7 +15,7 @@ - + + + +

Arrr

+

Translate English into Pirate speak...

+ + +
+ + + diff --git a/pyscript.core/test/piratical.py b/pyscript.core/test/piratical.py new file mode 100644 index 00000000..82bef268 --- /dev/null +++ b/pyscript.core/test/piratical.py @@ -0,0 +1,9 @@ +import arrr +from js import document + + +def translate_english(event): + input_text = document.querySelector("#english") + english = input_text.value + output_div = document.querySelector("#output") + output_div.innerText = arrr.translate(english) diff --git a/pyscript.core/test/piratical.toml b/pyscript.core/test/piratical.toml new file mode 100644 index 00000000..cdebd8db --- /dev/null +++ b/pyscript.core/test/piratical.toml @@ -0,0 +1 @@ +packages = ["arrr"] diff --git a/pyscript.core/test/split-config.html b/pyscript.core/test/split-config.html new file mode 100644 index 00000000..434426bc --- /dev/null +++ b/pyscript.core/test/split-config.html @@ -0,0 +1,20 @@ + + + + + + PyScript Config + + + + [[fetch]] + files = ["a.py"] + + + + diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 99cc8bc7..2cbca689 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -15,7 +15,7 @@ - + +
+
+ """ + ) + hello = self.page.locator("#hello") + assert hello.inner_text() == "hello\nworld" + + goodbye = self.page.locator("#goodbye") + assert goodbye.inner_text() == "goodbye world" + def test_target_script_py(self): self.pyscript_run( """ @@ -83,7 +102,7 @@ class TestDisplay(PyScriptTest): """ ) text = self.page.inner_text("body") - assert text == 'ONE\nTWO\nTHREE' + assert text == "ONE\nTWO\nTHREE" def test_consecutive_display_target(self): self.pyscript_run( @@ -200,8 +219,8 @@ class TestDisplay(PyScriptTest): """ ) - output = self.page.locator('script-py') - assert output.inner_text() == 'AAA\nBBB' + output = self.page.locator("script-py") + assert output.inner_text() == "AAA\nBBB" def test_append_false(self): self.pyscript_run( @@ -213,8 +232,8 @@ class TestDisplay(PyScriptTest): """ ) - output = self.page.locator('script-py') - assert output.inner_text() == 'BBB' + output = self.page.locator("script-py") + assert output.inner_text() == "BBB" def test_display_multiple_values(self): self.pyscript_run( @@ -227,7 +246,7 @@ class TestDisplay(PyScriptTest): """ ) - output = self.page.locator('script-py') + output = self.page.locator("script-py") assert output.inner_text() == "hello\nworld" def test_display_multiple_append_false(self): @@ -240,7 +259,7 @@ class TestDisplay(PyScriptTest): """ ) - output = self.page.locator('script-py') + output = self.page.locator("script-py") assert output.inner_text() == "world" # TODO: this is a display.py issue to fix when append=False is used From 801c63947af877cc3036b3f07bae5ec275fbd5e7 Mon Sep 17 00:00:00 2001 From: Jeff Glass Date: Mon, 25 Sep 2023 07:30:22 -0500 Subject: [PATCH 061/105] Skip test_interpreter_config (#1752) * skip test_interpreter_config *Clarify the skip() comments on a couple other config tests --- pyscript.core/tests/integration/test_py_config.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py index 34d24555..b913a757 100644 --- a/pyscript.core/tests/integration/test_py_config.py +++ b/pyscript.core/tests/integration/test_py_config.py @@ -110,6 +110,7 @@ class TestConfig(PyScriptTest): # The test checks if loading a different interpreter is possible # and that too from a locally downloaded file without needing # the use of explicit `indexURL` calculation. + @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") def test_interpreter_config(self, pyodide_tar): unzip(pyodide_tar, extract_to=self.tmpdir) self.pyscript_run( @@ -201,7 +202,7 @@ class TestConfig(PyScriptTest): ) assert banner.text_content() == expected - @pytest.mark.skip("FIXME: We need to restore the banner.") + @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") def test_no_interpreter(self): snippet = """ @@ -216,7 +217,7 @@ class TestConfig(PyScriptTest): div.text_content() == "(PY1000): Fatal error: config.interpreter is empty" ) - @pytest.mark.skip("FIXME: We need to restore the banner.") + @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") def test_multiple_interpreter(self): snippet = """ From b9a1227e47e8a83d75cfcb868b48be42463ff2e6 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Mon, 25 Sep 2023 16:14:20 +0000 Subject: [PATCH 062/105] Unskip some tests, delete others (#1742) Clean up a bit the testsuite and integration tests. Highlights: - Some of the @skipped tests just worked -- I unskipped them - some worked after some small tweak to adapt to the new pyscript next - some are still skipped, but I tweaked the skip message to be more precise and descriptive - Moreover, I killed/removed the ones which no longer make sense in the context of pyscript next; in particular, I removed all the ones which tested Element (which is now gone) and the one which tested py-config features which are no longer needed (e.g., multiple interpreters). The testsuite passes locally. --- pyscript.core/tests/integration/support.py | 3 +- .../tests/integration/test_01_basic.py | 12 +- .../tests/integration/test_02_display.py | 32 +- .../tests/integration/test_03_element.py | 303 ------------------ .../tests/integration/test_event_handling.py | 4 - .../tests/integration/test_py_config.py | 147 +-------- .../integration/test_runtime_attributes.py | 64 ---- .../tests/integration/test_script_type.py | 4 +- pyscript.core/tests/integration/test_style.py | 27 +- 9 files changed, 39 insertions(+), 557 deletions(-) delete mode 100644 pyscript.core/tests/integration/test_03_element.py delete mode 100644 pyscript.core/tests/integration/test_runtime_attributes.py diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py index c43a03ea..c27efeae 100644 --- a/pyscript.core/tests/integration/support.py +++ b/pyscript.core/tests/integration/support.py @@ -126,7 +126,7 @@ def filter_page_content(lines, exclude=None): @pytest.mark.usefixtures("init") -@with_execution_thread("main", "worker") +@with_execution_thread("main") # , "worker") # XXX re-enable workers eventually class PyScriptTest: """ Base class to write PyScript integration tests, based on playwright. @@ -179,6 +179,7 @@ class PyScriptTest: # create a symlink to BUILD inside tmpdir tmpdir.join("build").mksymlinkto(BUILD) self.tmpdir.chdir() + self.tmpdir.join('favicon.ico').write("") self.logger = logger self.execution_thread = execution_thread self.dev_server = None diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index 57b1f32f..fbba9390 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -167,7 +167,6 @@ class TestBasic(PyScriptTest): "C true false", "D
"] - @pytest.mark.skip(reason="FIX TEST: Works on CHROME") def test_packages(self): self.pyscript_run( """ @@ -188,8 +187,6 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] - # TODO: if there's no """, wait_for_pyscript=False, ) @@ -211,8 +211,6 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") - # TODO: if there's no """, wait_for_pyscript=False, ) @@ -350,7 +351,6 @@ class TestBasic(PyScriptTest): assert script_py_tag.evaluate("node => node.srcCode") == 'print("hello from script py")' - @pytest.mark.skip(reason="FIX TEST: works in chrome!") def test_py_attribute_without_id(self): self.pyscript_run( """ diff --git a/pyscript.core/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py index 90c304d2..662055b1 100644 --- a/pyscript.core/tests/integration/test_02_display.py +++ b/pyscript.core/tests/integration/test_02_display.py @@ -2,6 +2,7 @@ import base64 import io import os import re +import html import numpy as np import pytest @@ -315,7 +316,6 @@ class TestDisplay(PyScriptTest): == "['A', 1, '!']\n{'B': 2, 'List': ['A', 1, '!']}\n('C', 3, '!')" ) - @pytest.mark.skip("The asserts are commented out. Investigate") def test_display_should_escape(self): self.pyscript_run( """ @@ -325,13 +325,10 @@ class TestDisplay(PyScriptTest): """ ) - # out = self.page.locator("script-py > div") - node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) - node_list[0] - # assert out.inner_html() == html.escape("

hello world

") - # assert out.inner_text() == "

hello world

" + out = self.page.locator("script-py > div") + assert out.inner_html() == html.escape("

hello world

") + assert out.inner_text() == '

hello world

' - @pytest.mark.skip("The asserts are commented out. Investigate") def test_display_HTML(self): self.pyscript_run( """ @@ -341,17 +338,13 @@ class TestDisplay(PyScriptTest): """ ) - # out = self.page.locator("script-py > div") - node_list = self.page.query_selector_all(DISPLAY_OUTPUT_ID_PATTERN) - node_list[0] - # assert out.inner_html() == "

hello world

" - # assert out.inner_text() == "hello world" + out = self.page.locator("script-py > div") + assert out.inner_html() == "

hello world

" + assert out.inner_text() == "hello world" - @pytest.mark.skip( - "FIX TEST: Works correctly in Chrome, but fails in TEST with the error:\n\n" - "It's likely that the Test framework injections in config are causing" - "this error." - ) + # waiit_for_pyscript is broken: it waits until the python code is about to + # start, to until the python code has finished execution + @pytest.mark.skip("FIXME: wait_for_pyscript is broken") def test_image_display(self): self.pyscript_run( """ @@ -435,11 +428,6 @@ class TestDisplay(PyScriptTest): assert console_text.index("1print") == (console_text.index("2print") - 1) assert console_text.index("1console") == (console_text.index("2console") - 1) - @pytest.mark.skip( - "FIX TEST: Works correctly in Chrome, but fails in TEST with the error:\n\n" - "It's likely that the Test framework injections in config are causing" - "this error." - ) def test_image_renders_correctly(self): """This is just a sanity check to make sure that images are rendered correctly.""" buffer = io.BytesIO() diff --git a/pyscript.core/tests/integration/test_03_element.py b/pyscript.core/tests/integration/test_03_element.py deleted file mode 100644 index bf082f1f..00000000 --- a/pyscript.core/tests/integration/test_03_element.py +++ /dev/null @@ -1,303 +0,0 @@ -import pytest - -from .support import PyScriptTest - - -class TestElement(PyScriptTest): - """Test the Element api""" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_id(self): - """Test the element id""" - self.pyscript_run( - """ -
- - """ - ) - assert self.console.log.lines[-1] == "foo" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "foo" in py_terminal.inner_text() - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_value(self): - """Test the element value""" - self.pyscript_run( - """ - - - """ - ) - assert self.console.log.lines[-1] == "bar" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "bar" in py_terminal.inner_text() - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_innerHtml(self): - """Test the element innerHtml""" - self.pyscript_run( - """ -
bar
- - """ - ) - assert self.console.log.lines[-1] == "bar" - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "bar" in py_terminal.inner_text() - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_write_no_append(self): - """Test the element write""" - self.pyscript_run( - """ -
- - """ - ) - div = self.page.wait_for_selector("#foo") - assert "World!" in div.inner_text() - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_write_append(self): - """Test the element write""" - self.pyscript_run( - """ -
- - """ - ) - parent_div = self.page.wait_for_selector("#foo") - - assert "Hello!" in parent_div.inner_text() - # confirm that the second write was appended - assert "Hello!
World!
" in parent_div.inner_html() - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_clear_div(self): - """Test the element clear""" - self.pyscript_run( - """ -
Hello!
- - """ - ) - div = self.page.locator("#foo") - assert div.inner_text() == "" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_clear_input(self): - """Test the element clear""" - self.pyscript_run( - """ - - - """ - ) - input = self.page.wait_for_selector("#foo") - assert input.input_value() == "" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_select(self): - """Test the element select""" - self.pyscript_run( - """ - - - """ - ) - assert self.console.log.lines[-1] == "bar" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_select_content(self): - """Test the element select""" - self.pyscript_run( - """ - - - """ - ) - assert self.console.log.lines[-1] == "Bar" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_clone_no_id(self): - """Test the element clone""" - self.pyscript_run( - """ -
Hello!
- - """ - ) - divs = self.page.locator("#foo") - assert divs.count() == 2 - assert divs.first.inner_text() == "Hello!" - assert divs.last.inner_text() == "Hello!" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_clone_with_id(self): - """Test the element clone""" - self.pyscript_run( - """ -
Hello!
- - """ - ) - divs = self.page.locator("#foo") - assert divs.count() == 1 - assert divs.inner_text() == "Hello!" - - clone = self.page.locator("#bar") - assert clone.inner_text() == "Hello!" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_clone_to_other_element(self): - """Test the element clone""" - self.pyscript_run( - """ -
-
- Bond -
-
- James -
-
- - """ - ) - bond_divs = self.page.locator("#bond") - james_divs = self.page.locator("#james") - bond_2_divs = self.page.locator("#bond-2") - - assert bond_divs.count() == 1 - assert james_divs.count() == 1 - assert bond_2_divs.count() == 1 - - container_div = self.page.locator("#container") - # Make sure that the clones are rendered in the right order - assert container_div.inner_text() == "Bond\nJames\nBond" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_remove_single_class(self): - """Test the element remove_class""" - self.pyscript_run( - """ -
- - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "baz" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_remove_multiple_classes(self): - """Test the element remove_class""" - self.pyscript_run( - """ -
- - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_add_single_class(self): - """Test the element add_class""" - self.pyscript_run( - """ - -
Hi!
- - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "red" - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_element_add_multiple_class(self): - """Test the element add_class""" - self.pyscript_run( - """ - -
Hi!
- - """ - ) - div = self.page.locator("#foo") - assert div.get_attribute("class") == "red bold" diff --git a/pyscript.core/tests/integration/test_event_handling.py b/pyscript.core/tests/integration/test_event_handling.py index a0a15e7b..70de16a8 100644 --- a/pyscript.core/tests/integration/test_event_handling.py +++ b/pyscript.core/tests/integration/test_event_handling.py @@ -2,10 +2,6 @@ import pytest from .support import PyScriptTest -pytest.skip( - reason="FIXME: @when decorator missing from pyscript", allow_module_level=True -) - class TestEventHandler(PyScriptTest): def test_when_decorator_with_event(self): diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py index b913a757..f9722bb3 100644 --- a/pyscript.core/tests/integration/test_py_config.py +++ b/pyscript.core/tests/integration/test_py_config.py @@ -1,45 +1,9 @@ import os -import tarfile -import tempfile -from pathlib import Path import pytest -import requests from .support import PyScriptTest, with_execution_thread -PYODIDE_VERSION = "0.23.4" - - -@pytest.fixture -def pyodide_tar(request): - """ - Fixture which returns a local copy of pyodide. It uses pytest-cache to - avoid re-downloading it between runs. - """ - URL = ( - f"https://github.com/pyodide/pyodide/releases/download/{PYODIDE_VERSION}/" - f"pyodide-core-{PYODIDE_VERSION}.tar.bz2" - ) - tar_name = Path(URL).name - - val = request.config.cache.get(tar_name, None) - if val is None: - response = requests.get(URL, stream=True) - TMP_DIR = tempfile.mkdtemp() - TMP_TAR_LOCATION = os.path.join(TMP_DIR, tar_name) - with open(TMP_TAR_LOCATION, "wb") as f: - f.write(response.raw.read()) - val = TMP_TAR_LOCATION - request.config.cache.set(tar_name, val) - return val - - -def unzip(location, extract_to="."): - file = tarfile.open(name=location, mode="r:bz2") - file.extractall(path=extract_to) - - # Disable the main/worker dual testing, for two reasons: # # 1. the logic happens before we start the worker, so there is @@ -103,37 +67,6 @@ class TestConfig(PyScriptTest): ) assert self.console.log.lines[-1] == "config name: app with external config" - # The default pyodide version is newer than - # the one we are loading below (after downloading locally) - # which is 0.22.0 - - # The test checks if loading a different interpreter is possible - # and that too from a locally downloaded file without needing - # the use of explicit `indexURL` calculation. - @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") - def test_interpreter_config(self, pyodide_tar): - unzip(pyodide_tar, extract_to=self.tmpdir) - self.pyscript_run( - """ - - { - "interpreters": [{ - "src": "/pyodide/pyodide.js", - "name": "my-own-pyodide", - "lang": "python" - }] - } - - - - """, - ) - - assert self.console.log.lines[-1] == f"version {PYODIDE_VERSION}" @pytest.mark.skip("FIXME: We need to restore the banner.") def test_invalid_json_config(self): @@ -148,14 +81,13 @@ class TestConfig(PyScriptTest): wait_for_pyscript=False, ) banner = self.page.wait_for_selector(".py-error") - assert "SyntaxError: Unexpected end of JSON input" in self.console.error.text + #assert "Unexpected end of JSON input" in self.console.error.text expected = ( - "(PY1000): The config supplied: [[ is an invalid JSON and cannot be " - "parsed: SyntaxError: Unexpected end of JSON input" + "(PY1000): Invalid JSON\n" + "Unexpected end of JSON input" ) assert banner.inner_text() == expected - @pytest.mark.skip("FIXME: We need to restore the banner.") def test_invalid_toml_config(self): # we need wait_for_pyscript=False because we bail out very soon, # before being able to write 'PyScript page fully initialized' @@ -168,15 +100,15 @@ class TestConfig(PyScriptTest): wait_for_pyscript=False, ) banner = self.page.wait_for_selector(".py-error") - assert "SyntaxError: Expected DoubleQuote" in self.console.error.text + #assert "Expected DoubleQuote" in self.console.error.text expected = ( - "(PY1000): The config supplied: [[ is an invalid TOML and cannot be parsed: " - "SyntaxError: Expected DoubleQuote, Whitespace, or [a-z], [A-Z], " - '[0-9], "-", "_" but "\\n" found.' + "(PY1000): Invalid TOML\n" + "Expected DoubleQuote, Whitespace, or [a-z], [A-Z], " + '[0-9], "-", "_" but end of input found.' ) assert banner.inner_text() == expected - @pytest.mark.skip("FIXME: We need to restore the banner.") + @pytest.mark.skip("FIXME: emit a warning in case of multiple py-config") def test_multiple_py_config(self): self.pyscript_run( """ @@ -185,13 +117,13 @@ class TestConfig(PyScriptTest): - this is ignored and won't even be parsed + name = "this is ignored" """ ) @@ -202,54 +134,6 @@ class TestConfig(PyScriptTest): ) assert banner.text_content() == expected - @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") - def test_no_interpreter(self): - snippet = """ - - { - "interpreters": [] - } - - """ - self.pyscript_run(snippet, wait_for_pyscript=False) - div = self.page.wait_for_selector(".py-error") - assert ( - div.text_content() == "(PY1000): Fatal error: config.interpreter is empty" - ) - - @pytest.mark.skip("Interpreters key is not implemented in PyScript Next") - def test_multiple_interpreter(self): - snippet = """ - - { - "interpreters": [ - { - "src": "https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js", - "name": "pyodide-0.23.2", - "lang": "python" - }, - { - "src": "http://...", - "name": "this will be ignored", - "lang": "this as well" - } - ] - } - - - - """ - self.pyscript_run(snippet) - banner = self.page.wait_for_selector(".py-warning") - expected = ( - "Multiple interpreters are not supported yet.Only the first will be used" - ) - assert banner.text_content() == expected - assert self.console.log.lines[-1] == "hello world" - def test_paths(self): self.writefile("a.py", "x = 'hello from A'") self.writefile("b.py", "x = 'hello from B'") @@ -273,7 +157,7 @@ class TestConfig(PyScriptTest): "hello from B", ] - @pytest.mark.skip("FIXME: We need to restore the banner.") + @pytest.mark.skip("FIXME: emit an error if fetch fails") def test_paths_that_do_not_exist(self): self.pyscript_run( """ @@ -281,16 +165,19 @@ class TestConfig(PyScriptTest): [[fetch]] files = ["./f.py"]
+ + """, wait_for_pyscript=False, ) expected = "(PY0404): Fetching from URL ./f.py failed with " "error 404" - inner_html = self.page.locator(".py-error").inner_html() - assert expected in inner_html assert expected in self.console.error.lines[-1] + assert self.console.log.lines == [] def test_paths_from_packages(self): self.writefile("utils/__init__.py", "") diff --git a/pyscript.core/tests/integration/test_runtime_attributes.py b/pyscript.core/tests/integration/test_runtime_attributes.py deleted file mode 100644 index 621b43a1..00000000 --- a/pyscript.core/tests/integration/test_runtime_attributes.py +++ /dev/null @@ -1,64 +0,0 @@ -import pytest - -from .support import PyScriptTest - - -class TestPyScriptRuntimeAttributes(PyScriptTest): - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_injected_html_with_py_event(self): - self.pyscript_run( - r""" -
- - """ - ) - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_added_py_event(self): - self.pyscript_run( - r""" - - - """ - ) - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] - - @pytest.mark.skip("FIXME: Element interface is gone. Replace with PyDom") - def test_added_then_removed_py_event(self): - self.pyscript_run( - r""" - - - """ - ) - self.page.locator("button").click() - self.page.locator("button").click() - assert self.console.log.lines == ["hello pyscript"] diff --git a/pyscript.core/tests/integration/test_script_type.py b/pyscript.core/tests/integration/test_script_type.py index 8173f1b3..fd338290 100644 --- a/pyscript.core/tests/integration/test_script_type.py +++ b/pyscript.core/tests/integration/test_script_type.py @@ -81,12 +81,12 @@ class TestScriptTypePyScript(PyScriptTest): ) assert self.console.log.lines[-1] == "hello from foo" - @pytest.mark.skip("FIXME: test failure is unrelated") + @pytest.mark.skip("FIXME: wait_for_pyscript is broken") def test_script_type_py_worker_attribute(self): self.writefile("foo.py", "print('hello from foo')") self.pyscript_run( """ - + """ ) assert self.console.log.lines[-1] == "hello from foo" diff --git a/pyscript.core/tests/integration/test_style.py b/pyscript.core/tests/integration/test_style.py index 6eb6e851..cc37315b 100644 --- a/pyscript.core/tests/integration/test_style.py +++ b/pyscript.core/tests/integration/test_style.py @@ -3,11 +3,6 @@ from playwright.sync_api import expect from .support import PyScriptTest, skip_worker -pytest.skip( - reason="FIX TESTS: These tests should reflect new PyScript and remove/change css ", - allow_module_level=True, -) - class TestStyle(PyScriptTest): def test_pyscript_not_defined(self): @@ -15,12 +10,11 @@ class TestStyle(PyScriptTest): doc = """ - + hello - - hello + hello """ @@ -28,20 +22,3 @@ class TestStyle(PyScriptTest): self.goto("test-not-defined-css.html") expect(self.page.locator("py-config")).to_be_hidden() expect(self.page.locator("py-script")).to_be_hidden() - expect(self.page.locator("py-repl")).to_be_hidden() - - @skip_worker("FIXME: display()") - def test_pyscript_defined(self): - """Test elements have visibility that should""" - self.pyscript_run( - """ - - name = "foo" - - - display("hello") - """ - ) - expect(self.page.locator("py-config")).to_be_hidden() - expect(self.page.locator("py-script")).to_be_visible() - expect(self.page.locator("py-repl")).to_be_visible() From 3ac2ac098285f61a4d06c26534aecdb0f6decc32 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 26 Sep 2023 15:56:50 +0200 Subject: [PATCH 063/105] Added `py:all-done` event (#1756) --- pyscript.core/package-lock.json | 50 +++++++-------- pyscript.core/package.json | 4 +- pyscript.core/src/all-done.js | 62 +++++++++++++++++++ pyscript.core/src/core.js | 35 +++-------- pyscript.core/src/hooks.js | 21 +++++++ pyscript.core/test/all-done.html | 39 ++++++++++++ pyscript.core/test/dialog.html | 31 ++++++++++ .../tests/integration/test_01_basic.py | 44 ++++++++++--- pyscript.core/types/all-done.d.ts | 1 + pyscript.core/types/core.d.ts | 14 +---- pyscript.core/types/hooks.d.ts | 12 ++++ 11 files changed, 239 insertions(+), 74 deletions(-) create mode 100644 pyscript.core/src/all-done.js create mode 100644 pyscript.core/src/hooks.js create mode 100644 pyscript.core/test/all-done.html create mode 100644 pyscript.core/test/dialog.html create mode 100644 pyscript.core/types/all-done.d.ts create mode 100644 pyscript.core/types/hooks.d.ts diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index d225830a..c9e8c964 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,17 +1,17 @@ { "name": "@pyscript/core", - "version": "0.2.3", + "version": "0.2.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.2.3", + "version": "0.2.4", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.2" + "polyscript": "^0.4.6" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", @@ -49,9 +49,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", - "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.2.tgz", + "integrity": "sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -851,9 +851,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.528", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.528.tgz", - "integrity": "sha512-UdREXMXzLkREF4jA8t89FQjA8WHI6ssP38PMY4/4KhXFQbtImnghh4GkCgrtiZwLKUKVD2iTVXvDVQjfomEQuA==", + "version": "1.4.529", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.529.tgz", + "integrity": "sha512-6uyPyXTo8lkv8SWAmjKFbG42U073TXlzD4R8rW3EzuznhFS2olCIAfjjQtV2dV2ar/vRF55KUd3zQYnCB0dd3A==", "dev": true }, "node_modules/entities": { @@ -1278,15 +1278,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/import-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", @@ -1299,6 +1290,15 @@ "node": ">=8" } }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1776,9 +1776,9 @@ "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, "node_modules/polyscript": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.2.tgz", - "integrity": "sha512-3mM5Y/DdpYND8/INAUmgF5VL4InVc04xADB+of129t8RjXi3eZK4xoGRPZdTYzW+wM56WNptnC8fC9Zt7jKLoA==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.6.tgz", + "integrity": "sha512-yRL8iwa8NHCWYIkYIRZ7Ujwd69WaDKAoeFxhQRLkTmcdlKKFxoFJStwyb5PONWZUl+mb+oXGkrPPsRaAJHHipQ==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", @@ -2421,12 +2421,12 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/reusify": { diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 973f0f27..543baab5 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.2.3", + "version": "0.2.4", "type": "module", "description": "PyScript", "module": "./index.js", @@ -33,7 +33,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.2" + "polyscript": "^0.4.6" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", diff --git a/pyscript.core/src/all-done.js b/pyscript.core/src/all-done.js new file mode 100644 index 00000000..8eb8afd2 --- /dev/null +++ b/pyscript.core/src/all-done.js @@ -0,0 +1,62 @@ +import TYPES from "./types.js"; +import hooks from "./hooks.js"; + +const DONE = "py:all-done"; + +const { + onAfterRun, + onAfterRunAsync, + codeAfterRunWorker, + codeAfterRunWorkerAsync, +} = hooks; + +const waitForIt = []; +const codes = []; + +const codeFor = (element) => { + const isAsync = element.hasAttribute("async"); + const { promise, resolve } = Promise.withResolvers(); + const type = `${DONE}:${waitForIt.push(promise)}`; + + // resolve each promise once notified + addEventListener(type, resolve, { once: true }); + + if (element.hasAttribute("worker")) { + const code = ` + from pyscript import window as _w + _w.dispatchEvent(_w.Event.new("${type}")) + `; + if (isAsync) codeAfterRunWorkerAsync.add(code); + else codeAfterRunWorker.add(code); + return code; + } + + // dispatch only once the ready element is the same + const code = (_, el) => { + if (el === element) dispatchEvent(new Event(type)); + }; + + if (isAsync) onAfterRunAsync.add(code); + else onAfterRun.add(code); + return code; +}; + +const selector = []; +for (const [TYPE] of TYPES) + selector.push(`script[type="${TYPE}"]`, `${TYPE}-script`); + +// loop over all known scripts and elements +for (const element of document.querySelectorAll(selector.join(","))) + codes.push(codeFor(element)); + +// wait for all the things then cleanup +Promise.all(waitForIt).then(() => { + // cleanup unnecessary hooks + for (const code of codes) { + onAfterRun.delete(code); + onAfterRunAsync.delete(code); + codeAfterRunWorker.delete(code); + codeAfterRunWorkerAsync.delete(code); + } + dispatchEvent(new Event(DONE)); +}); diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index d3f0c0e0..30900f77 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -1,16 +1,21 @@ /*! (c) PyScript Development Team */ import "@ungap/with-resolvers"; -import { INVALID_CONTENT, define, XWorker } from "polyscript"; -// TODO: this is not strictly polyscript related but handy ... not sure -// we should factor this utility out a part but this works anyway. +// These imports can hook more than usual and help debugging possible polyscript issues +import { + INVALID_CONTENT, + define, + XWorker, +} from "../node_modules/polyscript/esm/index.js"; import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js"; import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; +import "./all-done.js"; import TYPES from "./types.js"; import configs from "./config.js"; +import hooks from "./hooks.js"; import sync from "./sync.js"; import stdlib from "./stdlib.js"; import { ErrorCode } from "./exceptions.js"; @@ -66,28 +71,6 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => { interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") }); }; -export const hooks = { - /** @type {Set} */ - onBeforeRun: new Set(), - /** @type {Set} */ - onBeforeRunAsync: new Set(), - /** @type {Set} */ - onAfterRun: new Set(), - /** @type {Set} */ - onAfterRunAsync: new Set(), - /** @type {Set} */ - onInterpreterReady: new Set(), - - /** @type {Set} */ - codeBeforeRunWorker: new Set(), - /** @type {Set} */ - codeBeforeRunWorkerAsync: new Set(), - /** @type {Set} */ - codeAfterRunWorker: new Set(), - /** @type {Set} */ - codeAfterRunWorkerAsync: new Set(), -}; - const workerHooks = { codeBeforeRunWorker: () => [stdlib, ...hooks.codeBeforeRunWorker].map(dedent).join("\n"), @@ -100,7 +83,7 @@ const workerHooks = { }; const exportedConfig = {}; -export { exportedConfig as config }; +export { exportedConfig as config, hooks }; for (const [TYPE, interpreter] of TYPES) { const { config, plugins, error } = configs.get(TYPE); diff --git a/pyscript.core/src/hooks.js b/pyscript.core/src/hooks.js new file mode 100644 index 00000000..2ba29457 --- /dev/null +++ b/pyscript.core/src/hooks.js @@ -0,0 +1,21 @@ +export default { + /** @type {Set} */ + onBeforeRun: new Set(), + /** @type {Set} */ + onBeforeRunAsync: new Set(), + /** @type {Set} */ + onAfterRun: new Set(), + /** @type {Set} */ + onAfterRunAsync: new Set(), + /** @type {Set} */ + onInterpreterReady: new Set(), + + /** @type {Set} */ + codeBeforeRunWorker: new Set(), + /** @type {Set} */ + codeBeforeRunWorkerAsync: new Set(), + /** @type {Set} */ + codeAfterRunWorker: new Set(), + /** @type {Set} */ + codeAfterRunWorkerAsync: new Set(), +}; diff --git a/pyscript.core/test/all-done.html b/pyscript.core/test/all-done.html new file mode 100644 index 00000000..a0848175 --- /dev/null +++ b/pyscript.core/test/all-done.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + print(2) + + + print(3) + + + + print(5) + + + diff --git a/pyscript.core/test/dialog.html b/pyscript.core/test/dialog.html new file mode 100644 index 00000000..05c9736a --- /dev/null +++ b/pyscript.core/test/dialog.html @@ -0,0 +1,31 @@ + + + + + + PyScript Next + + + + + + + + Loading PyScript ... + + + diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index fbba9390..18557efe 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -20,8 +20,10 @@ class TestBasic(PyScriptTest): """ ) - assert self.console.log.lines == ["hello from script py", - "hello from py-script"] + assert self.console.log.lines == [ + "hello from script py", + "hello from py-script", + ] def test_execution_thread(self): self.pyscript_run( @@ -162,10 +164,12 @@ class TestBasic(PyScriptTest): """ ) - assert self.console.log.lines[-4:] == ["A true false", - "B
", - "C true false", - "D
"] + assert self.console.log.lines[-4:] == [ + "A true false", + "B
", + "C true false", + "D
", + ] def test_packages(self): self.pyscript_run( @@ -346,10 +350,15 @@ class TestBasic(PyScriptTest): ) pyscript_tag = self.page.locator("py-script") assert pyscript_tag.inner_html() == "" - assert pyscript_tag.evaluate("node => node.srcCode") == 'print("hello from py-script")' + assert ( + pyscript_tag.evaluate("node => node.srcCode") + == 'print("hello from py-script")' + ) script_py_tag = self.page.locator('script[type="py"]') - assert script_py_tag.evaluate("node => node.srcCode") == 'print("hello from script py")' - + assert ( + script_py_tag.evaluate("node => node.srcCode") + == 'print("hello from script py")' + ) def test_py_attribute_without_id(self): self.pyscript_run( @@ -366,3 +375,20 @@ class TestBasic(PyScriptTest): self.wait_for_console("hello world!") assert self.console.log.lines[-1] == "hello world!" assert self.console.error.lines == [] + + def test_py_all_done_event(self): + self.pyscript_run( + """ + + + """ + ) + btn = self.page.wait_for_selector("button") + btn.click() + self.wait_for_console("1") + assert self.console.log.lines[-1] == "2" + assert self.console.error.lines == [] diff --git a/pyscript.core/types/all-done.d.ts b/pyscript.core/types/all-done.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/pyscript.core/types/all-done.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index b3610456..5d64bae9 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -10,17 +10,7 @@ export function PyWorker(file: string, options?: { }): Worker & { sync: ProxyHandler; }; -export namespace hooks { - let onBeforeRun: Set; - let onBeforeRunAsync: Set; - let onAfterRun: Set; - let onAfterRunAsync: Set; - let onInterpreterReady: Set; - let codeBeforeRunWorker: Set; - let codeBeforeRunWorkerAsync: Set; - let codeAfterRunWorker: Set; - let codeAfterRunWorkerAsync: Set; -} -export { exportedConfig as config }; import sync from "./sync.js"; declare const exportedConfig: {}; +import hooks from "./hooks.js"; +export { exportedConfig as config, hooks }; diff --git a/pyscript.core/types/hooks.d.ts b/pyscript.core/types/hooks.d.ts new file mode 100644 index 00000000..80269b4d --- /dev/null +++ b/pyscript.core/types/hooks.d.ts @@ -0,0 +1,12 @@ +declare namespace _default { + let onBeforeRun: Set; + let onBeforeRunAsync: Set; + let onAfterRun: Set; + let onAfterRunAsync: Set; + let onInterpreterReady: Set; + let codeBeforeRunWorker: Set; + let codeBeforeRunWorkerAsync: Set; + let codeAfterRunWorker: Set; + let codeAfterRunWorkerAsync: Set; +} +export default _default; From abfc68765fc1a59de07d909e86d0c764f613f483 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Wed, 27 Sep 2023 08:05:40 +0000 Subject: [PATCH 064/105] Enable worker tests (#1757) This PR re-enables tests on `worker`s. Highlights: * by default, each test is run twice: the main thread version uses ` + + {extra_head} - {py_config_maybe} {snippet} @@ -578,7 +571,7 @@ class PyScriptTest: Ensure that there is an alert banner on the page with the given message. Currently it only handles a single. """ - banner = self.page.wait_for_selector(".alert-banner") + banner = self.page.wait_for_selector(".py-error") banner_text = banner.inner_text() if expected_message not in banner_text: diff --git a/pyscript.core/tests/integration/test_00_support.py b/pyscript.core/tests/integration/test_00_support.py index 7e164ae0..f3500a65 100644 --- a/pyscript.core/tests/integration/test_00_support.py +++ b/pyscript.core/tests/integration/test_00_support.py @@ -474,22 +474,3 @@ class TestSupport(PyScriptTest): assert [ "Failed to load resource: the server responded with a status of 404 (Not Found)" ] == self.console.all.lines - - def test__pyscript_format_inject_execution_thread(self): - """ - This is slightly different than other tests: it doesn't use playwright, it - just tests that our own internal helper works - """ - doc = self._pyscript_format("Hello", execution_thread="main") - cfg = self._parse_py_config(doc) - assert cfg == {"execution_thread": "main"} - - def test__pyscript_format_modify_existing_py_config(self): - src = """ - - hello = 42 - - """ - doc = self._pyscript_format(src, execution_thread="main") - cfg = self._parse_py_config(doc) - assert cfg == {"execution_thread": "main", "hello": 42} diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index 18557efe..6bb306cc 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -2,7 +2,7 @@ import re import pytest -from .support import PyScriptTest +from .support import PyScriptTest, skip_worker, only_main class TestBasic(PyScriptTest): @@ -11,40 +11,45 @@ class TestBasic(PyScriptTest): """ import js - js.console.log('hello from py-script') + js.console.log('2. hello from py-script') """ ) - assert self.console.log.lines == [ - "hello from script py", - "hello from py-script", - ] + if self.execution_thread == "main": + # in main, the order of execution is guaranteed + assert self.console.log.lines == [ + "1. hello from script py", + "2. hello from py-script", + ] + else: + # in workers, each tag is executed by its own worker, so they can + # come out of order + lines = sorted(self.console.log.lines) + assert lines == ["1. hello from script py", "2. hello from py-script"] def test_execution_thread(self): self.pyscript_run( """ - + """, - wait_for_pyscript=False, ) assert self.execution_thread in ("main", "worker") - if self.execution_thread == "main": - pass - elif self.execution_thread == "worker": - pass - assert self.console.log.lines == [] + in_worker = self.execution_thread == "worker" + in_worker = str(in_worker).lower() + assert self.console.log.lines[-1] == f"worker? {in_worker}" # TODO: if there's no py-script there are surely no plugins neither # this test must be discussed or rewritten to make sense now - @pytest.mark.skip( - reason="FIXME: No banner and should also add a WARNING about CORS" - ) + @pytest.mark.skip(reason="NEXT: No banner and should also add a WARNING about CORS") def test_no_cors_headers(self): self.disable_cors_headers() self.pyscript_run( @@ -79,6 +84,7 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello pyscript" + @skip_worker("NEXT: exceptions should be displayed in the DOM") def test_python_exception(self): self.pyscript_run( """ @@ -104,6 +110,7 @@ class TestBasic(PyScriptTest): assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error" + @skip_worker("NEXT: py-click doesn't work inside workers") def test_python_exception_in_event_handler(self): self.pyscript_run( """ @@ -131,6 +138,7 @@ class TestBasic(PyScriptTest): assert tb_lines[0] == "Traceback (most recent call last):" assert tb_lines[-1] == "Exception: this is an error inside handler" + @only_main def test_execution_in_order(self): """ Check that they script py tags are executed in the same order they are @@ -151,6 +159,7 @@ class TestBasic(PyScriptTest): "four", ] + @skip_worker("NEXT: something very weird happens here") def test_escaping_of_angle_brackets(self): """ Check that script tags escape angle brackets @@ -158,13 +167,16 @@ class TestBasic(PyScriptTest): self.pyscript_run( """ - + import js; js.console.log("C", 1<2, 1>2) - js.console.log("D
")
+ import js; js.console.log("D
")
""" ) - assert self.console.log.lines[-4:] == [ + # in workers the order of execution is not guaranteed, better to play + # safe + lines = sorted(self.console.log.lines[-4:]) + assert lines == [ "A true false", "B
", "C true false", @@ -191,7 +203,7 @@ class TestBasic(PyScriptTest): "hello asciitree", # printed by us ] - @pytest.mark.skip("FIXME: No banner") + @pytest.mark.skip("NEXT: No banner") def test_non_existent_package(self): self.pyscript_run( """ @@ -215,7 +227,7 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't fetch metadata for 'i-dont-exist'") - @pytest.mark.skip("FIXME: No banner") + @pytest.mark.skip("NEXT: No banner") def test_no_python_wheel(self): self.pyscript_run( """ @@ -238,6 +250,7 @@ class TestBasic(PyScriptTest): assert expected_alert_banner_msg in alert_banner.inner_text() self.check_py_errors("Can't find a pure Python 3 wheel for 'opsdroid'") + @only_main def test_dynamically_add_py_script_tag(self): self.pyscript_run( """ @@ -265,6 +278,7 @@ class TestBasic(PyScriptTest): ) assert self.console.log.lines[-1] == "hello from foo" + @skip_worker("NEXT: banner not shown") def test_py_script_src_not_found(self): self.pyscript_run( """ @@ -275,17 +289,12 @@ class TestBasic(PyScriptTest): assert "Failed to load resource" in self.console.error.lines[0] # TODO: we need to be sure errors make sense from both main and worker worlds - # expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404" - # assert any((expected_msg in line) for line in self.console.js_error.lines) - # assert self.assert_banner_message(expected_msg) - - # pyscript_tag = self.page.locator("script-py") - # assert pyscript_tag.inner_html() == "" - - # self.check_js_errors(expected_msg) + expected_msg = "(PY0404): Fetching from URL foo.py failed with error 404" + assert any((expected_msg in line) for line in self.console.error.lines) + assert self.assert_banner_message(expected_msg) # TODO: ... and we shouldn't: it's a module and we better don't leak in global - @pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window") + @pytest.mark.skip("NEXT: we don't expose pyscript on window") def test_js_version(self): self.pyscript_run( """ @@ -301,7 +310,7 @@ class TestBasic(PyScriptTest): ) # TODO: ... and we shouldn't: it's a module and we better don't leak in global - @pytest.mark.skip("DIFFERENT BEHAVIOUR: we don't expose pyscript on window") + @pytest.mark.skip("NEXT: we don't expose pyscript on window") def test_python_version(self): self.pyscript_run( """ @@ -325,22 +334,7 @@ class TestBasic(PyScriptTest): is not None ) - def test_assert_no_banners(self): - """ - Test that the DOM doesn't contain error/warning banners - """ - self.pyscript_run( - """ - - """ - ) - - assert self.page.locator(".py-error").inner_text() == "hello world" - - @pytest.mark.skip("ERROR_SCRIPT: works with not with """ ) - btn = self.page.wait_for_selector("button") - btn.click() - self.wait_for_console("1") - assert self.console.log.lines[-1] == "2" + assert self.console.log.lines == ["1", "2"] assert self.console.error.lines == [] diff --git a/pyscript.core/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py index 662055b1..9fc227e5 100644 --- a/pyscript.core/tests/integration/test_02_display.py +++ b/pyscript.core/tests/integration/test_02_display.py @@ -1,3 +1,5 @@ +################################################################################ + import base64 import io import os @@ -13,9 +15,11 @@ from .support import ( filter_inner_text, filter_page_content, wait_for_render, + skip_worker, + only_main, ) -DISPLAY_OUTPUT_ID_PATTERN = r'[id^="py-"]' +DISPLAY_OUTPUT_ID_PATTERN = r'script-py[id^="py-"]' class TestDisplay(PyScriptTest): @@ -68,6 +72,7 @@ class TestDisplay(PyScriptTest): mydiv = self.page.locator("#mydiv") assert mydiv.inner_text() == "hello world" + @skip_worker("NEXT: display(target=...) does not work") def test_tag_target_attribute(self): self.pyscript_run( """ @@ -87,6 +92,7 @@ class TestDisplay(PyScriptTest): goodbye = self.page.locator("#goodbye") assert goodbye.inner_text() == "goodbye world" + @skip_worker("NEXT: display target does not work properly") def test_target_script_py(self): self.pyscript_run( """ @@ -105,6 +111,7 @@ class TestDisplay(PyScriptTest): text = self.page.inner_text("body") assert text == "ONE\nTWO\nTHREE" + @skip_worker("NEXT: display target does not work properly") def test_consecutive_display_target(self): self.pyscript_run( """ @@ -142,6 +149,7 @@ class TestDisplay(PyScriptTest): lines = tag.inner_text().splitlines() assert lines == ["hello", "world"] + @only_main # with workers, two tags are two separate interpreters def test_implicit_target_from_a_different_tag(self): self.pyscript_run( """ @@ -163,6 +171,7 @@ class TestDisplay(PyScriptTest): assert py0.inner_text() == "" assert py1.inner_text() == "hello" + @skip_worker("NEXT: py-click doesn't work") def test_no_explicit_target(self): self.pyscript_run( """ @@ -179,6 +188,7 @@ class TestDisplay(PyScriptTest): text = self.page.locator("script-py").text_content() assert "hello world" in text + @skip_worker("NEXT: display target does not work properly") def test_explicit_target_pyscript_tag(self): self.pyscript_run( """ @@ -195,6 +205,7 @@ class TestDisplay(PyScriptTest): text = self.page.locator("script-py").nth(1).inner_text() assert text == "hello" + @skip_worker("NEXT: display target does not work properly") def test_explicit_target_on_button_tag(self): self.pyscript_run( """ @@ -327,7 +338,7 @@ class TestDisplay(PyScriptTest): ) out = self.page.locator("script-py > div") assert out.inner_html() == html.escape("

hello world

") - assert out.inner_text() == '

hello world

' + assert out.inner_text() == "

hello world

" def test_display_HTML(self): self.pyscript_run( @@ -342,9 +353,7 @@ class TestDisplay(PyScriptTest): assert out.inner_html() == "

hello world

" assert out.inner_text() == "hello world" - # waiit_for_pyscript is broken: it waits until the python code is about to - # start, to until the python code has finished execution - @pytest.mark.skip("FIXME: wait_for_pyscript is broken") + @skip_worker("NEXT: matplotlib-pyodide backend does not work") def test_image_display(self): self.pyscript_run( """ @@ -357,7 +366,8 @@ class TestDisplay(PyScriptTest): plt.plot(xpoints, ypoints) display(plt) - """ + """, + timeout=30 * 1000, ) wait_for_render(self.page, "*", " @@ -453,5 +460,5 @@ class TestDisplay(PyScriptTest): """ ) - rendered_img_src = self.page.locator("img").get_attribute("src") - assert rendered_img_src == expected_img_src + img_src = self.page.locator("img").get_attribute("src") + assert img_src.startswith('data:image/png;charset=utf-8;base64') diff --git a/pyscript.core/tests/integration/test_async.py b/pyscript.core/tests/integration/test_async.py index 3bac8b70..a9779eb5 100644 --- a/pyscript.core/tests/integration/test_async.py +++ b/pyscript.core/tests/integration/test_async.py @@ -1,5 +1,5 @@ import pytest -from .support import PyScriptTest, filter_inner_text +from .support import PyScriptTest, filter_inner_text, only_main class TestAsync(PyScriptTest): @@ -52,6 +52,7 @@ class TestAsync(PyScriptTest): self.wait_for_console("DONE") assert self.console.log.lines[-2:] == ["[3, 2, 1]", "DONE"] + @only_main def test_multiple_async(self): self.pyscript_run( """ @@ -88,6 +89,7 @@ class TestAsync(PyScriptTest): "b func done", ] + @only_main def test_multiple_async_multiple_display_targeted(self): self.pyscript_run( """ @@ -145,6 +147,7 @@ class TestAsync(PyScriptTest): self.wait_for_console("DONE") assert self.page.locator("script-py").inner_text() == "A" + @only_main def test_sync_and_async_order(self): """ The order of execution is defined as follows: diff --git a/pyscript.core/tests/integration/test_interpreter.py b/pyscript.core/tests/integration/test_interpreter.py index 9a7fcb5e..d7147208 100644 --- a/pyscript.core/tests/integration/test_interpreter.py +++ b/pyscript.core/tests/integration/test_interpreter.py @@ -3,7 +3,7 @@ import pytest from .support import PyScriptTest pytest.skip( - reason="FIXME: pyscript API changed doesn't expose pyscript to window anymore", + reason="NEXT: pyscript API changed doesn't expose pyscript to window anymore", allow_module_level=True, ) diff --git a/pyscript.core/tests/integration/test_plugins.py b/pyscript.core/tests/integration/test_plugins.py index 53ded193..8ee70738 100644 --- a/pyscript.core/tests/integration/test_plugins.py +++ b/pyscript.core/tests/integration/test_plugins.py @@ -3,7 +3,7 @@ import pytest from .support import PyScriptTest, skip_worker pytest.skip( - reason="FIX LATER: pyscript NEXT doesn't support plugins yet", + reason="NEXT: plugins not supported", allow_module_level=True, ) diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py index f9722bb3..0a868115 100644 --- a/pyscript.core/tests/integration/test_py_config.py +++ b/pyscript.core/tests/integration/test_py_config.py @@ -4,6 +4,7 @@ import pytest from .support import PyScriptTest, with_execution_thread + # Disable the main/worker dual testing, for two reasons: # # 1. the logic happens before we start the worker, so there is @@ -30,7 +31,7 @@ class TestConfig(PyScriptTest): ) assert self.console.log.lines[-1] == "config name: foobar" - @pytest.mark.skip("ERROR_SCRIPT: works with not with """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert "I've clicked [object HTMLButtonElement] with id foo_id" in console_text + self.wait_for_console("clicked foo_id") self.assert_no_banners() def test_when_decorator_without_event(self): @@ -42,7 +40,6 @@ class TestEventHandler(PyScriptTest): ) self.page.locator("text=foo_button").click() self.wait_for_console("The button was clicked") - assert "The button was clicked" in self.console.log.lines self.assert_no_banners() def test_multiple_when_decorators_with_event(self): @@ -53,23 +50,18 @@ class TestEventHandler(PyScriptTest): """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert "I've clicked [object HTMLButtonElement] with id foo_id" in console_text - + self.wait_for_console("foo_click! id=foo_id") self.page.locator("text=bar_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id bar_id") - assert "I've clicked [object HTMLButtonElement] with id bar_id" in console_text + self.wait_for_console("bar_click! id=bar_id") self.assert_no_banners() def test_two_when_decorators(self): @@ -83,15 +75,14 @@ class TestEventHandler(PyScriptTest): @when("click", selector="#foo_id") @when("mouseover", selector=".bar_class") def foo(evt): - print(f"An event of type {evt.type} happened") + print(f"got event: {evt.type}") """ ) self.page.locator("text=bar_button").hover() + self.wait_for_console("got event: mouseover") self.page.locator("text=foo_button").click() - self.wait_for_console("An event of type click happened") - assert "An event of type mouseover happened" in self.console.log.lines - assert "An event of type click happened" in self.console.log.lines + self.wait_for_console("got event: click") self.assert_no_banners() def test_two_when_decorators_same_element(self): @@ -104,15 +95,14 @@ class TestEventHandler(PyScriptTest): @when("click", selector="#foo_id") @when("mouseover", selector="#foo_id") def foo(evt): - print(f"An event of type {evt.type} happened") + print(f"got event: {evt.type}") """ ) self.page.locator("text=foo_button").hover() + self.wait_for_console("got event: mouseover") self.page.locator("text=foo_button").click() - self.wait_for_console("An event of type click happened") - assert "An event of type mouseover happened" in self.console.log.lines - assert "An event of type click happened" in self.console.log.lines + self.wait_for_console("got event: click") self.assert_no_banners() def test_when_decorator_multiple_elements(self): @@ -148,19 +138,18 @@ class TestEventHandler(PyScriptTest): @when("click", selector="#foo_id") @when("click", selector="#foo_id") def foo(evt): - print(f"I've clicked {evt.target} with id {evt.target.id}") + foo.n += 1 + print(f"click {foo.n} on {evt.target.id}") + foo.n = 0 """ ) self.page.locator("text=foo_button").click() - console_text = self.console.all.lines - self.wait_for_console("I've clicked [object HTMLButtonElement] with id foo_id") - assert ( - console_text.count("I've clicked [object HTMLButtonElement] with id foo_id") - == 2 - ) + self.wait_for_console("click 1 on foo_id") + self.wait_for_console("click 2 on foo_id") self.assert_no_banners() + @skip_worker("NEXT: error banner not shown") def test_when_decorator_invalid_selector(self): """When the selector parameter of @when is invalid, it should show an error""" self.pyscript_run( diff --git a/pyscript.core/tests/integration/test_zzz_docs_snippets.py b/pyscript.core/tests/integration/test_zzz_docs_snippets.py deleted file mode 100644 index 92b7ee57..00000000 --- a/pyscript.core/tests/integration/test_zzz_docs_snippets.py +++ /dev/null @@ -1,305 +0,0 @@ -import re -import pytest - -from .support import PyScriptTest, skip_worker - - -@pytest.mark.skip( - reason="SKIPPING Docs: these should be reviewed ALL TOGETHER as we fix docs" -) -class TestDocsSnippets(PyScriptTest): - @skip_worker("FIXME: js.document") - def test_tutorials_py_click(self): - self.pyscript_run( - """ - -

- - - """ - ) - - btn = self.page.wait_for_selector("#get-time") - btn.click() - - current_time = self.page.wait_for_selector("#current-time") - - pattern = "\\d+-\\d+-\\d+\\s\\d+:\\d+:\\d+" # e.g. 08-09-2022 15:57:32 - assert re.search(pattern, current_time.inner_text()) - self.assert_no_banners() - - def test_tutorials_requests(self): - self.pyscript_run( - """ - - packages = ["requests", "pyodide-http"] - - - - """ - ) - - py_terminal = self.page.wait_for_selector("py-terminal") - # Just a small check to confirm that the response was received - assert "userId" in py_terminal.inner_text() - self.assert_no_banners() - - @skip_worker("FIXME: js.document") - def test_tutorials_py_config_fetch(self): - # flake8: noqa - self.pyscript_run( - """ - - [[fetch]] - from = "https://pyscript.net/examples/" - files = ["utils.py"] - [[fetch]] - from = "https://gist.githubusercontent.com/FabioRosado/faba0b7f6ad4438b07c9ac567c73b864/raw/37603b76dc7ef7997bf36781ea0116150f727f44/" - files = ["todo.py"] - - -
-
-

- To Do List -

-
-
- - -
-
- Fold laundry

' - in first_task.inner_html() - ) - self.assert_no_banners() - - def test_tutorials_py_config_interpreter(self): - """Load a previous version of Pyodide""" - self.pyscript_run( - """ - - [[interpreters]] - src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js" - name = "pyodide-0.23.0" - lang = "python" - - - """ - ) - - py_terminal = self.page.wait_for_selector("py-terminal") - assert "0.23.0" in py_terminal.inner_text() - self.assert_no_banners() - - @skip_worker("FIXME: display()") - def test_tutorials_writing_to_page(self): - self.pyscript_run( - """ -
- -
- -
- -
- - - - """ - ) - btn_manual = self.page.wait_for_selector("#manual") - btn_display = self.page.wait_for_selector("#display") - btn_print = self.page.wait_for_selector("#print") - - btn_manual.click() - manual_write_div = self.page.wait_for_selector("#manual-write") - assert "

Hello World

" in manual_write_div.inner_html() - - btn_display.click() - display_write_div = self.page.wait_for_selector("#display-write") - assert "I display things!" in display_write_div.inner_text() - - btn_print.click() - py_terminal = self.page.wait_for_selector("py-terminal") - assert "I print things!" in py_terminal.inner_text() - self.assert_no_banners() - - def test_guides_asyncio(self): - self.pyscript_run( - """ - - """ - ) - py_terminal = self.page.wait_for_selector("py-terminal") - - assert "0\n1\n2\n" in py_terminal.inner_text() - - @skip_worker("FIXME: js.document") - def test_reference_pyterminal_xterm(self): - self.pyscript_run( - """ - - xterm = true - - - """ - ) - self.page.get_by_text("test-done").wait_for() - - py_terminal = self.page.locator("py-terminal") - print(dir(py_terminal)) - print(type(py_terminal)) - assert py_terminal.evaluate("el => el.xterm.cols") == 40 - assert py_terminal.evaluate("el => el.xterm.rows") == 10 - - @skip_worker(reason="FIXME: js.document (@when decorator)") - def test_reference_when_simple(self): - self.pyscript_run( - """ - - - """ - ) - self.page.get_by_text("Click Me to Say Hi").click() - self.wait_for_console("Hello, world!") - assert ("Hello, world!") in self.console.log.lines - - @skip_worker(reason="FIXME: js.document (@when decorator)") - def test_reference_when_complex(self): - self.pyscript_run( - """ -
- - - -
- - """ - ) - - def getBackgroundColor(locator): - return locator.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('background-color')" - ) - - first_button = self.page.get_by_text("First") - assert getBackgroundColor(first_button) == "rgb(239, 239, 239)" - - first_button.click() - self.wait_for_console("set") - - assert getBackgroundColor(first_button) == "rgb(0, 128, 0)" - assert getBackgroundColor(self.page.get_by_text("Second")) == "rgb(255, 0, 0)" - assert getBackgroundColor(self.page.get_by_text("Third")) == "rgb(255, 0, 0)" From c6aaacdbf17eb8e6d58f6d6cd8ccb4d511d211f0 Mon Sep 17 00:00:00 2001 From: Antonio Cuni Date: Wed, 27 Sep 2023 15:02:49 +0000 Subject: [PATCH 065/105] Re-enable CI tests (#1760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This re-enables CI tests on every PR 🎉. This uses make test-integration, which runs tests sequentially. In theory, we also have test-integration-parallel but it seems to be very flaky: many tests randomly timeout. I didn't spend too much time investigating this, it's probably worth its own investigation in a separate PR, but for now it's important to re-enable CI tests, even if they are a bit slower. --- .github/workflows/test.yml | 83 +++++++++++++++++++ .github/workflows/test_report.yml | 16 ++++ Makefile | 42 ++++------ pyscriptjs/environment.yml => environment.yml | 0 pyscript.core/tests/integration/support.py | 7 +- .../tests/integration/test_01_basic.py | 42 +++++----- .../tests/integration/test_02_display.py | 2 +- .../tests/integration/test_py_config.py | 1 - 8 files changed, 141 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/test_report.yml rename pyscriptjs/environment.yml => environment.yml (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..cbe1ff49 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,83 @@ +name: "[CI] Test" + +on: + push: # Only run on merges into main that modify certain files + branches: + - main + paths: + - pyscript.core/** + - .github/workflows/test.yml + + pull_request: # Only run on merges into main that modify certain files + branches: + - main + paths: + - pyscript.core/** + - .github/workflows/test.yml + workflow_dispatch: + +jobs: + BuildAndTest: + runs-on: ubuntu-latest-8core + env: + MINICONDA_PYTHON_VERSION: py38 + MINICONDA_VERSION: 4.11.0 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 3 + + # display a git log: when you run CI on PRs, github automatically + # merges the PR into main and run the CI on that commit. The idea + # here is to show enough of git log to understand what is the + # actual commit (in the PR) that we are using. See also + # 'fetch-depth: 3' above. + - name: git log + run: git log --graph -3 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: 20.x + + - name: Cache node modules + uses: actions/cache@v3 + env: + cache-name: cache-node-modules + with: + # npm cache files are stored in `~/.npm` on Linux/macOS + path: ~/.npm + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: setup Miniconda + uses: conda-incubator/setup-miniconda@v2 + + - name: Setup Environment + run: make setup + + - name: Build + run: make build + + - name: Integration Tests + #run: make test-integration-parallel + run: make test-integration + + - uses: actions/upload-artifact@v3 + with: + name: pyscript + path: | + pyscript.core/dist/ + if-no-files-found: error + retention-days: 7 + + - uses: actions/upload-artifact@v3 + if: success() || failure() + with: + name: test_results + path: test_results/ + if-no-files-found: error diff --git a/.github/workflows/test_report.yml b/.github/workflows/test_report.yml new file mode 100644 index 00000000..6debdbdc --- /dev/null +++ b/.github/workflows/test_report.yml @@ -0,0 +1,16 @@ +name: Test Report +on: + workflow_run: + workflows: ['\[CI\] Test'] + types: + - completed +jobs: + report: + runs-on: ubuntu-latest-8core + steps: + - uses: dorny/test-reporter@v1.6.0 + with: + artifact: test_results + name: Test reports + path: "*.xml" + reporter: java-junit diff --git a/Makefile b/Makefile index aaea8212..fde0a05d 100644 --- a/Makefile +++ b/Makefile @@ -7,12 +7,13 @@ examples ?= ../$(base_dir)/examples app_dir ?= $(shell git rev-parse --show-prefix) CONDA_EXE := conda -CONDA_ENV ?= $(base_dir)/pyscriptjs/env +CONDA_ENV ?= $(base_dir)/env env := $(CONDA_ENV) conda_run := $(CONDA_EXE) run -p $(env) PYTEST_EXE := $(CONDA_ENV)/bin/pytest -GOOD_NODE_VER := 14 -GOOD_NPM_VER := 6 + +MIN_NODE_VER := 14 +MIN_NPM_VER := 6 NODE_VER := $(shell node -v | cut -d. -f1 | sed 's/^v\(.*\)/\1/') NPM_VER := $(shell npm -v | cut -d. -f1) @@ -22,20 +23,21 @@ else SED_I_ARG := -i endif -GOOD_NODE := $(shell if [ $(NODE_VER) -ge $(GOOD_NODE_VER) ]; then echo true; else echo false; fi) -GOOD_NPM := $(shell if [ $(NPM_VER) -ge $(GOOD_NPM_VER) ]; then echo true; else echo false; fi) - .PHONY: check-node check-node: - @echo Build requires Node $(GOOD_NODE_VER).x or higher: $(NODE_VER) detected && $(GOOD_NODE) + @if [ $(NODE_VER) -lt $(MIN_NODE_VER) ]; then \ + echo "Build requires Node $(MIN_NODE_VER).x or higher: $(NODE_VER) detected"; \ + false; \ + fi .PHONY: check-npm check-npm: - @echo Build requires npm $(GOOD_NPM_VER).x or higher: $(NPM_VER) detected && $(GOOD_NPM) + @if [ $(NPM_VER) -lt $(MIN_NPM_VER) ]; then \ + echo "Build requires Node $(MIN_NPM_VER).x or higher: $(NPM_VER) detected"; \ + false; \ + fi -setup: - make check-node - make check-npm +setup: check-node check-npm cd pyscript.core && npm install && cd .. $(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml $(conda_run) playwright install @@ -53,13 +55,10 @@ shell: @echo 'conda activate $(env)' dev: - npm run dev + cd pyscript.core && npm run dev build: - npm run build - -build-fast: - node esbuild.mjs + cd pyscript.core && npm run build # use the following rule to do all the checks done by precommit: in # particular, use this if you want to run eslint. @@ -85,27 +84,22 @@ run-examples: setup build examples npm install make dev -test: - cd pyscript.core && npm run build && cp -R dist ../pyscriptjs/build/ - make test-integration - make test-examples - # run all integration tests *including examples* sequentially # TODO: (fpliger) The cd pyscript.core before running the tests shouldn't be needed but for # but for some reason it seems to bother pytest tmppaths (or test cache?). Unclear. test-integration: mkdir -p test_results - cd pyscript.core && $(PYTEST_EXE) -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=../integration.xml + $(PYTEST_EXE) -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml # run all integration tests *except examples* in parallel (examples use too much memory) test-integration-parallel: mkdir -p test_results - $(PYTEST_EXE) --numprocesses auto -vv $(ARGS) pyscript/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'not zz_examples' + $(PYTEST_EXE) --numprocesses auto -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml # run integration tests on only examples sequentially (to avoid running out of memory) test-examples: mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) pyscript/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'zz_examples' + $(PYTEST_EXE) -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'zz_examples' test-py: @echo "Tests from $(src_dir)" diff --git a/pyscriptjs/environment.yml b/environment.yml similarity index 100% rename from pyscriptjs/environment.yml rename to environment.yml diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py index 22812650..dd8d2235 100644 --- a/pyscript.core/tests/integration/support.py +++ b/pyscript.core/tests/integration/support.py @@ -169,7 +169,7 @@ class PyScriptTest: creates an HTML page to run the specified snippet. """ - DEFAULT_TIMEOUT = 20000 + DEFAULT_TIMEOUT = 30 * 1000 @pytest.fixture() def init(self, request, tmpdir, logger, page, execution_thread): @@ -240,10 +240,7 @@ class PyScriptTest: def init_page(self, page): self.page = page - - # set default timeout to 60000 millliseconds from 30000 page.set_default_timeout(self.DEFAULT_TIMEOUT) - self.console = ConsoleMessageCollection(self.logger) self._js_errors = [] self._py_errors = [] @@ -424,7 +421,7 @@ class PyScriptTest: return text in self.console.all.lines if timeout is None: - timeout = 10 * 1000 + timeout = self.DEFAULT_TIMEOUT # NOTE: we cannot use playwright's own page.expect_console_message(), # because if you call it AFTER the text has already been emitted, it # waits forever. Instead, we have to use our own custom logic. diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index 6bb306cc..3696b4f2 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -11,26 +11,22 @@ class TestBasic(PyScriptTest): """ + """ + ) + assert self.console.log.lines == ["hello from script py"] + def test_py_script_hello(self): + self.pyscript_run( + """ import js - js.console.log('2. hello from py-script') + js.console.log('hello from py-script') """ ) - if self.execution_thread == "main": - # in main, the order of execution is guaranteed - assert self.console.log.lines == [ - "1. hello from script py", - "2. hello from py-script", - ] - else: - # in workers, each tag is executed by its own worker, so they can - # come out of order - lines = sorted(self.console.log.lines) - assert lines == ["1. hello from script py", "2. hello from py-script"] + assert self.console.log.lines == ["hello from py-script"] def test_execution_thread(self): self.pyscript_run( @@ -47,20 +43,25 @@ class TestBasic(PyScriptTest): in_worker = str(in_worker).lower() assert self.console.log.lines[-1] == f"worker? {in_worker}" - # TODO: if there's no py-script there are surely no plugins neither - # this test must be discussed or rewritten to make sense now - @pytest.mark.skip(reason="NEXT: No banner and should also add a WARNING about CORS") + @skip_worker('NEXT: it should show a nice error on the page') def test_no_cors_headers(self): self.disable_cors_headers() self.pyscript_run( """ - + """, wait_for_pyscript=False, ) assert self.headers == {} - if self.execution_thread == "worker": + if self.execution_thread == "main": + self.wait_for_pyscript() + assert self.console.log.lines == ['hello'] + self.assert_no_banners() + else: + # XXX adapt and fix the test expected_alert_banner_msg = ( '(PY1000): When execution_thread is "worker", the site must be cross origin ' "isolated, but crossOriginIsolated is false. To be cross origin isolated, " @@ -71,8 +72,7 @@ class TestBasic(PyScriptTest): ) alert_banner = self.page.wait_for_selector(".alert-banner") assert expected_alert_banner_msg in alert_banner.inner_text() - else: - self.assert_no_banners() + def test_print(self): self.pyscript_run( diff --git a/pyscript.core/tests/integration/test_02_display.py b/pyscript.core/tests/integration/test_02_display.py index 9fc227e5..09e4a170 100644 --- a/pyscript.core/tests/integration/test_02_display.py +++ b/pyscript.core/tests/integration/test_02_display.py @@ -457,7 +457,7 @@ class TestDisplay(PyScriptTest): img = Image.new("RGB", (4, 4), color=(0, 0, 0)) display(img, target='img-target', append=False) - """ + """, ) img_src = self.page.locator("img").get_attribute("src") diff --git a/pyscript.core/tests/integration/test_py_config.py b/pyscript.core/tests/integration/test_py_config.py index 0a868115..d6576485 100644 --- a/pyscript.core/tests/integration/test_py_config.py +++ b/pyscript.core/tests/integration/test_py_config.py @@ -67,7 +67,6 @@ class TestConfig(PyScriptTest): ) assert self.console.log.lines[-1] == "config name: app with external config" - @pytest.mark.skip("NEXT: We need to restore the banner.") def test_invalid_json_config(self): # we need wait_for_pyscript=False because we bail out very soon, # before being able to write 'PyScript page fully initialized' From 97699eaded8e0d4998e54c558a5d21041a5ca17f Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 28 Sep 2023 16:05:51 +0200 Subject: [PATCH 066/105] Fix #1764 - Unescape `innerHTML` artifacts (#1767) --- pyscript.core/package-lock.json | 60 ++++++++++--------- pyscript.core/package.json | 4 +- pyscript.core/src/core.js | 12 ++-- pyscript.core/test/html-decode.html | 24 +++++++- .../tests/integration/test_01_basic.py | 21 ++++--- 5 files changed, 78 insertions(+), 43 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index c9e8c964..45037bd1 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -11,13 +11,13 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.6" + "polyscript": "^0.4.7" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-terser": "^0.4.3", "eslint": "^8.50.0", - "rollup": "^3.29.3", + "rollup": "^3.29.4", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.2", @@ -49,9 +49,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.2.tgz", - "integrity": "sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.0.tgz", + "integrity": "sha512-zJmuCWj2VLBt4c25CfBIbMZLGLyhkvs7LznyVX5HfpzeocThgIj5XQK4L+g3U36mMcx8bPMhGyPpwCATamC4jQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -410,9 +410,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.11", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.11.tgz", - "integrity": "sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.0.tgz", + "integrity": "sha512-v+Jcv64L2LbfTC6OnRcaxtqJNJuQAVhZKSJfR/6hn7lhnChUXl4amwVviqN1k411BB+3rRoKMitELRn1CojeRA==", "dev": true, "funding": [ { @@ -429,8 +429,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001538", - "electron-to-chromium": "^1.4.526", + "caniuse-lite": "^1.0.30001539", + "electron-to-chromium": "^1.4.530", "node-releases": "^2.0.13", "update-browserslist-db": "^1.0.13" }, @@ -481,9 +481,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001539", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001539.tgz", - "integrity": "sha512-hfS5tE8bnNiNvEOEkm8HElUHroYwlqMMENEzELymy77+tJ6m+gA2krtHl5hxJaj71OlpC2cHZbdSMX1/YEqEkA==", + "version": "1.0.30001541", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz", + "integrity": "sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw==", "dev": true, "funding": [ { @@ -525,15 +525,15 @@ } }, "node_modules/coincident": { - "version": "0.11.6", - "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.11.6.tgz", - "integrity": "sha512-Ld82kMrjDwNjpi+WE2C1v5ADPvOa+NANBWL8o1ohj+UhFTzDX3OMQOE9NSnjbUuMh+U/WBp39+uO2WFs8vJ3sw==", + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.13.3.tgz", + "integrity": "sha512-S97aRYpTb0EOI1o0V3lgxPtvk1GNQqLew9IorDRNg/1sN6m8EdOgJtGt/dVwkWkDNNgG7xRIra6Yf9qHne67Dw==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0" }, "optionalDependencies": { - "ws": "^8.13.0" + "ws": "^8.14.2" } }, "node_modules/color-convert": { @@ -851,9 +851,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.529", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.529.tgz", - "integrity": "sha512-6uyPyXTo8lkv8SWAmjKFbG42U073TXlzD4R8rW3EzuznhFS2olCIAfjjQtV2dV2ar/vRF55KUd3zQYnCB0dd3A==", + "version": "1.4.532", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.532.tgz", + "integrity": "sha512-piIR0QFdIGKmOJTSNg5AwxZRNWQSXlRYycqDB9Srstx4lip8KpcmRxVP6zuFWExWziHYZpJ0acX7TxqX95KBpg==", "dev": true }, "node_modules/entities": { @@ -1223,6 +1223,11 @@ "node": ">=8" } }, + "node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==" + }, "node_modules/icss-replace-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", @@ -1776,15 +1781,16 @@ "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, "node_modules/polyscript": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.6.tgz", - "integrity": "sha512-yRL8iwa8NHCWYIkYIRZ7Ujwd69WaDKAoeFxhQRLkTmcdlKKFxoFJStwyb5PONWZUl+mb+oXGkrPPsRaAJHHipQ==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.7.tgz", + "integrity": "sha512-nkAKkhZBsyfxdRglIWmvyGsI54MsG2F0BwygkLWAseYBfs5dspB7plAg1tlckqWkUE01wr3Ha/kenwJkEUvbhQ==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", "codedent": "^0.1.2", - "coincident": "^0.11.6" + "coincident": "^0.13.3", + "html-escaper": "^3.0.3" } }, "node_modules/postcss": { @@ -2455,9 +2461,9 @@ } }, "node_modules/rollup": { - "version": "3.29.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.3.tgz", - "integrity": "sha512-T7du6Hum8jOkSWetjRgbwpM6Sy0nECYrYRSmZjayFcOddtKJWU4d17AC3HNUk7HRuqy4p+G7aEZclSHytqUmEg==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 543baab5..1322c6d1 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -33,13 +33,13 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.6" + "polyscript": "^0.4.7" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/plugin-terser": "^0.4.3", "eslint": "^8.50.0", - "rollup": "^3.29.3", + "rollup": "^3.29.4", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.2", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 30900f77..e704bffb 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -9,7 +9,11 @@ import { XWorker, } from "../node_modules/polyscript/esm/index.js"; import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js"; -import { dedent, dispatch } from "../node_modules/polyscript/esm/utils.js"; +import { + dedent, + dispatch, + unescape, +} from "../node_modules/polyscript/esm/utils.js"; import { Hook } from "../node_modules/polyscript/esm/worker/hooks.js"; import "./all-done.js"; @@ -108,12 +112,12 @@ for (const [TYPE, interpreter] of TYPES) { if (asText) return dedent(tag.textContent); + const code = dedent(unescape(tag.innerHTML)); console.warn( `Deprecated: use + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
+ import js; js.console.log(1<2, 1>2) + import js; js.console.log("
")
+ + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index 3696b4f2..05b82ce8 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -43,7 +43,7 @@ class TestBasic(PyScriptTest): in_worker = str(in_worker).lower() assert self.console.log.lines[-1] == f"worker? {in_worker}" - @skip_worker('NEXT: it should show a nice error on the page') + @skip_worker("NEXT: it should show a nice error on the page") def test_no_cors_headers(self): self.disable_cors_headers() self.pyscript_run( @@ -58,7 +58,7 @@ class TestBasic(PyScriptTest): assert self.headers == {} if self.execution_thread == "main": self.wait_for_pyscript() - assert self.console.log.lines == ['hello'] + assert self.console.log.lines == ["hello"] self.assert_no_banners() else: # XXX adapt and fix the test @@ -73,7 +73,6 @@ class TestBasic(PyScriptTest): alert_banner = self.page.wait_for_selector(".alert-banner") assert expected_alert_banner_msg in alert_banner.inner_text() - def test_print(self): self.pyscript_run( """ @@ -159,18 +158,22 @@ class TestBasic(PyScriptTest): "four", ] - @skip_worker("NEXT: something very weird happens here") def test_escaping_of_angle_brackets(self): """ Check that script tags escape angle brackets """ self.pyscript_run( """ - - - import js; js.console.log("C", 1<2, 1>2) - import js; js.console.log("D
")
- + + + import js + js.console.log("C", 1<2, 1>2) + js.console.log("D
") +
""" ) # in workers the order of execution is not guaranteed, better to play From dffac642a1d64e2e40e023bcc8f25b4be82b0306 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 28 Sep 2023 17:49:11 +0200 Subject: [PATCH 067/105] Fix #1765 - Pass the optional config `interpreter` value (#1768) --- pyscript.core/src/core.js | 1 + 1 file changed, 1 insertion(+) diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index e704bffb..cb0758e0 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -130,6 +130,7 @@ for (const [TYPE, interpreter] of TYPES) { config, interpreter, env: `${TYPE}-script`, + version: config?.interpreter, onerror(error, element) { errors.set(element, error); }, From 7a23e355b9b7d1d779d4ffdb0ae80ef44025629d Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 28 Sep 2023 21:15:04 +0200 Subject: [PATCH 068/105] Add experimental files config parser (#1770) --- pyscript.core/package-lock.json | 12 ++++++------ pyscript.core/package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 45037bd1..b488f372 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,17 +1,17 @@ { "name": "@pyscript/core", - "version": "0.2.4", + "version": "0.2.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.2.4", + "version": "0.2.5", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.7" + "polyscript": "^0.4.8" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", @@ -1781,9 +1781,9 @@ "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, "node_modules/polyscript": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.7.tgz", - "integrity": "sha512-nkAKkhZBsyfxdRglIWmvyGsI54MsG2F0BwygkLWAseYBfs5dspB7plAg1tlckqWkUE01wr3Ha/kenwJkEUvbhQ==", + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.8.tgz", + "integrity": "sha512-YlgjdMeEnv/i6WOqkh7gc52iSPY1l/psA+egu7z1GNrjwq6udw4WuQPz3rHRbaFhTUdYsVulLd8SBugjbVH6sQ==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 1322c6d1..0e6459ed 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.2.4", + "version": "0.2.5", "type": "module", "description": "PyScript", "module": "./index.js", @@ -33,7 +33,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.7" + "polyscript": "^0.4.8" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", From 5c4e400d320b218c21f784d17597f959a8ba2aab Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 29 Sep 2023 14:01:35 +0200 Subject: [PATCH 069/105] Fix #1766 - Ensure correct hooks types (#1772) --- pyscript.core/package-lock.json | 8 +++++++- pyscript.core/package.json | 3 ++- pyscript.core/src/core.js | 2 ++ pyscript.core/src/hooks.js | 25 ++++++++++++++++--------- pyscript.core/types/hooks.d.ts | 3 ++- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index b488f372..570c2c2f 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.8" + "polyscript": "^0.4.8", + "type-checked-collections": "^0.1.7" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", @@ -2802,6 +2803,11 @@ "node": ">= 0.8.0" } }, + "node_modules/type-checked-collections": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/type-checked-collections/-/type-checked-collections-0.1.7.tgz", + "integrity": "sha512-fLIydlJy7IG9XL4wjRwEcKhxx/ekLXiWiMvcGo01cOMF+TN+5ZqajM1mRNRz2bNNi1bzou2yofhjZEQi7kgl9A==" + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 0e6459ed..e6882826 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -33,7 +33,8 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.8" + "polyscript": "^0.4.8", + "type-checked-collections": "^0.1.7" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index cb0758e0..dc62c92d 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -137,6 +137,8 @@ for (const [TYPE, interpreter] of TYPES) { ...workerHooks, onWorkerReady(_, xworker) { assign(xworker.sync, sync); + for (const callback of hooks.onWorkerReady) + callback(_, xworker); }, onBeforeRun(wrap, element) { currentElement = element; diff --git a/pyscript.core/src/hooks.js b/pyscript.core/src/hooks.js index 2ba29457..ebfe2b70 100644 --- a/pyscript.core/src/hooks.js +++ b/pyscript.core/src/hooks.js @@ -1,21 +1,28 @@ +import { typedSet } from "type-checked-collections"; + +const SetFunction = typedSet({ typeof: "function" }); +const SetString = typedSet({ typeof: "string" }); + export default { /** @type {Set} */ - onBeforeRun: new Set(), + onInterpreterReady: new SetFunction(), /** @type {Set} */ - onBeforeRunAsync: new Set(), + onBeforeRun: new SetFunction(), /** @type {Set} */ - onAfterRun: new Set(), + onBeforeRunAsync: new SetFunction(), /** @type {Set} */ - onAfterRunAsync: new Set(), + onAfterRun: new SetFunction(), /** @type {Set} */ - onInterpreterReady: new Set(), + onAfterRunAsync: new SetFunction(), + /** @type {Set} */ + onWorkerReady: new SetFunction(), /** @type {Set} */ - codeBeforeRunWorker: new Set(), + codeBeforeRunWorker: new SetString(), /** @type {Set} */ - codeBeforeRunWorkerAsync: new Set(), + codeBeforeRunWorkerAsync: new SetString(), /** @type {Set} */ - codeAfterRunWorker: new Set(), + codeAfterRunWorker: new SetString(), /** @type {Set} */ - codeAfterRunWorkerAsync: new Set(), + codeAfterRunWorkerAsync: new SetString(), }; diff --git a/pyscript.core/types/hooks.d.ts b/pyscript.core/types/hooks.d.ts index 80269b4d..de71ecc8 100644 --- a/pyscript.core/types/hooks.d.ts +++ b/pyscript.core/types/hooks.d.ts @@ -1,9 +1,10 @@ declare namespace _default { + let onInterpreterReady: Set; let onBeforeRun: Set; let onBeforeRunAsync: Set; let onAfterRun: Set; let onAfterRunAsync: Set; - let onInterpreterReady: Set; + let onWorkerReady: Set; let codeBeforeRunWorker: Set; let codeBeforeRunWorkerAsync: Set; let codeAfterRunWorker: Set; From fdc35ce3edbc9c4b505e8b65d21ed0a665f3594f Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 29 Sep 2023 15:24:20 +0200 Subject: [PATCH 070/105] Add a selector to the HTML tag + export config (#1773) --- pyscript.core/tests/integration/support.py | 14 ++++++-------- .../tests/integration/test_02_display.py | 2 +- pyscript.core/tests/integration/test_py_config.py | 15 ++++++--------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py index dd8d2235..889279fb 100644 --- a/pyscript.core/tests/integration/support.py +++ b/pyscript.core/tests/integration/support.py @@ -471,9 +471,7 @@ class PyScriptTest: self.logger.log( "wait_for_pyscript", f"Waited for {elapsed_ms/1000:.2f} s", color="yellow" ) - # We still don't know why this wait is necessary, but without it - # events aren't being triggered in the tests. - self.page.wait_for_timeout(100) + self.page.wait_for_selector("html.all-done") SCRIPT_TAG_REGEX = re.compile('( """ ) @@ -59,9 +57,8 @@ class TestConfig(PyScriptTest): """ ) From 50f7ab0f34958f37119f00a0a6ef13753a33fa66 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Mon, 2 Oct 2023 13:38:28 +0200 Subject: [PATCH 071/105] Improved py:all-done event (#1778) --- pyscript.core/package-lock.json | 8 ++--- pyscript.core/package.json | 2 +- pyscript.core/src/all-done.js | 61 +++++---------------------------- pyscript.core/src/core.js | 26 ++++++++++---- pyscript.core/test/display.html | 30 ++++++++++++++++ 5 files changed, 62 insertions(+), 65 deletions(-) create mode 100644 pyscript.core/test/display.html diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 570c2c2f..4a73cc8a 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.8", + "polyscript": "^0.4.11", "type-checked-collections": "^0.1.7" }, "devDependencies": { @@ -1782,9 +1782,9 @@ "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, "node_modules/polyscript": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.8.tgz", - "integrity": "sha512-YlgjdMeEnv/i6WOqkh7gc52iSPY1l/psA+egu7z1GNrjwq6udw4WuQPz3rHRbaFhTUdYsVulLd8SBugjbVH6sQ==", + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.4.11.tgz", + "integrity": "sha512-wNvCUJp003OR/Q9C0eZJ84MHYeJiMtPTt1pqtsRQ0odRV/M1b3qVQ23oD5DAjq1weXQv1EdfpILwFOpw6VnirA==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index e6882826..080e022b 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -33,7 +33,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.4.8", + "polyscript": "^0.4.11", "type-checked-collections": "^0.1.7" }, "devDependencies": { diff --git a/pyscript.core/src/all-done.js b/pyscript.core/src/all-done.js index 8eb8afd2..4a005660 100644 --- a/pyscript.core/src/all-done.js +++ b/pyscript.core/src/all-done.js @@ -1,62 +1,17 @@ import TYPES from "./types.js"; -import hooks from "./hooks.js"; - -const DONE = "py:all-done"; - -const { - onAfterRun, - onAfterRunAsync, - codeAfterRunWorker, - codeAfterRunWorkerAsync, -} = hooks; const waitForIt = []; -const codes = []; -const codeFor = (element) => { - const isAsync = element.hasAttribute("async"); - const { promise, resolve } = Promise.withResolvers(); - const type = `${DONE}:${waitForIt.push(promise)}`; - - // resolve each promise once notified - addEventListener(type, resolve, { once: true }); - - if (element.hasAttribute("worker")) { - const code = ` - from pyscript import window as _w - _w.dispatchEvent(_w.Event.new("${type}")) - `; - if (isAsync) codeAfterRunWorkerAsync.add(code); - else codeAfterRunWorker.add(code); - return code; +for (const [TYPE] of TYPES) { + const selectors = [`script[type="${TYPE}"]`, `${TYPE}-script`]; + for (const element of document.querySelectorAll(selectors.join(","))) { + const { promise, resolve } = Promise.withResolvers(); + waitForIt.push(promise); + element.addEventListener(`${TYPE}:done`, resolve, { once: true }); } - - // dispatch only once the ready element is the same - const code = (_, el) => { - if (el === element) dispatchEvent(new Event(type)); - }; - - if (isAsync) onAfterRunAsync.add(code); - else onAfterRun.add(code); - return code; -}; - -const selector = []; -for (const [TYPE] of TYPES) - selector.push(`script[type="${TYPE}"]`, `${TYPE}-script`); - -// loop over all known scripts and elements -for (const element of document.querySelectorAll(selector.join(","))) - codes.push(codeFor(element)); +} // wait for all the things then cleanup Promise.all(waitForIt).then(() => { - // cleanup unnecessary hooks - for (const code of codes) { - onAfterRun.delete(code); - onAfterRunAsync.delete(code); - codeAfterRunWorker.delete(code); - codeAfterRunWorkerAsync.delete(code); - } - dispatchEvent(new Event(DONE)); + dispatchEvent(new Event("py:all-done")); }); diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index dc62c92d..a1d5f503 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -90,6 +90,11 @@ const exportedConfig = {}; export { exportedConfig as config, hooks }; for (const [TYPE, interpreter] of TYPES) { + const dispatchDone = (element, isAsync, result) => { + if (isAsync) result.then(() => dispatch(element, TYPE, "done")); + else dispatch(element, TYPE, "done"); + }; + const { config, plugins, error } = configs.get(TYPE); // create a unique identifier when/if needed @@ -211,9 +216,13 @@ for (const [TYPE, interpreter] of TYPES) { defineProperty(element, "target", { value: show }); // notify before the code runs - dispatch(element, TYPE); - wrap[`run${isAsync ? "Async" : ""}`]( - await fetchSource(element, wrap.io, true), + dispatch(element, TYPE, "ready"); + dispatchDone( + element, + isAsync, + wrap[`run${isAsync ? "Async" : ""}`]( + await fetchSource(element, wrap.io, true), + ), ); } else { // resolve PyScriptElement to allow connectedCallback @@ -246,18 +255,21 @@ for (const [TYPE, interpreter] of TYPES) { async connectedCallback() { if (!this.executed) { this.executed = true; + const isAsync = this.hasAttribute("async"); const { io, run, runAsync } = await this._wrap.promise; - const runner = this.hasAttribute("async") ? runAsync : run; this.srcCode = await fetchSource( this, io, !this.childElementCount, ); this.replaceChildren(); - // notify before the code runs - dispatch(this, TYPE); - runner(this.srcCode); this.style.display = "block"; + dispatch(this, TYPE, "ready"); + dispatchDone( + this, + isAsync, + (isAsync ? runAsync : run)(this.srcCode), + ); } } } diff --git a/pyscript.core/test/display.html b/pyscript.core/test/display.html new file mode 100644 index 00000000..f7ca53c7 --- /dev/null +++ b/pyscript.core/test/display.html @@ -0,0 +1,30 @@ + + + + + + PyScript Next + + + + + + +

hello 2

+ + + From bc1cac9c417d3b3ba9ae4bb91b48929c9e43fbe2 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Mon, 2 Oct 2023 15:39:34 +0200 Subject: [PATCH 072/105] Fix #1780 - Clean up elements before writing (#1781) --- pyscript.core/src/stdlib/pyscript/display.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyscript.core/src/stdlib/pyscript/display.py b/pyscript.core/src/stdlib/pyscript/display.py index 2e642f48..c9fd8d25 100644 --- a/pyscript.core/src/stdlib/pyscript/display.py +++ b/pyscript.core/src/stdlib/pyscript/display.py @@ -3,7 +3,7 @@ import html import io import re -from pyscript.magic_js import document, window, current_target +from pyscript.magic_js import current_target, document, window _MIME_METHODS = { "__repr__": "text/plain", @@ -154,8 +154,10 @@ def display(*values, target=None, append=True): # if element is a + """ + ) + assert self.console.error.lines == [] + def test_script_py_hello(self): self.pyscript_run( """ From a00a6750b4ed3964c9398e6e5609f27cc38a06f9 Mon Sep 17 00:00:00 2001 From: Valerio Maggio Date: Tue, 3 Oct 2023 18:23:44 +0100 Subject: [PATCH 074/105] FIX to display function handling null element reference, and wrong target parameter values (#1784) * blacked * More robust code for display, with tests Display now includes more robust controls when checking the input target parameters, with appropriate exception raised (i.e. ValueError or TypeError) whether target is either an empty string, or a not-string, not-None type, respectively. The TypeError aligns with other similar behaviour with other Pyton functions (e.g. str.split with integer separator). Also, now display raises a ValueError whether the target element is not found or not existing. All changes are supported by tests. * traceback lines in check_py_error & removed clones check_py_error function now automatically includes check of the traceback in console errors. This way tests in basic and display have been refactored, and lots of duplicated code removed. * removed useless console check lines. If check_py_errors function is running, those console log lines are useless to check. --- pyscript.core/src/stdlib/pyscript/__init__.py | 12 +++- pyscript.core/src/stdlib/pyscript/display.py | 14 +++++ pyscript.core/src/stdlib/pyscript/magic_js.py | 10 +-- .../tests/integration/test_01_basic.py | 8 --- .../tests/integration/test_02_display.py | 62 +++++++++++++++++++ 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/pyscript.core/src/stdlib/pyscript/__init__.py b/pyscript.core/src/stdlib/pyscript/__init__.py index 6cb4ccfd..26cddb34 100644 --- a/pyscript.core/src/stdlib/pyscript/__init__.py +++ b/pyscript.core/src/stdlib/pyscript/__init__.py @@ -29,7 +29,14 @@ # pyscript.magic_js. This is the blessed way to access them from pyscript, # as it works transparently in both the main thread and worker cases. -from pyscript.magic_js import RUNNING_IN_WORKER, PyWorker, window, document, sync, current_target +from pyscript.magic_js import ( + RUNNING_IN_WORKER, + PyWorker, + window, + document, + sync, + current_target, +) from pyscript.display import HTML, display try: @@ -38,6 +45,5 @@ except: from pyscript.util import NotSupported when = NotSupported( - "pyscript.when", - "pyscript.when currently not available with this interpreter" + "pyscript.when", "pyscript.when currently not available with this interpreter" ) diff --git a/pyscript.core/src/stdlib/pyscript/display.py b/pyscript.core/src/stdlib/pyscript/display.py index c9fd8d25..f6bff53e 100644 --- a/pyscript.core/src/stdlib/pyscript/display.py +++ b/pyscript.core/src/stdlib/pyscript/display.py @@ -148,9 +148,23 @@ def _write(element, value, append=False): def display(*values, target=None, append=True): if target is None: target = current_target() + elif not isinstance(target, str): + raise TypeError(f"target must be str or None, not {target.__class__.__name__}") + elif target == "": + raise ValueError("Cannot have an empty target") + elif target.startswith("#"): + # note: here target is str and not None! + # align with @when behavior + target = target[1:] element = document.getElementById(target) + # If target cannot be found on the page, a ValueError is raised + if element is None: + raise ValueError( + f"Invalid selector with id={target}. Cannot be found in the page." + ) + # if element is a +
+ """ + ) + mydiv = self.page.locator("#mydiv") + assert mydiv.inner_text() == "hello world" + + def test_non_existing_id_target_raises_value_error(self): + self.pyscript_run( + """ + + """ + ) + error_msg = ( + f"Invalid selector with id=non-existing. Cannot be found in the page." + ) + self.check_py_errors(f"ValueError: {error_msg}") + + def test_empty_string_target_raises_value_error(self): + self.pyscript_run( + """ + + """ + ) + self.check_py_errors(f"ValueError: Cannot have an empty target") + + def test_non_string_target_values_raise_typerror(self): + self.pyscript_run( + """ + + """ + ) + error_msg = f"target must be str or None, not bool" + self.check_py_errors(f"TypeError: {error_msg}") + + self.pyscript_run( + """ + + """ + ) + error_msg = f"target must be str or None, not int" + self.check_py_errors(f"TypeError: {error_msg}") + @skip_worker("NEXT: display(target=...) does not work") def test_tag_target_attribute(self): self.pyscript_run( From b4503ef7293053c7d9e48c23cb28e8cd4e54eee0 Mon Sep 17 00:00:00 2001 From: Madhur Tandon <20173739+madhur-tandon@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:46:34 +0530 Subject: [PATCH 075/105] remove pyscriptjs and synclink (#1787) * remove pyscriptjs and synclink * remove chdir fixture --- .github/workflows/publish-unstable.yml | 9 +- .gitignore | 1 - .pre-commit-config.yaml | 12 - Makefile | 9 - examples/handtrack/say_hello.html | 3 +- pyproject.toml | 1 - pyscript.core/tests/integration/conftest.py | 5 +- .../tests/integration/test_zz_examples.py | 6 - pyscriptjs/.eslintrc.js | 48 - pyscriptjs/.prettierignore | 6 - pyscriptjs/.prettierrc.js | 9 - pyscriptjs/Makefile | 137 - pyscriptjs/README.md | 3 - pyscriptjs/__mocks__/_pyscript.js | 14 - pyscriptjs/__mocks__/cssMock.js | 1 - pyscriptjs/__mocks__/fileMock.js | 16 - pyscriptjs/directoryManifest.mjs | 53 - pyscriptjs/esbuild.mjs | 138 - pyscriptjs/jest-environment-jsdom.js | 28 - pyscriptjs/jest.config.js | 25 - pyscriptjs/package-lock.json | 10525 ---------------- pyscriptjs/package.json | 47 - pyscriptjs/public/.gitkeep | 0 pyscriptjs/public/index.html | 54 - pyscriptjs/src/components/elements.ts | 11 - pyscriptjs/src/components/pyrepl.ts | 237 - pyscriptjs/src/components/pyscript.ts | 261 - pyscriptjs/src/exceptions.ts | 87 - pyscriptjs/src/fetch.ts | 57 - pyscriptjs/src/interpreter_client.ts | 86 - pyscriptjs/src/interpreter_worker/worker.ts | 26 - pyscriptjs/src/logger.ts | 64 - pyscriptjs/src/main.ts | 458 - pyscriptjs/src/plugin.ts | 385 - pyscriptjs/src/plugins/calculateFetchPaths.ts | 26 - pyscriptjs/src/plugins/importmap.ts | 56 - pyscriptjs/src/plugins/pyterminal.ts | 275 - pyscriptjs/src/plugins/python/py_markdown.py | 34 - pyscriptjs/src/plugins/python/py_tutor.py | 212 - pyscriptjs/src/plugins/splashscreen.ts | 111 - pyscriptjs/src/plugins/stdiodirector.ts | 133 - pyscriptjs/src/pyconfig.ts | 266 - pyscriptjs/src/pyexec.ts | 73 - pyscriptjs/src/python/pyscript/__init__.py | 50 - .../python/pyscript/_deprecated_globals.py | 61 - .../src/python/pyscript/_event_handling.py | 29 - pyscriptjs/src/python/pyscript/_event_loop.py | 81 - pyscriptjs/src/python/pyscript/_html.py | 149 - pyscriptjs/src/python/pyscript/_internal.py | 115 - pyscriptjs/src/python/pyscript/_mime.py | 113 - pyscriptjs/src/python/pyscript/_plugin.py | 66 - pyscriptjs/src/python_package.ts | 9 - pyscriptjs/src/remote_interpreter.ts | 294 - pyscriptjs/src/shadow_roots.ts | 18 - pyscriptjs/src/stdio.ts | 127 - pyscriptjs/src/styles/pyscript_base.css | 349 - pyscriptjs/src/utils.ts | 110 - pyscriptjs/src/version.ts | 10 - pyscriptjs/tests/py-unit/__init__.py | 0 pyscriptjs/tests/py-unit/_pyscript_js.py | 10 - pyscriptjs/tests/py-unit/conftest.py | 29 - pyscriptjs/tests/py-unit/js.py | 7 - .../tests/py-unit/pyscript_plugins_tester.py | 120 - pyscriptjs/tests/py-unit/test_pyscript.py | 207 - .../tests/py-unit/test_python_plugins.py | 171 - .../tests/unit/calculateFetchPaths.test.ts | 62 - pyscriptjs/tests/unit/exceptions.test.ts | 123 - pyscriptjs/tests/unit/fetch.test.ts | 107 - pyscriptjs/tests/unit/logger.test.ts | 46 - pyscriptjs/tests/unit/main.test.ts | 68 - pyscriptjs/tests/unit/plugin.test.ts | 116 - pyscriptjs/tests/unit/pyconfig.test.ts | 168 - pyscriptjs/tests/unit/pyodide.test.ts | 89 - pyscriptjs/tests/unit/setup.ts | 8 - pyscriptjs/tests/unit/stdio.test.ts | 136 - pyscriptjs/tests/unit/utils.test.ts | 78 - pyscriptjs/tsconfig.json | 19 - 77 files changed, 4 insertions(+), 17149 deletions(-) delete mode 100644 pyscriptjs/.eslintrc.js delete mode 100644 pyscriptjs/.prettierignore delete mode 100644 pyscriptjs/.prettierrc.js delete mode 100644 pyscriptjs/Makefile delete mode 100644 pyscriptjs/README.md delete mode 100644 pyscriptjs/__mocks__/_pyscript.js delete mode 100644 pyscriptjs/__mocks__/cssMock.js delete mode 100644 pyscriptjs/__mocks__/fileMock.js delete mode 100644 pyscriptjs/directoryManifest.mjs delete mode 100644 pyscriptjs/esbuild.mjs delete mode 100644 pyscriptjs/jest-environment-jsdom.js delete mode 100644 pyscriptjs/jest.config.js delete mode 100644 pyscriptjs/package-lock.json delete mode 100644 pyscriptjs/package.json delete mode 100644 pyscriptjs/public/.gitkeep delete mode 100644 pyscriptjs/public/index.html delete mode 100644 pyscriptjs/src/components/elements.ts delete mode 100644 pyscriptjs/src/components/pyrepl.ts delete mode 100644 pyscriptjs/src/components/pyscript.ts delete mode 100644 pyscriptjs/src/exceptions.ts delete mode 100644 pyscriptjs/src/fetch.ts delete mode 100644 pyscriptjs/src/interpreter_client.ts delete mode 100644 pyscriptjs/src/interpreter_worker/worker.ts delete mode 100644 pyscriptjs/src/logger.ts delete mode 100644 pyscriptjs/src/main.ts delete mode 100644 pyscriptjs/src/plugin.ts delete mode 100644 pyscriptjs/src/plugins/calculateFetchPaths.ts delete mode 100644 pyscriptjs/src/plugins/importmap.ts delete mode 100644 pyscriptjs/src/plugins/pyterminal.ts delete mode 100644 pyscriptjs/src/plugins/python/py_markdown.py delete mode 100644 pyscriptjs/src/plugins/python/py_tutor.py delete mode 100644 pyscriptjs/src/plugins/splashscreen.ts delete mode 100644 pyscriptjs/src/plugins/stdiodirector.ts delete mode 100644 pyscriptjs/src/pyconfig.ts delete mode 100644 pyscriptjs/src/pyexec.ts delete mode 100644 pyscriptjs/src/python/pyscript/__init__.py delete mode 100644 pyscriptjs/src/python/pyscript/_deprecated_globals.py delete mode 100644 pyscriptjs/src/python/pyscript/_event_handling.py delete mode 100644 pyscriptjs/src/python/pyscript/_event_loop.py delete mode 100644 pyscriptjs/src/python/pyscript/_html.py delete mode 100644 pyscriptjs/src/python/pyscript/_internal.py delete mode 100644 pyscriptjs/src/python/pyscript/_mime.py delete mode 100644 pyscriptjs/src/python/pyscript/_plugin.py delete mode 100644 pyscriptjs/src/python_package.ts delete mode 100644 pyscriptjs/src/remote_interpreter.ts delete mode 100644 pyscriptjs/src/shadow_roots.ts delete mode 100644 pyscriptjs/src/stdio.ts delete mode 100644 pyscriptjs/src/styles/pyscript_base.css delete mode 100644 pyscriptjs/src/utils.ts delete mode 100644 pyscriptjs/src/version.ts delete mode 100644 pyscriptjs/tests/py-unit/__init__.py delete mode 100644 pyscriptjs/tests/py-unit/_pyscript_js.py delete mode 100644 pyscriptjs/tests/py-unit/conftest.py delete mode 100644 pyscriptjs/tests/py-unit/js.py delete mode 100644 pyscriptjs/tests/py-unit/pyscript_plugins_tester.py delete mode 100644 pyscriptjs/tests/py-unit/test_pyscript.py delete mode 100644 pyscriptjs/tests/py-unit/test_python_plugins.py delete mode 100644 pyscriptjs/tests/unit/calculateFetchPaths.test.ts delete mode 100644 pyscriptjs/tests/unit/exceptions.test.ts delete mode 100644 pyscriptjs/tests/unit/fetch.test.ts delete mode 100644 pyscriptjs/tests/unit/logger.test.ts delete mode 100644 pyscriptjs/tests/unit/main.test.ts delete mode 100644 pyscriptjs/tests/unit/plugin.test.ts delete mode 100644 pyscriptjs/tests/unit/pyconfig.test.ts delete mode 100644 pyscriptjs/tests/unit/pyodide.test.ts delete mode 100644 pyscriptjs/tests/unit/setup.ts delete mode 100644 pyscriptjs/tests/unit/stdio.test.ts delete mode 100644 pyscriptjs/tests/unit/utils.test.ts delete mode 100644 pyscriptjs/tsconfig.json diff --git a/.github/workflows/publish-unstable.yml b/.github/workflows/publish-unstable.yml index a608e49c..cb11a8d7 100644 --- a/.github/workflows/publish-unstable.yml +++ b/.github/workflows/publish-unstable.yml @@ -1,20 +1,13 @@ name: "Publish Unstable" on: - push: # Only run on merges into main that modify files under pyscriptjs/ and examples/ + push: # Only run on merges into main that modify files under pyscript.core/ and examples/ branches: - main paths: - pyscript.core/** - examples/** - pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/ - branches: - - main - paths: - - pyscriptjs/** - - examples/** - workflow_dispatch: jobs: diff --git a/.gitignore b/.gitignore index 3e952354..c1e2cf98 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,6 @@ coverage.xml *.py,cover .hypothesis/ .pytest_cache/ -pyscriptjs/examples # Translations *.mo diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e09caf8..6ed5f8e5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -51,15 +51,3 @@ repos: - id: prettier exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/ args: [--tab-width, "4"] - - - repo: https://github.com/pre-commit/mirrors-eslint - rev: v8.36.0 - hooks: - - id: eslint - files: pyscriptjs/src/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx - types: [file] - additional_dependencies: - - eslint@8.25.0 - - typescript@5.0.4 - - "@typescript-eslint/eslint-plugin@5.58.0" - - "@typescript-eslint/parser@5.58.0" diff --git a/Makefile b/Makefile index fde0a05d..4db11559 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,6 @@ tag := latest git_hash ?= $(shell git log -1 --pretty=format:%h) base_dir ?= $(shell git rev-parse --show-toplevel) -src_dir ?= $(base_dir)/pyscriptjs/src examples ?= ../$(base_dir)/examples app_dir ?= $(shell git rev-parse --show-prefix) @@ -101,14 +100,6 @@ test-examples: mkdir -p test_results $(PYTEST_EXE) -vv $(ARGS) pyscript.core/tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'zz_examples' -test-py: - @echo "Tests from $(src_dir)" - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/py-unit/ --log-cli-level=warning --junitxml=test_results/py-unit.xml - -test-ts: - npm run test - fmt: fmt-py fmt-ts @echo "Format completed" diff --git a/examples/handtrack/say_hello.html b/examples/handtrack/say_hello.html index 95900406..97601ec3 100644 --- a/examples/handtrack/say_hello.html +++ b/examples/handtrack/say_hello.html @@ -11,8 +11,7 @@ rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> - - + diff --git a/pyproject.toml b/pyproject.toml index d1d0d8c3..4d1d6b94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,6 @@ dynamic = ["version"] [tool.codespell] ignore-words-list = "afterall" -skip = "pyscriptjs/node_modules/*,*.js,*.json" [tool.ruff] builtins = [ diff --git a/pyscript.core/tests/integration/conftest.py b/pyscript.core/tests/integration/conftest.py index 40461857..fe26c72a 100644 --- a/pyscript.core/tests/integration/conftest.py +++ b/pyscript.core/tests/integration/conftest.py @@ -54,7 +54,7 @@ def pytest_configure(config): --no-fake-server, but because of how pytest works, they are available only if this is the "root conftest" for the test session. - This means that if you are in the pyscriptjs directory: + This means that if you are in the pyscript.core directory: $ py.test # does NOT work $ py.test tests/integration/ # works @@ -70,10 +70,9 @@ def pytest_configure(config): """ if not hasattr(config.option, "dev"): msg = """ - Running a bare "pytest" command from the pyscriptjs directory + Running a bare "pytest" command from the pyscript.core directory is not supported. Please use one of the following commands: - pytest tests/integration - - pytest tests/py-unit - pytest tests/* - cd tests/integration; pytest """ diff --git a/pyscript.core/tests/integration/test_zz_examples.py b/pyscript.core/tests/integration/test_zz_examples.py index 70e7696d..a0651714 100644 --- a/pyscript.core/tests/integration/test_zz_examples.py +++ b/pyscript.core/tests/integration/test_zz_examples.py @@ -15,7 +15,6 @@ from .support import ROOT, PyScriptTest, wait_for_render, with_execution_thread reason="SKIPPING EXAMPLES: these should be moved elsewhere and updated" ) @with_execution_thread(None) -@pytest.mark.usefixtures("chdir") class TestExamples(PyScriptTest): """ Each example requires the same three tests: @@ -26,11 +25,6 @@ class TestExamples(PyScriptTest): - Testing that the page contains appropriate content after rendering """ - @pytest.fixture() - def chdir(self): - # make sure that the http server serves from the right directory - ROOT.join("pyscriptjs").chdir() - def test_hello_world(self): self.goto("examples/hello_world.html") self.wait_for_pyscript() diff --git a/pyscriptjs/.eslintrc.js b/pyscriptjs/.eslintrc.js deleted file mode 100644 index 9c12d37d..00000000 --- a/pyscriptjs/.eslintrc.js +++ /dev/null @@ -1,48 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - parserOptions: { - ecmaVersion: 2020, - sourceType: 'module', - tsconfigRootDir: __dirname, - project: ['./tsconfig.json'], - }, - env: { - es6: true, - browser: true, - }, - plugins: ['@typescript-eslint'], - ignorePatterns: ['node_modules', 'src/interpreter_worker/*'], - rules: { - // ts-ignore is already an explicit override, no need to have a second lint - '@typescript-eslint/ban-ts-comment': 'off', - - // any related lints - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/no-unsafe-return': 'off', - - // other rules - 'no-prototype-builtins': 'error', - '@typescript-eslint/no-unused-vars': ['error', { args: 'none' }], - '@typescript-eslint/no-floating-promises': 'error', - '@typescript-eslint/restrict-plus-operands': 'error', - '@typescript-eslint/no-empty-function': 'error', - '@typescript-eslint/restrict-template-expressions': ['error', { allowBoolean: true }], - }, - overrides: [ - { - files: ['src/components/pyscript.ts'], - rules: { - '@typescript-eslint/unbound-method': 'off', - }, - }, - ], -}; diff --git a/pyscriptjs/.prettierignore b/pyscriptjs/.prettierignore deleted file mode 100644 index 0a170957..00000000 --- a/pyscriptjs/.prettierignore +++ /dev/null @@ -1,6 +0,0 @@ -build -node_modules - - -# Ignore all HTML files -*.html diff --git a/pyscriptjs/.prettierrc.js b/pyscriptjs/.prettierrc.js deleted file mode 100644 index 01d6f2da..00000000 --- a/pyscriptjs/.prettierrc.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - arrowParens: 'avoid', - bracketSameLine: true, - singleQuote: true, - printWidth: 120, - semi: true, - tabWidth: 4, - trailingComma: 'all', -}; diff --git a/pyscriptjs/Makefile b/pyscriptjs/Makefile deleted file mode 100644 index cb4a7193..00000000 --- a/pyscriptjs/Makefile +++ /dev/null @@ -1,137 +0,0 @@ -tag := latest -git_hash ?= $(shell git log -1 --pretty=format:%h) - -base_dir ?= $(shell git rev-parse --show-toplevel) -src_dir ?= $(base_dir)/pyscriptjs/src -examples ?= ../$(base_dir)/examples -app_dir ?= $(shell git rev-parse --show-prefix) - -CONDA_EXE := conda -CONDA_ENV ?= $(base_dir)/pyscriptjs/env -env := $(CONDA_ENV) -conda_run := $(CONDA_EXE) run -p $(env) -PYTEST_EXE := $(CONDA_ENV)/bin/pytest -GOOD_NODE_VER := 14 -GOOD_NPM_VER := 6 -NODE_VER := $(shell node -v | cut -d. -f1 | sed 's/^v\(.*\)/\1/') -NPM_VER := $(shell npm -v | cut -d. -f1) - -ifeq ($(shell uname -s), Darwin) - SED_I_ARG := -i '' -else - SED_I_ARG := -i -endif - -GOOD_NODE := $(shell if [ $(NODE_VER) -ge $(GOOD_NODE_VER) ]; then echo true; else echo false; fi) -GOOD_NPM := $(shell if [ $(NPM_VER) -ge $(GOOD_NPM_VER) ]; then echo true; else echo false; fi) - -.PHONY: check-node -check-node: - @echo Build requires Node $(GOOD_NODE_VER).x or higher: $(NODE_VER) detected && $(GOOD_NODE) - -.PHONY: check-npm -check-npm: - @echo Build requires npm $(GOOD_NPM_VER).x or higher: $(NPM_VER) detected && $(GOOD_NPM) - -setup: - make check-node - make check-npm - npm install - $(CONDA_EXE) env $(shell [ -d $(env) ] && echo update || echo create) -p $(env) --file environment.yml - $(conda_run) playwright install - $(CONDA_EXE) install -c anaconda pytest -y - -clean: - find . -name \*.py[cod] -delete - rm -rf .pytest_cache .coverage coverage.xml - -clean-all: clean - rm -rf $(env) *.egg-info - -shell: - @export CONDA_ENV_PROMPT='<{name}>' - @echo 'conda activate $(env)' - -dev: - npm run dev - -build: - npm run build - -build-fast: - node esbuild.mjs - -# use the following rule to do all the checks done by precommit: in -# particular, use this if you want to run eslint. -precommit-check: - pre-commit run --all-files - -examples: - mkdir -p ./examples - cp -r ../examples/* ./examples - chmod -R 755 examples - find ./examples/toga -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../../build/+g {} \; - find ./examples/webgl -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../../../build/+g {} \; - find ./examples -type f -name '*.html' -exec sed $(SED_I_ARG) s+https://pyscript.net/latest/+../build/+g {} \; - npm run build - rm -rf ./examples/build - mkdir -p ./examples/build - cp -R ./build/* ./examples/build - @echo "To serve examples run: $(conda_run) python -m http.server 8080 --directory examples" - -# run prerequisites and serve pyscript examples at http://localhost:8000/examples/ -run-examples: setup build examples - make examples - npm install - make dev - -test: - make test-ts - make test-py - make test-integration-parallel - make test-examples - -# run all integration tests *including examples* sequentially -test-integration: - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml - -# run all integration tests *except examples* in parallel (examples use too much memory) -test-integration-parallel: - mkdir -p test_results - $(PYTEST_EXE) --numprocesses auto -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'not zz_examples' - -# run integration tests on only examples sequentially (to avoid running out of memory) -test-examples: - make examples - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/integration/ --log-cli-level=warning --junitxml=test_results/integration.xml -k 'zz_examples' - -test-py: - @echo "Tests from $(src_dir)" - mkdir -p test_results - $(PYTEST_EXE) -vv $(ARGS) tests/py-unit/ --log-cli-level=warning --junitxml=test_results/py-unit.xml - -test-ts: - npm run test - -fmt: fmt-py fmt-ts - @echo "Format completed" - -fmt-check: fmt-ts-check fmt-py-check - @echo "Format check completed" - -fmt-ts: - npm run format - -fmt-ts-check: - npm run format:check - -fmt-py: - $(conda_run) black --skip-string-normalization . - $(conda_run) isort --profile black . - -fmt-py-check: - $(conda_run) black -l 88 --check . - -.PHONY: $(MAKECMDGOALS) diff --git a/pyscriptjs/README.md b/pyscriptjs/README.md deleted file mode 100644 index afbcd9e4..00000000 --- a/pyscriptjs/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# PyScript Demonstrator - -[A simple webapp to demonstrate the capabilities of PyScript.](https://github.com/pyscript/pyscript/blob/main/docs/development/setting-up-environment.md#pyscript-demonstrator) diff --git a/pyscriptjs/__mocks__/_pyscript.js b/pyscriptjs/__mocks__/_pyscript.js deleted file mode 100644 index 5ea00107..00000000 --- a/pyscriptjs/__mocks__/_pyscript.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * this file mocks the `src/python/pyscript.py` file - * since importing of `.py` files isn't usually supported - * inside JS/TS files. - * - * It sets the value of whatever is imported from - * `src/python/pyscript.py` the contents of that file - * - * This is needed since the imported object is further - * passed to a function which only accepts a string. - */ - -const fs = require('fs'); -module.exports = fs.readFileSync('./src/python/pyscript.py', 'utf8'); diff --git a/pyscriptjs/__mocks__/cssMock.js b/pyscriptjs/__mocks__/cssMock.js deleted file mode 100644 index 9dc5fc1e..00000000 --- a/pyscriptjs/__mocks__/cssMock.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = ''; diff --git a/pyscriptjs/__mocks__/fileMock.js b/pyscriptjs/__mocks__/fileMock.js deleted file mode 100644 index 1fce9017..00000000 --- a/pyscriptjs/__mocks__/fileMock.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * this file mocks python files that are not explicitly - * matched by a regex in jest.config.js, since importing of - * `.py` files isn't usually supported inside JS/TS files. - * - * This is needed since the imported object is further - * passed to a function which only accepts a string. - * - * The mocked contents of the `.py` file will be "", e.g. - * nothing. - */ - -console.warn(`.py files that are not explicitly mocked in \ - jest.config.js and /__mocks__/ are mocked as empty strings`); - -module.exports = ''; diff --git a/pyscriptjs/directoryManifest.mjs b/pyscriptjs/directoryManifest.mjs deleted file mode 100644 index ef8a1000..00000000 --- a/pyscriptjs/directoryManifest.mjs +++ /dev/null @@ -1,53 +0,0 @@ -// This logic split out because it is shared by: -// 1. esbuild.mjs -// 2. Jest setup.ts - -import path, { join } from 'path'; -import { opendir, readFile } from 'fs/promises'; - -/** - * List out everything in a directory, but skip __pycache__ directory. Used to - * list out the directory paths and the [file path, file contents] pairs in the - * Python package. All paths are relative to the directory we are listing. The - * directories are sorted topologically so that a parent directory always - * appears before its children. - * - * This is consumed in main.ts which calls mkdir for each directory and then - * writeFile to create each file. - * - * @param {string} dir The path to the directory we want to list out - * @returns {dirs: string[], files: [string, string][]} - */ -export async function directoryManifest(dir) { - const result = { dirs: [], files: [] }; - await _directoryManifestHelper(dir, '.', result); - return result; -} - -/** - * Recursive helper function for directoryManifest - */ -async function _directoryManifestHelper(root, dir, result) { - const dirObj = await opendir(join(root, dir)); - for await (const d of dirObj) { - const entry = join(dir, d.name); - if (d.isDirectory()) { - if (d.name === '__pycache__') { - continue; - } - result.dirs.push(entry); - await _directoryManifestHelper(root, entry, result); - } else if (d.isFile()) { - result.files.push([normalizePath(entry), await readFile(join(root, entry), { encoding: 'utf-8' })]); - } - } -} - -/** - * Normalize paths under different operating systems to - * the correct path that will be used for src on browser. - * @param {string} originalPath - */ -function normalizePath(originalPath) { - return path.normalize(originalPath).replace(/\\/g, '/'); -} diff --git a/pyscriptjs/esbuild.mjs b/pyscriptjs/esbuild.mjs deleted file mode 100644 index cfa694b8..00000000 --- a/pyscriptjs/esbuild.mjs +++ /dev/null @@ -1,138 +0,0 @@ -import { build } from 'esbuild'; -import { spawn } from 'child_process'; -import { join } from 'path'; -import { watchFile } from 'fs'; -import { cp, lstat, readdir } from 'fs/promises'; -import { directoryManifest } from './directoryManifest.mjs'; -import { fileURLToPath } from 'url'; - -const __dirname = fileURLToPath(new URL('.', import.meta.url)); - -const production = !process.env.NODE_WATCH || process.env.NODE_ENV === 'production'; - -const copy_targets = [ - { src: 'public/index.html', dest: 'build' }, - { src: 'src/plugins/python/*', dest: 'build/plugins/python' }, -]; - -if (!production) { - copy_targets.push({ src: 'build/*', dest: 'examples/build' }); -} - -/** - * An esbuild plugin that injects the Pyscript Python package. - * - * It uses onResolve to attach our custom namespace to the import and then uses - * onLoad to inject the file contents. - */ -function bundlePyscriptPythonPlugin() { - const namespace = 'bundlePyscriptPythonPlugin'; - return { - name: namespace, - setup(build) { - // Resolve the pyscript_package to our custom namespace - // The path doesn't really matter, but we need a separate namespace - // or else the file system resolver will raise an error. - build.onResolve({ filter: /^pyscript_python_package.esbuild_injected.json$/ }, args => { - return { path: 'dummy', namespace }; - }); - // Inject our manifest as JSON contents, and use the JSON loader. - // Also tell esbuild to watch the files & directories we've listed - // for updates. - build.onLoad({ filter: /^dummy$/, namespace }, async args => { - const manifest = await directoryManifest('./src/python'); - return { - contents: JSON.stringify(manifest), - loader: 'json', - watchFiles: manifest.files.map(([k, v]) => k), - watchDirs: manifest.dirs, - }; - }); - }, - }; -} - -const pyScriptConfig = { - entryPoints: ['src/main.ts'], - loader: { '.py': 'text' }, - bundle: true, - format: 'iife', - globalName: 'pyscript', - plugins: [bundlePyscriptPythonPlugin()], -}; - -const interpreterWorkerConfig = { - entryPoints: ['src/interpreter_worker/worker.ts'], - loader: { '.py': 'text' }, - bundle: true, - format: 'iife', - plugins: [bundlePyscriptPythonPlugin()], -}; - -const copyPath = (source, dest, ...rest) => cp(join(__dirname, source), join(__dirname, dest), ...rest); - -const esbuild = async () => { - const timer = `\x1b[1mpyscript\x1b[0m \x1b[2m(${production ? 'prod' : 'dev'})\x1b[0m built in`; - console.time(timer); - - await Promise.all([ - build({ - ...pyScriptConfig, - sourcemap: true, - minify: false, - outfile: 'build/pyscript.js', - }), - build({ - ...pyScriptConfig, - sourcemap: true, - minify: true, - outfile: 'build/pyscript.min.js', - }), - // XXX I suppose we should also build a minified version - // TODO (HC): Simplify config a bit - build({ - ...interpreterWorkerConfig, - sourcemap: false, - minify: false, - outfile: 'build/interpreter_worker.js', - }), - ]); - - const copy = []; - for (const { src, dest } of copy_targets) { - if (src.endsWith('/*')) { - copy.push(copyPath(src.slice(0, -2), dest, { recursive: true })); - } else { - copy.push(copyPath(src, dest + src.slice(src.lastIndexOf('/')))); - } - } - await Promise.all(copy); - - console.timeEnd(timer); -}; - -esbuild().then(() => { - if (!production) { - (async function watchPath(path) { - for (const file of await readdir(path)) { - const whole = join(path, file); - if (/\.(js|ts|css|py)$/.test(file)) { - watchFile(whole, async () => { - await esbuild(); - }); - } else if ((await lstat(whole)).isDirectory()) { - watchPath(whole); - } - } - })('src'); - - const server = spawn('python', ['-m', 'http.server', '--directory', './examples', '8080'], { - stdio: 'inherit', - detached: false, - }); - - process.on('exit', () => { - server.kill(); - }); - } -}); diff --git a/pyscriptjs/jest-environment-jsdom.js b/pyscriptjs/jest-environment-jsdom.js deleted file mode 100644 index 4ff695fc..00000000 --- a/pyscriptjs/jest-environment-jsdom.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const { TextEncoder, TextDecoder } = require('util'); -const { MessageChannel } = require('node:worker_threads'); - -const { default: $JSDOMEnvironment, TestEnvironment } = require('jest-environment-jsdom'); - -Object.defineProperty(exports, '__esModule', { - value: true, -}); - -class JSDOMEnvironment extends $JSDOMEnvironment { - constructor(...args) { - const { global } = super(...args); - if (!global.TextEncoder) { - global.TextEncoder = TextEncoder; - } - if (!global.TextDecoder) { - global.TextDecoder = TextDecoder; - } - if (!global.MessageChannel) { - global.MessageChannel = MessageChannel; - } - } -} - -exports.default = JSDOMEnvironment; -exports.TestEnvironment = TestEnvironment === $JSDOMEnvironment ? JSDOMEnvironment : TestEnvironment; diff --git a/pyscriptjs/jest.config.js b/pyscriptjs/jest.config.js deleted file mode 100644 index 788ff3b1..00000000 --- a/pyscriptjs/jest.config.js +++ /dev/null @@ -1,25 +0,0 @@ -//jest.config.js -module.exports = { - preset: 'ts-jest', - setupFilesAfterEnv: ['./tests/unit/setup.ts'], - testEnvironment: './jest-environment-jsdom.js', - extensionsToTreatAsEsm: ['.ts'], - transform: { - '^.+\\.tsx?$': [ - 'ts-jest', - { - tsconfig: 'tsconfig.json', - useESM: true, - }, - ], - }, - verbose: true, - testEnvironmentOptions: { - url: 'http://localhost', - }, - moduleNameMapper: { - '^.*?pyscript.py$': '/__mocks__/_pyscript.js', - '^[./a-zA-Z0-9$_-]+\\.py$': '/__mocks__/fileMock.js', - '\\.(css)$': '/__mocks__/cssMock.js', - }, -}; diff --git a/pyscriptjs/package-lock.json b/pyscriptjs/package-lock.json deleted file mode 100644 index 50639199..00000000 --- a/pyscriptjs/package-lock.json +++ /dev/null @@ -1,10525 +0,0 @@ -{ - "name": "pyscript", - "version": "0.0.1", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "pyscript", - "version": "0.0.1", - "dependencies": { - "basic-devtools": "^0.1.6", - "not-so-weak": "^1.0.0" - }, - "devDependencies": { - "@codemirror/commands": "^6.2.2", - "@codemirror/lang-python": "^6.1.2", - "@codemirror/language": "^6.6.0", - "@codemirror/state": "^6.2.0", - "@codemirror/theme-one-dark": "^6.1.1", - "@codemirror/view": "^6.9.3", - "@hoodmane/toml-j0.4": "^1.1.2", - "@jest/globals": "29.1.2", - "@types/codemirror": "^5.60.5", - "@types/jest": "29.1.2", - "@types/node": "18.8.3", - "@typescript-eslint/eslint-plugin": "5.58.0", - "@typescript-eslint/parser": "5.58.0", - "codemirror": "6.0.1", - "cross-env": "7.0.3", - "esbuild": "0.17.12", - "eslint": "8.25.0", - "jest": "29.1.2", - "jest-environment-jsdom": "29.1.2", - "prettier": "2.7.1", - "pyodide": "0.23.2", - "synclink": "0.2.4", - "ts-jest": "29.0.3", - "typescript": "5.0.4", - "xterm": "^5.1.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.19.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@codemirror/autocomplete": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz", - "integrity": "sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.6.0", - "@lezer/common": "^1.0.0" - }, - "peerDependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/commands": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz", - "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.2.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-python": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.2.tgz", - "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==", - "dev": true, - "dependencies": { - "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" - } - }, - "node_modules/@codemirror/language": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", - "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "node_modules/@codemirror/lint": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.0.tgz", - "integrity": "sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/search": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz", - "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "node_modules/@codemirror/state": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", - "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", - "dev": true - }, - "node_modules/@codemirror/theme-one-dark": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz", - "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==", - "dev": true, - "dependencies": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, - "node_modules/@codemirror/view": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.3.tgz", - "integrity": "sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow==", - "dev": true, - "dependencies": { - "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@hoodmane/toml-j0.4": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@hoodmane/toml-j0.4/-/toml-j0.4-1.1.2.tgz", - "integrity": "sha512-vQvFpjssFt39GcYwsFLDts6eReKSWeDwFt3AufXnM62ACIG2MgvOVomNRo4kQUYV0G3+zpu4LezUWw5JCFgF0Q==", - "dev": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.1.2.tgz", - "integrity": "sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.1.2", - "@jest/expect": "^29.1.2", - "@jest/types": "^29.1.2", - "jest-mock": "^29.1.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@lezer/common": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", - "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==", - "dev": true - }, - "node_modules/@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dev": true, - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/lr": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", - "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==", - "dev": true, - "dependencies": { - "@lezer/common": "^1.0.0" - } - }, - "node_modules/@lezer/python": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.3.tgz", - "integrity": "sha512-rUdt5/H8JjVY3YIROZF2ZNUMx7eYB7h0cmC8c4TfkgJt4xcn6vLpjCOCk1usP4vV3YfMC+VDB786dKjJ6tL5Hw==", - "dev": true, - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/codemirror": { - "version": "5.60.7", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.7.tgz", - "integrity": "sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA==", - "dev": true, - "dependencies": { - "@types/tern": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "dev": true, - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", - "dev": true, - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "17.0.23", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", - "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", - "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/type-utils": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz", - "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", - "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz", - "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.58.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, - "dependencies": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base-64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", - "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", - "dev": true - }, - "node_modules/basic-devtools": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/basic-devtools/-/basic-devtools-0.1.6.tgz", - "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001469", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", - "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dev": true, - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", - "dev": true - }, - "node_modules/cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "bin": { - "cross-env": "src/bin/cross-env.js", - "cross-env-shell": "src/bin/cross-env-shell.js" - }, - "engines": { - "node": ">=10.14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.334", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", - "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", - "dev": true, - "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.1.2", - "@jest/types": "^29.1.2", - "import-local": "^3.0.2", - "jest-cli": "^29.1.2" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-jsdom": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.1.2.tgz", - "integrity": "sha512-D+XNIKia5+uDjSMwL/G1l6N9MCb7LymKI8FpcLo7kkISjc/Sa9w+dXXEa7u1Wijo3f8sVLqfxdGqYtRhmca+Xw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.1.2", - "@jest/fake-timers": "^29.1.2", - "@jest/types": "^29.1.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.1.2", - "jest-util": "^29.1.2", - "jsdom": "^20.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "acorn": "^8.8.1", - "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.2", - "parse5": "^7.1.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/not-so-weak": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz", - "integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ==" - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/pyodide": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.23.2.tgz", - "integrity": "sha512-GK4YDZVgzfAXK/7X0IiCI+142k0Ah/HwYTzDHtG8zC47dflWYuPozeFbOngShuL1M9Un5sCmHFqiH3boxJv0pQ==", - "dev": true, - "dependencies": { - "base-64": "^1.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.5.0" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-mod": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.2.tgz", - "integrity": "sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ==", - "dev": true - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "dev": true, - "license": "MIT" - }, - "node_modules/synclink": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/synclink/-/synclink-0.2.4.tgz", - "integrity": "sha512-wgG4jQgPe1OPgE7gJgP3/3jCiVkEcXr1jzl+7pbGtBtp7Og2o337YGNYFwCz2ulERKoYzPyYMCDfAYjShgzCTg==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "dependencies": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=12.20" - } - }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "dev": true - }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/xterm": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz", - "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", - "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", - "dev": true - }, - "@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", - "dev": true, - "requires": { - "@babel/types": "^7.21.3", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-compilation-targets": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", - "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.20.5", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.18.6" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.19.0" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@codemirror/autocomplete": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.4.2.tgz", - "integrity": "sha512-8WE2xp+D0MpWEv5lZ6zPW1/tf4AGb358T5GWYiKEuCP8MvFfT3tH2mIF9Y2yr2e3KbHuSvsVhosiEyqCpiJhZQ==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.6.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/commands": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.2.2.tgz", - "integrity": "sha512-s9lPVW7TxXrI/7voZ+HmD/yiAlwAYn9PH5SUVSUhsxXHhv4yl5eZ3KLntSoTynfdgVYM0oIpccQEWRBQgmNZyw==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.2.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0" - } - }, - "@codemirror/lang-python": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.2.tgz", - "integrity": "sha512-nbQfifLBZstpt6Oo4XxA2LOzlSp4b/7Bc5cmodG1R+Cs5PLLCTUvsMNWDnziiCfTOG/SW1rVzXq/GbIr6WXlcw==", - "dev": true, - "requires": { - "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" - } - }, - "@codemirror/language": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", - "integrity": "sha512-cwUd6lzt3MfNYOobdjf14ZkLbJcnv4WtndYaoBkbor/vF+rCNguMPK0IRtvZJG4dsWiaWPcK8x1VijhvSxnstg==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0", - "style-mod": "^4.0.0" - } - }, - "@codemirror/lint": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.2.0.tgz", - "integrity": "sha512-KVCECmR2fFeYBr1ZXDVue7x3q5PMI0PzcIbA+zKufnkniMBo1325t0h1jM85AKp8l3tj67LRxVpZfgDxEXlQkg==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/search": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.3.0.tgz", - "integrity": "sha512-rBhZxzT34CarfhgCZGhaLBScABDN3iqJxixzNuINp9lrb3lzm0nTpR77G1VrxGO3HOGK7j62jcJftQM7eCOIuw==", - "dev": true, - "requires": { - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "crelt": "^1.0.5" - } - }, - "@codemirror/state": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.2.0.tgz", - "integrity": "sha512-69QXtcrsc3RYtOtd+GsvczJ319udtBf1PTrr2KbLWM/e2CXUPnh0Nz9AUo8WfhSQ7GeL8dPVNUmhQVgpmuaNGA==", - "dev": true - }, - "@codemirror/theme-one-dark": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.1.tgz", - "integrity": "sha512-+CfzmScfJuD6uDF5bHJkAjWTQ2QAAHxODCPxUEgcImDYcJLT+4l5vLnBHmDVv46kCC5uUJGMrBJct2Z6JbvqyQ==", - "dev": true, - "requires": { - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0", - "@lezer/highlight": "^1.0.0" - } - }, - "@codemirror/view": { - "version": "6.9.3", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.9.3.tgz", - "integrity": "sha512-BJ5mvEIhFM+SrNwc5X8pLIvMM9ffjkviVbxpg84Xk2OE8ZyKaEbId8kX+nAYEEso7+qnbwsXe1bkAHsasebMow==", - "dev": true, - "requires": { - "@codemirror/state": "^6.1.4", - "style-mod": "^4.0.0", - "w3c-keyname": "^2.2.4" - } - }, - "@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@hoodmane/toml-j0.4": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@hoodmane/toml-j0.4/-/toml-j0.4-1.1.2.tgz", - "integrity": "sha512-vQvFpjssFt39GcYwsFLDts6eReKSWeDwFt3AufXnM62ACIG2MgvOVomNRo4kQUYV0G3+zpu4LezUWw5JCFgF0Q==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.10.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", - "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.4" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - } - }, - "@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "requires": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - } - }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3" - } - }, - "@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "@jest/globals": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.1.2.tgz", - "integrity": "sha512-uMgfERpJYoQmykAd0ffyMq8wignN4SvLUG6orJQRe9WAlTRc9cdpCaE/29qurXixYJVZWUqIBXhSk8v5xN1V9g==", - "dev": true, - "requires": { - "@jest/environment": "^29.1.2", - "@jest/expect": "^29.1.2", - "@jest/types": "^29.1.2", - "jest-mock": "^29.1.2" - } - }, - "@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - } - }, - "@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - } - }, - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "@lezer/common": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", - "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==", - "dev": true - }, - "@lezer/highlight": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", - "integrity": "sha512-3vLKLPThO4td43lYRBygmMY18JN3CPh9w+XS2j8WC30vR4yZeFG4z1iFe4jXE43NtGqe//zHW5q8ENLlHvz9gw==", - "dev": true, - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/lr": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", - "integrity": "sha512-JPQe3mwJlzEVqy67iQiiGozhcngbO8QBgpqZM6oL1Wj/dXckrEexpBLeFkq0edtW5IqnPRFxA24BHJni8Js69w==", - "dev": true, - "requires": { - "@lezer/common": "^1.0.0" - } - }, - "@lezer/python": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.3.tgz", - "integrity": "sha512-rUdt5/H8JjVY3YIROZF2ZNUMx7eYB7h0cmC8c4TfkgJt4xcn6vLpjCOCk1usP4vV3YfMC+VDB786dKjJ6tL5Hw==", - "dev": true, - "requires": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/codemirror": { - "version": "5.60.7", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.7.tgz", - "integrity": "sha512-QXIC+RPzt/1BGSuD6iFn6UMC9TDp+9hkOANYNPVsjjrDdzKphfRkwQDKGp2YaC54Yhz0g6P5uYTCCibZZEiMAA==", - "dev": true, - "requires": { - "@types/tern": "*" - } - }, - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-y+nlX0h87U0R+wsGn6EBuoRWYyv3KFtwRNP3QWp9+k2tJ2/bqcGS3UxD7jgT+tiwJWWq3UsyV4Y+T6rsMT4XMg==", - "dev": true, - "requires": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "@types/jsdom": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", - "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/tough-cookie": "*", - "parse5": "^7.0.0" - } - }, - "@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true - }, - "@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", - "dev": true - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/semver": { - "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", - "dev": true, - "requires": { - "@types/estree": "*" - } - }, - "@types/tough-cookie": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", - "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", - "dev": true - }, - "@types/yargs": { - "version": "17.0.23", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.23.tgz", - "integrity": "sha512-yuogunc04OnzGQCrfHx+Kk883Q4X0aSwmYZhKjI21m+SVYzjIbrWl8dOOwSv5hf2Um2pdCOXWo9isteZTNXUZQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "@typescript-eslint/eslint-plugin": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz", - "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/type-utils": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/parser": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz", - "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz", - "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz", - "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "5.58.0", - "@typescript-eslint/utils": "5.58.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/types": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz", - "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz", - "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/visitor-keys": "5.58.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - } - }, - "@typescript-eslint/utils": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz", - "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.58.0", - "@typescript-eslint/types": "5.58.0", - "@typescript-eslint/typescript-estree": "5.58.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "5.58.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz", - "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==", - "dev": true, - "requires": { - "@typescript-eslint/types": "5.58.0", - "eslint-visitor-keys": "^3.3.0" - } - }, - "abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-globals": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", - "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", - "dev": true, - "requires": { - "acorn": "^8.1.0", - "acorn-walk": "^8.0.2" - } - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, - "babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "requires": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base-64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", - "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", - "dev": true - }, - "basic-devtools": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/basic-devtools/-/basic-devtools-0.1.6.tgz", - "integrity": "sha512-g9zJ63GmdUesS3/Fwv0B5SYX6nR56TQXmGr+wE5PRTNCnGQMYWhUx/nZB/mMWnQJVLPPAp89oxDNlasdtNkW5Q==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001469", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001469.tgz", - "integrity": "sha512-Rcp7221ScNqQPP3W+lVOYDyjdR6dC+neEQCttoNr5bAyz54AboB4iwpnWgyi8P4YUsPybVzT4LgWiBbI3drL4g==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "codemirror": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", - "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", - "dev": true, - "requires": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/commands": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/lint": "^6.0.0", - "@codemirror/search": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@codemirror/view": "^6.0.0" - } - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "crelt": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", - "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==", - "dev": true - }, - "cross-env": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", - "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cssom": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", - "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, - "data-urls": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", - "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "requires": { - "webidl-conversions": "^7.0.0" - } - }, - "electron-to-chromium": { - "version": "1.4.334", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.334.tgz", - "integrity": "sha512-laZ1odk+TRen6q0GeyQx/JEkpD3iSZT7ewopCpKqg9bTjP1l8XRfU3Bg20CFjNPZkp5+NDBl3iqd4o/kPO+Vew==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, - "eslint": { - "version": "8.25.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", - "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", - "dev": true, - "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", - "@humanwhocodes/module-importer": "^1.0.1", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.1", - "globals": "^13.15.0", - "globby": "^11.1.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", - "dev": true - }, - "espree": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz", - "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jest": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.1.2.tgz", - "integrity": "sha512-5wEIPpCezgORnqf+rCaYD1SK+mNN7NsstWzIsuvsnrhR/hSxXWd82oI7DkrbJ+XTD28/eG8SmxdGvukrGGK6Tw==", - "dev": true, - "requires": { - "@jest/core": "^29.1.2", - "@jest/types": "^29.1.2", - "import-local": "^3.0.2", - "jest-cli": "^29.1.2" - } - }, - "jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - } - }, - "jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - } - }, - "jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - } - }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - } - }, - "jest-environment-jsdom": { - "version": "29.1.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.1.2.tgz", - "integrity": "sha512-D+XNIKia5+uDjSMwL/G1l6N9MCb7LymKI8FpcLo7kkISjc/Sa9w+dXXEa7u1Wijo3f8sVLqfxdGqYtRhmca+Xw==", - "dev": true, - "requires": { - "@jest/environment": "^29.1.2", - "@jest/fake-timers": "^29.1.2", - "@jest/types": "^29.1.2", - "@types/jsdom": "^20.0.0", - "@types/node": "*", - "jest-mock": "^29.1.2", - "jest-util": "^29.1.2", - "jsdom": "^20.0.0" - } - }, - "jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true - }, - "jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - } - }, - "jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true - }, - "jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - } - }, - "jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - } - }, - "jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - } - } - } - }, - "jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - } - }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - }, - "jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - } - }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-sdsl": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", - "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsdom": { - "version": "20.0.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", - "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "acorn": "^8.8.1", - "acorn-globals": "^7.0.0", - "cssom": "^0.5.0", - "cssstyle": "^2.3.0", - "data-urls": "^3.0.2", - "decimal.js": "^10.4.2", - "domexception": "^4.0.0", - "escodegen": "^2.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.2", - "parse5": "^7.1.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^11.0.0", - "ws": "^8.11.0", - "xml-name-validator": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node-fetch": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", - "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", - "dev": true, - "requires": { - "whatwg-url": "^5.0.0" - }, - "dependencies": { - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - } - } - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "not-so-weak": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/not-so-weak/-/not-so-weak-1.0.0.tgz", - "integrity": "sha512-kgpM6y09QLyfQXfA0AAupX8ZUqKn4caDxQTMVNsyKK02IQ+9P9ylcL1ioQem4qciUCy3IitESXQfMBfnGuGNOQ==" - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "requires": { - "entities": "^4.4.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "dev": true - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pure-rand": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", - "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", - "dev": true - }, - "pyodide": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/pyodide/-/pyodide-0.23.2.tgz", - "integrity": "sha512-GK4YDZVgzfAXK/7X0IiCI+142k0Ah/HwYTzDHtG8zC47dflWYuPozeFbOngShuL1M9Un5sCmHFqiH3boxJv0pQ==", - "dev": true, - "requires": { - "base-64": "^1.0.0", - "node-fetch": "^2.6.1", - "ws": "^8.5.0" - } - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", - "dev": true, - "requires": { - "is-core-module": "^2.9.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.1.tgz", - "integrity": "sha512-OEJWVeimw8mgQuj3HfkNl4KqRevH7lzeQNaWRPfx0PPse7Jk6ozcsG4FKVgtzDsC1KUF+YlTHh17NcgHOPykLw==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, - "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "style-mod": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.2.tgz", - "integrity": "sha512-C4myMmRTO8iaC5Gg+N1ftK2WT4eXUTMAa+HEFPPrfVeO/NtqLTtAmV1HbqnuGtLwCek44Ra76fdGUkSqjiMPcQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "symbol-tree": { - "version": "3.2.4", - "dev": true - }, - "synclink": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/synclink/-/synclink-0.2.4.tgz", - "integrity": "sha512-wgG4jQgPe1OPgE7gJgP3/3jCiVkEcXr1jzl+7pbGtBtp7Og2o337YGNYFwCz2ulERKoYzPyYMCDfAYjShgzCTg==", - "dev": true - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", - "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - } - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "fast-json-stable-stringify": "2.x", - "jest-util": "^29.0.0", - "json5": "^2.2.1", - "lodash.memoize": "4.x", - "make-error": "1.x", - "semver": "7.x", - "yargs-parser": "^21.0.1" - } - }, - "tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", - "dev": true - }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - } - } - }, - "w3c-keyname": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.6.tgz", - "integrity": "sha512-f+fciywl1SJEniZHD6H+kUO8gOnwIr7f4ijKA6+ZvJFjeGi1r4PDLl53Ayud9O/rk64RqgoQine0feoeOU0kXg==", - "dev": true - }, - "w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "requires": { - "xml-name-validator": "^4.0.0" - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true - }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "xterm": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz", - "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - } - } -} diff --git a/pyscriptjs/package.json b/pyscriptjs/package.json deleted file mode 100644 index a86c47d3..00000000 --- a/pyscriptjs/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "pyscript", - "version": "0.0.1", - "scripts": { - "build": "npm run tsc && node esbuild.mjs", - "dev": "NODE_WATCH=1 node esbuild.mjs", - "tsc": "tsc --noEmit", - "format:check": "prettier --check './src/**/*.{mjs,js,html,ts}'", - "format": "prettier --write './src/**/*.{mjs,js,html,ts}'", - "lint": "eslint './src/**/*.{mjs,js,html,ts}'", - "lint:fix": "eslint --fix './src/**/*.{mjs,js,html,ts}'", - "xprelint": "npm run format", - "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage", - "test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch" - }, - "devDependencies": { - "@codemirror/commands": "^6.2.2", - "@codemirror/lang-python": "^6.1.2", - "@codemirror/language": "^6.6.0", - "@codemirror/state": "^6.2.0", - "@codemirror/theme-one-dark": "^6.1.1", - "@codemirror/view": "^6.9.3", - "@hoodmane/toml-j0.4": "^1.1.2", - "@jest/globals": "29.1.2", - "@types/codemirror": "^5.60.5", - "@types/jest": "29.1.2", - "@types/node": "18.8.3", - "@typescript-eslint/eslint-plugin": "5.58.0", - "@typescript-eslint/parser": "5.58.0", - "codemirror": "6.0.1", - "cross-env": "7.0.3", - "esbuild": "0.17.12", - "eslint": "8.25.0", - "jest": "29.1.2", - "jest-environment-jsdom": "29.1.2", - "prettier": "2.7.1", - "pyodide": "0.23.2", - "synclink": "0.2.4", - "ts-jest": "29.0.3", - "typescript": "5.0.4", - "xterm": "^5.1.0" - }, - "dependencies": { - "basic-devtools": "^0.1.6", - "not-so-weak": "^1.0.0" - } -} diff --git a/pyscriptjs/public/.gitkeep b/pyscriptjs/public/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/pyscriptjs/public/index.html b/pyscriptjs/public/index.html deleted file mode 100644 index 8443107f..00000000 --- a/pyscriptjs/public/index.html +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - PyScript - - - -
-

<py-script>

- -
- - import sys - print(sys.version) - - -

Example

-
-<!DOCTYPE html>
-<html lang="en">
-    <head>
-    <meta charset="utf-8" />
-    <meta name="viewport" content="width=device-width,initial-scale=1" />
-    <title>PyScript Hello World</title>
-    <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
-    <script defer src="https://pyscript.net/latest/pyscript.js"></script>
-    </head>
-
-    <body>
-    Hello world! <br>
-    This is the current date and time, as computed by Python:
-    <py-script>
-from datetime import datetime
-now = datetime.now()
-now.strftime("%m/%d/%Y, %H:%M:%S")
-    </py-script>
-    </body>
-</html>
-
- - diff --git a/pyscriptjs/src/components/elements.ts b/pyscriptjs/src/components/elements.ts deleted file mode 100644 index 7f3336d7..00000000 --- a/pyscriptjs/src/components/elements.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { InterpreterClient } from '../interpreter_client'; -import type { PyScriptApp } from '../main'; -import { make_PyRepl } from './pyrepl'; - -function createCustomElements(interpreter: InterpreterClient, app: PyScriptApp) { - const PyRepl = make_PyRepl(interpreter, app); - - customElements.define('py-repl', PyRepl); -} - -export { createCustomElements }; diff --git a/pyscriptjs/src/components/pyrepl.ts b/pyscriptjs/src/components/pyrepl.ts deleted file mode 100644 index 20034641..00000000 --- a/pyscriptjs/src/components/pyrepl.ts +++ /dev/null @@ -1,237 +0,0 @@ -import { $, $$ } from 'basic-devtools'; - -import { basicSetup, EditorView } from 'codemirror'; -import { python } from '@codemirror/lang-python'; -import { indentUnit } from '@codemirror/language'; -import { Compartment } from '@codemirror/state'; -import { keymap, Command } from '@codemirror/view'; -import { defaultKeymap } from '@codemirror/commands'; -import { oneDarkTheme } from '@codemirror/theme-one-dark'; - -import { ensureUniqueId, htmlDecode } from '../utils'; -import { pyExec } from '../pyexec'; -import { getLogger } from '../logger'; -import { InterpreterClient } from '../interpreter_client'; -import type { PyScriptApp } from '../main'; -import { Stdio } from '../stdio'; -import { robustFetch } from '../fetch'; -import { _createAlertBanner } from '../exceptions'; - -const logger = getLogger('py-repl'); -const RUNBUTTON = ``; - -export function make_PyRepl(interpreter: InterpreterClient, app: PyScriptApp) { - /* High level structure of py-repl DOM, and the corresponding JS names. - - this - boxDiv
- editorDiv
- outDiv
-
-
- */ - class PyRepl extends HTMLElement { - outDiv: HTMLElement; - editor: EditorView; - stdout_manager: Stdio | null; - stderr_manager: Stdio | null; - static observedAttributes = ['src']; - connectedCallback() { - ensureUniqueId(this); - - if (!this.hasAttribute('exec-id')) { - this.setAttribute('exec-id', '0'); - } - if (!this.hasAttribute('root')) { - this.setAttribute('root', this.id); - } - - const pySrc = htmlDecode(this.innerHTML).trim(); - this.innerHTML = ''; - const boxDiv = this.makeBoxDiv(); - const shadowRoot = $('.py-repl-editor > div', boxDiv).attachShadow({ mode: 'open' }); - // avoid inheriting styles from the outer component - shadowRoot.innerHTML = ``; - this.appendChild(boxDiv); - this.editor = this.makeEditor(pySrc, shadowRoot); - this.editor.focus(); - logger.debug(`element ${this.id} successfully connected`); - } - - get src() { - return this.getAttribute('src'); - } - - set src(value) { - this.setAttribute('src', value); - } - - attributeChangedCallback(name: string, oldVal: string, newVal: string) { - if (name === 'src' && newVal !== oldVal) { - void this.loadReplSrc(); - } - } - - /** - * Fetch url from src attribute of py-repl tags and - * preload the code from fetch response into the Corresponding py-repl tag, - * but please note that they will not be pre-run unless you click the runbotton. - */ - async loadReplSrc() { - try { - const response = await robustFetch(this.src); - if (!response.ok) { - return; - } - const cmcontentElement = $('div.cm-content', this.editor.dom); - const { lastElementChild } = cmcontentElement; - cmcontentElement.replaceChildren(lastElementChild); - lastElementChild.textContent = await response.text(); - logger.info(`loading code from ${this.src} to repl...success`); - } catch (err) { - const e = err as Error; - _createAlertBanner(e.message); - } - } - - /** Create and configure the codemirror editor - */ - makeEditor(pySrc: string, parent: ShadowRoot): EditorView { - const languageConf = new Compartment(); - const extensions = [ - indentUnit.of(' '), - basicSetup, - languageConf.of(python()), - keymap.of([ - ...defaultKeymap, - { key: 'Ctrl-Enter', run: this.execute.bind(this) as Command, preventDefault: true }, - { key: 'Shift-Enter', run: this.execute.bind(this) as Command, preventDefault: true }, - ]), - ]; - - if (this.getAttribute('theme') === 'dark') { - extensions.push(oneDarkTheme); - } - - return new EditorView({ - doc: pySrc, - extensions, - parent, - }); - } - - // ******** main entry point for py-repl DOM building ********** - // - // The following functions are written in a top-down, depth-first - // order (so that the order of code roughly matches the order of - // execution) - makeBoxDiv(): HTMLElement { - const boxDiv = document.createElement('div'); - boxDiv.className = 'py-repl-box'; - - const editorDiv = this.makeEditorDiv(); - this.outDiv = this.makeOutDiv(); - - boxDiv.appendChild(editorDiv); - boxDiv.appendChild(this.outDiv); - - return boxDiv; - } - - makeEditorDiv(): HTMLElement { - const editorDiv = document.createElement('div'); - editorDiv.className = 'py-repl-editor'; - editorDiv.setAttribute('aria-label', 'Python Script Area'); - - const runButton = this.makeRunButton(); - const editorShadowContainer = document.createElement('div'); - - // avoid outer elements intercepting key events (reveal as example) - editorShadowContainer.addEventListener('keydown', event => { - event.stopPropagation(); - }); - - editorDiv.append(editorShadowContainer, runButton); - - return editorDiv; - } - - makeRunButton(): HTMLElement { - const runButton = document.createElement('button'); - runButton.className = 'absolute py-repl-run-button'; - runButton.innerHTML = RUNBUTTON; - runButton.setAttribute('aria-label', 'Python Script Run Button'); - runButton.addEventListener('click', this.execute.bind(this) as (e: MouseEvent) => void); - return runButton; - } - - makeOutDiv(): HTMLElement { - const outDiv = document.createElement('div'); - outDiv.className = 'py-repl-output'; - outDiv.id = this.id + '-repl-output'; - return outDiv; - } - - // ********************* execution logic ********************* - - /** Execute the python code written in the editor, and automatically - * display() the last evaluated expression - */ - async execute(): Promise { - const pySrc = this.getPySrc(); - const outEl = this.outDiv; - - // execute the python code - await app.plugins.beforePyReplExec({ interpreter: interpreter, src: pySrc, outEl: outEl, pyReplTag: this }); - const { result } = await pyExec(interpreter, pySrc, outEl); - await app.plugins.afterPyReplExec({ - interpreter: interpreter, - src: pySrc, - outEl: outEl, - pyReplTag: this, - result, - }); - - this.autogenerateMaybe(); - } - - getPySrc(): string { - return this.editor.state.doc.toString(); - } - - // XXX the autogenerate logic is very messy. We should redo it, and it - // should be the default. - autogenerateMaybe(): void { - if (this.hasAttribute('auto-generate')) { - const allPyRepls = $$(`py-repl[root='${this.getAttribute('root')}'][exec-id]`, document); - const lastRepl = allPyRepls[allPyRepls.length - 1]; - const lastExecId = lastRepl.getAttribute('exec-id'); - const nextExecId = parseInt(lastExecId) + 1; - - const newPyRepl = document.createElement('py-repl'); - - //Attributes to be copied from old REPL to auto-generated REPL - for (const attribute of ['root', 'output-mode', 'output', 'stderr']) { - const attr = this.getAttribute(attribute); - if (attr) { - newPyRepl.setAttribute(attribute, attr); - } - } - - newPyRepl.id = this.getAttribute('root') + '-' + nextExecId.toString(); - - if (this.hasAttribute('auto-generate')) { - newPyRepl.setAttribute('auto-generate', ''); - this.removeAttribute('auto-generate'); - } - - newPyRepl.setAttribute('exec-id', nextExecId.toString()); - if (this.parentElement) { - this.parentElement.appendChild(newPyRepl); - } - } - } - } - - return PyRepl; -} diff --git a/pyscriptjs/src/components/pyscript.ts b/pyscriptjs/src/components/pyscript.ts deleted file mode 100644 index 722ef8ed..00000000 --- a/pyscriptjs/src/components/pyscript.ts +++ /dev/null @@ -1,261 +0,0 @@ -import { $$, $x } from 'basic-devtools'; - -import { shadowRoots } from '../shadow_roots'; -import { ltrim, htmlDecode, ensureUniqueId, createDeprecationWarning } from '../utils'; -import { getLogger } from '../logger'; -import { pyExec, displayPyException } from '../pyexec'; -import { _createAlertBanner } from '../exceptions'; -import { robustFetch } from '../fetch'; -import { PyScriptApp } from '../main'; -import { Stdio } from '../stdio'; -import { InterpreterClient } from '../interpreter_client'; - -const logger = getLogger('py-script'); - -// used to flag already initialized nodes -const knownPyScriptTags: WeakSet = new WeakSet(); - -export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp) { - /** - * A common VS ", -} - - -def eval_formatter(obj, print_method): - """ - Evaluates a formatter method. - """ - if print_method == "__repr__": - return repr(obj) - elif hasattr(obj, print_method): - if print_method == "savefig": - buf = io.BytesIO() - obj.savefig(buf, format="png") - buf.seek(0) - return base64.b64encode(buf.read()).decode("utf-8") - return getattr(obj, print_method)() - elif print_method == "_repr_mimebundle_": - return {}, {} - return None - - -def format_mime(obj): - """ - Formats object using _repr_x_ methods. - """ - if isinstance(obj, str): - return html.escape(obj), "text/plain" - - mimebundle = eval_formatter(obj, "_repr_mimebundle_") - if isinstance(mimebundle, tuple): - format_dict, _ = mimebundle - else: - format_dict = mimebundle - - output, not_available = None, [] - for method, mime_type in reversed(MIME_METHODS.items()): - if mime_type in format_dict: - output = format_dict[mime_type] - else: - output = eval_formatter(obj, method) - - if output is None: - continue - elif mime_type not in MIME_RENDERERS: - not_available.append(mime_type) - continue - break - if output is None: - if not_available: - console.warn( - f"Rendered object requested unavailable MIME renderers: {not_available}" - ) - output = repr(output) - mime_type = "text/plain" - elif isinstance(output, tuple): - output, meta = output - else: - meta = {} - return MIME_RENDERERS[mime_type](output, meta), mime_type diff --git a/pyscriptjs/src/python/pyscript/_plugin.py b/pyscriptjs/src/python/pyscript/_plugin.py deleted file mode 100644 index f870217f..00000000 --- a/pyscriptjs/src/python/pyscript/_plugin.py +++ /dev/null @@ -1,66 +0,0 @@ -from _pyscript_js import define_custom_element -from js import console -from pyodide.ffi import create_proxy - - -class Plugin: - def __init__(self, name=None): - if not name: - name = self.__class__.__name__ - - self.name = name - self._custom_elements = [] - self.app = None - - def init(self, app): - self.app = app - - def configure(self, config): - pass - - def afterSetup(self, interpreter): - pass - - def afterStartup(self, interpreter): - pass - - def beforePyScriptExec(self, interpreter, src, pyScriptTag): - pass - - def afterPyScriptExec(self, interpreter, src, pyScriptTag, result): - pass - - def beforePyReplExec(self, interpreter, src, outEl, pyReplTag): - pass - - def afterPyReplExec(self, interpreter, src, outEl, pyReplTag, result): - pass - - def onUserError(self, error): - pass - - def register_custom_element(self, tag): - """ - Decorator to register a new custom element as part of a Plugin and associate - tag to it. Internally, it delegates the registration to the PyScript internal - [JS] plugin manager, who actually creates the JS custom element that can be - attached to the page and instantiate an instance of the class passing the custom - element to the plugin constructor. - - Exammple: - >> plugin = Plugin("PyTutorial") - >> @plugin.register_custom_element("py-tutor") - >> class PyTutor: - >> def __init__(self, element): - >> self.element = element - """ - # TODO: Ideally would be better to use the logger. - console.info(f"Defining new custom element {tag}") - - def wrapper(class_): - # TODO: this is very pyodide specific but will have to do - # until we have JS interface that works across interpreters - define_custom_element(tag, create_proxy(class_)) # noqa: F821 - - self._custom_elements.append(tag) - return create_proxy(wrapper) diff --git a/pyscriptjs/src/python_package.ts b/pyscriptjs/src/python_package.ts deleted file mode 100644 index beac1ff7..00000000 --- a/pyscriptjs/src/python_package.ts +++ /dev/null @@ -1,9 +0,0 @@ -// This file exists because I can only convince jest to mock real file system -// files, not fake modules. This confuses me because jest.mock has a virtual -// option for mocking things that don't live in the file system but it doesn't -// seem to work. - -// @ts-ignore -import python_package from 'pyscript_python_package.esbuild_injected.json'; -declare const python_package: { dirs: string[]; files: [string, string][] }; -export { python_package }; diff --git a/pyscriptjs/src/remote_interpreter.ts b/pyscriptjs/src/remote_interpreter.ts deleted file mode 100644 index 1585f9eb..00000000 --- a/pyscriptjs/src/remote_interpreter.ts +++ /dev/null @@ -1,294 +0,0 @@ -import type { AppConfig } from './pyconfig'; -import { version } from './version'; -import { getLogger } from './logger'; -import { Stdio } from './stdio'; -import { InstallError, ErrorCode } from './exceptions'; -import { robustFetch } from './fetch'; -import type { loadPyodide as loadPyodideDeclaration, PyodideInterface, PyProxy, PyProxyDict } from 'pyodide'; -import type { ProxyMarked } from 'synclink'; -import * as Synclink from 'synclink'; -import { showWarning } from './utils'; -import { define_custom_element } from './plugin'; -import { deepQuerySelector } from './shadow_roots'; - -import { python_package } from './python_package'; - -declare const loadPyodide: typeof loadPyodideDeclaration; -const logger = getLogger('pyscript/pyodide'); - -export type InterpreterInterface = (PyodideInterface & ProxyMarked) | null; - -interface Micropip extends PyProxy { - install(packageName: string | string[]): Promise; -} - -type FSInterface = { - writeFile(path: string, data: Uint8Array | string, options?: { canOwn?: boolean; encoding?: string }): void; - mkdirTree(path: string): void; - mkdir(path: string): void; -} & ProxyMarked; - -type PATHFSInterface = { - resolve(path: string): string; -} & ProxyMarked; - -type PATHInterface = { - dirname(path: string): string; -} & ProxyMarked; - -type PyScriptInternalModule = ProxyMarked & { - set_version_info(ver: string): void; - uses_top_level_await(code: string): boolean; - run_pyscript(code: string, display_target_id?: string): { result: any }; - install_pyscript_loop(): void; - start_loop(): void; - schedule_deferred_tasks(): void; -}; - -/* -RemoteInterpreter class is responsible to process requests from the -`InterpreterClient` class -- these can be requests for installation of -a package, executing code, etc. - -Currently, the only interpreter available is Pyodide as indicated by the -`InterpreterInterface` type above. This serves as a Union of types of -different interpreters which will be added in near future. - -Methods available handle loading of the interpreter, initialization, -running code, loading and installation of packages, loading from files etc. - -The class will be turned `abstract` in future, to support more runtimes -such as MicroPython. - */ -export class RemoteInterpreter extends Object { - src: string; - interface: InterpreterInterface; - FS: FSInterface; - PATH: PATHInterface; - PATH_FS: PATHFSInterface; - pyscript_internal: PyScriptInternalModule; - - globals: PyProxyDict & ProxyMarked; - // TODO: Remove this once `runtimes` is removed! - interpreter: InterpreterInterface & ProxyMarked; - - constructor(src = 'https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js') { - super(); - this.src = src; - } - - /** - * loads the interface for the interpreter and saves an instance of it - * in the `this.interface` property along with calling of other - * additional convenience functions. - * */ - - /** - * Although `loadPyodide` is used below, - * notice that it is not imported i.e. - * import { loadPyodide } from 'pyodide'; - * is not used at the top of this file. - * - * This is because, if it's used, loadPyodide - * behaves mischievously i.e. it tries to load - * additional files but with paths that are wrong such as: - * - * http://127.0.0.1:8080/build/... - * which results in a 404 since `build` doesn't - * contain these files and is clearly the wrong - * path. - */ - async loadInterpreter(config: AppConfig, stdio: Synclink.Remote): Promise { - // TODO: move this to "main thread"! - const _pyscript_js_main = { define_custom_element, showWarning, deepQuerySelector }; - - this.interface = Synclink.proxy( - await loadPyodide({ - stdout: (msg: string) => { - stdio.stdout_writeline(msg).syncify(); - }, - stderr: (msg: string) => { - stdio.stderr_writeline(msg).syncify(); - }, - fullStdLib: false, - }), - ); - this.interface.registerComlink(Synclink); - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - this.FS = this.interface.FS; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - this.PATH = (this.interface as any)._module.PATH; - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - this.PATH_FS = (this.interface as any)._module.PATH_FS; - - // TODO: Remove this once `runtimes` is removed! - this.interpreter = this.interface; - this.interface.registerJsModule('_pyscript_js', _pyscript_js_main); - - // Write pyscript package into file system - for (const dir of python_package.dirs) { - this.FS.mkdir('/home/pyodide/' + dir); - } - for (const [path, value] of python_package.files) { - this.FS.writeFile('/home/pyodide/' + path, value); - } - //Refresh the module cache so Python consistently finds pyscript module - this.invalidate_module_path_cache(); - - this.globals = Synclink.proxy(this.interface.globals as PyProxyDict); - logger.info('importing pyscript'); - this.pyscript_internal = Synclink.proxy(this.interface.pyimport('pyscript._internal')) as PyProxy & - typeof this.pyscript_internal; - this.pyscript_internal.set_version_info(version); - this.pyscript_internal.install_pyscript_loop(); - - if (config.packages) { - logger.info('Found packages in configuration to install. Loading micropip...'); - await this.loadPackage('micropip'); - } - // import some carefully selected names into the global namespace - this.interface.runPython(` - import js - import pyscript - from pyscript import Element, display, HTML - `); - - logger.info('pyodide loaded and initialized'); - } - - /** - * delegates the registration of JS modules to - * the underlying interface. - * */ - registerJsModule(name: string, module: object): void { - this.interface.registerJsModule(name, module); - } - - /** - * delegates the loading of packages to - * the underlying interface. - * */ - async loadPackage(names: string | string[]): Promise { - logger.info(`pyodide.loadPackage: ${names.toString()}`); - // The signature of `loadPackage` changed in Pyodide 0.22; while we generally - // don't support older versions of Pyodide in any given release of PyScript, this - // significant change is useful in some testing scenarios (for now) - const messageCallback = logger.info.bind(logger) as typeof logger.info; - // Comparing version as number to avoid issues with lexicographic comparison - if (Number(this.interpreter.version.split('.')[1]) >= 22) { - await this.interface.loadPackage(names, { - messageCallback, - errorCallback: messageCallback, - }); - } else { - // @ts-expect-error Types don't include this deprecated call signature - await this.interface.loadPackage(names, messageCallback, messageCallback); - } - } - - /** - * delegates the installation of packages - * (using a package manager, which can be specific to - * the interface) to the underlying interface. - * - * For Pyodide, we use `micropip` - * */ - async installPackage(package_name: string | string[]): Promise { - if (package_name.length > 0) { - logger.info(`micropip install ${package_name.toString()}`); - - const micropip = this.interface.pyimport('micropip') as Micropip; - try { - await micropip.install(package_name); - micropip.destroy(); - } catch (err) { - const e = err as Error; - let fmt_names: string; - if (Array.isArray(package_name)) { - fmt_names = package_name.join(', '); - } else { - fmt_names = package_name; - } - let exceptionMessage = `Unable to install package(s) '${fmt_names}'.`; - - // If we can't fetch `package_name` micropip.install throws a huge - // Python traceback in `e.message` this logic is to handle the - // error and throw a more sensible error message instead of the - // huge traceback. - if (e.message.includes("Can't find a pure Python 3 wheel")) { - exceptionMessage += - ` Reason: Can't find a pure Python 3 Wheel for package(s) '${fmt_names}'.` + - `See: https://pyodide.org/en/stable/usage/faq.html#micropip-can-t-find-a-pure-python-wheel ` + - `for more information.`; - } else if (e.message.includes("Can't fetch metadata")) { - exceptionMessage += - ' Unable to find package in PyPI. ' + - 'Please make sure you have entered a correct package name.'; - } else { - exceptionMessage += - ` Reason: ${e.message}. Please open an issue at ` + - `https://github.com/pyscript/pyscript/issues/new if you require help or ` + - `you think it's a bug.`; - } - - logger.error(e); - - throw new InstallError(ErrorCode.MICROPIP_INSTALL_ERROR, exceptionMessage); - } - } - } - - /** - * - * @param path : the path in the filesystem - * @param url : the url to be fetched - * - * Given a file available at `url` URL (eg: `http://dummy.com/hi.py`), the - * function downloads the file and saves it to the `path` (eg: - * `a/b/c/foo.py`) on the FS. - * - * Example usage: await loadFromFile(`a/b/c/foo.py`, - * `http://dummy.com/hi.py`) - * - * Write content of `http://dummy.com/hi.py` to `a/b/c/foo.py` - * - * NOTE: The `path` parameter expects to have the `filename` in it i.e. - * `a/b/c/foo.py` is valid while `a/b/c` (i.e. only the folders) are - * incorrect. - * - * The path will be resolved relative to the current working directory, - * which is initially `/home/pyodide`. So by default `a/b.py` will be placed - * in `/home/pyodide/a/b.py`, `../a/b.py` will be placed into `/home/a/b.py` - * and `/a/b.py` will be placed into `/a/b.py`. - */ - async loadFileFromURL(path: string, url: string): Promise { - path = this.PATH_FS.resolve(path); - const dir: string = this.PATH.dirname(path); - this.FS.mkdirTree(dir); - - // `robustFetch` checks for failures in getting a response - const response = await robustFetch(url); - const buffer = await response.arrayBuffer(); - const data = new Uint8Array(buffer); - - this.FS.writeFile(path, data, { canOwn: true }); - } - - /** - * delegates clearing importlib's module path - * caches to the underlying interface - */ - invalidate_module_path_cache(): void { - const importlib = this.interface.pyimport('importlib') as PyProxy & { invalidate_caches(): void }; - importlib.invalidate_caches(); - } - - pyimport(mod_name: string): PyProxy & Synclink.ProxyMarked { - return Synclink.proxy(this.interface.pyimport(mod_name)); - } - - setHandler(func_name: string, handler: any): void { - const pyscript_module = this.interface.pyimport('pyscript'); - pyscript_module[func_name] = handler; - } -} diff --git a/pyscriptjs/src/shadow_roots.ts b/pyscriptjs/src/shadow_roots.ts deleted file mode 100644 index c8307435..00000000 --- a/pyscriptjs/src/shadow_roots.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { $ } from 'basic-devtools'; -import { WSet } from 'not-so-weak'; - -// weakly retain shadow root nodes in an iterable way -// so that it's possible to query these and find elements by ID -export const shadowRoots: WSet = new WSet(); - -// returns an element by ID if present within any of the live shadow roots -const findInShadowRoots = (selector: string): Element | null => { - for (const shadowRoot of shadowRoots) { - const element = $(selector, shadowRoot); - if (element) return element; - } - return null; -}; - -// find an element by ID either via document or via any live shadow root -export const deepQuerySelector = (selector: string) => $(selector, document) || findInShadowRoots(selector); diff --git a/pyscriptjs/src/stdio.ts b/pyscriptjs/src/stdio.ts deleted file mode 100644 index 492a6897..00000000 --- a/pyscriptjs/src/stdio.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { $ } from 'basic-devtools'; - -import { createSingularWarning, escape } from './utils'; - -export interface Stdio { - stdout_writeline: (msg: string) => void; - stderr_writeline: (msg: string) => void; -} - -/** Default implementation of Stdio: stdout and stderr are both sent to the - * console - */ -export const DEFAULT_STDIO: Stdio = { - stdout_writeline: console.log, - stderr_writeline: console.log, -}; - -/** Stdio provider which captures and store the messages. - * Useful for tests. - */ -export class CaptureStdio implements Stdio { - captured_stdout: string; - captured_stderr: string; - - constructor() { - this.reset(); - } - - reset() { - this.captured_stdout = ''; - this.captured_stderr = ''; - } - - stdout_writeline(msg: string) { - this.captured_stdout += msg + '\n'; - } - - stderr_writeline(msg: string) { - this.captured_stderr += msg + '\n'; - } -} - -/** Stdio provider for sending output to DOM element - * specified by ID. Used with "output" keyword. - * - */ -export class TargetedStdio implements Stdio { - source_element: HTMLElement; - source_attribute: string; - capture_stdout: boolean; - capture_stderr: boolean; - - constructor(source_element: HTMLElement, source_attribute: string, capture_stdout = true, capture_stderr = true) { - this.source_element = source_element; - this.source_attribute = source_attribute; - this.capture_stdout = capture_stdout; - this.capture_stderr = capture_stderr; - } - - /** Writes the given msg to an element with a given ID. The ID is the value an attribute - * of the source_element specified by source_attribute. - * Both the element to be targeted and the ID of the element to write to - * are determined at write-time, not when the TargetdStdio object is - * created. This way, if either the 'output' attribute of the HTML tag - * or the ID of the target element changes during execution of the Python - * code, the output is still routed (or not) as expected - * - * @param msg The output to be written - */ - writeline_by_attribute(msg: string) { - const target_id = this.source_element.getAttribute(this.source_attribute); - const target = $('#' + target_id, document); - if (target === null) { - // No matching ID - createSingularWarning( - `${this.source_attribute} = "${target_id}" does not match the id of any element on the page.`, - ); - } else { - msg = escape(msg).replace('\n', '
'); - if (!msg.endsWith('
') && !msg.endsWith('
')) { - msg = msg + '
'; - } - target.innerHTML += msg; - } - } - - stdout_writeline(msg: string) { - if (this.capture_stdout) { - this.writeline_by_attribute(msg); - } - } - - stderr_writeline(msg: string) { - if (this.capture_stderr) { - this.writeline_by_attribute(msg); - } - } -} - -/** Redirect stdio streams to multiple listeners - */ -export class StdioMultiplexer implements Stdio { - _listeners: Stdio[]; - - constructor() { - this._listeners = []; - } - - addListener(obj: Stdio) { - this._listeners.push(obj); - } - - removeListener(obj: Stdio) { - const index = this._listeners.indexOf(obj); - if (index > -1) { - this._listeners.splice(index, 1); - } - } - - stdout_writeline(msg: string) { - for (const obj of this._listeners) obj.stdout_writeline(msg); - } - - stderr_writeline(msg: string) { - for (const obj of this._listeners) obj.stderr_writeline(msg); - } -} diff --git a/pyscriptjs/src/styles/pyscript_base.css b/pyscriptjs/src/styles/pyscript_base.css deleted file mode 100644 index f6edd6a1..00000000 --- a/pyscriptjs/src/styles/pyscript_base.css +++ /dev/null @@ -1,349 +0,0 @@ -/* py-config - not a component */ -py-config { - display: none; -} -/* py-{el} - components not defined */ -py-script:not(:defined) { - display: none; -} - -py-repl:not(:defined) { - display: none; -} - -py-title:not(:defined) { - display: none; -} - -py-inputbox:not(:defined) { - display: none; -} - -py-button:not(:defined) { - display: none; -} - -py-box:not(:defined) { - display: none; -} - -html { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', - Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; - line-height: 1.5; -} - -.spinner::after { - content: ''; - box-sizing: border-box; - width: 40px; - height: 40px; - position: absolute; - top: calc(40% - 20px); - left: calc(50% - 20px); - border-radius: 50%; -} - -.spinner.smooth::after { - border-top: 4px solid rgba(255, 255, 255, 1); - border-left: 4px solid rgba(255, 255, 255, 1); - border-right: 4px solid rgba(255, 255, 255, 0); - animation: spinner 0.6s linear infinite; -} - -@keyframes spinner { - to { - transform: rotate(360deg); - } -} - -.label { - text-align: center; - width: 100%; - display: block; - color: rgba(255, 255, 255, 0.8); - font-size: 0.8rem; - margin-top: 6rem; -} - -/* Pop-up second layer begin */ - -.py-overlay { - position: fixed; - display: flex; - justify-content: center; - align-items: center; - color: white; - top: 0; - bottom: 0; - left: 0; - right: 0; - background: rgba(0, 0, 0, 0.5); - transition: opacity 500ms; - visibility: hidden; - color: visible; - opacity: 1; -} - -.py-overlay { - visibility: visible; - opacity: 1; -} - -.py-pop-up { - text-align: center; - width: 600px; -} - -.py-pop-up p { - margin: 5px; -} - -.py-pop-up a { - position: absolute; - color: white; - text-decoration: none; - font-size: 200%; - top: 3.5%; - right: 5%; -} - -/* Pop-up second layer end */ -.alert-banner { - position: relative; - padding: 0.5rem 1.5rem 0.5rem 0.5rem; - margin: 5px 0; -} - -.alert-banner p { - margin: 0; -} - -.py-error { - background-color: #ffe9e8; - border: solid; - border-color: #f0625f; - color: #9d041c; -} - -.py-warning { - background-color: rgb(255, 244, 229); - border: solid; - border-color: #ffa016; - color: #794700; -} - -.alert-banner.py-error > #alert-close-button { - color: #9d041c; -} - -.alert-banner.py-warning > #alert-close-button { - color: #794700; -} - -#alert-close-button { - position: absolute; - right: 0.5rem; - top: 0.5rem; - cursor: pointer; - background: transparent; - border: none; -} - -.py-box { - display: flex; - flex-direction: row; - justify-content: flex-start; -} - -.py-box div.py-box-child * { - max-width: 100%; -} - -.py-repl-box { - flex-direction: column; -} - -.py-repl-editor { - --tw-border-opacity: 1; - border-color: rgba(209, 213, 219, var(--tw-border-opacity)); - border-width: 1px; - position: relative; - --tw-ring-inset: var(--tw-empty, /*!*/ /*!*/); - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: rgba(59, 130, 246, 0.5); - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - position: relative; - - box-sizing: border-box; - border-width: 1px; - border-style: solid; - border-color: rgb(209, 213, 219); -} - -.editor-box:hover button { - opacity: 1; -} - -.py-repl-run-button { - opacity: 0; - bottom: 0.25rem; - right: 0.25rem; - position: absolute; - padding: 0; - line-height: inherit; - color: inherit; - cursor: pointer; - background-color: transparent; - background-image: none; - -webkit-appearance: button; - text-transform: none; - font-family: inherit; - font-size: 100%; - margin: 0; - text-rendering: auto; - letter-spacing: normal; - word-spacing: normal; - line-height: normal; - text-transform: none; - text-indent: 0px; - text-shadow: none; - display: inline-block; - text-align: center; - align-items: flex-start; - cursor: default; - box-sizing: border-box; - background-color: -internal-light-dark(rgb(239, 239, 239), rgb(59, 59, 59)); - margin: 0em; - padding: 1px 6px; - border: 0; -} - -.py-repl-run-button:hover { - opacity: 1; -} - -.py-title { - text-transform: uppercase; - text-align: center; -} - -.py-title h1 { - font-weight: 700; - font-size: 1.875rem; -} - -.py-input { - padding: 0.5rem; - --tw-border-opacity: 1; - border-color: rgba(209, 213, 219, var(--tw-border-opacity)); - border-width: 1px; - border-radius: 0.25rem; - margin-right: 0.75rem; - border-style: solid; - width: auto; -} - -.py-box input.py-input { - width: -webkit-fill-available; -} - -.central-content { - max-width: 20rem; - margin-left: auto; - margin-right: auto; -} - -input { - text-rendering: auto; - color: -internal-light-dark(black, white); - letter-spacing: normal; - word-spacing: normal; - line-height: normal; - text-transform: none; - text-indent: 0px; - text-shadow: none; - display: inline-block; - text-align: start; - appearance: auto; - -webkit-rtl-ordering: logical; - background-color: -internal-light-dark(rgb(255, 255, 255), rgb(59, 59, 59)); - margin: 0em; - padding: 1px 2px; - border-width: 2px; - border-style: inset; - border-color: -internal-light-dark(rgb(118, 118, 118), rgb(133, 133, 133)); - border-image: initial; -} - -.py-button { - --tw-text-opacity: 1; - color: rgba(255, 255, 255, var(--tw-text-opacity)); - padding: 0.5rem; - --tw-bg-opacity: 1; - background-color: rgba(37, 99, 235, var(--tw-bg-opacity)); - --tw-border-opacity: 1; - border-color: rgba(37, 99, 235, var(--tw-border-opacity)); - border-width: 1px; - border-radius: 0.25rem; - cursor: pointer; -} - -.py-li-element p { - margin: 5px; -} - -.py-li-element p { - display: inline; -} - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; - font-size: 100%; - line-height: 1.15; - margin: 0; -} - -.line-through { - text-decoration: line-through; -} - -/* ===== py-terminal plugin ===== */ -/* XXX: it would be nice if these rules were stored in e.g. pyterminal.css and - bundled together at build time (by rollup?) */ - -.py-terminal { - min-height: 10em; - background-color: black; - color: white; - padding: 0.5rem; - overflow: auto; -} - -.py-terminal-hidden { - display: none; -} - -/* avoid changing the page layout when the terminal is docked and hidden */ -html:has(py-terminal[docked]:not(py-terminal[docked].py-terminal-hidden)) { - padding-bottom: 40vh; -} - -py-terminal[docked] { - position: fixed; - bottom: 0; - width: 100vw; - max-height: 40vh; - overflow: auto; -} - -py-terminal[docked] .py-terminal { - margin: 0; -} diff --git a/pyscriptjs/src/utils.ts b/pyscriptjs/src/utils.ts deleted file mode 100644 index ff599801..00000000 --- a/pyscriptjs/src/utils.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { $$ } from 'basic-devtools'; - -import { _createAlertBanner } from './exceptions'; - -export function escape(str: string): string { - return str.replace(//g, '>'); -} - -export function htmlDecode(input: string): string | null { - const doc = new DOMParser().parseFromString(ltrim(escape(input)), 'text/html'); - return doc.documentElement.textContent; -} - -export function ltrim(code: string): string { - const lines = code.split('\n'); - if (lines.length == 0) return code; - - const lengths = lines - .filter(line => line.trim().length != 0) - .map(line => { - return line.match(/^\s*/)?.pop()?.length; - }); - - const k = Math.min(...lengths); - - return k != 0 ? lines.map(line => line.substring(k)).join('\n') : code; -} - -let _uniqueIdCounter = 0; -export function ensureUniqueId(el: HTMLElement) { - if (el.id === '') el.id = `py-internal-${_uniqueIdCounter++}`; -} - -export function showWarning(msg: string, messageType: 'text' | 'html' = 'text'): void { - _createAlertBanner(msg, 'warning', messageType); -} - -export function readTextFromPath(path: string) { - const request = new XMLHttpRequest(); - request.open('GET', path, false); - request.send(); - const returnValue = request.responseText; - - return returnValue; -} - -export function inJest(): boolean { - return typeof process === 'object' && process.env.JEST_WORKER_ID !== undefined; -} - -export function joinPaths(parts: string[], separator = '/') { - const res = parts - .map(function (part) { - return part.trim().replace(/(^[/]*|[/]*$)/g, ''); - }) - .filter(p => p !== '' && p !== '.') - .join(separator || '/'); - if (parts[0].startsWith('/')) { - return '/' + res; - } - return res; -} - -export function createDeprecationWarning(msg: string, elementName: string): void { - createSingularWarning(msg, elementName); -} - -/** Adds a warning banner with content {msg} at the top of the page if - * and only if no banner containing the {sentinelText} already exists. - * If sentinelText is null, the full text of {msg} is used instead - * - * @param msg {string} The full text content of the warning banner to be displayed - * @param sentinelText {string} [null] The text to match against existing warning banners. - * If null, the full text of 'msg' is used instead. - */ -export function createSingularWarning(msg: string, sentinelText?: string): void { - const banners = $$('.alert-banner, .py-warning', document); - let bannerCount = 0; - for (const banner of banners) { - if (banner.innerHTML.includes(sentinelText || msg)) { - bannerCount++; - } - } - if (bannerCount == 0) { - _createAlertBanner(msg, 'warning'); - } -} - -/** - * @returns A new asynchronous lock - * @private - */ -export function createLock(): () => Promise<() => void> { - // This is a promise that is resolved when the lock is open, not resolved when lock is held. - let _lock = Promise.resolve(); - - /** - * Acquire the async lock - * @returns A zero argument function that releases the lock. - * @private - */ - async function acquireLock() { - const old_lock = _lock; - let releaseLock: () => void; - _lock = new Promise(resolve => (releaseLock = resolve)); - await old_lock; - return releaseLock; - } - return acquireLock; -} diff --git a/pyscriptjs/src/version.ts b/pyscriptjs/src/version.ts deleted file mode 100644 index 28ec30db..00000000 --- a/pyscriptjs/src/version.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @fileoverview Version of pyscript - * The version is based on calver which contains YEAR.MONTH.DAY.MODIFIER. - * The Modifier can be an optional text tag, such as "dev", "rc", etc. - * - * We are adding this file because we can't add version in main.js due to - * circular imports. - */ - -export const version = '2022.12.1.dev'; diff --git a/pyscriptjs/tests/py-unit/__init__.py b/pyscriptjs/tests/py-unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyscriptjs/tests/py-unit/_pyscript_js.py b/pyscriptjs/tests/py-unit/_pyscript_js.py deleted file mode 100644 index 41f4927c..00000000 --- a/pyscriptjs/tests/py-unit/_pyscript_js.py +++ /dev/null @@ -1,10 +0,0 @@ -from unittest.mock import Mock - -import js - -showWarning = Mock() -define_custom_element = Mock() - - -def deepQuerySelector(selector): - return js.document.querySelector(selector) diff --git a/pyscriptjs/tests/py-unit/conftest.py b/pyscriptjs/tests/py-unit/conftest.py deleted file mode 100644 index 464d883a..00000000 --- a/pyscriptjs/tests/py-unit/conftest.py +++ /dev/null @@ -1,29 +0,0 @@ -"""All data required for testing examples""" -import sys -from pathlib import Path - -import pytest - -pyscriptjs = Path(__file__).parents[2] - -# add pyscript folder to path -python_source = pyscriptjs / "src" / "python" -sys.path.append(str(python_source)) - -# add Python plugins folder to path -python_plugins_source = pyscriptjs / "src" / "plugins" / "python" -sys.path.append(str(python_plugins_source)) - - -# patch pyscript module where needed -import pyscript_plugins_tester as ppt # noqa: E402 -from pyscript import _plugin # noqa: E402 - -_plugin.define_custom_element = ppt.define_custom_element - - -@pytest.fixture() -def plugins_manager(): - """return a new instance of a Test version the PyScript application plugins manager""" - yield ppt.plugins_manager # PluginsManager() - ppt.plugins_manager.reset() diff --git a/pyscriptjs/tests/py-unit/js.py b/pyscriptjs/tests/py-unit/js.py deleted file mode 100644 index f1e4cd82..00000000 --- a/pyscriptjs/tests/py-unit/js.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Mock module that emulates some of the pyodide js module features for the sake of tests""" -from unittest.mock import Mock - -document = Mock() -console = Mock() -setTimeout = Mock() -Object = Mock() diff --git a/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py b/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py deleted file mode 100644 index 288347fa..00000000 --- a/pyscriptjs/tests/py-unit/pyscript_plugins_tester.py +++ /dev/null @@ -1,120 +0,0 @@ -import xml.dom -from xml.dom.minidom import Node # nosec - -import js -import pyscript - - -class classList: - """Class that (lightly) emulates the behaviour of HTML Nodes ClassList""" - - def __init__(self): - self._classes = [] - - def add(self, classname: str): - """Add classname to the classList""" - self._classes.append(classname) - - def remove(self, classname: str): - """Remove classname from the classList""" - self._classes.remove(classname) - - -class PluginsManager: - """ - Emulator of PyScript PluginsManager that can be used to simulate plugins lifecycle events - - TODO: Currently missing most of the lifecycle events in PluginsManager implementation. Need - to add more than just addPythonPlugin - """ - - def __init__(self): - self.plugins = [] - - # mapping containing all the custom elements createed by plugins - self._custom_elements = {} - - def addPythonPlugin(self, pluginInstance: pyscript.Plugin): - """ - Add a pluginInstance to the plugins managed by the PluginManager and calls - pluginInstance.init(self) to initialized the plugin with the manager - """ - pluginInstance.init(self) - self.plugins.append(pluginInstance) - - def reset(self): - """ - Unregister all plugins and related custom elements. - """ - for plugin in self.plugins: - plugin.app = None - - self.plugins = [] - self._custom_elements = {} - - -class CustomElement: - def __init__(self, plugin_class: pyscript.Plugin): - self.pyPluginInstance = plugin_class(self) - self.attributes = {} - self.innerHTML = "" - - def connectedCallback(self): - return self.pyPluginInstance.connect() - - def getAttribute(self, attr: str): - return self.attributes.get(attr) - - -def define_custom_element(tag, plugin_class: pyscript.Plugin): - """ - Mock method to emulate the behaviour of the PyScript `define_custom_element` - that basically creates a new CustomElement passing plugin_class as Python - proxy object. For more info check out the logic of the original implementation at: - - src/plugin.ts:define_custom_element - """ - ce = CustomElement(plugin_class) - plugins_manager._custom_elements[tag] = ce - - -plugins_manager = PluginsManager() - -# Init pyscript testing mocks -impl = xml.dom.getDOMImplementation() - - -class Node: - """ - Represent an HTML Node. - - This classes us an abstraction on top of xml.dom.minidom.Node - """ - - def __init__(self, el: Node): - self._el = el - self.classList = classList() - - # Automatic delegation is a simple and short boilerplate: - def __getattr__(self, attr: str): - return getattr(self._el, attr) - - def createElement(self, *args, **kws): - newEl = self._el.createElement(*args, **kws) - return Node(newEl) - - -class Document(Node): - """ - Represent an HTML Document. - - This classes us an abstraction on top of xml.dom.minidom.Document - """ - - def __init__(self): - self._el = impl.createDocument(None, "document", None) - - -js.document = doc = Document() -js.document.head = doc.createElement("head") -js.document.body = doc.createElement("body") diff --git a/pyscriptjs/tests/py-unit/test_pyscript.py b/pyscriptjs/tests/py-unit/test_pyscript.py deleted file mode 100644 index 532b0efa..00000000 --- a/pyscriptjs/tests/py-unit/test_pyscript.py +++ /dev/null @@ -1,207 +0,0 @@ -import sys -import textwrap -from unittest.mock import Mock - -import js -import pyscript -from pyscript import HTML, Element -from pyscript._deprecated_globals import DeprecatedGlobal -from pyscript._internal import set_version_info, uses_top_level_await -from pyscript._mime import format_mime - - -class TestElement: - def test_id_is_correct(self): - el = Element("something") - assert el.id == "something" - - def test_element(self, monkeypatch): - el = Element("something") - document = Mock() - call_result = "some_result" - document.querySelector = Mock(return_value=call_result) - monkeypatch.setattr(js, "document", document) - assert not el._element - real_element = el.element - assert real_element - assert document.querySelector.call_count == 1 - document.querySelector.assert_called_with("#something") - assert real_element == call_result - - -def test_format_mime_str(): - obj = "just a string" - out, mime = format_mime(obj) - assert out == obj - assert mime == "text/plain" - - -def test_format_mime_str_escaping(): - obj = "

hello

" - out, mime = format_mime(obj) - assert out == "<p>hello</p>" - assert mime == "text/plain" - - -def test_format_mime_repr_escaping(): - out, mime = format_mime(sys) - assert out == "<module 'sys' (built-in)>" - assert mime == "text/plain" - - -def test_format_mime_HTML(): - obj = HTML("

hello

") - out, mime = format_mime(obj) - assert out == "

hello

" - assert mime == "text/html" - - -def test_uses_top_level_await(): - # Basic Case - src = "x = 1" - assert uses_top_level_await(src) is False - - # Comments are not top-level await - src = textwrap.dedent( - """ - #await async for async with asyncio - """ - ) - - assert uses_top_level_await(src) is False - - # Top-level-await cases - src = textwrap.dedent( - """ - async def foo(): - pass - await foo - """ - ) - assert uses_top_level_await(src) is True - - src = textwrap.dedent( - """ - async with object(): - pass - """ - ) - assert uses_top_level_await(src) is True - - src = textwrap.dedent( - """ - async for _ in range(10): - pass - """ - ) - assert uses_top_level_await(src) is True - - # Acceptable await/async for/async with cases - src = textwrap.dedent( - """ - async def foo(): - await foo() - """ - ) - assert uses_top_level_await(src) is False - - src = textwrap.dedent( - """ - async def foo(): - async with object(): - pass - """ - ) - assert uses_top_level_await(src) is False - - src = textwrap.dedent( - """ - async def foo(): - async for _ in range(10): - pass - """ - ) - assert uses_top_level_await(src) is False - - -def test_set_version_info(): - version_string = "1234.56.78.ABCD" - set_version_info(version_string) - assert pyscript.__version__ == version_string - assert pyscript.version_info == (1234, 56, 78, "ABCD") - - -class MyDeprecatedGlobal(DeprecatedGlobal): - """ - A subclass of DeprecatedGlobal, for tests. - - Instead of showing warnings into the DOM (which we don't have inside unit - tests), we record the warnings into a field. - """ - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.warnings = [] - - def _show_warning(self, message): - self.warnings.append(message) - - -class TestDeprecatedGlobal: - def test_repr(self): - glob = MyDeprecatedGlobal("foo", None, "my message") - assert repr(glob) == "" - - def test_show_warning_override(self): - """ - Test that our overriding of _show_warning actually works. - """ - glob = MyDeprecatedGlobal("foo", None, "my message") - glob._show_warning("foo") - glob._show_warning("bar") - assert glob.warnings == ["foo", "bar"] - - def test_getattr(self): - class MyFakeObject: - name = "FooBar" - - glob = MyDeprecatedGlobal("MyFakeObject", MyFakeObject, "this is my warning") - assert glob.name == "FooBar" - assert glob.warnings == ["this is my warning"] - - def test_dont_show_warning_twice(self): - class MyFakeObject: - name = "foo" - surname = "bar" - - glob = MyDeprecatedGlobal("MyFakeObject", MyFakeObject, "this is my warning") - assert glob.name == "foo" - assert glob.surname == "bar" - assert len(glob.warnings) == 1 - - def test_call(self): - def foo(x, y): - return x + y - - glob = MyDeprecatedGlobal("foo", foo, "this is my warning") - assert glob(1, y=2) == 3 - assert glob.warnings == ["this is my warning"] - - def test_iter(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - assert list(glob) == ["a", "b", "c"] - assert glob.warnings == ["this is my warning"] - - def test_getitem(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - assert glob["a"] == 1 - assert glob.warnings == ["this is my warning"] - - def test_setitem(self): - d = {"a": 1, "b": 2, "c": 3} - glob = MyDeprecatedGlobal("d", d, "this is my warning") - glob["a"] = 100 - assert glob.warnings == ["this is my warning"] - assert glob["a"] == 100 diff --git a/pyscriptjs/tests/py-unit/test_python_plugins.py b/pyscriptjs/tests/py-unit/test_python_plugins.py deleted file mode 100644 index d60707ab..00000000 --- a/pyscriptjs/tests/py-unit/test_python_plugins.py +++ /dev/null @@ -1,171 +0,0 @@ -import html -from unittest.mock import Mock - -import js -import py_markdown -import py_tutor -import pyscript_plugins_tester as ppt - -TUTOR_SOURCE = """ - - packages = [ - "folium", - "pandas" - ] - plugins = [ - "../build/plugins/python/py_tutor.py" - ] - - - -import folium -import json -import pandas as pd - -from pyodide.http import open_url - -# the rest of the code goes one - -""" - - -class TestPyMarkdown: - def test_plugin_hooks(self, monkeypatch): - console_mock = Mock() - monkeypatch.setattr(py_markdown, "console", console_mock) - config = "just a config" - interpreter = "just an interpreter" - - py_markdown.plugin.configure(config) - console_mock.log.assert_called_with("configuration received: just a config") - - py_markdown.plugin.afterStartup(interpreter) - console_mock.log.assert_called_with( - "interpreter received:", "just an interpreter" - ) - - -class TestPyTutor: - def check_prism_added(self): - """ - Assert that the add_prism method has been correctly executed and the - related prism assets have been added to the page head - """ - # GIVEN a previous call to py_tutor.plugin.append_script_to_page - head = js.document.head - - # EXPECT the head to contain a link element pointing to the prism.min.css - links = head.getElementsByTagName("link") - assert len(links) == 1 - link = links[0] - assert link.type == "text/css" - assert link.rel == "stylesheet" - assert link.href == "./assets/prism/prism.min.css" - - # EXPECT the head to contain a script src == prism.min.js - scripts = head.getElementsByTagName("script") - assert len(scripts) == 1 - script = scripts[0] - assert script.type == "text/javascript" - assert script.src == "./assets/prism/prism.min.js" - - def check_append_script_to_page(self): - """ - Assert that the append_script_to_page has been correctly executed and the - py_tutor.PAGE_SCRIPT code needed for the plugin JS animation has been added - to the page body - """ - # GIVEN a previous call to py_tutor.plugin.append_script_to_page - body = js.document.body - - # EXPECT the body of the page to contain a script of type text/javascript - # and that contains the py_tutor.PAGE_SCRIPT script - scripts = body.getElementsByTagName("script") - assert len(scripts) == 1 - script = scripts[0] - assert script.type == "text/javascript" - - # Check the actual JS script code - # To do so we have 2 methods (it depends on browser support so we check either...) - if script.childNodes: - # in this case it means the content has been added as a child element - node = script.childNodes[0] - assert node.data == py_tutor.PAGE_SCRIPT - else: - assert script.text == py_tutor.PAGE_SCRIPT - - def check_create_code_section(self): - """ - Assert that the create_code_section has been correctly executed and the - related code section has been created and added to the page. - """ - # GIVEN a previous call to py_tutor.plugin.check_create_code_section - console = py_tutor.js.console - - # EXPECT the console to have the messages printed by the plugin while - # executing the plugin operations - console.info.assert_any_call("Creating code introspection section.") - console.info.assert_any_call("Creating new code section element.") - - # EXPECT the page body to contain a section with the input source code - body = js.document.body - sections = body.getElementsByTagName("section") - section = sections[0] - assert "code" in section.classList._classes - section_innerHTML = py_tutor.TEMPLATE_CODE_SECTION.format( - source=html.escape(TUTOR_SOURCE), modules_section="" - ) - assert html.escape(TUTOR_SOURCE) in section.innerHTML - assert section.innerHTML == section_innerHTML - - def test_connected_calls(self, plugins_manager: ppt.PluginsManager): - """ - Test that all parts of the plugin have been added to the page body and head - properly. This test effectively calls `self.check_prism_added`, - `self.check_append_script_to_page` and `check_create_code_section` assert - the new nodes have been added properly. - """ - # GIVEN THAT we add the plugin to the app plugin manager - # this will: - # - init the plugin instance passing the plugins_manager as parent app - # - add the plugin instance to plugins_manager.plugins - assert not py_tutor.plugin.app - plugins_manager.addPythonPlugin(py_tutor.plugin) - - # EXPECT: the plugin app to now be the plugin manager - assert py_tutor.plugin.app == plugins_manager - tutor_ce = plugins_manager._custom_elements["py-tutor"] - # tutor_ce_python_instance = tutor_ce.pyPluginInstance - # GIVEN: The following innerHTML on the ce elements - tutor_ce.innerHTML = TUTOR_SOURCE - - # GIVEN: the CustomElement connectedCallback gets called - tutor_ce.connectedCallback() - - # EXPECT: the - self.check_prism_added() - - self.check_append_script_to_page() - - self.check_create_code_section() - - def test_plugin_registered(self, plugins_manager: ppt.PluginsManager): - """ - Test that, when registered, plugin actually has an app attribute set - and that it's present in plugins manager plugins list. - """ - # EXPECT py_tutor.plugin to not have any app associate - assert not py_tutor.plugin.app - - # EXPECT: the plugin manager to not have any plugin registered - assert not plugins_manager.plugins - - # GIVEN THAT we add the plugin to the app plugin manager - plugins_manager.addPythonPlugin(py_tutor.plugin) - - # EXPECT: the plugin app to now be the plugin manager - assert py_tutor.plugin.app == plugins_manager - assert "py-tutor" in py_tutor.plugin._custom_elements - - # EXPECT: the pytutor.plugin manager to be part of - assert py_tutor.plugin in plugins_manager.plugins diff --git a/pyscriptjs/tests/unit/calculateFetchPaths.test.ts b/pyscriptjs/tests/unit/calculateFetchPaths.test.ts deleted file mode 100644 index 31a4d8d7..00000000 --- a/pyscriptjs/tests/unit/calculateFetchPaths.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { calculateFetchPaths } from '../../src/plugins/calculateFetchPaths'; -import { FetchConfig } from '../../src/pyconfig'; - -describe('CalculateFetchPaths', () => { - it('should calculate paths when only from is provided', () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://a.com/data.csv' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([{ url: 'http://a.com/data.csv', path: 'data.csv' }]); - }); - - it('should calculate paths when only files is provided', () => { - const fetch_cfg: FetchConfig[] = [{ files: ['foo/__init__.py', 'foo/mod.py', 'foo2/mod.py'] }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'foo/__init__.py', path: 'foo/__init__.py' }, - { url: 'foo/mod.py', path: 'foo/mod.py' }, - { url: 'foo2/mod.py', path: 'foo2/mod.py' }, - ]); - }); - - it('should calculate paths when files and to_folder is provided', () => { - const fetch_cfg: FetchConfig[] = [{ files: ['foo/__init__.py', 'foo/mod.py'], to_folder: '/my/lib/' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'foo/__init__.py', path: '/my/lib/foo/__init__.py' }, - { url: 'foo/mod.py', path: '/my/lib/foo/mod.py' }, - ]); - }); - - it('should calculate paths when from and files and to_folder is provided', () => { - const fetch_cfg: FetchConfig[] = [ - { from: 'http://a.com/download/', files: ['foo/__init__.py', 'foo/mod.py'], to_folder: '/my/lib/' }, - ]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([ - { url: 'http://a.com/download/foo/__init__.py', path: '/my/lib/foo/__init__.py' }, - { url: 'http://a.com/download/foo/mod.py', path: '/my/lib/foo/mod.py' }, - ]); - }); - - it("should error out while calculating paths when filename cannot be determined from 'from'", () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://google.com/', to_folder: '/tmp' }]; - expect(() => calculateFetchPaths(fetch_cfg)).toThrowError( - "Couldn't determine the filename from the path http://google.com/", - ); - }); - - it('should calculate paths when to_file is explicitly supplied', () => { - const fetch_cfg: FetchConfig[] = [{ from: 'http://a.com/data.csv?version=1', to_file: 'pkg/tmp/data.csv' }]; - const res = calculateFetchPaths(fetch_cfg); - expect(res).toStrictEqual([{ path: 'pkg/tmp/data.csv', url: 'http://a.com/data.csv?version=1' }]); - }); - - it('should error out when both to_file and files parameters are provided', () => { - const fetch_cfg: FetchConfig[] = [ - { from: 'http://a.com/data.csv?version=1', to_file: 'pkg/tmp/data.csv', files: ['a.py', 'b.py'] }, - ]; - expect(() => calculateFetchPaths(fetch_cfg)).toThrowError( - "Cannot use 'to_file' and 'files' parameters together!", - ); - }); -}); diff --git a/pyscriptjs/tests/unit/exceptions.test.ts b/pyscriptjs/tests/unit/exceptions.test.ts deleted file mode 100644 index fc276e4f..00000000 --- a/pyscriptjs/tests/unit/exceptions.test.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { expect, it, jest, describe, afterEach } from '@jest/globals'; -import { _createAlertBanner, UserError, FetchError, ErrorCode } from '../../src/exceptions'; - -describe('Test _createAlertBanner', () => { - afterEach(() => { - // Ensure we always have a clean body - document.body.innerHTML = `
Hello World
`; - }); - - it("error level shouldn't contain close button", async () => { - _createAlertBanner('Something went wrong!', 'error'); - - const banner = document.getElementsByClassName('alert-banner'); - const closeButton = document.getElementById('alert-close-button'); - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe('Something went wrong!'); - expect(closeButton).toBeNull(); - }); - - it('warning level should contain close button', async () => { - _createAlertBanner('This is a warning', 'warning'); - - const banner = document.getElementsByClassName('alert-banner'); - const closeButton = document.getElementById('alert-close-button'); - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toContain('This is a warning'); - expect(closeButton).not.toBeNull(); - }); - - it('error level banner should log to console', async () => { - const logSpy = jest.spyOn(console, 'error'); - - _createAlertBanner('Something went wrong!'); - - expect(logSpy).toHaveBeenCalledWith('Something went wrong!'); - }); - - it('warning level banner should log to console', async () => { - const logSpy = jest.spyOn(console, 'warn'); - - _createAlertBanner('This warning', 'warning'); - - expect(logSpy).toHaveBeenCalledWith('This warning'); - }); - - it('close button should remove element from page', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - _createAlertBanner('Warning!', 'warning'); - - // Just a sanity check - banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(1); - - const closeButton = document.getElementById('alert-close-button'); - if (closeButton) { - closeButton.click(); - // Confirm that clicking the close button, removes the element - banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - } else { - fail('Unable to find close button on the page, but should exist'); - } - }); - - it("toggling logging off on error alert shouldn't log to console", async () => { - const errorLogSpy = jest.spyOn(console, 'error'); - - _createAlertBanner('Test error', 'error', 'text', false); - expect(errorLogSpy).not.toHaveBeenCalledWith('Test error'); - }); - - it("toggling logging off on warning alert shouldn't log to console", async () => { - const warnLogSpy = jest.spyOn(console, 'warn'); - _createAlertBanner('Test warning', 'warning', 'text', false); - expect(warnLogSpy).not.toHaveBeenCalledWith('Test warning'); - }); - - it('_createAlertbanner messageType text writes message to content', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - const message = '

Test message

'; - _createAlertBanner(message, 'error', 'text'); - banner = document.getElementsByClassName('alert-banner'); - - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe('<p>Test message</p>'); - expect(banner[0].textContent).toBe(message); - }); - - it('_createAlertbanner messageType html writes message to innerHTML', async () => { - let banner = document.getElementsByClassName('alert-banner'); - expect(banner.length).toBe(0); - - const message = '

Test message

'; - _createAlertBanner(message, 'error', 'html'); - banner = document.getElementsByClassName('alert-banner'); - - expect(banner.length).toBe(1); - expect(banner[0].innerHTML).toBe(message); - expect(banner[0].textContent).toBe('Test message'); - }); -}); - -describe('Test Exceptions', () => { - it('UserError contains errorCode and shows in message', async () => { - const errorCode = ErrorCode.BAD_CONFIG; - const message = 'Test error'; - const userError = new UserError(ErrorCode.BAD_CONFIG, message); - expect(userError.errorCode).toBe(errorCode); - expect(userError.message).toBe(`(${errorCode}): ${message}`); - }); - - it('FetchError contains errorCode and shows in message', async () => { - const errorCode = ErrorCode.FETCH_NOT_FOUND_ERROR; - const message = 'Test error'; - const fetchError = new FetchError(errorCode, message); - expect(fetchError.errorCode).toBe(errorCode); - expect(fetchError.message).toBe(`(${errorCode}): ${message}`); - }); -}); diff --git a/pyscriptjs/tests/unit/fetch.test.ts b/pyscriptjs/tests/unit/fetch.test.ts deleted file mode 100644 index 21bb7604..00000000 --- a/pyscriptjs/tests/unit/fetch.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { describe, it, expect, jest } from '@jest/globals'; -import { FetchError, ErrorCode } from '../../src/exceptions'; -import { robustFetch } from '../../src/fetch'; -import { Response } from 'node-fetch'; - -describe('robustFetch', () => { - it('should return a response object', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response((status = '200'), 'Hello World'))); - - const response = await robustFetch('https://pyscript.net'); - expect(response).toBeInstanceOf(Response); - expect(response.status).toBe(200); - }); - - it('receiving a 404 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 404 }))); - - const url = 'https://pyscript.net/non-existent-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_NOT_FOUND_ERROR, - `Fetching from URL ${url} failed with error 404 (Not Found). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 401 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('', { status: 401 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_UNAUTHORIZED_ERROR, - `Fetching from URL ${url} failed with error 401 (Unauthorized). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 403 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('', { status: 403 }))); - - const url = 'https://pyscript.net/secret-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_FORBIDDEN_ERROR, - `Fetching from URL ${url} failed with error 403 (Forbidden). ` + `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 500 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 500 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_SERVER_ERROR, - `Fetching from URL ${url} failed with error 500 (Internal Server Error). ` + - `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('receiving a 503 when fetching should throw FetchError with the right errorCode', async () => { - global.fetch = jest.fn(() => Promise.resolve(new Response('Not Found', { status: 503 }))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_UNAVAILABLE_ERROR, - `Fetching from URL ${url} failed with error 503 (Service Unavailable). ` + - `Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('handle TypeError when using a bad url', async () => { - global.fetch = jest.fn(() => Promise.reject(new TypeError('Failed to fetch'))); - - const url = 'https://pyscript.net/protected-page'; - const expectedError = new FetchError( - ErrorCode.FETCH_ERROR, - `Fetching from URL ${url} failed with error 'Failed to fetch'. Are your filename and path correct?`, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); - - it('handle failed to fetch when using local file', async () => { - global.fetch = jest.fn(() => Promise.reject(new TypeError('Failed to fetch'))); - - const url = './my-awesome-pyscript.py'; - - const expectedError = new FetchError( - ErrorCode.FETCH_ERROR, - `PyScript: Access to local files - (using [[fetch]] configurations in <py-config>) - is not available when directly opening a HTML file; - you must use a webserver to serve the additional files. - See this reference - on starting a simple webserver with Python. - `, - ); - - expect(() => robustFetch(url)).rejects.toThrow(expectedError); - }); -}); diff --git a/pyscriptjs/tests/unit/logger.test.ts b/pyscriptjs/tests/unit/logger.test.ts deleted file mode 100644 index 64132740..00000000 --- a/pyscriptjs/tests/unit/logger.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { jest } from '@jest/globals'; -import { getLogger } from '../../src/logger'; - -describe('getLogger', () => { - it('getLogger caches results', () => { - let a1 = getLogger('a'); - let b = getLogger('b'); - let a2 = getLogger('a'); - - expect(a1).not.toBe(b); - expect(a1).toBe(a2); - }); - - it('logger.info prints to console.info', () => { - console.info = jest.fn(); - - const logger = getLogger('prefix1'); - logger.info('hello world'); - expect(console.info).toHaveBeenCalledWith('[prefix1] hello world'); - }); - - it('logger.info handles multiple args', () => { - console.info = jest.fn(); - - const logger = getLogger('prefix2'); - logger.info('hello', 'world', 1, 2, 3); - expect(console.info).toHaveBeenCalledWith('[prefix2] hello', 'world', 1, 2, 3); - }); - - it('logger.{debug,warn,error} also works', () => { - console.info = jest.fn(); - console.debug = jest.fn(); - console.warn = jest.fn(); - console.error = jest.fn(); - - const logger = getLogger('prefix3'); - logger.debug('this is a debug'); - logger.warn('this is a warning'); - logger.error('this is an error'); - - expect(console.info).not.toHaveBeenCalled(); - expect(console.debug).toHaveBeenCalledWith('[prefix3] this is a debug'); - expect(console.warn).toHaveBeenCalledWith('[prefix3] this is a warning'); - expect(console.error).toHaveBeenCalledWith('[prefix3] this is an error'); - }); -}); diff --git a/pyscriptjs/tests/unit/main.test.ts b/pyscriptjs/tests/unit/main.test.ts deleted file mode 100644 index 2fa9c829..00000000 --- a/pyscriptjs/tests/unit/main.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { describe, it, beforeEach, expect } from '@jest/globals'; -import { UserError, ErrorCode } from '../../src/exceptions'; -import { PyScriptApp } from '../../src/main'; - -describe('Test withUserErrorHandler', () => { - class MyApp extends PyScriptApp { - myRealMain: any; - - constructor(myRealMain) { - super(); - this.myRealMain = myRealMain; - } - - async _realMain() { - this.myRealMain(); - } - } - - beforeEach(() => { - // Ensure we always have a clean body - document.body.innerHTML = `
Hello World
`; - }); - - it("userError doesn't stop execution", async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'Computer says no'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): Computer says no'); - }); - - it('userError escapes by default', async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'hello
'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): hello <br>'); - }); - - it("userError messageType=html don't escape", async () => { - function myRealMain() { - throw new UserError(ErrorCode.GENERIC, 'hello
', 'html'); - } - - const app = new MyApp(myRealMain); - await app.main(); - const banners = document.getElementsByClassName('alert-banner'); - expect(banners.length).toBe(1); - expect(banners[0].innerHTML).toBe('(PY0000): hello
'); - }); - - it('any other exception should stop execution and raise', async () => { - function myRealMain() { - throw new Error('Explosions!'); - } - - const app = new MyApp(myRealMain); - expect(app.main()).rejects.toThrow(new Error('Explosions!')); - }); -}); diff --git a/pyscriptjs/tests/unit/plugin.test.ts b/pyscriptjs/tests/unit/plugin.test.ts deleted file mode 100644 index b349e0ad..00000000 --- a/pyscriptjs/tests/unit/plugin.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { validateConfigParameter, validateConfigParameterFromArray } from '../../src/plugin'; -import { UserError } from '../../src/exceptions'; - -describe('validateConfigParameter', () => { - const validator = a => a.charAt(0) === 'a'; - - it('should not change a matching config option', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(pyconfig).toStrictEqual({ a: 'a1', dummy: 'dummy' }); - }); - - it('should set the default value if no value is present', () => { - const pyconfig = { dummy: 'dummy' }; - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(pyconfig).toStrictEqual({ a: 'a_default', dummy: 'dummy' }); - }); - - it('should error if the provided value is not valid', () => { - const pyconfig = { a: 'NotValidValue', dummy: 'dummy' }; - const func = () => - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'a_default', - hintMessage: "Should start with 'a'", - }); - expect(func).toThrow(UserError); - expect(func).toThrow('(PY1000): Invalid value "NotValidValue" for config.a. Should start with \'a\''); - }); - - it('should error if the provided default is not valid', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - const func = () => - validateConfigParameter({ - config: pyconfig, - name: 'a', - validator: validator, - defaultValue: 'NotValidDefault', - hintMessage: "Should start with 'a'", - }); - expect(func).toThrow(Error); - expect(func).toThrow( - 'Default value "NotValidDefault" for a is not a valid argument, according to the provided validator function. Should start with \'a\'', - ); - }); -}); - -describe('validateConfigParameterFromArray', () => { - const possibilities = ['a1', 'a2', true, 42, 'a_default']; - - it('should not change a matching config option', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(pyconfig).toStrictEqual({ a: 'a1', dummy: 'dummy' }); - }); - - it('should set the default value if no value is present', () => { - const pyconfig = { dummy: 'dummy' }; - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(pyconfig).toStrictEqual({ a: 'a_default', dummy: 'dummy' }); - }); - - it('should error if the provided value is not in possible_values', () => { - const pyconfig = { a: 'NotValidValue', dummy: 'dummy' }; - const func = () => - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'a_default', - }); - expect(func).toThrow(Error); - expect(func).toThrow( - '(PY1000): Invalid value "NotValidValue" for config.a. The only accepted values are: ["a1", "a2", true, 42, "a_default"]', - ); - }); - - it('should error if the provided default is not in possible_values', () => { - const pyconfig = { a: 'a1', dummy: 'dummy' }; - const func = () => - validateConfigParameterFromArray({ - config: pyconfig, - name: 'a', - possibleValues: possibilities, - defaultValue: 'NotValidDefault', - }); - expect(func).toThrow(Error); - expect(func).toThrow( - 'Default value "NotValidDefault" for a is not a valid argument, according to the provided validator function. The only accepted values are: ["a1", "a2", true, 42, "a_default"]', - ); - }); -}); diff --git a/pyscriptjs/tests/unit/pyconfig.test.ts b/pyscriptjs/tests/unit/pyconfig.test.ts deleted file mode 100644 index 78e29660..00000000 --- a/pyscriptjs/tests/unit/pyconfig.test.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { jest, describe, it, expect } from '@jest/globals'; -import { loadConfigFromElement, defaultConfig } from '../../src/pyconfig'; -import { version } from '../../src/version'; -import { UserError } from '../../src/exceptions'; - -// inspired by trump typos -const covfefeConfig = { - name: 'covfefe', - interpreters: [ - { - src: '/demo/covfefe.js', - name: 'covfefe', - lang: 'covfefe', - }, - ], - wonderful: 'disgrace', -}; - -const covfefeConfigToml = ` -name = "covfefe" - -wonderful = "hijacked" - -[[interpreters]] -src = "/demo/covfefe.js" -name = "covfefe" -lang = "covfefe" -`; - -// ideally, I would like to be able to just do "new HTMLElement" in the tests -// below, but it is not permitted. The easiest work around is to create a fake -// custom element: not that we are not using any specific feature of custom -// elements: the sole purpose to FakeElement is to be able to instantiate them -// in the tests. -class FakeElement extends HTMLElement { - constructor() { - super(); - } -} -customElements.define('fake-element', FakeElement); - -function make_config_element(attrs) { - const el = new FakeElement(); - for (const [key, value] of Object.entries(attrs)) { - el.setAttribute(key, value as string); - } - return el; -} - -describe('loadConfigFromElement', () => { - const xhrMockClass = () => ({ - open: jest.fn(), - send: jest.fn(), - responseText: JSON.stringify(covfefeConfig), - }); - // @ts-ignore - window.XMLHttpRequest = jest.fn().mockImplementation(xhrMockClass); - - it('should load the default config', () => { - const config = loadConfigFromElement(null); - expect(config).toBe(defaultConfig); - expect(config.pyscript.version).toBe(version); - }); - - it('an empty should load the default config', () => { - const el = make_config_element({}); - let config = loadConfigFromElement(el); - expect(config).toBe(defaultConfig); - expect(config.pyscript.version).toBe(version); - }); - - it('should load the JSON config from inline', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = JSON.stringify(covfefeConfig); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // schema_version wasn't present in `inline config` but is still set due to merging with default - expect(config.schema_version).toBe(1); - }); - - it('should load the JSON config from src attribute', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // wonderful is an extra key supplied by the user and is unaffected by merging process - expect(config.wonderful).toBe('disgrace'); - // schema_version wasn't present in `config from src` but is still set due to merging with default - expect(config.schema_version).toBe(1); - }); - - it('should load the JSON config from both inline and src', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - el.innerHTML = JSON.stringify({ version: '0.2a', wonderful: 'hijacked' }); - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // config from src had an extra key "wonderful" with value "disgrace" - // inline config had the same extra key "wonderful" with value "hijacked" - // the merge process works for extra keys that clash as well - // so the final value is "hijacked" since inline takes precedence over src - expect(config.wonderful).toBe('hijacked'); - // version wasn't present in `config from src` but is still set due to merging with default and inline - expect(config.version).toBe('0.2a'); - }); - - it('should be able to load an inline TOML config', () => { - // TOML is the default type - const el = make_config_element({}); - el.innerHTML = covfefeConfigToml; - const config = loadConfigFromElement(el); - expect(config.interpreters[0].lang).toBe('covfefe'); - expect(config.pyscript?.time).not.toBeNull(); - // schema_version wasn't present in `inline config` but is still set due to merging with default - expect(config.schema_version).toBe(1); - expect(config.wonderful).toBe('hijacked'); - }); - - it('should NOT be able to load an inline config in JSON format with type as TOML', () => { - const el = make_config_element({}); - el.innerHTML = JSON.stringify(covfefeConfig); - expect(() => loadConfigFromElement(el)).toThrow( - /config supplied: {.*} is an invalid TOML and cannot be parsed/, - ); - }); - - it('should NOT be able to load an inline config in TOML format with type as JSON', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should NOT be able to load an inline TOML config with a JSON config from src with type as toml', () => { - const el = make_config_element({ src: '/covfefe.json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow( - /config supplied: {.*} is an invalid TOML and cannot be parsed/, - ); - }); - - it('should NOT be able to load an inline TOML config with a JSON config from src with type as json', () => { - const el = make_config_element({ type: 'json', src: '/covfefe.json' }); - el.innerHTML = covfefeConfigToml; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should error out when passing an invalid JSON', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = '[['; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should error out when passing an invalid TOML', () => { - const el = make_config_element({}); - el.innerHTML = '[['; - expect(() => loadConfigFromElement(el)).toThrow(UserError); - }); - - it('should not escape characters like &', () => { - const el = make_config_element({ type: 'json' }); - el.innerHTML = JSON.stringify({ - fetch: [{ from: 'https://datausa.io/api/data?drilldowns=Nation&measures=Population' }], - }); - const config = loadConfigFromElement(el); - expect(config.fetch[0].from).toBe('https://datausa.io/api/data?drilldowns=Nation&measures=Population'); - }); -}); diff --git a/pyscriptjs/tests/unit/pyodide.test.ts b/pyscriptjs/tests/unit/pyodide.test.ts deleted file mode 100644 index 2b382ae7..00000000 --- a/pyscriptjs/tests/unit/pyodide.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { AppConfig } from '../../src/pyconfig'; -import { InterpreterClient } from '../../src/interpreter_client'; -import { CaptureStdio } from '../../src/stdio'; -import * as Synclink from 'synclink'; -import { describe, beforeAll, afterAll, it, expect } from '@jest/globals'; -// We can't import RemoteInterpreter at top level because we need to mock the -// Python package in setup.ts -// But we can import the types at top level. -// TODO: is there a better way to handle this? -import type { RemoteInterpreter } from '../../src/remote_interpreter'; - -describe('RemoteInterpreter', () => { - let interpreter: InterpreterClient; - let stdio: CaptureStdio = new CaptureStdio(); - let RemoteInterpreter; - const { port1, port2 } = new Synclink.FakeMessageChannel() as unknown as MessageChannel; - beforeAll(async () => { - const SRC = '../pyscriptjs/node_modules/pyodide/pyodide.js'; - const config: AppConfig = { interpreters: [{ src: SRC }], packages: [] }; - // Dynamic import of RemoteInterpreter sees our mocked Python package. - ({ RemoteInterpreter } = await import('../../src/remote_interpreter')); - const remote_interpreter = new RemoteInterpreter(SRC); - - port1.start(); - port2.start(); - Synclink.expose(remote_interpreter, port2); - const wrapped_remote_interpreter = Synclink.wrap(port1); - interpreter = new InterpreterClient( - config, - stdio, - wrapped_remote_interpreter as Synclink.Remote, - ); - - /** - * Since import { loadPyodide } from 'pyodide'; - * is not used inside `src/pyodide.ts`, the function - * `interpreter.loadInterpreter();` below which calls - * `loadPyodide()` results in an expected issue of: - * ReferenceError: loadPyodide is not defined - * - * To make jest happy, while also not importing - * explicitly inside `src/pyodide.ts`, the - * following lines - so as to dynamically import - * and make it available in the global namespace - * - are used. - * - * Pyodide uses a "really hacky" method to get the - * URL/Path where packages/package data are stored; - * it throws an error, catches it, and parses it. In - * Jest, this calculated path is different than in - * the browser/Node, so files cannot be found and the - * test fails. We set indexURL below the correct location - * to fix this. - * See https://github.com/pyodide/pyodide/blob/7dfee03a82c19069f714a09da386547aeefef242/src/js/pyodide.ts#L161-L179 - */ - const pyodideSpec = await import('pyodide'); - global.loadPyodide = async options => - pyodideSpec.loadPyodide(Object.assign({ indexURL: '../pyscriptjs/node_modules/pyodide/' }, options)); - await interpreter.initializeRemote(); - }); - - afterAll(async () => { - port1.close(); - port2.close(); - }); - - it('should check if interpreter is an instance of abstract Interpreter', async () => { - expect(interpreter).toBeInstanceOf(InterpreterClient); - }); - - it('should check if interpreter can run python code asynchronously', async () => { - expect((await interpreter.run('2+3')).result).toBe(5); - }); - - it('should capture stdout', async () => { - stdio.reset(); - await interpreter.run("print('hello')"); - expect(stdio.captured_stdout).toBe('hello\n'); - }); - - it('should check if interpreter is able to load a package', async () => { - stdio.reset(); - await interpreter._remote.loadPackage('numpy'); - await interpreter.run('import numpy as np'); - await interpreter.run('x = np.ones((10,))'); - await interpreter.run('print(x)'); - expect(stdio.captured_stdout).toBe('[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n'); - }); -}); diff --git a/pyscriptjs/tests/unit/setup.ts b/pyscriptjs/tests/unit/setup.ts deleted file mode 100644 index a2c21c0e..00000000 --- a/pyscriptjs/tests/unit/setup.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { jest } from '@jest/globals'; -import { directoryManifest } from '../../directoryManifest.mjs'; - -jest.unstable_mockModule('../../src/python_package', async () => ({ - python_package: await directoryManifest('./src/python/'), -})); - -globalThis.jest = jest; diff --git a/pyscriptjs/tests/unit/stdio.test.ts b/pyscriptjs/tests/unit/stdio.test.ts deleted file mode 100644 index 56297776..00000000 --- a/pyscriptjs/tests/unit/stdio.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { expect } from '@jest/globals'; -import { type Stdio, CaptureStdio, StdioMultiplexer, TargetedStdio } from '../../src/stdio'; - -describe('CaptureStdio', () => { - it('captured streams are initialized to empty string', () => { - let stdio = new CaptureStdio(); - expect(stdio.captured_stdout).toBe(''); - expect(stdio.captured_stderr).toBe(''); - }); - - it('stdout() and stderr() captures', () => { - let stdio = new CaptureStdio(); - stdio.stdout_writeline('hello'); - stdio.stdout_writeline('world'); - stdio.stderr_writeline('this is an error'); - expect(stdio.captured_stdout).toBe('hello\nworld\n'); - expect(stdio.captured_stderr).toBe('this is an error\n'); - }); - - it('reset() works', () => { - let stdio = new CaptureStdio(); - stdio.stdout_writeline('aaa'); - stdio.stderr_writeline('bbb'); - stdio.reset(); - expect(stdio.captured_stdout).toBe(''); - expect(stdio.captured_stderr).toBe(''); - }); -}); - -describe('StdioMultiplexer', () => { - let a: CaptureStdio; - let b: CaptureStdio; - let multi: StdioMultiplexer; - - beforeEach(() => { - a = new CaptureStdio(); - b = new CaptureStdio(); - multi = new StdioMultiplexer(); - }); - - it('works without listeners', () => { - // no listeners, messages are ignored - multi.stdout_writeline('out 1'); - multi.stderr_writeline('err 1'); - expect(a.captured_stdout).toBe(''); - expect(a.captured_stderr).toBe(''); - expect(b.captured_stdout).toBe(''); - expect(b.captured_stderr).toBe(''); - }); - - it('redirects to multiple listeners', () => { - multi.addListener(a); - multi.stdout_writeline('out 1'); - multi.stderr_writeline('err 1'); - - multi.addListener(b); - multi.stdout_writeline('out 2'); - multi.stderr_writeline('err 2'); - - expect(a.captured_stdout).toBe('out 1\nout 2\n'); - expect(a.captured_stderr).toBe('err 1\nerr 2\n'); - - expect(b.captured_stdout).toBe('out 2\n'); - expect(b.captured_stderr).toBe('err 2\n'); - }); -}); - -describe('TargetedStdio', () => { - let capture: CaptureStdio; - let targeted: TargetedStdio; - let error_targeted: TargetedStdio; - let multi: StdioMultiplexer; - - beforeEach(() => { - //DOM element to capture stdout and stderr - let target_div = document.getElementById('output-id'); - - if (target_div === null) { - target_div = document.createElement('div'); - target_div.id = 'output-id'; - document.body.appendChild(target_div); - } else { - target_div.innerHTML = ''; - } - - //DOM element to capture stderr - let error_div = document.getElementById('error-id'); - - if (error_div === null) { - error_div = document.createElement('div'); - error_div.id = 'error-id'; - document.body.appendChild(error_div); - } else { - error_div.innerHTML = ''; - } - - const tag = document.createElement('div'); - tag.setAttribute('output', 'output-id'); - tag.setAttribute('stderr', 'error-id'); - - capture = new CaptureStdio(); - targeted = new TargetedStdio(tag, 'output', true, true); - error_targeted = new TargetedStdio(tag, 'stderr', false, true); - - multi = new StdioMultiplexer(); - multi.addListener(capture); - multi.addListener(targeted); - multi.addListener(error_targeted); - }); - - it('targeted id is set by constructor', () => { - expect(targeted.source_attribute).toBe('output'); - }); - - it('targeted stdio/stderr also goes to multiplexer', () => { - multi.stdout_writeline('out 1'); - multi.stderr_writeline('out 2'); - expect(capture.captured_stdout).toBe('out 1\n'); - expect(capture.captured_stderr).toBe('out 2\n'); - expect(document.getElementById('output-id')?.innerHTML).toBe('out 1
out 2
'); - expect(document.getElementById('error-id')?.innerHTML).toBe('out 2
'); - }); - - it('Add and remove targeted listener', () => { - multi.stdout_writeline('out 1'); - multi.removeListener(targeted); - multi.stdout_writeline('out 2'); - multi.addListener(targeted); - multi.stdout_writeline('out 3'); - - //all three should be captured by multiplexer - expect(capture.captured_stdout).toBe('out 1\nout 2\nout 3\n'); - //out 2 should not be present in the DOM element - expect(document.getElementById('output-id')?.innerHTML).toBe('out 1
out 3
'); - }); -}); diff --git a/pyscriptjs/tests/unit/utils.test.ts b/pyscriptjs/tests/unit/utils.test.ts deleted file mode 100644 index 848cd8f8..00000000 --- a/pyscriptjs/tests/unit/utils.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { beforeEach, expect, describe, it } from '@jest/globals'; -import { ensureUniqueId, joinPaths, createSingularWarning } from '../../src/utils'; - -describe('Utils', () => { - let element: HTMLElement; - - beforeEach(() => { - element = document.createElement('div'); - }); - - it('ensureUniqueId sets unique id on element', async () => { - expect(element.id).toBe(''); - - ensureUniqueId(element); - - expect(element.id).toBe('py-internal-0'); - }); - - it('ensureUniqueId sets unique id with increasing counter', async () => { - const secondElement = document.createElement('div'); - - expect(element.id).toBe(''); - expect(secondElement.id).toBe(''); - - ensureUniqueId(element); - ensureUniqueId(secondElement); - - // The counter will have been incremented on - // the previous test, make sure it keeps increasing - expect(element.id).toBe('py-internal-1'); - expect(secondElement.id).toBe('py-internal-2'); - }); -}); - -describe('JoinPaths', () => { - it('should remove trailing slashes from the beginning and the end', () => { - const paths: string[] = ['///abc/d/e///']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('/abc/d/e'); - }); - - it('should not remove slashes from the middle to preserve protocols such as http', () => { - const paths: string[] = ['http://google.com', '///data.txt']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('http://google.com/data.txt'); - }); - - it('should not join paths when they are empty strings', () => { - const paths: string[] = ['', '///hhh/ll/pp///', '', 'kkk']; - const joinedPath = joinPaths(paths); - expect(joinedPath).toStrictEqual('hhh/ll/pp/kkk'); - }); - - describe('createSingularBanner', () => { - it('should create one and new banner containing the sentinel text, and not duplicate it', () => { - //One warning banner with the desired text should be created - createSingularWarning('A unique error message', 'unique'); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - - //Should still only be one banner, since the second uses the existing sentinel value "unique" - createSingularWarning('This banner should not appear', 'unique'); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - - //If the sentinel value is not provided, the entire msg is used as the sentinel - createSingularWarning('A unique error message', null); - expect(document.getElementsByClassName('alert-banner')?.length).toEqual(1); - expect(document.getElementsByClassName('alert-banner')[0].textContent).toEqual( - expect.stringContaining('A unique error message'), - ); - }); - }); -}); diff --git a/pyscriptjs/tsconfig.json b/pyscriptjs/tsconfig.json deleted file mode 100644 index d9c7d053..00000000 --- a/pyscriptjs/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/tsconfig", - "_version": "3.0.0", - - "include": ["src/**/*"], - "exclude": ["node_modules/*", "__sapper__/*", "public/*", "src/interpreter_worker/*"], - "compilerOptions": { - "moduleResolution": "node", - "target": "ES2020", - "module": "ES2020", - "types": ["jest", "node"], - "strict": false, - "esModuleInterop": true, - "skipLibCheck": true, - "isolatedModules": true, - "forceConsistentCasingInFileNames": true, - "lib": ["es2017", "dom", "DOM.Iterable"] - } -} From d5b6935c0bc02a0009acae0c2823171d23f6b889 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 5 Oct 2023 13:54:55 +0200 Subject: [PATCH 076/105] Wait for plugins before defining the custom type (#1788) --- pyscript.core/src/config.js | 4 +- pyscript.core/src/core.js | 294 ++++++++++++++++++------------------ 2 files changed, 149 insertions(+), 149 deletions(-) diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js index b4dedabb..553bbed4 100644 --- a/pyscript.core/src/config.js +++ b/pyscript.core/src/config.js @@ -50,7 +50,7 @@ const syntaxError = (type, url, { message }) => { const configs = new Map(); for (const [TYPE] of TYPES) { - /** @type {Promise | undefined} A Promise wrapping any plugins which should be loaded. */ + /** @type {Promise<[...any]>} A Promise wrapping any plugins which should be loaded. */ let plugins; /** @type {any} The PyScript configuration parsed from the JSON or TOML object*. May be any of the return types of JSON.parse() or toml-j0.4's parse() ( {number | string | boolean | null | object | Array} ) */ @@ -119,7 +119,7 @@ for (const [TYPE] of TYPES) { } // assign plugins as Promise.all only if needed - if (toBeAwaited.length) plugins = Promise.all(toBeAwaited); + plugins = Promise.all(toBeAwaited); configs.set(TYPE, { config: parsed, plugins, error }); } diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index a1d5f503..b203cc95 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -128,162 +128,162 @@ for (const [TYPE, interpreter] of TYPES) { // define the module as both ` + + + + + + diff --git a/pyscript.core/test/worker.html b/pyscript.core/test/worker.html index 2cbca689..0258328c 100644 --- a/pyscript.core/test/worker.html +++ b/pyscript.core/test/worker.html @@ -8,8 +8,10 @@ diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index 498248b2..6ae562f2 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -1,4 +1,5 @@ declare const exportedPyWorker: any; declare const exportedHooks: any; declare const exportedConfig: any; -export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config }; +declare const exportedWhenDefined: any; +export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; diff --git a/pyscript.core/types/hooks.d.ts b/pyscript.core/types/hooks.d.ts index de71ecc8..e79ff791 100644 --- a/pyscript.core/types/hooks.d.ts +++ b/pyscript.core/types/hooks.d.ts @@ -1,13 +1,38 @@ -declare namespace _default { - let onInterpreterReady: Set; - let onBeforeRun: Set; - let onBeforeRunAsync: Set; - let onAfterRun: Set; - let onAfterRunAsync: Set; - let onWorkerReady: Set; - let codeBeforeRunWorker: Set; - let codeBeforeRunWorkerAsync: Set; - let codeAfterRunWorker: Set; - let codeAfterRunWorkerAsync: Set; +export function main(name: any): any; +export function worker(name: any): any; +export function codeFor(branch: any): {}; +export function createFunction(self: any, name: any): any; +export namespace hooks { + namespace main { + let onWorker: Set; + let onReady: Set; + let onBeforeRun: Set; + let onBeforeRunAsync: Set; + let onAfterRun: Set; + let onAfterRunAsync: Set; + let codeBeforeRun: Set; + let codeBeforeRunAsync: Set; + let codeAfterRun: Set; + let codeAfterRunAsync: Set; + } + namespace worker { + let onReady_1: Set; + export { onReady_1 as onReady }; + let onBeforeRun_1: Set; + export { onBeforeRun_1 as onBeforeRun }; + let onBeforeRunAsync_1: Set; + export { onBeforeRunAsync_1 as onBeforeRunAsync }; + let onAfterRun_1: Set; + export { onAfterRun_1 as onAfterRun }; + let onAfterRunAsync_1: Set; + export { onAfterRunAsync_1 as onAfterRunAsync }; + let codeBeforeRun_1: Set; + export { codeBeforeRun_1 as codeBeforeRun }; + let codeBeforeRunAsync_1: Set; + export { codeBeforeRunAsync_1 as codeBeforeRunAsync }; + let codeAfterRun_1: Set; + export { codeAfterRun_1 as codeAfterRun }; + let codeAfterRunAsync_1: Set; + export { codeAfterRunAsync_1 as codeAfterRunAsync }; + } } -export default _default; diff --git a/pyscript.core/types/plugins-helper.d.ts b/pyscript.core/types/plugins-helper.d.ts new file mode 100644 index 00000000..7af7edde --- /dev/null +++ b/pyscript.core/types/plugins-helper.d.ts @@ -0,0 +1,2 @@ +declare function _default(main: any, wrap: any, element: any, hook: any): Promise; +export default _default; From cd95a42e5e470dde7e07a75139f3a75629d33b54 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Thu, 26 Oct 2023 19:44:31 +0200 Subject: [PATCH 089/105] Fix #1812 - Avoid duplicated pyscript module (#1813) --- pyscript.core/src/core.js | 3 --- pyscript.core/src/stdlib.js | 9 +++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index e91e4137..61567c0f 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -21,7 +21,6 @@ import "./all-done.js"; import TYPES from "./types.js"; import configs from "./config.js"; import sync from "./sync.js"; -import stdlib from "./stdlib.js"; import bootstrapNodeAndPlugins from "./plugins-helper.js"; import { ErrorCode } from "./exceptions.js"; import { robustFetch as fetch, getText } from "./fetch.js"; @@ -52,8 +51,6 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => { : currentElement.id; }, }); - - interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") }); }; // avoid multiple initialization of the same library diff --git a/pyscript.core/src/stdlib.js b/pyscript.core/src/stdlib.js index ffbc3daf..2abfe304 100644 --- a/pyscript.core/src/stdlib.js +++ b/pyscript.core/src/stdlib.js @@ -10,16 +10,16 @@ import pyscript from "./stdlib/pyscript.js"; const { entries } = Object; -const python = ["from pathlib import Path as _Path"]; +const python = ["from pathlib import Path as _Path", "_path = None"]; const write = (base, literal) => { for (const [key, value] of entries(literal)) { - const path = `_Path("${base}/${key}")`; + python.push(`_path = _Path("${base}/${key}")`); if (typeof value === "string") { const code = JSON.stringify(value); - python.push(`${path}.write_text(${code})`); + python.push(`_path.write_text(${code})`); } else { - python.push(`${path}.mkdir(parents=True, exist_ok=True)`); + python.push("_path.mkdir(parents=True, exist_ok=True)"); write(`${base}/${key}`, value); } } @@ -28,6 +28,7 @@ const write = (base, literal) => { write(".", pyscript); python.push("del _Path"); +python.push("del _path"); python.push("\n"); export default python.join("\n"); From d9bf5cae12de6806ce9e04f2455440e7a1b8e157 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 27 Oct 2023 15:30:21 +0200 Subject: [PATCH 090/105] Fix #1814 - Basic mpy integration (#1815) --- Makefile | 2 +- pyscript.core/package-lock.json | 60 +++++++++++++++++++++++++++++++++ pyscript.core/package.json | 4 ++- pyscript.core/src/stdlib.js | 11 ++++-- pyscript.core/test/hooks.html | 46 ++++++++++++++----------- pyscript.core/test/mpy.html | 12 +++++-- pyscript.core/test/mpy.spec.js | 37 ++++++++++++++++++++ 7 files changed, 146 insertions(+), 26 deletions(-) create mode 100644 pyscript.core/test/mpy.spec.js diff --git a/Makefile b/Makefile index 408dc31d..90a975a8 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,7 @@ clean: # Build PyScript. build: - cd pyscript.core && npm run build + cd pyscript.core && npx playwright install && npm run build # Run the precommit checks (run eslint). precommit-check: diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 26f8dabc..42e754ae 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -17,6 +17,7 @@ "type-checked-collections": "^0.1.7" }, "devDependencies": { + "@playwright/test": "^1.39.0", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", @@ -220,6 +221,21 @@ "node": ">= 8" } }, + "node_modules/@playwright/test": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", + "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "dev": true, + "dependencies": { + "playwright": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", @@ -2060,6 +2076,50 @@ "resolved": "https://registry.npmjs.org/plain-tag/-/plain-tag-0.1.3.tgz", "integrity": "sha512-yyVAOFKTAElc7KdLt2+UKGExNYwYb/Y/WE9i+1ezCQsJE8gbKSjewfpRqK2nQgZ4d4hhAAGgDCOcIZVilqE5UA==" }, + "node_modules/playwright": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", + "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "dev": true, + "dependencies": { + "playwright-core": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", + "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/polyscript": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.1.tgz", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index afe82225..a84ecd0f 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -20,11 +20,12 @@ }, "scripts": { "server": "npx static-handler --coi .", - "build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts", + "build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts && npm run test:mpy", "build:core": "rm -rf dist && rollup --config rollup/core.config.js", "build:plugins": "node rollup/plugins.cjs", "build:stdlib": "node rollup/stdlib.cjs", "build:toml": "node rollup/toml.cjs", + "test:mpy": "static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; playwright test --fully-parallel test/ || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE", "dev": "node dev.cjs", "release": "npm run build && npm run zip", "size": "echo -e \"\\033[1mdist/*.js file size\\033[0m\"; for js in $(ls dist/*.js); do echo -e \"\\033[2m$js:\\033[0m $(cat $js | brotli | wc -c) bytes\"; done", @@ -46,6 +47,7 @@ "type-checked-collections": "^0.1.7" }, "devDependencies": { + "@playwright/test": "^1.39.0", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", diff --git a/pyscript.core/src/stdlib.js b/pyscript.core/src/stdlib.js index 2abfe304..0bdf2545 100644 --- a/pyscript.core/src/stdlib.js +++ b/pyscript.core/src/stdlib.js @@ -10,7 +10,11 @@ import pyscript from "./stdlib/pyscript.js"; const { entries } = Object; -const python = ["from pathlib import Path as _Path", "_path = None"]; +const python = [ + "import os as _os", + "from pathlib import Path as _Path", + "_path = None", +]; const write = (base, literal) => { for (const [key, value] of entries(literal)) { @@ -19,7 +23,9 @@ const write = (base, literal) => { const code = JSON.stringify(value); python.push(`_path.write_text(${code})`); } else { - python.push("_path.mkdir(parents=True, exist_ok=True)"); + // @see https://github.com/pyscript/pyscript/pull/1813#issuecomment-1781502909 + python.push(`if not _os.path.exists("${base}/${key}"):`); + python.push(" _path.mkdir(parents=True, exist_ok=True)"); write(`${base}/${key}`, value); } } @@ -29,6 +35,7 @@ write(".", pyscript); python.push("del _Path"); python.push("del _path"); +python.push("del _os"); python.push("\n"); export default python.join("\n"); diff --git a/pyscript.core/test/hooks.html b/pyscript.core/test/hooks.html index a369b1ec..c614dbd0 100644 --- a/pyscript.core/test/hooks.html +++ b/pyscript.core/test/hooks.html @@ -6,28 +6,19 @@ PyScript Next Plugin Bug? - - diff --git a/pyscript.core/test/mpy.html b/pyscript.core/test/mpy.html index f98e58b6..f6e54650 100644 --- a/pyscript.core/test/mpy.html +++ b/pyscript.core/test/mpy.html @@ -5,7 +5,9 @@ PyScript Next @@ -13,11 +15,15 @@ + + from pyscript import display + display("Hello", "M-PyScript Main 2", append=False) + from pyscript import display - display("Hello", "M-PyScript Next Worker", append=False) + display("Hello", "M-PyScript Worker", append=False) diff --git a/pyscript.core/test/mpy.spec.js b/pyscript.core/test/mpy.spec.js new file mode 100644 index 00000000..aee7bc8e --- /dev/null +++ b/pyscript.core/test/mpy.spec.js @@ -0,0 +1,37 @@ +import { test, expect } from '@playwright/test'; + +test('MicroPython display', async ({ page }) => { + await page.goto('http://localhost:8080/test/mpy.html'); + await page.waitForSelector('html.done'); + const body = await page.evaluate(() => document.body.innerText); + await expect(body.trim()).toBe([ + 'M-PyScript Main 1', + 'M-PyScript Main 2', + 'M-PyScript Worker', + ].join('\n')); +}); + +test('MicroPython hooks', async ({ page }) => { + const logs = []; + page.on('console', msg => { + const text = msg.text(); + if (!text.startsWith('[')) + logs.push(text); + }); + await page.goto('http://localhost:8080/test/hooks.html'); + await page.waitForSelector('html.done'); + await expect(logs.join('\n')).toBe([ + 'main onReady', + 'main onBeforeRun', + 'main codeBeforeRun', + 'actual code in main', + 'main codeAfterRun', + 'main onAfterRun', + 'worker onReady', + 'worker onBeforeRun', + 'worker codeBeforeRun', + 'actual code in worker', + 'worker codeAfterRun', + 'worker onAfterRun', + ].join('\n')); +}); From 72f266532bb906574baabc4605618f5607027030 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 31 Oct 2023 15:16:15 +0100 Subject: [PATCH 091/105] PyScript Terminal - the latest kind (#1816) --- pyscript.core/package-lock.json | 126 ++++++------- pyscript.core/package.json | 6 +- pyscript.core/src/config.js | 2 +- pyscript.core/src/core.js | 1 + pyscript.core/src/plugins/py-terminal.js | 158 +++++++++++++++++ pyscript.core/test/hooks.html | 2 + pyscript.core/test/mpy.html | 3 +- pyscript.core/test/mpy.spec.js | 4 +- pyscript.core/test/py-terminal.html | 28 +++ .../tests/integration/test_py_terminal.py | 167 ++---------------- pyscript.core/types/core.d.ts | 3 +- pyscript.core/types/plugins.d.ts | 7 +- pyscript.core/types/plugins/py-terminal.d.ts | 2 + 13 files changed, 282 insertions(+), 227 deletions(-) create mode 100644 pyscript.core/src/plugins/py-terminal.js create mode 100644 pyscript.core/test/py-terminal.html create mode 100644 pyscript.core/types/plugins/py-terminal.d.ts diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 42e754ae..993a0fa4 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,17 +1,17 @@ { "name": "@pyscript/core", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.3.0", + "version": "0.3.1", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.5.1", + "polyscript": "^0.5.6", "sticky-module": "^0.1.0", "to-json-callback": "^0.1.1", "type-checked-collections": "^0.1.7" @@ -23,7 +23,7 @@ "@webreflection/toml-j0.4": "^1.1.3", "chokidar": "^3.5.3", "eslint": "^8.52.0", - "rollup": "^4.1.4", + "rollup": "^4.2.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", @@ -306,9 +306,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.1.4.tgz", - "integrity": "sha512-WlzkuFvpKl6CLFdc3V6ESPt7gq5Vrimd2Yv9IzKXdOpgbH4cdDSS1JLiACX8toygihtH5OlxyQzhXOph7Ovlpw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.2.0.tgz", + "integrity": "sha512-8PlggAxGxavr+pkCNeV1TM2wTb2o+cUWDg9M1cm9nR27Dsn287uZtSLYXoQqQcmq+sYfF7lHfd3sWJJinH9GmA==", "cpu": [ "arm" ], @@ -319,9 +319,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.1.4.tgz", - "integrity": "sha512-D1e+ABe56T9Pq2fD+R3ybe1ylCDzu3tY4Qm2Mj24R9wXNCq35+JbFbOpc2yrroO2/tGhTobmEl2Bm5xfE/n8RA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.2.0.tgz", + "integrity": "sha512-+71T85hbMFrJI+zKQULNmSYBeIhru55PYoF/u75MyeN2FcxE4HSPw20319b+FcZ4lWx2Nx/Ql9tN+hoaD3GH/A==", "cpu": [ "arm64" ], @@ -332,9 +332,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.1.4.tgz", - "integrity": "sha512-7vTYrgEiOrjxnjsgdPB+4i7EMxbVp7XXtS+50GJYj695xYTTEMn3HZVEvgtwjOUkAP/Q4HDejm4fIAjLeAfhtg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.2.0.tgz", + "integrity": "sha512-IIIQLuG43QIElT1JZqUP/zqIdiJl4t9U/boa0GZnQTw9m1X0k3mlBuysbgYXeloLT1RozdL7bgw4lpSaI8GOXw==", "cpu": [ "arm64" ], @@ -345,9 +345,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.1.4.tgz", - "integrity": "sha512-eGJVZScKSLZkYjhTAESCtbyTBq9SXeW9+TX36ki5gVhDqJtnQ5k0f9F44jNK5RhAMgIj0Ht9+n6HAgH0gUUyWQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.2.0.tgz", + "integrity": "sha512-BXcXvnLaea1Xz900omrGJhxHFJfH9jZ0CpJuVsbjjhpniJ6qiLXz3xA8Lekaa4MuhFcJd4f0r+Ky1G4VFbYhWw==", "cpu": [ "x64" ], @@ -358,9 +358,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.1.4.tgz", - "integrity": "sha512-HnigYSEg2hOdX1meROecbk++z1nVJDpEofw9V2oWKqOWzTJlJf1UXVbDE6Hg30CapJxZu5ga4fdAQc/gODDkKg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.2.0.tgz", + "integrity": "sha512-f4K3MKw9Y4AKi4ANGnmPIglr+S+8tO858YrGVuqAHXxJdVghBmz9CPU9kDpOnGvT4g4vg5uNyIFpOOFvffXyMA==", "cpu": [ "arm" ], @@ -371,9 +371,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.1.4.tgz", - "integrity": "sha512-TzJ+N2EoTLWkaClV2CUhBlj6ljXofaYzF/R9HXqQ3JCMnCHQZmQnbnZllw7yTDp0OG5whP4gIPozR4QiX+00MQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.2.0.tgz", + "integrity": "sha512-bNsTYQBgp4H7w6cT7FZhesxpcUPahsSIy4NgdZjH1ZwEoZHxi4XKglj+CsSEkhsKi+x6toVvMylhjRKhEMYfnA==", "cpu": [ "arm64" ], @@ -384,9 +384,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.1.4.tgz", - "integrity": "sha512-aVPmNMdp6Dlo2tWkAduAD/5TL/NT5uor290YvjvFvCv0Q3L7tVdlD8MOGDL+oRSw5XKXKAsDzHhUOPUNPRHVTQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.2.0.tgz", + "integrity": "sha512-Jp1NxBJpGLuxRU2ihrQk4IZ+ia5nffobG6sOFUPW5PMYkF0kQtxEbeDuCa69Xif211vUOcxlOnf5IOEIpTEySA==", "cpu": [ "arm64" ], @@ -397,9 +397,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.1.4.tgz", - "integrity": "sha512-77Fb79ayiDad0grvVsz4/OB55wJRyw9Ao+GdOBA9XywtHpuq5iRbVyHToGxWquYWlEf6WHFQQnFEttsAzboyKg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.2.0.tgz", + "integrity": "sha512-3p3iRtQmv2aXw+vtKNyZMLOQ+LSRsqArXjKAh2Oj9cqwfIRe7OXvdkOzWfZOIp1F/x5KJzVAxGxnniF4cMbnsQ==", "cpu": [ "x64" ], @@ -410,9 +410,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.1.4.tgz", - "integrity": "sha512-/t6C6niEQTqmQTVTD9TDwUzxG91Mlk69/v0qodIPUnjjB3wR4UA3klg+orR2SU3Ux2Cgf2pWPL9utK80/1ek8g==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.2.0.tgz", + "integrity": "sha512-atih7IF/reUZe4LBLC5Izd44hth2tfDIG8LaPp4/cQXdHh9jabcZEvIeRPrpDq0i/Uu487Qu5gl5KwyAnWajnw==", "cpu": [ "x64" ], @@ -423,9 +423,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.1.4.tgz", - "integrity": "sha512-ZY5BHHrOPkMbCuGWFNpJH0t18D2LU6GMYKGaqaWTQ3CQOL57Fem4zE941/Ek5pIsVt70HyDXssVEFQXlITI5Gg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.2.0.tgz", + "integrity": "sha512-vYxF3tKJeUE4ceYzpNe2p84RXk/fGK30I8frpRfv/MyPStej/mRlojztkN7Jtd1014HHVeq/tYaMBz/3IxkxZw==", "cpu": [ "arm64" ], @@ -436,9 +436,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.1.4.tgz", - "integrity": "sha512-XG2mcRfFrJvYyYaQmvCIvgfkaGinfXrpkBuIbJrTl9SaIQ8HumheWTIwkNz2mktCKwZfXHQNpO7RgXLIGQ7HXA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.2.0.tgz", + "integrity": "sha512-1LZJ6zpl93SaPQvas618bMFarVwufWTaczH4ESAbFcwiC4OtznA6Ym+hFPyIGaJaGEB8uMWWac0uXGPXOg5FGA==", "cpu": [ "ia32" ], @@ -449,9 +449,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.1.4.tgz", - "integrity": "sha512-ANFqWYPwkhIqPmXw8vm0GpBEHiPpqcm99jiiAp71DbCSqLDhrtr019C5vhD0Bw4My+LmMvciZq6IsWHqQpl2ZQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.2.0.tgz", + "integrity": "sha512-dgQfFdHCNg08nM5zBmqxqc9vrm0DVzhWotpavbPa0j4//MAOKZEB75yGAfzQE9fUJ+4pvM1239Y4IhL8f6sSog==", "cpu": [ "x64" ], @@ -781,13 +781,13 @@ } }, "node_modules/coincident": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.2.tgz", - "integrity": "sha512-Xc/lh56dl/v5GT1R3bEWxiLzF5ZTiXE5Flcd0+qvrBGhZsvDha8bgqhpocrvJmELuerhDO3+EQKDdCzPBPodJQ==", + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.3.tgz", + "integrity": "sha512-vd5xP+d5vCCcwTTUxQb3LHRi+dhXnuD+Bgjyf1r1H0IPjfXGDs3z2C4RZJifCJmokqf3Ff9BiFealewTBMTgYw==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", - "gc-hook": "^0.2.1" + "gc-hook": "^0.2.3" }, "optionalDependencies": { "ws": "^8.14.2" @@ -2121,15 +2121,15 @@ } }, "node_modules/polyscript": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.1.tgz", - "integrity": "sha512-jMFFWCJjYKcan7RV5UBVNg9IfVSss7wB6l5RIdx28pnBu1WSyA7sApLz7NEVbF14g5a5OjwtlvZCphQEA4CfQQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.6.tgz", + "integrity": "sha512-T1iufSnsq33K5m2vECiVvgDd5zJiSum+eNv3/SUTb38vIxQpDG2W4aVffoIXIgPYe2Bij/aU2xW1P9M2CHUifw==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", "codedent": "^0.1.2", - "coincident": "^0.14.2", + "coincident": "^0.14.3", "html-escaper": "^3.0.3", "sticky-module": "^0.1.0" } @@ -2814,9 +2814,9 @@ } }, "node_modules/rollup": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.1.4.tgz", - "integrity": "sha512-U8Yk1lQRKqCkDBip/pMYT+IKaN7b7UesK3fLSTuHBoBJacCE+oBqo/dfG/gkUdQNNB2OBmRP98cn2C2bkYZkyw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.2.0.tgz", + "integrity": "sha512-deaMa9Z+jPVeBD2dKXv+h7EbdKte9++V2potc/ADqvVgEr6DEJ3ia9u0joarjC2lX/ubaCRYz3QVx0TzuVqAJA==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -2826,18 +2826,18 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.1.4", - "@rollup/rollup-android-arm64": "4.1.4", - "@rollup/rollup-darwin-arm64": "4.1.4", - "@rollup/rollup-darwin-x64": "4.1.4", - "@rollup/rollup-linux-arm-gnueabihf": "4.1.4", - "@rollup/rollup-linux-arm64-gnu": "4.1.4", - "@rollup/rollup-linux-arm64-musl": "4.1.4", - "@rollup/rollup-linux-x64-gnu": "4.1.4", - "@rollup/rollup-linux-x64-musl": "4.1.4", - "@rollup/rollup-win32-arm64-msvc": "4.1.4", - "@rollup/rollup-win32-ia32-msvc": "4.1.4", - "@rollup/rollup-win32-x64-msvc": "4.1.4", + "@rollup/rollup-android-arm-eabi": "4.2.0", + "@rollup/rollup-android-arm64": "4.2.0", + "@rollup/rollup-darwin-arm64": "4.2.0", + "@rollup/rollup-darwin-x64": "4.2.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.2.0", + "@rollup/rollup-linux-arm64-gnu": "4.2.0", + "@rollup/rollup-linux-arm64-musl": "4.2.0", + "@rollup/rollup-linux-x64-gnu": "4.2.0", + "@rollup/rollup-linux-x64-musl": "4.2.0", + "@rollup/rollup-win32-arm64-msvc": "4.2.0", + "@rollup/rollup-win32-ia32-msvc": "4.2.0", + "@rollup/rollup-win32-x64-msvc": "4.2.0", "fsevents": "~2.3.2" } }, diff --git a/pyscript.core/package.json b/pyscript.core/package.json index a84ecd0f..3598b95e 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.3.0", + "version": "0.3.1", "type": "module", "description": "PyScript", "module": "./index.js", @@ -41,7 +41,7 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.5.1", + "polyscript": "^0.5.6", "sticky-module": "^0.1.0", "to-json-callback": "^0.1.1", "type-checked-collections": "^0.1.7" @@ -53,7 +53,7 @@ "@webreflection/toml-j0.4": "^1.1.3", "chokidar": "^3.5.3", "eslint": "^8.52.0", - "rollup": "^4.1.4", + "rollup": "^4.2.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js index 06aa53ee..55b4c6cb 100644 --- a/pyscript.core/src/config.js +++ b/pyscript.core/src/config.js @@ -113,7 +113,7 @@ for (const [TYPE] of TYPES) { value().then(({ notify }) => notify(error.message)); } } else if (!parsed?.plugins?.includes(`!${key}`)) { - toBeAwaited.push(value()); + toBeAwaited.push(value().then(({ default: p }) => p)); } } diff --git a/pyscript.core/src/core.js b/pyscript.core/src/core.js index 61567c0f..880ad214 100644 --- a/pyscript.core/src/core.js +++ b/pyscript.core/src/core.js @@ -70,6 +70,7 @@ const [ }); export { + TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js new file mode 100644 index 00000000..49622ba4 --- /dev/null +++ b/pyscript.core/src/plugins/py-terminal.js @@ -0,0 +1,158 @@ +// PyScript py-terminal plugin +import { TYPES, hooks } from "../core.js"; + +const CDN = "https://cdn.jsdelivr.net/npm/xterm"; +const XTERM = "5.3.0"; +const XTERM_READLINE = "1.1.1"; +const SELECTOR = [...TYPES.keys()] + .map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`) + .join(","); + +const pyTerminal = async () => { + const terminals = document.querySelectorAll(SELECTOR); + + // no results will look further for runtime nodes + if (!terminals.length) return; + + // we currently support only one terminal as in "classic" + if (terminals.length > 1) + console.warn("Unable to satisfy multiple terminals"); + + // if we arrived this far, let's drop the MutationObserver + mo.disconnect(); + + const [element] = terminals; + // hopefully to be removed in the near future! + if (element.matches('script[type="mpy"],mpy-script')) + throw new Error("Unsupported terminal"); + + // import styles once and lazily (only on valid terminal) + if (!document.querySelector(`link[href^="${CDN}"]`)) { + document.head.append( + Object.assign(document.createElement("link"), { + rel: "stylesheet", + href: `${CDN}@${XTERM}/css/xterm.min.css`, + }), + ); + } + + // lazy load these only when a valid terminal is found + const [{ Terminal }, { Readline }] = await Promise.all([ + import(/* webpackIgnore: true */ `${CDN}@${XTERM}/+esm`), + import( + /* webpackIgnore: true */ `${CDN}-readline@${XTERM_READLINE}/+esm` + ), + ]); + + const readline = new Readline(); + + // common main thread initialization for both worker + // or main case, bootstrapping the terminal on its target + const init = (options) => { + let target = element; + const selector = element.getAttribute("target"); + if (selector) { + target = + document.getElementById(selector) || + document.querySelector(selector); + if (!target) throw new Error(`Unknown target ${selector}`); + } else { + target = document.createElement(`${element.type}-terminal`); + target.style.display = "block"; + element.after(target); + } + const terminal = new Terminal({ + theme: { + background: "#191A19", + foreground: "#F5F2E7", + }, + ...options, + }); + terminal.loadAddon(readline); + terminal.open(target); + terminal.focus(); + }; + + // branch logic for the worker + if (element.hasAttribute("worker")) { + // when the remote thread onReady triggers: + // setup the interpreter stdout and stderr + const workerReady = ({ interpreter }, { sync }) => { + sync.pyterminal_drop_hooks(); + const decoder = new TextDecoder(); + const generic = { + isatty: true, + write(buffer) { + sync.pyterminal_write(decoder.decode(buffer)); + return buffer.length; + }, + }; + interpreter.setStdout(generic); + interpreter.setStderr(generic); + }; + + // run in python code able to replace builtins.input + // using the xworker.sync non blocking prompt + const codeBefore = ` + import builtins + from pyscript import sync as _sync + + builtins.input = lambda prompt: _sync.pyterminal_read(prompt) + `; + + // at the end of the code, make the terminal interactive + const codeAfter = ` + import code as _code + _code.interact() + `; + + // add a hook on the main thread to setup all sync helpers + // also bootstrapping the XTerm target on main + hooks.main.onWorker.add(function worker(_, xworker) { + hooks.main.onWorker.delete(worker); + init({ + disableStdin: false, + cursorBlink: true, + cursorStyle: "block", + }); + xworker.sync.pyterminal_read = readline.read.bind(readline); + xworker.sync.pyterminal_write = readline.write.bind(readline); + // allow a worker to drop main thread hooks ASAP + xworker.sync.pyterminal_drop_hooks = () => { + hooks.worker.onReady.delete(workerReady); + hooks.worker.codeBeforeRun.delete(codeBefore); + hooks.worker.codeAfterRun.delete(codeAfter); + }; + }); + + // setup remote thread JS/Python code for whenever the + // worker is ready to become a terminal + hooks.worker.onReady.add(workerReady); + hooks.worker.codeBeforeRun.add(codeBefore); + hooks.worker.codeAfterRun.add(codeAfter); + } else { + // in the main case, just bootstrap XTerm without + // allowing any input as that's not possible / awkward + hooks.main.onReady.add(function main({ io }) { + console.warn("py-terminal is read only on main thread"); + hooks.main.onReady.delete(main); + init({ + disableStdin: true, + cursorBlink: false, + cursorStyle: "underline", + }); + io.stdout = (value) => { + readline.write(`${value}\n`); + }; + io.stderr = (error) => { + readline.write(`${error.message || error}\n`); + }; + }); + } +}; + +const mo = new MutationObserver(pyTerminal); +mo.observe(document, { childList: true, subtree: true }); + +// try to check the current document ASAP +export default pyTerminal(); diff --git a/pyscript.core/test/hooks.html b/pyscript.core/test/hooks.html index c614dbd0..b706a15d 100644 --- a/pyscript.core/test/hooks.html +++ b/pyscript.core/test/hooks.html @@ -49,7 +49,9 @@ + + + + + + import sys + from pyscript import display + display("Hello", "PyScript Next - PyTerminal", append=False) + print("this should go to the terminal") + print("another line") + + # this works as expected + print("this goes to stderr", file=sys.stderr) + + + + diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py index 470e1fe6..9d9677c2 100644 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -1,17 +1,12 @@ import time -import pytest from playwright.sync_api import expect from .support import PyScriptTest, skip_worker -pytest.skip( - reason="FIX LATER: pyscript NEXT doesn't support the Terminal yet", - allow_module_level=True, -) - class TestPyTerminal(PyScriptTest): + @skip_worker("FIXME: the auto worker dance removes terminal") def test_py_terminal(self): """ 1. should redirect stdout and stderr to the DOM @@ -20,9 +15,7 @@ class TestPyTerminal(PyScriptTest): """ self.pyscript_run( """ - - - - """ - ) - term1 = self.page.locator("#term1") - term2 = self.page.locator("#term2") - term1_lines = term1.inner_text().splitlines() - term2_lines = term2.inner_text().splitlines() - assert term1_lines == ["one", "two", "three"] - assert term2_lines == ["two", "three"] + - def test_auto_attribute(self): - self.pyscript_run( - """ - - - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_hidden() - self.page.locator("button").click() - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_auto(self): - """ - config.terminal == "auto" is the default: a is - automatically added to the page - """ - self.pyscript_run( - """ - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_hidden() - assert "No found, adding one" in self.console.info.text - # - self.page.locator("button").click() - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_true(self): - """ - If we set config.terminal == true, a is automatically added - """ - self.pyscript_run( - """ - - terminal = true - - - - """ - ) - term = self.page.locator("py-terminal") - expect(term).to_be_visible() - assert term.inner_text() == "hello world\n" - - def test_config_false(self): - """ - If we set config.terminal == false, no is added - """ - self.pyscript_run( - """ - - terminal = false - - """ - ) - term = self.page.locator("py-terminal") - assert term.count() == 0 - - def test_config_docked(self): - """ - config.docked == "docked" is also the default: a is - automatically added to the page - """ - self.pyscript_run( - """ - + """ ) term = self.page.locator("py-terminal") self.page.locator("button").click() - expect(term).to_be_visible() - assert term.get_attribute("docked") == "" + last_line = self.page.get_by_text("hello world") + last_line.wait_for() + assert term.inner_text().rstrip() == "hello world" + @skip_worker("FIXME: the auto worker dance removes terminal") def test_xterm_function(self): """Test a few basic behaviors of the xtermjs terminal. @@ -164,10 +62,7 @@ class TestPyTerminal(PyScriptTest): """ self.pyscript_run( """ - - xterm = true - - - - - """ - ) - - # Wait for "done" to actually appear in the xterm; may be delayed, - # since xtermjs processes its input buffer in chunks - last_line = self.page.get_by_test_id("b").get_by_text("done") - last_line.wait_for() - - # Yes, this is not ideal. See note in `test_xterm_function` - time.sleep(1) - - rows = self.page.locator("#a .xterm-rows") - - # First line should be yellow - first_line = rows.locator("div").nth(0) - first_char = first_line.locator("span").nth(0) - color = first_char.evaluate( - "(element) => getComputedStyle(element).getPropertyValue('color')" - ) - assert color == "rgb(196, 160, 0)" diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index 6ae562f2..4a597f46 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -1,5 +1,6 @@ +import TYPES from "./types.js"; declare const exportedPyWorker: any; declare const exportedHooks: any; declare const exportedConfig: any; declare const exportedWhenDefined: any; -export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; +export { TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; diff --git a/pyscript.core/types/plugins.d.ts b/pyscript.core/types/plugins.d.ts index 1afe1308..abce670d 100644 --- a/pyscript.core/types/plugins.d.ts +++ b/pyscript.core/types/plugins.d.ts @@ -1,4 +1,5 @@ -declare namespace _default { - function error(): Promise; -} +declare const _default: { + error: () => Promise; + "py-terminal": () => Promise; +}; export default _default; diff --git a/pyscript.core/types/plugins/py-terminal.d.ts b/pyscript.core/types/plugins/py-terminal.d.ts new file mode 100644 index 00000000..35a35db4 --- /dev/null +++ b/pyscript.core/types/plugins/py-terminal.d.ts @@ -0,0 +1,2 @@ +declare const _default: Promise; +export default _default; From b31af823d1863aef6dcf0a76148dcf72074da9f8 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 31 Oct 2023 16:58:20 +0100 Subject: [PATCH 092/105] Use as default target (#1826) --- pyscript.core/package-lock.json | 4 ++-- pyscript.core/package.json | 2 +- pyscript.core/src/plugins/py-terminal.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 993a0fa4..f64d85a7 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.3.1", + "version": "0.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.3.1", + "version": "0.3.2", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 3598b95e..17357afb 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.3.1", + "version": "0.3.2", "type": "module", "description": "PyScript", "module": "./index.js", diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js index 49622ba4..cefb7395 100644 --- a/pyscript.core/src/plugins/py-terminal.js +++ b/pyscript.core/src/plugins/py-terminal.js @@ -57,7 +57,7 @@ const pyTerminal = async () => { document.querySelector(selector); if (!target) throw new Error(`Unknown target ${selector}`); } else { - target = document.createElement(`${element.type}-terminal`); + target = document.createElement("py-terminal"); target.style.display = "block"; element.after(target); } From 54df7171a2eb336b663aa8f64f5642c351050ce5 Mon Sep 17 00:00:00 2001 From: Nicholas Tollervey Date: Wed, 1 Nov 2023 10:23:33 +0000 Subject: [PATCH 093/105] Update publish-snapshot.yml (#1827) Ensure playwright is installed when building. --- .github/workflows/publish-snapshot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-snapshot.yml b/.github/workflows/publish-snapshot.yml index 17699458..944a26f3 100644 --- a/.github/workflows/publish-snapshot.yml +++ b/.github/workflows/publish-snapshot.yml @@ -41,7 +41,7 @@ jobs: ${{ runner.os }}- - name: Install Dependencies - run: npm install + run: npm install && npx playwright install - name: Build Pyscript.core run: npm run build From e81830a2ea7775edd5287427a89c7ac9e5b33b40 Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Wed, 1 Nov 2023 10:33:38 -0500 Subject: [PATCH 094/105] Value property to PyDom.Element and ElementCollection (#1828) * add base test for input value field * add value property to Element * add test for non supported element * prevent users to set value attribute on elements that do not support it * add test for setting value on collections * add value property to collection and add more tests * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- pyscript.core/src/stdlib/pyweb/pydom.py | 24 ++++++++++ pyscript.core/test/pyscript_dom/index.html | 5 +- .../test/pyscript_dom/tests/test_dom.py | 48 +++++++++++++++++++ pyscript.core/types/stdlib/pyscript.d.ts | 9 ++-- 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/pyscript.core/src/stdlib/pyweb/pydom.py b/pyscript.core/src/stdlib/pyweb/pydom.py index 834c2de6..1101a977 100644 --- a/pyscript.core/src/stdlib/pyweb/pydom.py +++ b/pyscript.core/src/stdlib/pyweb/pydom.py @@ -131,6 +131,22 @@ class Element(BaseElement): def id(self, value): self._js.id = value + @property + def value(self): + return self._js.value + + @value.setter + def value(self, value): + # in order to avoid confusion to the user, we don't allow setting the + # value of elements that don't have a value attribute + if not hasattr(self._js, "value"): + raise AttributeError( + f"Element {self._js.tagName} has no value attribute. If you want to " + "force a value attribute, set it directly using the `_js.value = ` " + "javascript API attribute instead." + ) + self._js.value = value + def clone(self, new_id=None): clone = Element(self._js.cloneNode(True)) clone.id = new_id @@ -264,6 +280,14 @@ class ElementCollection: def html(self, value): self._set_attribute("html", value) + @property + def value(self): + return self._get_attribute("value") + + @value.setter + def value(self, value): + self._set_attribute("value", value) + @property def children(self): return self._elements diff --git a/pyscript.core/test/pyscript_dom/index.html b/pyscript.core/test/pyscript_dom/index.html index 450d99f2..80f684d5 100644 --- a/pyscript.core/test/pyscript_dom/index.html +++ b/pyscript.core/test/pyscript_dom/index.html @@ -64,8 +64,8 @@

Content multi-elem-h2

- - + +
@@ -89,7 +89,6 @@ const log = console.log.bind(console) let testsStarted = false; console.log = (...args) => { - log("---IN---"); let txt = args.join(" "); let token = "
"; if (txt.endsWith("FAILED")) diff --git a/pyscript.core/test/pyscript_dom/tests/test_dom.py b/pyscript.core/test/pyscript_dom/tests/test_dom.py index 29663224..c55d20e1 100644 --- a/pyscript.core/test/pyscript_dom/tests/test_dom.py +++ b/pyscript.core/test/pyscript_dom/tests/test_dom.py @@ -244,3 +244,51 @@ class TestCreation: assert new_el.parent == parent_div assert pydom[selector][0].children[0] == new_el + + +class TestInput: + input_ids = [ + "test_rr_input_text", + "test_rr_input_button", + "test_rr_input_email", + "test_rr_input_password", + ] + + def test_value(self): + for id_ in self.input_ids: + expected_type = id_.split("_")[-1] + result = pydom[f"#{id_}"] + input_el = result[0] + assert input_el._js.type == expected_type + assert input_el.value == f"Content {id_}" == input_el._js.value + + # Check that we can set the value + new_value = f"New Value {expected_type}" + input_el.value = new_value + assert input_el.value == new_value + + # Check that we can set the value back to the original using + # the collection + new_value = f"Content {id_}" + result.value = new_value + assert input_el.value == new_value + + def test_set_value_collection(self): + for id_ in self.input_ids: + input_el = pydom[f"#{id_}"] + + assert input_el.value[0] == f"Content {id_}" == input_el[0].value + + new_value = f"New Value {id_}" + input_el.value = new_value + assert input_el.value[0] == new_value == input_el[0].value + + def test_element_without_value(self): + result = pydom[f"#tests-terminal"][0] + with pytest.raises(AttributeError): + result.value = "some value" + + def test_element_without_collection(self): + result = pydom[f"#tests-terminal"] + with pytest.raises(AttributeError): + result.value = "some value" diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts index fa33defe..0df1bf95 100644 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -1,13 +1,14 @@ -declare namespace _default { - let pyscript: { +declare const _default: { + pyscript: { "__init__.py": string; "display.py": string; "event_handling.py": string; "magic_js.py": string; "util.py": string; }; - let pyweb: { + "pyscript.py": string; + pyweb: { "pydom.py": string; }; -} +}; export default _default; From c8ec29a3d8d1e9d3e5a3acc557b93aaf543f4c0f Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 3 Nov 2023 10:00:52 +0100 Subject: [PATCH 095/105] Improve offline dist content (#1836) --- .gitignore | 2 + .pre-commit-config.yaml | 2 +- pyscript.core/.eslintrc.cjs | 2 +- pyscript.core/package-lock.json | 144 +++++++++++++++++- pyscript.core/package.json | 11 +- pyscript.core/rollup/3rd-party.cjs | 52 +++++++ pyscript.core/rollup/core.config.js | 5 +- pyscript.core/rollup/toml.cjs | 14 -- pyscript.core/src/3rd-party/README.md | 7 + pyscript.core/src/config.js | 2 +- pyscript.core/src/plugins/py-terminal.js | 25 ++- pyscript.core/src/toml.js | 3 - pyscript.core/test/terminal.html | 37 ----- pyscript.core/test/terminal.py | 14 -- pyscript.core/types/3rd-party/toml.d.ts | 12 ++ .../types/3rd-party/xterm-readline.d.ts | 138 +++++++++++++++++ pyscript.core/types/3rd-party/xterm.d.ts | 4 + pyscript.core/types/stdlib/pyscript.d.ts | 9 +- 18 files changed, 385 insertions(+), 98 deletions(-) create mode 100644 pyscript.core/rollup/3rd-party.cjs delete mode 100644 pyscript.core/rollup/toml.cjs create mode 100644 pyscript.core/src/3rd-party/README.md delete mode 100644 pyscript.core/src/toml.js delete mode 100644 pyscript.core/test/terminal.html delete mode 100644 pyscript.core/test/terminal.py create mode 100644 pyscript.core/types/3rd-party/toml.d.ts create mode 100644 pyscript.core/types/3rd-party/xterm-readline.d.ts create mode 100644 pyscript.core/types/3rd-party/xterm.d.ts diff --git a/.gitignore b/.gitignore index 2d0bf719..d19ac9a9 100644 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,5 @@ pyscript.core/dist pyscript.core/dist.zip pyscript.core/src/plugins.js pyscript.core/src/stdlib/pyscript.js +pyscript.core/src/3rd-party/* +!pyscript.core/src/3rd-party/READMEmd diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aa8c8225..cd2d4d04 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -42,7 +42,7 @@ repos: rev: "v3.0.0-alpha.6" hooks: - id: prettier - exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/|pyscript.core/src/toml\.js + exclude: pyscript\.core/test|pyscript\.core/dist|pyscript\.core/types|pyscript.core/src/stdlib/pyscript.js|pyscript\.sw/|pyscript.core/src/3rd-party args: [--tab-width, "4"] - repo: https://github.com/pycqa/isort diff --git a/pyscript.core/.eslintrc.cjs b/pyscript.core/.eslintrc.cjs index 4ba8241e..ecdde662 100644 --- a/pyscript.core/.eslintrc.cjs +++ b/pyscript.core/.eslintrc.cjs @@ -19,7 +19,7 @@ module.exports = { ecmaVersion: "latest", sourceType: "module", }, - ignorePatterns: ["toml.js"], + ignorePatterns: ["3rd-party"], rules: { "no-implicit-globals": ["error"], }, diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index f64d85a7..d9eb4740 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -18,6 +18,7 @@ }, "devDependencies": { "@playwright/test": "^1.39.0", + "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", @@ -27,7 +28,9 @@ "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "xterm": "^5.3.0", + "xterm-readline": "^1.1.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -236,6 +239,71 @@ "node": ">=16" } }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", @@ -826,6 +894,12 @@ "node": ">= 10" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1113,6 +1187,12 @@ "integrity": "sha512-gpXfJslSi4hYDkA0mTLEpYKRv9siAgSUgZ+UWyk+J5Cttpd1ThCVwdclzIwQSclz3hYn049+M2fgrP1WpvF8xg==", "dev": true }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", @@ -1643,6 +1723,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1679,6 +1768,15 @@ "node": ">=8" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1794,6 +1892,18 @@ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", "dev": true }, + "node_modules/magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/mdn-data": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", @@ -3039,6 +3149,20 @@ "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==", "dev": true }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3306,6 +3430,24 @@ } } }, + "node_modules/xterm": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.3.0.tgz", + "integrity": "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg==", + "dev": true + }, + "node_modules/xterm-readline": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/xterm-readline/-/xterm-readline-1.1.1.tgz", + "integrity": "sha512-f87S2/jKwRZoZTxE2vkPgBCipDl6k6tTkMTb9pmwC4R6XkfR491fWBuToZd/nZasp6seD2u0jdABinUDWsK6dw==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "peerDependencies": { + "xterm": "^5.0.0" + } + }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 17357afb..4a8415e2 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -20,11 +20,11 @@ }, "scripts": { "server": "npx static-handler --coi .", - "build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts && npm run test:mpy", - "build:core": "rm -rf dist && rollup --config rollup/core.config.js", + "build": "npm run build:3rd-party && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts && npm run test:mpy", + "build:core": "rm -rf dist && rollup --config rollup/core.config.js && cp src/3rd-party/*.css dist/", "build:plugins": "node rollup/plugins.cjs", "build:stdlib": "node rollup/stdlib.cjs", - "build:toml": "node rollup/toml.cjs", + "build:3rd-party": "node rollup/3rd-party.cjs", "test:mpy": "static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; playwright test --fully-parallel test/ || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE", "dev": "node dev.cjs", "release": "npm run build && npm run zip", @@ -48,6 +48,7 @@ }, "devDependencies": { "@playwright/test": "^1.39.0", + "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", @@ -57,7 +58,9 @@ "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "xterm": "^5.3.0", + "xterm-readline": "^1.1.1" }, "repository": { "type": "git", diff --git a/pyscript.core/rollup/3rd-party.cjs b/pyscript.core/rollup/3rd-party.cjs new file mode 100644 index 00000000..3f955262 --- /dev/null +++ b/pyscript.core/rollup/3rd-party.cjs @@ -0,0 +1,52 @@ +const { copyFileSync, writeFileSync } = require("node:fs"); +const { join } = require("node:path"); + +const CDN = "https://cdn.jsdelivr.net/npm"; + +const targets = join(__dirname, "..", "src", "3rd-party"); +const node_modules = join(__dirname, "..", "node_modules"); + +const { devDependencies } = require(join(__dirname, "..", "package.json")); + +const v = (name) => devDependencies[name].replace(/[^\d.]/g, ""); + +// Fetch a module via jsdelivr CDN `/+esm` orchestration +// then sanitize the resulting outcome to avoid importing +// anything via `/npm/...` through Rollup +const resolve = (name) => { + const cdn = `${CDN}/${name}@${v(name)}/+esm`; + console.debug("fetching", cdn); + return fetch(cdn) + .then((b) => b.text()) + .then((text) => + text.replace( + /("|')\/npm\/(.+)?\+esm\1/g, + // normalize `/npm/module@version/+esm` as + // just `module` so that rollup can do the rest + (_, quote, module) => { + const i = module.lastIndexOf("@"); + return `${quote}${module.slice(0, i)}${quote}`; + }, + ), + ); +}; + +// key/value pairs as: +// "3rd-party/file-name.js" +// string as content or +// Promise as resolved content +const modules = { + "toml.js": join(node_modules, "@webreflection", "toml-j0.4", "toml.js"), + "xterm.js": resolve("xterm"), + "xterm.css": fetch(`${CDN}/xterm@${v("xterm")}/css/xterm.min.css`).then( + (b) => b.text(), + ), + "xterm-readline.js": resolve("xterm-readline"), +}; + +for (const [target, source] of Object.entries(modules)) { + if (typeof source === "string") copyFileSync(source, join(targets, target)); + else { + source.then((text) => writeFileSync(join(targets, target), text)); + } +} diff --git a/pyscript.core/rollup/core.config.js b/pyscript.core/rollup/core.config.js index bb5a10ec..16dc822e 100644 --- a/pyscript.core/rollup/core.config.js +++ b/pyscript.core/rollup/core.config.js @@ -2,6 +2,7 @@ // the default exported as npm entry. import { nodeResolve } from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; import terser from "@rollup/plugin-terser"; import postcss from "rollup-plugin-postcss"; @@ -11,7 +12,9 @@ export default [ { input: "./src/core.js", plugins: plugins.concat( - process.env.NO_MIN ? [nodeResolve()] : [nodeResolve(), terser()], + process.env.NO_MIN + ? [nodeResolve(), commonjs()] + : [nodeResolve(), commonjs(), terser()], ), output: { esModule: true, diff --git a/pyscript.core/rollup/toml.cjs b/pyscript.core/rollup/toml.cjs deleted file mode 100644 index ab31aa97..00000000 --- a/pyscript.core/rollup/toml.cjs +++ /dev/null @@ -1,14 +0,0 @@ -const { copyFileSync } = require("node:fs"); -const { join } = require("node:path"); - -copyFileSync( - join( - __dirname, - "..", - "node_modules", - "@webreflection", - "toml-j0.4", - "toml.js", - ), - join(__dirname, "..", "src", "toml.js"), -); diff --git a/pyscript.core/src/3rd-party/README.md b/pyscript.core/src/3rd-party/README.md new file mode 100644 index 00000000..93cc7fe1 --- /dev/null +++ b/pyscript.core/src/3rd-party/README.md @@ -0,0 +1,7 @@ +# PyScript 3rd Party + +This folder contains artifacts created via [3rd-party.cjs](../../rollup/3rd-party.cjs). + +As we would like to offer a way to run PyScript offline, and we already offer a `dist` folder with all the necessary scripts, we have created a foreign dependencies resolver that allow to lazy-load CDN dependencies out of the box. + +Please **note** these dependencies are **not interpreters**, because interpreters have their own mechanism, folders structure, WASM files, and whatnot, to work locally, but at least XTerm or the TOML parser, among other lazy dependencies, should be available within the dist folder. diff --git a/pyscript.core/src/config.js b/pyscript.core/src/config.js index 55b4c6cb..a027ef4e 100644 --- a/pyscript.core/src/config.js +++ b/pyscript.core/src/config.js @@ -89,7 +89,7 @@ for (const [TYPE] of TYPES) { } else if (toml || type === "toml") { try { const { parse } = await import( - /* webpackIgnore: true */ "./toml.js" + /* webpackIgnore: true */ "./3rd-party/toml.js" ); parsed = parse(text); } catch (e) { diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js index cefb7395..c9103f83 100644 --- a/pyscript.core/src/plugins/py-terminal.js +++ b/pyscript.core/src/plugins/py-terminal.js @@ -1,9 +1,6 @@ // PyScript py-terminal plugin import { TYPES, hooks } from "../core.js"; -const CDN = "https://cdn.jsdelivr.net/npm/xterm"; -const XTERM = "5.3.0"; -const XTERM_READLINE = "1.1.1"; const SELECTOR = [...TYPES.keys()] .map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`) .join(","); @@ -26,22 +23,18 @@ const pyTerminal = async () => { if (element.matches('script[type="mpy"],mpy-script')) throw new Error("Unsupported terminal"); - // import styles once and lazily (only on valid terminal) - if (!document.querySelector(`link[href^="${CDN}"]`)) { - document.head.append( - Object.assign(document.createElement("link"), { - rel: "stylesheet", - href: `${CDN}@${XTERM}/css/xterm.min.css`, - }), - ); - } + // import styles lazily + document.head.append( + Object.assign(document.createElement("link"), { + rel: "stylesheet", + href: new URL("./xterm.css", import.meta.url), + }), + ); // lazy load these only when a valid terminal is found const [{ Terminal }, { Readline }] = await Promise.all([ - import(/* webpackIgnore: true */ `${CDN}@${XTERM}/+esm`), - import( - /* webpackIgnore: true */ `${CDN}-readline@${XTERM_READLINE}/+esm` - ), + import(/* webpackIgnore: true */ "../3rd-party/xterm.js"), + import(/* webpackIgnore: true */ "../3rd-party/xterm-readline.js"), ]); const readline = new Readline(); diff --git a/pyscript.core/src/toml.js b/pyscript.core/src/toml.js deleted file mode 100644 index 8c635be8..00000000 --- a/pyscript.core/src/toml.js +++ /dev/null @@ -1,3 +0,0 @@ -const{SyntaxError:r,parse:t}=function(){function r(t,e,n,u){this.message=t,this.expected=e,this.found=n,this.location=u,this.name="SyntaxError","function"==typeof Error.captureStackTrace&&Error.captureStackTrace(this,r)}return function(r,t){function e(){this.constructor=r}e.prototype=t.prototype,r.prototype=new e}(r,Error),r.buildMessage=function(r,t){var e={literal:function(r){return'"'+u(r.text)+'"'},class:function(r){var t,e="";for(t=0;t0){for(t=1,n=1;t20||20===t.length&&t>n)&&(e=!0)}else{"+"===t[0]&&(t=t.substr(1));var u="9223372036854775807";(t.length>19||19===t.length&&t>u)&&(e=!0)}return e&&Dt(r+" is not a 64-bit signed integer."),t=parseInt(t,10),o(t)||Dt(r+" is not a 64-bit signed integer."),{type:"Integer",value:t}},kr="+",Br=jt("+",!1),Jr="-",Pr=jt("-",!1),Vr=/^[0-9]/,Wr=Ht([["0","9"]],!1,!1),qr="T",Gr=jt("T",!1),Kr=function(){var r=Tt(),t=new Date(r);return o(t.getTime())||Dt("Date-time "+r+" is invalid. It does not conform to RFC 3339 or this is a browser-specific problem."),{type:"DateTime",value:t}},Lr=Mt("FullDate (YYYY-mm-dd)"),Xr=":",$r=jt(":",!1),rt=Mt("Hour (HH)"),tt=Mt("Minute (MM)"),et=Mt("Second (SS)"),nt=Mt("TimeOffset (Z or +/-HH:MM)"),ut="Z",ot=jt("Z",!1),at="[",it=jt("[",!1),ct=",",ft=jt(",",!1),st="]",lt=jt("]",!1),ht=function(r){for(var t={type:"Array",value:r?r[0]:[]},e=0,n=t.value,u=n.length;eFt&&(Ft=mt,wt=[]),wt.push(r))}function Zt(){var r,e,n,u,o,a,i,c;for(r=mt,e=[],(n=Rt())===p&&(n=It())===p&&(n=Ut());n!==p;)e.push(n),(n=Rt())===p&&(n=It())===p&&(n=Ut());if(e!==p){if(n=mt,u=function(){var r,e;r=mt,e=function(){var r,e,n,u;r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it));e!==p&&(n=fe())!==p?(93===t.charCodeAt(mt)?(u=st,mt++):(u=p,0===Et&&Nt(lt)),u!==p?(xt=r,r=e=bt(n)):(mt=r,r=p)):(mt=r,r=p);return r}(),e!==p&&(xt=r,e=A(e));r=e,r===p&&(r=mt,(e=fe())!==p&&(xt=r,e=C(e)),(r=e)===p&&(r=mt,(e=zt())!==p&&(xt=r,e=b(e)),r=e));return r}(),u!==p){for(o=[],(a=Rt())===p&&(a=Ut());a!==p;)o.push(a),(a=Rt())===p&&(a=Ut());o!==p?(a=mt,(i=It())!==p&&(c=Zt())!==p?a=i=[i,c]:(mt=a,a=p),a===p&&(a=null),a!==p?n=u=[u,o,a]:(mt=n,n=p)):(mt=n,n=p)}else mt=n,n=p;n===p&&(n=null),n!==p?(xt=r,r=e=g()):(mt=r,r=p)}else mt=r,r=p;return r}function It(){var r;return Et++,10===t.charCodeAt(mt)?(r=m,mt++):(r=p,0===Et&&Nt(x)),r===p&&(t.substr(mt,2)===S?(r=S,mt+=2):(r=p,0===Et&&Nt(F))),Et--,r===p&&0===Et&&Nt(y),r}function Rt(){var r;return Et++,E.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(T)),Et--,r===p&&0===Et&&Nt(w),r}function Ut(){var r,e,n,u,o,a;if(Et++,r=mt,35===t.charCodeAt(mt)?(e=j,mt++):(e=p,0===Et&&Nt(H)),e!==p){for(n=[],u=mt,o=mt,Et++,a=It(),Et--,a===p?o=void 0:(mt=o,o=p),o!==p?(t.length>mt?(a=t.charAt(mt),mt++):(a=p,0===Et&&Nt(M)),a!==p?u=o=[o,a]:(mt=u,u=p)):(mt=u,u=p);u!==p;)n.push(u),u=mt,o=mt,Et++,a=It(),Et--,a===p?o=void 0:(mt=o,o=p),o!==p?(t.length>mt?(a=t.charAt(mt),mt++):(a=p,0===Et&&Nt(M)),a!==p?u=o=[o,a]:(mt=u,u=p)):(mt=u,u=p);n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return Et--,r===p&&(e=p,0===Et&&Nt(D)),r}function zt(){var r,e,n,u,o,a;if(r=mt,(e=Qt())!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p)if(61===t.charCodeAt(mt)?(u=O,mt++):(u=p,0===Et&&Nt(_)),u!==p){for(o=[],a=Rt();a!==p;)o.push(a),a=Rt();o!==p&&(a=Vt())!==p?(xt=r,r=e=N(e,a)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p}else mt=r,r=p;return r}function Qt(){var r;return(r=function(){var r,t,e;if(r=mt,t=[],(e=Yt())!==p)for(;e!==p;)t.push(e),e=Yt();else t=p;t!==p&&(xt=r,t=Z());return r=t,r}())===p&&(r=function(){var r,t,e;if(r=mt,kt()!==p){if(t=[],(e=Wt())!==p)for(;e!==p;)t.push(e),e=Wt();else t=p;t!==p&&(e=kt())!==p?(xt=r,r=z(t)):(mt=r,r=p)}else mt=r,r=p;return r}()),r}function Yt(){var r;return Et++,R.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(U)),Et--,r===p&&0===Et&&Nt(I),r}function kt(){var r;return Et++,34===t.charCodeAt(mt)?(r=Y,mt++):(r=p,0===Et&&Nt(k)),Et--,r===p&&0===Et&&Nt(Q),r}function Bt(){var r;return Et++,39===t.charCodeAt(mt)?(r=J,mt++):(r=p,0===Et&&Nt(P)),Et--,r===p&&0===Et&&Nt(B),r}function Jt(){var r;return Et++,t.substr(mt,3)===W?(r=W,mt+=3):(r=p,0===Et&&Nt(q)),Et--,r===p&&0===Et&&Nt(V),r}function Pt(){var r;return Et++,t.substr(mt,3)===K?(r=K,mt+=3):(r=p,0===Et&&Nt(L)),Et--,r===p&&0===Et&&Nt(G),r}function Vt(){var r;return(r=function(){var r;r=function(){var r,t,e,n;if(r=mt,Jt()!==p)if((t=It())===p&&(t=null),t!==p){for(e=[],n=Xt();n!==p;)e.push(n),n=Xt();e!==p&&(n=Jt())!==p?(xt=r,r=X(e)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}(),r===p&&(r=function(){var r,t,e;if(r=mt,kt()!==p){for(t=[],e=Wt();e!==p;)t.push(e),e=Wt();t!==p&&(e=kt())!==p?(xt=r,r=X(t)):(mt=r,r=p)}else mt=r,r=p;return r}())===p&&(r=function(){var r,t,e,n;if(r=mt,Pt()!==p)if((t=It())===p&&(t=null),t!==p){for(e=[],n=$t();n!==p;)e.push(n),n=$t();e!==p&&(n=Pt())!==p?(xt=r,r=X(e)):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}())===p&&(r=function(){var r,t,e;if(r=mt,Bt()!==p){for(t=[],e=Lt();e!==p;)t.push(e),e=Lt();t!==p&&(e=Bt())!==p?(xt=r,r=Ar()):(mt=r,r=p)}else mt=r,r=p;return r}());return r}())===p&&(r=function(){var r,e;r=mt,t.substr(mt,4)===Er?(e=Er,mt+=4):(e=p,0===Et&&Nt(Tr));e!==p&&(xt=r,e=Dr());r=e,r===p&&(r=mt,t.substr(mt,5)===jr?(e=jr,mt+=5):(e=p,0===Et&&Nt(Hr)),e!==p&&(xt=r,e=Mr()),r=e);return r}())===p&&(r=function(){var r,e,n,u;r=mt,e=function(){var r,e,n,u,o,a;Et++,r=mt,e=function(){var r,t,e,n,u;r=mt,(t=ue())!==p&&(e=ue())!==p&&(n=ue())!==p&&(u=ue())!==p?r=t=[t,e,n,u]:(mt=r,r=p);return r}(),e!==p?(45===t.charCodeAt(mt)?(n=Jr,mt++):(n=p,0===Et&&Nt(Pr)),n!==p?(u=function(){var r,t,e;r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);return r}(),u!==p?(45===t.charCodeAt(mt)?(o=Jr,mt++):(o=p,0===Et&&Nt(Pr)),o!==p?(a=function(){var r,t,e;r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);return r}(),a!==p?r=e=[e,n,u,o,a]:(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt(Lr));return r}(),e!==p?(84===t.charCodeAt(mt)?(n=qr,mt++):(n=p,0===Et&&Nt(Gr)),n!==p?(u=function(){var r,e,n;r=mt,e=function(){var r,e,n,u,o,a,i;r=mt,e=oe(),e!==p?(58===t.charCodeAt(mt)?(n=Xr,mt++):(n=p,0===Et&&Nt($r)),n!==p&&(u=ae())!==p?(58===t.charCodeAt(mt)?(o=Xr,mt++):(o=p,0===Et&&Nt($r)),o!==p?(a=function(){var r,t,e;Et++,r=mt,t=ue(),t!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(et));return r}(),a!==p?(i=function(){var r,e,n,u;r=mt,46===t.charCodeAt(mt)?(e=_r,mt++):(e=p,0===Et&&Nt(Nr));if(e!==p){if(n=[],(u=ue())!==p)for(;u!==p;)n.push(u),u=ue();else n=p;n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return r}(),i===p&&(i=null),i!==p?r=e=[e,n,u,o,a,i]:(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);return r}(),e!==p?(n=function(){var r,e,n,u,o;Et++,90===t.charCodeAt(mt)?(r=ut,mt++):(r=p,0===Et&&Nt(ot));r===p&&(r=mt,(e=ee())!==p&&(n=oe())!==p?(58===t.charCodeAt(mt)?(u=Xr,mt++):(u=p,0===Et&&Nt($r)),u!==p&&(o=ae())!==p?r=e=[e,n,u,o]:(mt=r,r=p)):(mt=r,r=p));Et--,r===p&&(e=p,0===Et&&Nt(nt));return r}(),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);return r}(),u!==p?(xt=r,r=e=Kr()):(mt=r,r=p)):(mt=r,r=p)):(mt=r,r=p);return r}())===p&&(r=function(){var r,e,n,u;r=mt,te()!==p?(e=mt,n=function(){var r,e,n,u,o,a,i;r=mt,46===t.charCodeAt(mt)?(e=_r,mt++):(e=p,0===Et&&Nt(Nr));if(e!==p)if((n=ue())!==p){for(u=[],o=mt,95===t.charCodeAt(mt)?(a=Zr,mt++):(a=p,0===Et&&Nt(Ir)),a===p&&(a=null),a!==p&&(i=ue())!==p?o=a=[a,i]:(mt=o,o=p);o!==p;)u.push(o),o=mt,95===t.charCodeAt(mt)?(a=Zr,mt++):(a=p,0===Et&&Nt(Ir)),a===p&&(a=null),a!==p&&(i=ue())!==p?o=a=[a,i]:(mt=o,o=p);u!==p?r=e=[e,n,u]:(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;return r}(),n!==p?((u=re())===p&&(u=null),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p),e===p&&(e=re()),e!==p?(xt=r,r=Or()):(mt=r,r=p)):(mt=r,r=p);return r}())===p&&(r=te())===p&&(r=function(){var r,e,n,u,o,a,i,c,f,s;r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it));if(e!==p){for(n=[],u=ce();u!==p;)n.push(u),u=ce();if(n!==p){if(u=mt,(o=ie())!==p){for(a=[],i=ce();i!==p;)a.push(i),i=ce();if(a!==p){if(i=mt,44===t.charCodeAt(mt)?(c=ct,mt++):(c=p,0===Et&&Nt(ft)),c!==p){for(f=[],s=ce();s!==p;)f.push(s),s=ce();f!==p?i=c=[c,f]:(mt=i,i=p)}else mt=i,i=p;i===p&&(i=null),i!==p?u=o=[o,a,i]:(mt=u,u=p)}else mt=u,u=p}else mt=u,u=p;u===p&&(u=null),u!==p?(93===t.charCodeAt(mt)?(o=st,mt++):(o=p,0===Et&&Nt(lt)),o!==p?(xt=r,r=e=ht(u)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;return r}())===p&&(r=function(){var r,e,n,u,o,a,i,c,f,s,l;r=mt,123===t.charCodeAt(mt)?(e=vt,mt++):(e=p,0===Et&&Nt(dt));if(e!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p){if(u=mt,(o=zt())!==p){for(a=[],i=mt,c=[],f=Rt();f!==p;)c.push(f),f=Rt();if(c!==p)if(44===t.charCodeAt(mt)?(f=ct,mt++):(f=p,0===Et&&Nt(ft)),f!==p){for(s=[],l=Rt();l!==p;)s.push(l),l=Rt();s!==p&&(l=zt())!==p?i=c=[c,f,s,l]:(mt=i,i=p)}else mt=i,i=p;else mt=i,i=p;for(;i!==p;){for(a.push(i),i=mt,c=[],f=Rt();f!==p;)c.push(f),f=Rt();if(c!==p)if(44===t.charCodeAt(mt)?(f=ct,mt++):(f=p,0===Et&&Nt(ft)),f!==p){for(s=[],l=Rt();l!==p;)s.push(l),l=Rt();s!==p&&(l=zt())!==p?i=c=[c,f,s,l]:(mt=i,i=p)}else mt=i,i=p;else mt=i,i=p}if(a!==p){for(i=[],c=Rt();c!==p;)i.push(c),c=Rt();i!==p?u=o=[o,a,i]:(mt=u,u=p)}else mt=u,u=p}else mt=u,u=p;u===p&&(u=null),u!==p?(125===t.charCodeAt(mt)?(o=gt,mt++):(o=p,0===Et&&Nt(At)),o!==p?(xt=r,r=e=Ct(u)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;return r}()),r}function Wt(){var r;return(r=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(rr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(tr)),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt($));return r}())===p&&(r=qt()),r}function qt(){var r,e,n,u;return r=mt,Gt()!==p?(e=function(){var r;Et++,cr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(fr));Et--,r===p&&0===Et&&Nt(ir);return r}(),e===p&&(e=kt())===p&&(e=Gt())===p&&(e=mt,117===t.charCodeAt(mt)?(n=er,mt++):(n=p,0===Et&&Nt(nr)),n!==p?(u=function(){var r,t,e,n,u;Et++,r=mt,t=Kt(),t!==p&&(e=Kt())!==p&&(n=Kt())!==p&&(u=Kt())!==p?r=t=[t,e,n,u]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(pr));return r}(),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p),e===p&&(e=mt,85===t.charCodeAt(mt)?(n=ur,mt++):(n=p,0===Et&&Nt(or)),n!==p?(u=function(){var r,t,e,n,u,o,a,i,c;Et++,r=mt,t=Kt(),t!==p&&(e=Kt())!==p&&(n=Kt())!==p&&(u=Kt())!==p&&(o=Kt())!==p&&(a=Kt())!==p&&(i=Kt())!==p&&(c=Kt())!==p?r=t=[t,e,n,u,o,a,i,c]:(mt=r,r=p);Et--,r===p&&(t=p,0===Et&&Nt(vr));return r}(),u!==p?e=n=[n,u]:(mt=e,e=p)):(mt=e,e=p))),e!==p?(xt=r,r=ar()):(mt=r,r=p)):(mt=r,r=p),r}function Gt(){var r;return Et++,92===t.charCodeAt(mt)?(r=lr,mt++):(r=p,0===Et&&Nt(hr)),Et--,r===p&&0===Et&&Nt(sr),r}function Kt(){var r;return dr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(gr)),r}function Lt(){var r,e,n;return Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p),e!==p?(Cr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(br)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p),Et--,r===p&&(e=p,0===Et&&Nt($)),r}function Xt(){var r,e,n;if(r=function(){var r,e,n;r=mt,e=mt,Et++,n=Jt(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(n=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(mr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(xr)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt($));return r}(),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p);r===p&&(r=qt());return r}(),r===p){if(r=mt,Gt()!==p)if(It()!==p){for(e=[],(n=Rt())===p&&(n=It());n!==p;)e.push(n),(n=Rt())===p&&(n=It());e!==p?(xt=r,r=yr()):(mt=r,r=p)}else mt=r,r=p;else mt=r,r=p;r===p&&(r=It())}return r}function $t(){var r,e,n;return r=mt,e=mt,Et++,t.substr(mt,3)===K?(n=K,mt+=3):(n=p,0===Et&&Nt(L)),Et--,n===p?e=void 0:(mt=e,e=p),e!==p?(n=function(){var r,e,n;Et++,r=mt,e=mt,Et++,n=It(),Et--,n===p?e=void 0:(mt=e,e=p);e!==p?(Fr.test(t.charAt(mt))?(n=t.charAt(mt),mt++):(n=p,0===Et&&Nt(wr)),n!==p?r=e=[e,n]:(mt=r,r=p)):(mt=r,r=p);Et--,r===p&&(e=p,0===Et&&Nt(Sr));return r}(),n!==p?(xt=r,r=e=Z()):(mt=r,r=p)):(mt=r,r=p),r===p&&(r=It()),r}function re(){var r,e,n,u;return r=mt,101===t.charCodeAt(mt)?(e=Rr,mt++):(e=p,0===Et&&Nt(Ur)),e===p&&(69===t.charCodeAt(mt)?(e=zr,mt++):(e=p,0===Et&&Nt(Qr))),e!==p?((n=ee())===p&&(n=null),n!==p&&(u=ne())!==p?r=e=[e,n,u]:(mt=r,r=p)):(mt=r,r=p),r}function te(){var r,t;return r=mt,(t=ee())===p&&(t=null),t!==p&&ne()!==p?(xt=r,r=t=Yr()):(mt=r,r=p),r}function ee(){var r;return 43===t.charCodeAt(mt)?(r=kr,mt++):(r=p,0===Et&&Nt(Br)),r===p&&(45===t.charCodeAt(mt)?(r=Jr,mt++):(r=p,0===Et&&Nt(Pr))),r}function ne(){var r,e,n,u,o,a;if(r=mt,(e=ue())!==p){for(n=[],u=mt,95===t.charCodeAt(mt)?(o=Zr,mt++):(o=p,0===Et&&Nt(Ir)),o===p&&(o=null),o!==p&&(a=ue())!==p?u=o=[o,a]:(mt=u,u=p);u!==p;)n.push(u),u=mt,95===t.charCodeAt(mt)?(o=Zr,mt++):(o=p,0===Et&&Nt(Ir)),o===p&&(o=null),o!==p&&(a=ue())!==p?u=o=[o,a]:(mt=u,u=p);n!==p?r=e=[e,n]:(mt=r,r=p)}else mt=r,r=p;return r}function ue(){var r;return Vr.test(t.charAt(mt))?(r=t.charAt(mt),mt++):(r=p,0===Et&&Nt(Wr)),r}function oe(){var r,t,e;return Et++,r=mt,(t=ue())!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p),Et--,r===p&&(t=p,0===Et&&Nt(rt)),r}function ae(){var r,t,e;return Et++,r=mt,(t=ue())!==p&&(e=ue())!==p?r=t=[t,e]:(mt=r,r=p),Et--,r===p&&(t=p,0===Et&&Nt(tt)),r}function ie(){var r,e,n,u,o,a,i;if(r=mt,(e=Vt())!==p){for(n=mt,u=[],o=ce();o!==p;)u.push(o),o=ce();if(u!==p)if(44===t.charCodeAt(mt)?(o=ct,mt++):(o=p,0===Et&&Nt(ft)),o!==p){for(a=[],i=ce();i!==p;)a.push(i),i=ce();a!==p&&(i=ie())!==p?n=u=[u,o,a,i]:(mt=n,n=p)}else mt=n,n=p;else mt=n,n=p;n===p&&(n=null),n!==p?(xt=r,r=e=pt(e,n)):(mt=r,r=p)}else mt=r,r=p;return r}function ce(){var r;return(r=Rt())===p&&(r=It())===p&&(r=Ut()),r}function fe(){var r,e,n,u,o,a,i,c,f,s;if(r=mt,91===t.charCodeAt(mt)?(e=at,mt++):(e=p,0===Et&&Nt(it)),e!==p){for(n=[],u=Rt();u!==p;)n.push(u),u=Rt();if(n!==p)if((u=Qt())!==p){for(o=[],a=mt,i=[],c=Rt();c!==p;)i.push(c),c=Rt();if(i!==p)if(46===t.charCodeAt(mt)?(c=_r,mt++):(c=p,0===Et&&Nt(Nr)),c!==p){for(f=[],s=Rt();s!==p;)f.push(s),s=Rt();f!==p&&(s=Qt())!==p?a=i=[i,c,f,s]:(mt=a,a=p)}else mt=a,a=p;else mt=a,a=p;for(;a!==p;){for(o.push(a),a=mt,i=[],c=Rt();c!==p;)i.push(c),c=Rt();if(i!==p)if(46===t.charCodeAt(mt)?(c=_r,mt++):(c=p,0===Et&&Nt(Nr)),c!==p){for(f=[],s=Rt();s!==p;)f.push(s),s=Rt();f!==p&&(s=Qt())!==p?a=i=[i,c,f,s]:(mt=a,a=p)}else mt=a,a=p;else mt=a,a=p}if(o!==p){for(a=[],i=Rt();i!==p;)a.push(i),i=Rt();a!==p?(93===t.charCodeAt(mt)?(i=st,mt++):(i=p,0===Et&&Nt(lt)),i!==p?(xt=r,r=e=yt(u,o)):(mt=r,r=p)):(mt=r,r=p)}else mt=r,r=p}else mt=r,r=p;else mt=r,r=p}else mt=r,r=p;return r}u=function(r){return"Value for "+r+" should not be redefined in the same table."},o=Number.isFinite||function(r){return"number"==typeof r&&isFinite(r)},a=Array.isArray||function(r){return"[object Array]"===Object.prototype.toString.call(r)},i=function(r,t){return Object.prototype.hasOwnProperty.call(r,t)},c="object"==typeof JSON&&JSON?JSON.stringify:function(r){return'"'+String(r).replace(/[\x00-\x1F"\\]/g,(function(r){switch(r){case'"':case"\\":return"\\"+r;case"\t":return"\\t";case"\n":return"\\n";case"\r":return"\\r";case"\b":return"\\b";case"\f":return"\\f";default:var t=r.charCodeAt(0).toString(16);return"\\u"+"0000".substr(t.length)+t}}))+'"'},f=function(r){switch(r){case'"':case"\\":return r;case"t":return"\t";case"n":return"\n";case"r":return"\r";case"b":return"\b";case"f":return"\f";default:Dt(c(r)+" cannot be escaped.")}},s=function(r){if((!o(r)||r<0||r>1114111)&&Dt("U+"+r.toString(16)+" is not a valid Unicode code point."),String.fromCodePoint)return String.fromCodePoint(r);var t="";return r>65535&&(r-=65536,t+=String.fromCharCode(r>>>10&1023|55296),r=56320|1023&r),t+=String.fromCharCode(r)},l=function(r,t){i(r,t)&&Dt(u(c(t)))},h=function(r,t,e){for(var n="",o=0,f=e.length;o{try{return t(n)}catch(t){throw t instanceof r?(t.line=t.location.start.line,t.column=t.location.start.column,t.offset=t.location.start.offset,new e(t.message,t.location.start)):t}};export{e as SyntaxError,n as parse}; -//# sourceMappingURL=toml.js.map diff --git a/pyscript.core/test/terminal.html b/pyscript.core/test/terminal.html deleted file mode 100644 index 10d5254b..00000000 --- a/pyscript.core/test/terminal.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - PyScript Next - Terminal - - - - - - -
- - diff --git a/pyscript.core/test/terminal.py b/pyscript.core/test/terminal.py deleted file mode 100644 index 089614d7..00000000 --- a/pyscript.core/test/terminal.py +++ /dev/null @@ -1,14 +0,0 @@ -###### magic monkey patching ###### -import builtins -import sys - -from pyodide.code import eval_code -from pyscript import sync - -sys.stdout = sync -builtins.input = sync.readline - -####### main code ###### -import code - -code.interact() diff --git a/pyscript.core/types/3rd-party/toml.d.ts b/pyscript.core/types/3rd-party/toml.d.ts new file mode 100644 index 00000000..14f8437c --- /dev/null +++ b/pyscript.core/types/3rd-party/toml.d.ts @@ -0,0 +1,12 @@ +/*! (c) Jak Wings - MIT */ declare class e extends SyntaxError { + constructor(r: any, { offset: t, line: e, column: n }: { + offset: any; + line: any; + column: any; + }); + offset: any; + line: any; + column: any; +} +declare function n(n: any): any; +export { e as SyntaxError, n as parse }; diff --git a/pyscript.core/types/3rd-party/xterm-readline.d.ts b/pyscript.core/types/3rd-party/xterm-readline.d.ts new file mode 100644 index 00000000..99a16d83 --- /dev/null +++ b/pyscript.core/types/3rd-party/xterm-readline.d.ts @@ -0,0 +1,138 @@ +declare var b: any; +declare var I: boolean; +declare namespace r { + export let __esModule: boolean; + export { Readline }; +} +declare class Readline { + highlighter: { + highlight(t: any, e: any): any; + highlightPrompt(t: any): any; + highlightChar(t: any, e: any): boolean; + }; + history: { + entries: any[]; + cursor: number; + maxEntries: any; + saveToLocalStorage(): void; + restoreFromLocalStorage(): void; + append(t: any): void; + resetCursor(): void; + next(): any; + prev(): any; + }; + disposables: any[]; + watermark: number; + highWatermark: number; + lowWatermark: number; + highWater: boolean; + state: { + line: { + buf: string; + pos: number; + buffer(): string; + pos_buffer(): string; + length(): number; + char_length(): number; + update(t: any, e: any): void; + insert(t: any): boolean; + moveBack(t: any): boolean; + moveForward(t: any): boolean; + moveHome(): boolean; + moveEnd(): boolean; + startOfLine(): number; + endOfLine(): number; + moveLineUp(t: any): boolean; + moveLineDown(t: any): boolean; + set_pos(t: any): void; + prevPos(t: any): number; + nextPos(t: any): number; + backspace(t: any): boolean; + delete(t: any): boolean; + deleteEndOfLine(): boolean; + }; + highlighting: boolean; + prompt: any; + tty: any; + highlighter: any; + history: any; + promptSize: any; + layout: p; + buffer(): string; + shouldHighlight(): boolean; + clearScreen(): void; + editInsert(t: any): void; + update(t: any): void; + editBackspace(t: any): void; + editDelete(t: any): void; + editDeleteEndOfLine(): void; + refresh(): void; + moveCursorBack(t: any): void; + moveCursorForward(t: any): void; + moveCursorUp(t: any): void; + moveCursorDown(t: any): void; + moveCursorHome(): void; + moveCursorEnd(): void; + moveCursorToEnd(): void; + previousHistory(): void; + nextHistory(): void; + moveCursor(): void; + }; + checkHandler: () => boolean; + ctrlCHandler: () => void; + pauseHandler: (t: any) => void; + activate(t: any): void; + term: any; + dispose(): void; + appendHistory(t: any): void; + setHighlighter(t: any): void; + setCheckHandler(t: any): void; + setCtrlCHandler(t: any): void; + setPauseHandler(t: any): void; + writeReady(): boolean; + write(t: any): void; + print(t: any): void; + println(t: any): void; + output(): this; + tty(): { + tabWidth: any; + col: any; + row: any; + out: any; + write(t: any): any; + print(t: any): any; + println(t: any): any; + clearScreen(): void; + calculatePosition(t: any, e: any): any; + computeLayout(t: any, e: any): { + promptSize: any; + cursor: any; + end: any; + }; + refreshLine(t: any, e: any, s: any, i: any, r: any): void; + clearOldRows(t: any): void; + moveCursor(t: any, e: any): void; + }; + read(t: any): Promise; + activeRead: { + prompt: any; + resolve: (value: any) => void; + reject: (reason?: any) => void; + }; + handleKeyEvent(t: any): boolean; + readData(t: any): void; + readPaste(t: any): void; + readKey(t: any): void; +} +declare class p { + constructor(t: any); + promptSize: any; + cursor: c; + end: c; +} +declare class c { + constructor(t: any, e: any); + row: any; + col: any; +} +export { b as Readline, I as __esModule, r as default }; diff --git a/pyscript.core/types/3rd-party/xterm.d.ts b/pyscript.core/types/3rd-party/xterm.d.ts new file mode 100644 index 00000000..636fd9ee --- /dev/null +++ b/pyscript.core/types/3rd-party/xterm.d.ts @@ -0,0 +1,4 @@ +declare var i: any; +declare var s: any; +declare var t: {}; +export { i as Terminal, s as __esModule, t as default }; diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts index 0df1bf95..fa33defe 100644 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -1,14 +1,13 @@ -declare const _default: { - pyscript: { +declare namespace _default { + let pyscript: { "__init__.py": string; "display.py": string; "event_handling.py": string; "magic_js.py": string; "util.py": string; }; - "pyscript.py": string; - pyweb: { + let pyweb: { "pydom.py": string; }; -}; +} export default _default; From aef028be6ea1667342264b79995375a54aa367ec Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 3 Nov 2023 15:19:30 +0100 Subject: [PATCH 096/105] Fix #1834 - Throw an error if more than a terminal exists (#1837) --- pyscript.core/src/plugins/py-terminal.js | 18 +++++-- pyscript.core/tests/integration/support.py | 14 ++++++ .../tests/integration/test_01_basic.py | 2 +- .../tests/integration/test_py_terminal.py | 49 ++++++++++++++++--- 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js index c9103f83..e00a5ca6 100644 --- a/pyscript.core/src/plugins/py-terminal.js +++ b/pyscript.core/src/plugins/py-terminal.js @@ -1,27 +1,35 @@ // PyScript py-terminal plugin import { TYPES, hooks } from "../core.js"; +import { notify } from "./error.js"; const SELECTOR = [...TYPES.keys()] .map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`) .join(","); +// show the error on main and +// stops the module from keep executing +const notifyAndThrow = (message) => { + notify(message); + throw new Error(message); +}; + const pyTerminal = async () => { const terminals = document.querySelectorAll(SELECTOR); // no results will look further for runtime nodes if (!terminals.length) return; - // we currently support only one terminal as in "classic" - if (terminals.length > 1) - console.warn("Unable to satisfy multiple terminals"); - // if we arrived this far, let's drop the MutationObserver + // as we only support one terminal per page (right now). mo.disconnect(); + // we currently support only one terminal as in "classic" + if (terminals.length > 1) notifyAndThrow("You can use at most 1 terminal."); + const [element] = terminals; // hopefully to be removed in the near future! if (element.matches('script[type="mpy"],mpy-script')) - throw new Error("Unsupported terminal"); + notifyAndThrow("Unsupported terminal."); // import styles lazily document.head.append( diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py index 5ac02bc0..c2e1089c 100644 --- a/pyscript.core/tests/integration/support.py +++ b/pyscript.core/tests/integration/support.py @@ -118,6 +118,20 @@ def only_main(fn): return decorated +def only_worker(fn): + """ + Decorator to mark a test which make sense only in the worker thread + """ + + @functools.wraps(fn) + def decorated(self, *args): + if self.execution_thread != "worker": + return + return fn(self, *args) + + return decorated + + def filter_inner_text(text, exclude=None): return "\n".join(filter_page_content(text.splitlines(), exclude=exclude)) diff --git a/pyscript.core/tests/integration/test_01_basic.py b/pyscript.core/tests/integration/test_01_basic.py index e2745b60..ffedcc34 100644 --- a/pyscript.core/tests/integration/test_01_basic.py +++ b/pyscript.core/tests/integration/test_01_basic.py @@ -80,7 +80,7 @@ class TestBasic(PyScriptTest): '"Cross-Origin-Opener-Policy":"same-origin"}. ' "The problem may be that one or both of these are missing." ) - alert_banner = self.page.wait_for_selector(".alert-banner") + alert_banner = self.page.wait_for_selector(".py-error") assert expected_alert_banner_msg in alert_banner.inner_text() def test_print(self): diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py index 9d9677c2..989f65cd 100644 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -1,12 +1,45 @@ import time +import pytest from playwright.sync_api import expect -from .support import PyScriptTest, skip_worker +from .support import PageErrors, PyScriptTest, only_worker, skip_worker class TestPyTerminal(PyScriptTest): - @skip_worker("FIXME: the auto worker dance removes terminal") + def test_multiple_terminals(self): + """ + Multiple terminals are not currently supported + """ + self.pyscript_run( + """ + + + """, + wait_for_pyscript=False, + check_js_errors=False, + ) + assert self.assert_banner_message("You can use at most 1 terminal") + + with pytest.raises(PageErrors, match="You can use at most 1 terminal"): + self.check_js_errors() + + @only_worker + def test_py_terminal_input(self): + """ + Only worker py-terminal accepts an input + """ + self.pyscript_run( + """ + + """, + wait_for_pyscript=False, + ) + self.page.get_by_text(">>> ", exact=True).wait_for() + self.page.keyboard.type("'the answer is ' + str(6 * 7)") + self.page.keyboard.press("Enter") + self.page.get_by_text("the answer is 42").wait_for() + def test_py_terminal(self): """ 1. should redirect stdout and stderr to the DOM @@ -21,8 +54,10 @@ class TestPyTerminal(PyScriptTest): print('this goes to stderr', file=sys.stderr) print('this goes to stdout') - """ + """, + wait_for_pyscript=False, ) + self.page.get_by_text("hello world").wait_for() term = self.page.locator("py-terminal") term_lines = term.inner_text().splitlines() assert term_lines[0:3] == [ @@ -31,7 +66,9 @@ class TestPyTerminal(PyScriptTest): "this goes to stdout", ] - @skip_worker("FIXME: the auto worker dance removes terminal") + @skip_worker( + "Workers don't have events + two different workers don't share the same I/O" + ) def test_button_action(self): self.pyscript_run( """ @@ -50,7 +87,6 @@ class TestPyTerminal(PyScriptTest): last_line.wait_for() assert term.inner_text().rstrip() == "hello world" - @skip_worker("FIXME: the auto worker dance removes terminal") def test_xterm_function(self): """Test a few basic behaviors of the xtermjs terminal. @@ -69,7 +105,8 @@ class TestPyTerminal(PyScriptTest): print("\x1b[3mItalic\x1b[23m") print("done") - """ + """, + wait_for_pyscript=False, ) # Wait for "done" to actually appear in the xterm; may be delayed, From 3e2a67d4345edd1ca7a43e29d212b5608d1d243b Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Fri, 3 Nov 2023 17:59:11 +0100 Subject: [PATCH 097/105] PyTerminal: use Pyodide instead of Python (#1833) --- pyscript.core/src/plugins/py-terminal.js | 19 +++++++------------ pyscript.core/test/py-terminal.html | 2 +- .../tests/integration/test_py_terminal.py | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js index e00a5ca6..aa9725bd 100644 --- a/pyscript.core/src/plugins/py-terminal.js +++ b/pyscript.core/src/plugins/py-terminal.js @@ -81,26 +81,23 @@ const pyTerminal = async () => { const workerReady = ({ interpreter }, { sync }) => { sync.pyterminal_drop_hooks(); const decoder = new TextDecoder(); + let data = ""; const generic = { isatty: true, write(buffer) { - sync.pyterminal_write(decoder.decode(buffer)); + data = decoder.decode(buffer); + sync.pyterminal_write(data); return buffer.length; }, }; interpreter.setStdout(generic); interpreter.setStderr(generic); + interpreter.setStdin({ + isatty: true, + stdin: () => sync.pyterminal_read(data), + }); }; - // run in python code able to replace builtins.input - // using the xworker.sync non blocking prompt - const codeBefore = ` - import builtins - from pyscript import sync as _sync - - builtins.input = lambda prompt: _sync.pyterminal_read(prompt) - `; - // at the end of the code, make the terminal interactive const codeAfter = ` import code as _code @@ -121,7 +118,6 @@ const pyTerminal = async () => { // allow a worker to drop main thread hooks ASAP xworker.sync.pyterminal_drop_hooks = () => { hooks.worker.onReady.delete(workerReady); - hooks.worker.codeBeforeRun.delete(codeBefore); hooks.worker.codeAfterRun.delete(codeAfter); }; }); @@ -129,7 +125,6 @@ const pyTerminal = async () => { // setup remote thread JS/Python code for whenever the // worker is ready to become a terminal hooks.worker.onReady.add(workerReady); - hooks.worker.codeBeforeRun.add(codeBefore); hooks.worker.codeAfterRun.add(codeAfter); } else { // in the main case, just bootstrap XTerm without diff --git a/pyscript.core/test/py-terminal.html b/pyscript.core/test/py-terminal.html index fd4429d9..2f83b24f 100644 --- a/pyscript.core/test/py-terminal.html +++ b/pyscript.core/test/py-terminal.html @@ -13,7 +13,7 @@ def greetings(event): print('hello world') - + import sys from pyscript import display display("Hello", "PyScript Next - PyTerminal", append=False) diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py index 989f65cd..ebead1a3 100644 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -40,6 +40,24 @@ class TestPyTerminal(PyScriptTest): self.page.keyboard.press("Enter") self.page.get_by_text("the answer is 42").wait_for() + @only_worker + def test_py_terminal_os_write(self): + """ + An `os.write("text")` should land in the terminal + """ + self.pyscript_run( + """ + + """, + wait_for_pyscript=False, + ) + self.page.get_by_text("hello\n").wait_for() + self.page.get_by_text("world\n").wait_for() + def test_py_terminal(self): """ 1. should redirect stdout and stderr to the DOM From f1a46be73834dc4d9d6efd768c0055bb905f0ba5 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 7 Nov 2023 17:17:40 +0100 Subject: [PATCH 098/105] Fix #1838 - Provides all TS from all projects (#1843) --- pyscript.core/package-lock.json | 172 ++++++++++++++++---------------- pyscript.core/package.json | 10 +- pyscript.core/tsconfig.json | 6 +- pyscript.core/types/core.d.ts | 44 +++++++- pyscript.core/types/fetch.d.ts | 1 + 5 files changed, 135 insertions(+), 98 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index d9eb4740..5512a6bd 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,18 +1,18 @@ { "name": "@pyscript/core", - "version": "0.3.2", + "version": "0.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.3.2", + "version": "0.3.3", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.5.6", - "sticky-module": "^0.1.0", + "polyscript": "^0.5.11", + "sticky-module": "^0.1.1", "to-json-callback": "^0.1.1", "type-checked-collections": "^0.1.7" }, @@ -23,8 +23,8 @@ "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", "chokidar": "^3.5.3", - "eslint": "^8.52.0", - "rollup": "^4.2.0", + "eslint": "^8.53.0", + "rollup": "^4.3.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", @@ -67,9 +67,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -90,9 +90,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.53.0.tgz", + "integrity": "sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -374,9 +374,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.2.0.tgz", - "integrity": "sha512-8PlggAxGxavr+pkCNeV1TM2wTb2o+cUWDg9M1cm9nR27Dsn287uZtSLYXoQqQcmq+sYfF7lHfd3sWJJinH9GmA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.3.0.tgz", + "integrity": "sha512-/4pns6BYi8MXdwnXM44yoGAcFYVHL/BYlB2q1HXZ6AzH++LaiEVWFpBWQ/glXhbMbv3E3o09igrHFbP/snhAvA==", "cpu": [ "arm" ], @@ -387,9 +387,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.2.0.tgz", - "integrity": "sha512-+71T85hbMFrJI+zKQULNmSYBeIhru55PYoF/u75MyeN2FcxE4HSPw20319b+FcZ4lWx2Nx/Ql9tN+hoaD3GH/A==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.3.0.tgz", + "integrity": "sha512-nLO/JsL9idr416vzi3lHm3Xm+QZh4qHij8k3Er13kZr5YhL7/+kBAx84kDmPc7HMexLmwisjDCeDIKNFp8mDlQ==", "cpu": [ "arm64" ], @@ -400,9 +400,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.2.0.tgz", - "integrity": "sha512-IIIQLuG43QIElT1JZqUP/zqIdiJl4t9U/boa0GZnQTw9m1X0k3mlBuysbgYXeloLT1RozdL7bgw4lpSaI8GOXw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.3.0.tgz", + "integrity": "sha512-dGhVBlllt4iHwTGy21IEoMOTN5wZoid19zEIxsdY29xcEiOEHqzDa7Sqrkh5OE7LKCowL61eFJXxYe/+pYa7ZQ==", "cpu": [ "arm64" ], @@ -413,9 +413,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.2.0.tgz", - "integrity": "sha512-BXcXvnLaea1Xz900omrGJhxHFJfH9jZ0CpJuVsbjjhpniJ6qiLXz3xA8Lekaa4MuhFcJd4f0r+Ky1G4VFbYhWw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.3.0.tgz", + "integrity": "sha512-h8wRfHeLEbU3NzaP1Oku7BYXCJQiTRr+8U0lklyOQXxXiEpHLL8tk1hFl+tezoRKLcPJD7joKaK74ASsqt3Ekg==", "cpu": [ "x64" ], @@ -426,9 +426,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.2.0.tgz", - "integrity": "sha512-f4K3MKw9Y4AKi4ANGnmPIglr+S+8tO858YrGVuqAHXxJdVghBmz9CPU9kDpOnGvT4g4vg5uNyIFpOOFvffXyMA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.3.0.tgz", + "integrity": "sha512-wP4VgR/gfV18sylTuym3sxRTkAgUR2vh6YLeX/GEznk5jCYcYSlx585XlcUcl0c8UffIZlRJ09raWSX3JDb4GA==", "cpu": [ "arm" ], @@ -439,9 +439,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.2.0.tgz", - "integrity": "sha512-bNsTYQBgp4H7w6cT7FZhesxpcUPahsSIy4NgdZjH1ZwEoZHxi4XKglj+CsSEkhsKi+x6toVvMylhjRKhEMYfnA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.3.0.tgz", + "integrity": "sha512-v/14JCYVkqRSJeQbxFx4oUkwVQQw6lFMN7bd4vuARBc3X2lmomkxBsc+BFiIDL/BK+CTx5AOh/k9XmqDnKWRVg==", "cpu": [ "arm64" ], @@ -452,9 +452,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.2.0.tgz", - "integrity": "sha512-Jp1NxBJpGLuxRU2ihrQk4IZ+ia5nffobG6sOFUPW5PMYkF0kQtxEbeDuCa69Xif211vUOcxlOnf5IOEIpTEySA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.3.0.tgz", + "integrity": "sha512-tNhfYqFH5OxtRzfkTOKdgFYlPSZnlDLNW4+leNEvQZhwTJxoTwsZAAhR97l3qVry/kkLyJPBK+Q8EAJLPinDIg==", "cpu": [ "arm64" ], @@ -465,9 +465,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.2.0.tgz", - "integrity": "sha512-3p3iRtQmv2aXw+vtKNyZMLOQ+LSRsqArXjKAh2Oj9cqwfIRe7OXvdkOzWfZOIp1F/x5KJzVAxGxnniF4cMbnsQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.3.0.tgz", + "integrity": "sha512-pw77m8QywdsoFdFOgmc8roF1inBI0rciqzO8ffRUgLoq7+ee9o5eFqtEcS6hHOOplgifAUUisP8cAnwl9nUYPw==", "cpu": [ "x64" ], @@ -478,9 +478,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.2.0.tgz", - "integrity": "sha512-atih7IF/reUZe4LBLC5Izd44hth2tfDIG8LaPp4/cQXdHh9jabcZEvIeRPrpDq0i/Uu487Qu5gl5KwyAnWajnw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.3.0.tgz", + "integrity": "sha512-tJs7v2MnV2F8w6X1UpPHl/43OfxjUy9SuJ2ZPoxn79v9vYteChVYO/ueLHCpRMmyTUIVML3N9z4azl9ENH8Xxg==", "cpu": [ "x64" ], @@ -491,9 +491,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.2.0.tgz", - "integrity": "sha512-vYxF3tKJeUE4ceYzpNe2p84RXk/fGK30I8frpRfv/MyPStej/mRlojztkN7Jtd1014HHVeq/tYaMBz/3IxkxZw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.3.0.tgz", + "integrity": "sha512-OKGxp6kATQdTyI2DF+e9s+hB3/QZB45b6e+dzcfW1SUqiF6CviWyevhmT4USsMEdP3mlpC9zxLz3Oh+WaTMOSw==", "cpu": [ "arm64" ], @@ -504,9 +504,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.2.0.tgz", - "integrity": "sha512-1LZJ6zpl93SaPQvas618bMFarVwufWTaczH4ESAbFcwiC4OtznA6Ym+hFPyIGaJaGEB8uMWWac0uXGPXOg5FGA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.3.0.tgz", + "integrity": "sha512-DDZ5AH68JJ2ClQFEA1aNnfA7Ybqyeh0644rGbrLOdNehTmzfICHiWSn0OprzYi9HAshTPQvlwrM+bi2kuaIOjQ==", "cpu": [ "ia32" ], @@ -517,9 +517,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.2.0.tgz", - "integrity": "sha512-dgQfFdHCNg08nM5zBmqxqc9vrm0DVzhWotpavbPa0j4//MAOKZEB75yGAfzQE9fUJ+4pvM1239Y4IhL8f6sSog==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.3.0.tgz", + "integrity": "sha512-dMvGV8p92GQ8jhNlGIKpyhVZPzJlT258pPrM5q2F8lKcc9Iv9BbfdnhX1OfinYWnb9ms5zLw6MlaMnqLfUkKnQ==", "cpu": [ "x64" ], @@ -849,13 +849,13 @@ } }, "node_modules/coincident": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.3.tgz", - "integrity": "sha512-vd5xP+d5vCCcwTTUxQb3LHRi+dhXnuD+Bgjyf1r1H0IPjfXGDs3z2C4RZJifCJmokqf3Ff9BiFealewTBMTgYw==", + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/coincident/-/coincident-0.14.4.tgz", + "integrity": "sha512-XLZs1S0ToZb8jAngtJQa5uFfhOdF168f+jodvkMOVpZl/JI9J+B1WdxX2PwU1vERxmahEubHv9Gr+a3XWOnccw==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", - "gc-hook": "^0.2.3" + "gc-hook": "^0.2.4" }, "optionalDependencies": { "ws": "^8.14.2" @@ -1224,15 +1224,15 @@ } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.53.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.53.0.tgz", + "integrity": "sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", + "@eslint/eslintrc": "^2.1.3", + "@eslint/js": "8.53.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1485,9 +1485,9 @@ } }, "node_modules/gc-hook": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.2.3.tgz", - "integrity": "sha512-XfA+XiE7QzJzonfvNjTXmcyGtprD6m85KEH9fngmxghVR7PJ4f3ZKsLI22QNpWJiDO5EIR6iMzz9wSxLBqw6+A==" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.2.4.tgz", + "integrity": "sha512-IP7xtJGpaqbzj7Jn3KMhvVPVp3W7LXGbtz/D1dd147ocWg/7nl9TT28TQ+/o+qmn1hI2oCrI86vUvv9WlIbGwQ==" }, "node_modules/generic-names": { "version": "4.0.0", @@ -2231,17 +2231,17 @@ } }, "node_modules/polyscript": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.6.tgz", - "integrity": "sha512-T1iufSnsq33K5m2vECiVvgDd5zJiSum+eNv3/SUTb38vIxQpDG2W4aVffoIXIgPYe2Bij/aU2xW1P9M2CHUifw==", + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/polyscript/-/polyscript-0.5.11.tgz", + "integrity": "sha512-/QAp2qkvR9i3n1oSy2mo6DOdCQDRIeZnJhSLjhwghmoAflB0q2VPod21Bl4PS0mlNv50441/zutWix/pFNAsIg==", "dependencies": { "@ungap/structured-clone": "^1.2.0", "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", "codedent": "^0.1.2", - "coincident": "^0.14.3", + "coincident": "^0.14.4", "html-escaper": "^3.0.3", - "sticky-module": "^0.1.0" + "sticky-module": "^0.1.1" } }, "node_modules/postcss": { @@ -2823,9 +2823,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -2924,9 +2924,9 @@ } }, "node_modules/rollup": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.2.0.tgz", - "integrity": "sha512-deaMa9Z+jPVeBD2dKXv+h7EbdKte9++V2potc/ADqvVgEr6DEJ3ia9u0joarjC2lX/ubaCRYz3QVx0TzuVqAJA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.3.0.tgz", + "integrity": "sha512-scIi1NrKLDIYSPK66jjECtII7vIgdAMFmFo8h6qm++I6nN9qDSV35Ku6erzGVqYjx+lj+j5wkusRMr++8SyDZg==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -2936,18 +2936,18 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.2.0", - "@rollup/rollup-android-arm64": "4.2.0", - "@rollup/rollup-darwin-arm64": "4.2.0", - "@rollup/rollup-darwin-x64": "4.2.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.2.0", - "@rollup/rollup-linux-arm64-gnu": "4.2.0", - "@rollup/rollup-linux-arm64-musl": "4.2.0", - "@rollup/rollup-linux-x64-gnu": "4.2.0", - "@rollup/rollup-linux-x64-musl": "4.2.0", - "@rollup/rollup-win32-arm64-msvc": "4.2.0", - "@rollup/rollup-win32-ia32-msvc": "4.2.0", - "@rollup/rollup-win32-x64-msvc": "4.2.0", + "@rollup/rollup-android-arm-eabi": "4.3.0", + "@rollup/rollup-android-arm64": "4.3.0", + "@rollup/rollup-darwin-arm64": "4.3.0", + "@rollup/rollup-darwin-x64": "4.3.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.3.0", + "@rollup/rollup-linux-arm64-gnu": "4.3.0", + "@rollup/rollup-linux-arm64-musl": "4.3.0", + "@rollup/rollup-linux-x64-gnu": "4.3.0", + "@rollup/rollup-linux-x64-musl": "4.3.0", + "@rollup/rollup-win32-arm64-msvc": "4.3.0", + "@rollup/rollup-win32-ia32-msvc": "4.3.0", + "@rollup/rollup-win32-x64-msvc": "4.3.0", "fsevents": "~2.3.2" } }, @@ -3139,9 +3139,9 @@ } }, "node_modules/sticky-module": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/sticky-module/-/sticky-module-0.1.0.tgz", - "integrity": "sha512-MYmkk/ihfpzQjOPfxbqScT2JS72H/8ueUtnBxxZiJbHopmJ1Lw62Lq/IimL34czVf1oQoG0Be/TDtJUyNVdEvA==" + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/sticky-module/-/sticky-module-0.1.1.tgz", + "integrity": "sha512-IuYgnyIMUx/m6rtu14l/LR2MaqOLtpXcWkxPmtPsiScRHEo+S4Tojk+DWFHOncSdFX/OsoLOM4+T92yOmI1AMw==" }, "node_modules/string-hash": { "version": "1.1.3", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 4a8415e2..98b4ffac 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.3.2", + "version": "0.3.3", "type": "module", "description": "PyScript", "module": "./index.js", @@ -41,8 +41,8 @@ "dependencies": { "@ungap/with-resolvers": "^0.1.0", "basic-devtools": "^0.1.6", - "polyscript": "^0.5.6", - "sticky-module": "^0.1.0", + "polyscript": "^0.5.11", + "sticky-module": "^0.1.1", "to-json-callback": "^0.1.1", "type-checked-collections": "^0.1.7" }, @@ -53,8 +53,8 @@ "@rollup/plugin-terser": "^0.4.4", "@webreflection/toml-j0.4": "^1.1.3", "chokidar": "^3.5.3", - "eslint": "^8.52.0", - "rollup": "^4.2.0", + "eslint": "^8.53.0", + "rollup": "^4.3.0", "rollup-plugin-postcss": "^4.0.2", "rollup-plugin-string": "^3.0.0", "static-handler": "^0.4.3", diff --git a/pyscript.core/tsconfig.json b/pyscript.core/tsconfig.json index e47fd091..f9fc9e68 100644 --- a/pyscript.core/tsconfig.json +++ b/pyscript.core/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "module": "ES2022", - "target": "ES2022", - "moduleResolution": "Classic", + "module": "NodeNext", + "target": "esnext", + "moduleResolution": "nodenext", "allowJs": true, "declaration": true, "emitDeclarationOnly": true, diff --git a/pyscript.core/types/core.d.ts b/pyscript.core/types/core.d.ts index 4a597f46..371bfc43 100644 --- a/pyscript.core/types/core.d.ts +++ b/pyscript.core/types/core.d.ts @@ -1,6 +1,42 @@ import TYPES from "./types.js"; -declare const exportedPyWorker: any; -declare const exportedHooks: any; -declare const exportedConfig: any; -declare const exportedWhenDefined: any; +/** + * A `Worker` facade able to bootstrap on the worker thread only a PyScript module. + * @param {string} file the python file to run ina worker. + * @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker. + * @returns {Worker & {sync: ProxyHandler}} + */ +declare function exportedPyWorker(file: string, options?: { + config?: string | object; + async?: boolean; +}): Worker & { + sync: ProxyHandler; +}; +declare const exportedHooks: { + main: { + onWorker: Set; + onReady: Set; + onBeforeRun: Set; + onBeforeRunAsync: Set; + onAfterRun: Set; + onAfterRunAsync: Set; + codeBeforeRun: Set; + codeBeforeRunAsync: Set; + codeAfterRun: Set; + codeAfterRunAsync: Set; + }; + worker: { + onReady: Set; + onBeforeRun: Set; + onBeforeRunAsync: Set; + onAfterRun: Set; + onAfterRunAsync: Set; + codeBeforeRun: Set; + codeBeforeRunAsync: Set; + codeAfterRun: Set; + codeAfterRunAsync: Set; + }; +}; +declare const exportedConfig: {}; +declare const exportedWhenDefined: (type: string) => Promise; +import sync from "./sync.js"; export { TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined }; diff --git a/pyscript.core/types/fetch.d.ts b/pyscript.core/types/fetch.d.ts index e3ce97ef..83b6bed2 100644 --- a/pyscript.core/types/fetch.d.ts +++ b/pyscript.core/types/fetch.d.ts @@ -9,3 +9,4 @@ */ export function robustFetch(url: string, options?: Request): Promise; export { getText }; +import { getText } from "polyscript/exports"; From 2d50ca86a672596e6ed7d36b2a3612b508bb5bb9 Mon Sep 17 00:00:00 2001 From: Andrea Giammarchi Date: Tue, 7 Nov 2023 19:22:08 +0100 Subject: [PATCH 099/105] Fix #1840 - Do not bootstrap interactive shell (#1846) --- pyscript.core/package-lock.json | 4 +-- pyscript.core/package.json | 2 +- pyscript.core/src/plugins/py-terminal.js | 8 ----- pyscript.core/test/py-terminal.html | 3 +- .../tests/integration/test_py_terminal.py | 31 ++++++++++--------- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/pyscript.core/package-lock.json b/pyscript.core/package-lock.json index 5512a6bd..81e5a1d1 100644 --- a/pyscript.core/package-lock.json +++ b/pyscript.core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pyscript/core", - "version": "0.3.3", + "version": "0.3.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@pyscript/core", - "version": "0.3.3", + "version": "0.3.4", "license": "APACHE-2.0", "dependencies": { "@ungap/with-resolvers": "^0.1.0", diff --git a/pyscript.core/package.json b/pyscript.core/package.json index 98b4ffac..e7cbadc3 100644 --- a/pyscript.core/package.json +++ b/pyscript.core/package.json @@ -1,6 +1,6 @@ { "name": "@pyscript/core", - "version": "0.3.3", + "version": "0.3.4", "type": "module", "description": "PyScript", "module": "./index.js", diff --git a/pyscript.core/src/plugins/py-terminal.js b/pyscript.core/src/plugins/py-terminal.js index aa9725bd..c8ecf702 100644 --- a/pyscript.core/src/plugins/py-terminal.js +++ b/pyscript.core/src/plugins/py-terminal.js @@ -98,12 +98,6 @@ const pyTerminal = async () => { }); }; - // at the end of the code, make the terminal interactive - const codeAfter = ` - import code as _code - _code.interact() - `; - // add a hook on the main thread to setup all sync helpers // also bootstrapping the XTerm target on main hooks.main.onWorker.add(function worker(_, xworker) { @@ -118,14 +112,12 @@ const pyTerminal = async () => { // allow a worker to drop main thread hooks ASAP xworker.sync.pyterminal_drop_hooks = () => { hooks.worker.onReady.delete(workerReady); - hooks.worker.codeAfterRun.delete(codeAfter); }; }); // setup remote thread JS/Python code for whenever the // worker is ready to become a terminal hooks.worker.onReady.add(workerReady); - hooks.worker.codeAfterRun.add(codeAfter); } else { // in the main case, just bootstrap XTerm without // allowing any input as that's not possible / awkward diff --git a/pyscript.core/test/py-terminal.html b/pyscript.core/test/py-terminal.html index 2f83b24f..9570c45b 100644 --- a/pyscript.core/test/py-terminal.html +++ b/pyscript.core/test/py-terminal.html @@ -15,13 +15,14 @@ import sys - from pyscript import display + from pyscript import display, document display("Hello", "PyScript Next - PyTerminal", append=False) print("this should go to the terminal") print("another line") # this works as expected print("this goes to stderr", file=sys.stderr) + document.addEventListener('click', lambda event: print(event.type)); diff --git a/pyscript.core/tests/integration/test_py_terminal.py b/pyscript.core/tests/integration/test_py_terminal.py index ebead1a3..0fd70fec 100644 --- a/pyscript.core/tests/integration/test_py_terminal.py +++ b/pyscript.core/tests/integration/test_py_terminal.py @@ -24,21 +24,22 @@ class TestPyTerminal(PyScriptTest): with pytest.raises(PageErrors, match="You can use at most 1 terminal"): self.check_js_errors() - @only_worker - def test_py_terminal_input(self): - """ - Only worker py-terminal accepts an input - """ - self.pyscript_run( - """ - - """, - wait_for_pyscript=False, - ) - self.page.get_by_text(">>> ", exact=True).wait_for() - self.page.keyboard.type("'the answer is ' + str(6 * 7)") - self.page.keyboard.press("Enter") - self.page.get_by_text("the answer is 42").wait_for() + # TODO: interactive shell still unclear + # @only_worker + # def test_py_terminal_input(self): + # """ + # Only worker py-terminal accepts an input + # """ + # self.pyscript_run( + # """ + # + # """, + # wait_for_pyscript=False, + # ) + # self.page.get_by_text(">>> ", exact=True).wait_for() + # self.page.keyboard.type("'the answer is ' + str(6 * 7)") + # self.page.keyboard.press("Enter") + # self.page.get_by_text("the answer is 42").wait_for() @only_worker def test_py_terminal_os_write(self): From d58237ea15e3862dad61e3c5ca77d229bc2df21a Mon Sep 17 00:00:00 2001 From: Jeff Glass Date: Tue, 7 Nov 2023 16:37:10 -0600 Subject: [PATCH 100/105] Update link to not use /latest (#1847) * Update link in README.me to use specific version, not /latest --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 11fb03d5..912c8b3c 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,14 @@ To try PyScript, import the appropriate pyscript files into the `` tag of ```html - - + + ``` From 0955a6be49a6491f7d7b06b1504ae7bf7da1d01c Mon Sep 17 00:00:00 2001 From: Nicholas Tollervey Date: Wed, 8 Nov 2023 13:28:12 +0000 Subject: [PATCH 101/105] Re-add CHANGELOG.md into root of the repository. (#1851) * Re-add CHANGELOG.md from the tip of "classic" into root of the repository. Tidy the formatting in CHANGELOG.md. Update the PR template to reflect the new location of the CHANGELOG.md. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Replace with specific version. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CHANGELOG.md | 87 ++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d5bf9b2d..3d816e97 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,5 +11,5 @@ - [ ] All tests pass locally -- [ ] I have updated `docs/changelog.md` +- [ ] I have updated `CHANGELOG.md` - [ ] I have created documentation for this(if applicable) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..c536d8c4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,87 @@ +# Release Notes + +## 2023.05.01 + +### Features + +- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal. +- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes. +- Added the `@when` decorator for attaching Python functions as event handlers +- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release. + +#### Runtime py- attributes + +- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435)) + +#### <script type="py"> + +- Added the ability to optionally use ` From e750fa7393cbdc0ce057447daf640999c4eeab03 Mon Sep 17 00:00:00 2001 From: Fabio Pliger Date: Fri, 10 Nov 2023 10:18:30 -0600 Subject: [PATCH 105/105] Add Deprecation message when loading from latest (#1848) * add tests to verify if we show an error banner when users load from latest * add deprecation manager to take care of showing a notification in case script src is being loaded from latest * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * make sure deprecation warning also register onWorker * restore tests for banner in worker * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * add a wait selector when testing banner since worker seems to take too long to render in CI * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix test_deprecate_loading_scripts_from_latest: I think that the previous failure was because we actually TRIED to execute the js from latest/core.js and it conflicted with our local copy. But to trigger the warning is enough to have a script pointing to pyscript.net/latest, there is no need to execute it: modify it with type="ignore-me" and an URL which doesn't exist. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Antonio Cuni --- .../src/plugins/deprecations-manager.js | 27 ++++++++++++++++++ pyscript.core/tests/integration/support.py | 4 ++- .../integration/test_warnings_and_banners.py | 28 +++++++++++++++++-- pyscript.core/types/plugins.d.ts | 1 + .../types/plugins/deprecations-manager.d.ts | 1 + pyscript.core/types/stdlib/pyscript.d.ts | 9 +++--- 6 files changed, 61 insertions(+), 9 deletions(-) create mode 100644 pyscript.core/src/plugins/deprecations-manager.js create mode 100644 pyscript.core/types/plugins/deprecations-manager.d.ts diff --git a/pyscript.core/src/plugins/deprecations-manager.js b/pyscript.core/src/plugins/deprecations-manager.js new file mode 100644 index 00000000..f57d18bd --- /dev/null +++ b/pyscript.core/src/plugins/deprecations-manager.js @@ -0,0 +1,27 @@ +// PyScript Derepcations Plugin +import { hooks } from "../core.js"; +import { notify } from "./error.js"; + +// react lazily on PyScript bootstrap +hooks.main.onReady.add(checkDeprecations); +hooks.main.onWorker.add(checkDeprecations); + +/** + * Check that there are no scripts loading from pyscript.net/latest + */ +function checkDeprecations() { + const scripts = document.querySelectorAll("script"); + for (const script of scripts) checkLoadingScriptsFromLatest(script.src); +} + +/** + * Check if src being loaded from pyscript.net/latest and display a notification if true + * * @param {string} src + */ +function checkLoadingScriptsFromLatest(src) { + if (/\/pyscript\.net\/latest/.test(src)) { + notify( + "Loading scripts from latest is deprecated and will be removed soon. Please use a specific version instead.", + ); + } +} diff --git a/pyscript.core/tests/integration/support.py b/pyscript.core/tests/integration/support.py index c2e1089c..4cc40db7 100644 --- a/pyscript.core/tests/integration/support.py +++ b/pyscript.core/tests/integration/support.py @@ -545,7 +545,9 @@ class PyScriptTest: - wait until pyscript has been fully loaded """ doc = self._pyscript_format( - snippet, execution_thread=self.execution_thread, extra_head=extra_head + snippet, + execution_thread=self.execution_thread, + extra_head=extra_head, ) if not wait_for_pyscript and timeout is not None: raise ValueError("Cannot set a timeout if wait_for_pyscript=False") diff --git a/pyscript.core/tests/integration/test_warnings_and_banners.py b/pyscript.core/tests/integration/test_warnings_and_banners.py index 9325ce94..6ffb726f 100644 --- a/pyscript.core/tests/integration/test_warnings_and_banners.py +++ b/pyscript.core/tests/integration/test_warnings_and_banners.py @@ -1,13 +1,35 @@ import pytest -from .support import PyScriptTest - -pytest.skip(reason="NEXT: Restore the banner", allow_module_level=True) +from .support import PyScriptTest, skip_worker class TestWarningsAndBanners(PyScriptTest): # Test the behavior of generated warning banners + def test_deprecate_loading_scripts_from_latest(self): + # Use a script tag with an invalid output attribute to generate a warning, but only one + self.pyscript_run( + """ + + """, + extra_head='', + ) + + # wait for the banner to appear (we could have a page.locater call but for some reason + # the worker takes to long to render on CI, since it's a test we can afford 2 calls) + loc = self.page.wait_for_selector(".py-error") + assert ( + loc.inner_text() + == "Loading scripts from latest is deprecated and will be removed soon. Please use a specific version instead." + ) + + # Only one banner should appear + loc = self.page.locator(".py-error") + assert loc.count() == 1 + + @pytest.mark.skip("NEXT: To check if behaviour is consistent with classic") def test_create_singular_warning(self): # Use a script tag with an invalid output attribute to generate a warning, but only one self.pyscript_run( diff --git a/pyscript.core/types/plugins.d.ts b/pyscript.core/types/plugins.d.ts index abce670d..286e91d0 100644 --- a/pyscript.core/types/plugins.d.ts +++ b/pyscript.core/types/plugins.d.ts @@ -1,4 +1,5 @@ declare const _default: { + "deprecations-manager": () => Promise; error: () => Promise; "py-terminal": () => Promise; }; diff --git a/pyscript.core/types/plugins/deprecations-manager.d.ts b/pyscript.core/types/plugins/deprecations-manager.d.ts new file mode 100644 index 00000000..cb0ff5c3 --- /dev/null +++ b/pyscript.core/types/plugins/deprecations-manager.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/pyscript.core/types/stdlib/pyscript.d.ts b/pyscript.core/types/stdlib/pyscript.d.ts index 0df1bf95..fa33defe 100644 --- a/pyscript.core/types/stdlib/pyscript.d.ts +++ b/pyscript.core/types/stdlib/pyscript.d.ts @@ -1,14 +1,13 @@ -declare const _default: { - pyscript: { +declare namespace _default { + let pyscript: { "__init__.py": string; "display.py": string; "event_handling.py": string; "magic_js.py": string; "util.py": string; }; - "pyscript.py": string; - pyweb: { + let pyweb: { "pydom.py": string; }; -}; +} export default _default;