@pyscript/core 0.2.9 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dev.cjs +31 -0
- package/dist/core.js +4 -3
- package/dist/core.js.map +1 -1
- package/dist/error-96hMSEw8.js +2 -0
- package/dist/error-96hMSEw8.js.map +1 -0
- package/docs/README.md +1 -1
- package/package.json +15 -5
- package/src/core.js +164 -134
- package/src/exceptions.js +4 -2
- package/src/fetch.js +1 -1
- package/src/hooks.js +85 -22
- package/src/plugins/error.js +2 -2
- package/src/plugins-helper.js +26 -0
- package/types/core.d.ts +5 -16
- package/types/hooks.d.ts +37 -12
- package/types/plugins-helper.d.ts +2 -0
- package/dist/error-q53fTtv2.js +0 -2
- package/dist/error-q53fTtv2.js.map +0 -1
@@ -0,0 +1,2 @@
|
|
1
|
+
import{hooks as e}from"./core.js";function o(e){const o=document.createElement("div");o.className="py-error",o.textContent=e,o.style.cssText="\n border: 1px solid red;\n background: #ffdddd;\n color: black;\n font-family: courier, monospace;\n white-space: pre;\n overflow-x: auto;\n padding: 8px;\n margin-top: 8px;\n ",document.body.append(o)}e.main.onReady.add((function n(r){e.main.onReady.delete(n);const{stderr:t}=r.io;r.io.stderr=(e,...n)=>(o(e.message||e),t(e,...n)),addEventListener("error",(({message:e})=>{e.startsWith("Uncaught PythonError")&&o(e)}))}));export{o as notify};
|
2
|
+
//# sourceMappingURL=error-96hMSEw8.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"error-96hMSEw8.js","sources":["../src/plugins/error.js"],"sourcesContent":["// PyScript Error Plugin\nimport { hooks } from \"../core.js\";\n\nhooks.main.onReady.add(function override(pyScript) {\n // be sure this override happens only once\n hooks.main.onReady.delete(override);\n\n // trap generic `stderr` to propagate to it regardless\n const { stderr } = pyScript.io;\n\n // override it with our own logic\n pyScript.io.stderr = (error, ...rest) => {\n notify(error.message || error);\n // let other plugins or stderr hook, if any, do the rest\n return stderr(error, ...rest);\n };\n\n // be sure uncaught Python errors are also visible\n addEventListener(\"error\", ({ message }) => {\n if (message.startsWith(\"Uncaught PythonError\")) notify(message);\n });\n});\n\n// Error hook utilities\n\n// Custom function to show notifications\n\n/**\n * Add a banner to the top of the page, notifying the user of an error\n * @param {string} message\n */\nexport function notify(message) {\n const div = document.createElement(\"div\");\n div.className = \"py-error\";\n div.textContent = message;\n div.style.cssText = `\n border: 1px solid red;\n background: #ffdddd;\n color: black;\n font-family: courier, monospace;\n white-space: pre;\n overflow-x: auto;\n padding: 8px;\n margin-top: 8px;\n `;\n document.body.append(div);\n}\n"],"names":["notify","message","div","document","createElement","className","textContent","style","cssText","body","append","hooks","main","onReady","add","override","pyScript","delete","stderr","io","error","rest","addEventListener","startsWith"],"mappings":"kCA+BO,SAASA,EAAOC,GACnB,MAAMC,EAAMC,SAASC,cAAc,OACnCF,EAAIG,UAAY,WAChBH,EAAII,YAAcL,EAClBC,EAAIK,MAAMC,QAAU,6MAUpBL,SAASM,KAAKC,OAAOR,EACzB,CA3CAS,EAAMC,KAAKC,QAAQC,KAAI,SAASC,EAASC,GAErCL,EAAMC,KAAKC,QAAQI,OAAOF,GAG1B,MAAMG,OAAEA,GAAWF,EAASG,GAG5BH,EAASG,GAAGD,OAAS,CAACE,KAAUC,KAC5BrB,EAAOoB,EAAMnB,SAAWmB,GAEjBF,EAAOE,KAAUC,IAI5BC,iBAAiB,SAAS,EAAGrB,cACrBA,EAAQsB,WAAW,yBAAyBvB,EAAOC,EAAQ,GAEvE"}
|
package/docs/README.md
CHANGED
@@ -159,7 +159,7 @@ The commonly shared utilities are:
|
|
159
159
|
* **display** in both main and worker, refers to the good old `display` utility except:
|
160
160
|
* in the *main* it automatically uses the current script `target` to display content
|
161
161
|
* 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
|
162
|
-
* in both main and worker, the `append=
|
162
|
+
* in both main and worker, the `append=True` is the *default* behavior, which is inherited from the classic PyScript.
|
163
163
|
|
164
164
|
#### Extra main-only features
|
165
165
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@pyscript/core",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.3.0",
|
4
4
|
"type": "module",
|
5
5
|
"description": "PyScript",
|
6
6
|
"module": "./index.js",
|
@@ -20,9 +20,16 @@
|
|
20
20
|
},
|
21
21
|
"scripts": {
|
22
22
|
"server": "npx static-handler --coi .",
|
23
|
-
"build": "
|
23
|
+
"build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts",
|
24
|
+
"build:core": "rm -rf dist && rollup --config rollup/core.config.js",
|
25
|
+
"build:plugins": "node rollup/plugins.cjs",
|
26
|
+
"build:stdlib": "node rollup/stdlib.cjs",
|
27
|
+
"build:toml": "node rollup/toml.cjs",
|
28
|
+
"dev": "node dev.cjs",
|
29
|
+
"release": "npm run build && npm run zip",
|
24
30
|
"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",
|
25
|
-
"ts": "tsc -p ."
|
31
|
+
"ts": "tsc -p .",
|
32
|
+
"zip": "zip -r dist.zip ./dist"
|
26
33
|
},
|
27
34
|
"keywords": [
|
28
35
|
"pyscript",
|
@@ -33,14 +40,17 @@
|
|
33
40
|
"dependencies": {
|
34
41
|
"@ungap/with-resolvers": "^0.1.0",
|
35
42
|
"basic-devtools": "^0.1.6",
|
36
|
-
"polyscript": "^0.
|
43
|
+
"polyscript": "^0.5.1",
|
44
|
+
"sticky-module": "^0.1.0",
|
45
|
+
"to-json-callback": "^0.1.1",
|
37
46
|
"type-checked-collections": "^0.1.7"
|
38
47
|
},
|
39
48
|
"devDependencies": {
|
40
49
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
41
50
|
"@rollup/plugin-terser": "^0.4.4",
|
42
51
|
"@webreflection/toml-j0.4": "^1.1.3",
|
43
|
-
"
|
52
|
+
"chokidar": "^3.5.3",
|
53
|
+
"eslint": "^8.52.0",
|
44
54
|
"rollup": "^4.1.4",
|
45
55
|
"rollup-plugin-postcss": "^4.0.2",
|
46
56
|
"rollup-plugin-string": "^3.0.0",
|
package/src/core.js
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
/*! (c) PyScript Development Team */
|
2
2
|
|
3
|
+
import stickyModule from "sticky-module";
|
3
4
|
import "@ungap/with-resolvers";
|
4
5
|
|
5
|
-
// These imports can hook more than usual and help debugging possible polyscript issues
|
6
6
|
import {
|
7
7
|
INVALID_CONTENT,
|
8
|
-
|
8
|
+
Hook,
|
9
9
|
XWorker,
|
10
|
-
|
11
|
-
import { queryTarget } from "../node_modules/polyscript/esm/script-handler.js";
|
12
|
-
import {
|
10
|
+
assign,
|
13
11
|
dedent,
|
12
|
+
define,
|
13
|
+
defineProperty,
|
14
14
|
dispatch,
|
15
|
+
queryTarget,
|
15
16
|
unescape,
|
16
|
-
|
17
|
-
|
17
|
+
whenDefined,
|
18
|
+
} from "polyscript/exports";
|
18
19
|
|
19
20
|
import "./all-done.js";
|
20
21
|
import TYPES from "./types.js";
|
21
22
|
import configs from "./config.js";
|
22
|
-
import hooks from "./hooks.js";
|
23
23
|
import sync from "./sync.js";
|
24
24
|
import stdlib from "./stdlib.js";
|
25
|
+
import bootstrapNodeAndPlugins from "./plugins-helper.js";
|
25
26
|
import { ErrorCode } from "./exceptions.js";
|
26
27
|
import { robustFetch as fetch, getText } from "./fetch.js";
|
27
|
-
|
28
|
-
const { assign, defineProperty } = Object;
|
28
|
+
import { hooks, main, worker, codeFor, createFunction } from "./hooks.js";
|
29
29
|
|
30
30
|
// allows lazy element features on code evaluation
|
31
31
|
let currentElement;
|
@@ -33,25 +33,6 @@ let currentElement;
|
|
33
33
|
// generic helper to disambiguate between custom element and script
|
34
34
|
const isScript = ({ tagName }) => tagName === "SCRIPT";
|
35
35
|
|
36
|
-
// helper for all script[type="py"] out there
|
37
|
-
const before = (script) => {
|
38
|
-
defineProperty(document, "currentScript", {
|
39
|
-
configurable: true,
|
40
|
-
get: () => script,
|
41
|
-
});
|
42
|
-
};
|
43
|
-
|
44
|
-
const after = () => {
|
45
|
-
delete document.currentScript;
|
46
|
-
};
|
47
|
-
|
48
|
-
// common life-cycle handlers for any node
|
49
|
-
const bootstrapNodeAndPlugins = (wrap, element, callback, hook) => {
|
50
|
-
// make it possible to reach the current target node via Python
|
51
|
-
callback(element);
|
52
|
-
for (const fn of hooks[hook]) fn(wrap, element);
|
53
|
-
};
|
54
|
-
|
55
36
|
let shouldRegister = true;
|
56
37
|
const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
|
57
38
|
// automatically use the pyscript stderr (when/if defined)
|
@@ -75,21 +56,35 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
|
|
75
56
|
interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") });
|
76
57
|
};
|
77
58
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
59
|
+
// avoid multiple initialization of the same library
|
60
|
+
const [
|
61
|
+
{
|
62
|
+
PyWorker: exportedPyWorker,
|
63
|
+
hooks: exportedHooks,
|
64
|
+
config: exportedConfig,
|
65
|
+
whenDefined: exportedWhenDefined,
|
66
|
+
},
|
67
|
+
alreadyLive,
|
68
|
+
] = stickyModule("@pyscript/core", {
|
69
|
+
PyWorker,
|
70
|
+
hooks,
|
71
|
+
config: {},
|
72
|
+
whenDefined,
|
73
|
+
});
|
74
|
+
|
75
|
+
export {
|
76
|
+
exportedPyWorker as PyWorker,
|
77
|
+
exportedHooks as hooks,
|
78
|
+
exportedConfig as config,
|
79
|
+
exportedWhenDefined as whenDefined,
|
87
80
|
};
|
88
81
|
|
89
|
-
const
|
90
|
-
export { exportedConfig as config, hooks };
|
82
|
+
const hooked = new Map();
|
91
83
|
|
92
84
|
for (const [TYPE, interpreter] of TYPES) {
|
85
|
+
// avoid any dance if the module already landed
|
86
|
+
if (alreadyLive) break;
|
87
|
+
|
93
88
|
const dispatchDone = (element, isAsync, result) => {
|
94
89
|
if (isAsync) result.then(() => dispatch(element, TYPE, "done"));
|
95
90
|
else dispatch(element, TYPE, "done");
|
@@ -135,106 +130,140 @@ for (const [TYPE, interpreter] of TYPES) {
|
|
135
130
|
// possible early errors sent by polyscript
|
136
131
|
const errors = new Map();
|
137
132
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
onWorkerReady(_, xworker) {
|
148
|
-
assign(xworker.sync, sync);
|
149
|
-
for (const callback of hooks.onWorkerReady)
|
150
|
-
callback(_, xworker);
|
151
|
-
},
|
152
|
-
onBeforeRun(wrap, element) {
|
153
|
-
currentElement = element;
|
154
|
-
bootstrapNodeAndPlugins(
|
155
|
-
wrap,
|
156
|
-
element,
|
157
|
-
before,
|
158
|
-
"onBeforeRun",
|
159
|
-
);
|
160
|
-
},
|
161
|
-
onBeforeRunAsync(wrap, element) {
|
162
|
-
currentElement = element;
|
163
|
-
bootstrapNodeAndPlugins(
|
164
|
-
wrap,
|
165
|
-
element,
|
166
|
-
before,
|
167
|
-
"onBeforeRunAsync",
|
168
|
-
);
|
169
|
-
},
|
170
|
-
onAfterRun(wrap, element) {
|
171
|
-
bootstrapNodeAndPlugins(wrap, element, after, "onAfterRun");
|
172
|
-
},
|
173
|
-
onAfterRunAsync(wrap, element) {
|
174
|
-
bootstrapNodeAndPlugins(
|
175
|
-
wrap,
|
176
|
-
element,
|
177
|
-
after,
|
178
|
-
"onAfterRunAsync",
|
179
|
-
);
|
180
|
-
},
|
181
|
-
async onInterpreterReady(wrap, element) {
|
182
|
-
if (shouldRegister) {
|
183
|
-
shouldRegister = false;
|
184
|
-
registerModule(wrap);
|
185
|
-
}
|
133
|
+
// specific main and worker hooks
|
134
|
+
const hooks = {
|
135
|
+
main: {
|
136
|
+
...codeFor(main),
|
137
|
+
async onReady(wrap, element) {
|
138
|
+
if (shouldRegister) {
|
139
|
+
shouldRegister = false;
|
140
|
+
registerModule(wrap);
|
141
|
+
}
|
186
142
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
143
|
+
// allows plugins to do whatever they want with the element
|
144
|
+
// before regular stuff happens in here
|
145
|
+
for (const callback of main("onReady"))
|
146
|
+
await callback(wrap, element);
|
191
147
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
148
|
+
// now that all possible plugins are configured,
|
149
|
+
// bail out if polyscript encountered an error
|
150
|
+
if (errors.has(element)) {
|
151
|
+
let { message } = errors.get(element);
|
152
|
+
errors.delete(element);
|
153
|
+
const clone = message === INVALID_CONTENT;
|
154
|
+
message = `(${ErrorCode.CONFLICTING_CODE}) ${message} for `;
|
155
|
+
message += element.cloneNode(clone).outerHTML;
|
156
|
+
wrap.io.stderr(message);
|
157
|
+
return;
|
158
|
+
}
|
203
159
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
160
|
+
if (isScript(element)) {
|
161
|
+
const {
|
162
|
+
attributes: { async: isAsync, target },
|
163
|
+
} = element;
|
164
|
+
const hasTarget = !!target?.value;
|
165
|
+
const show = hasTarget
|
166
|
+
? queryTarget(element, target.value)
|
167
|
+
: document.createElement("script-py");
|
212
168
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
169
|
+
if (!hasTarget) {
|
170
|
+
const { head, body } = document;
|
171
|
+
if (head.contains(element)) body.append(show);
|
172
|
+
else element.after(show);
|
173
|
+
}
|
174
|
+
if (!show.id) show.id = getID();
|
219
175
|
|
220
|
-
|
221
|
-
|
222
|
-
|
176
|
+
// allows the code to retrieve the target element via
|
177
|
+
// document.currentScript.target if needed
|
178
|
+
defineProperty(element, "target", { value: show });
|
223
179
|
|
224
|
-
|
225
|
-
|
226
|
-
|
180
|
+
// notify before the code runs
|
181
|
+
dispatch(element, TYPE, "ready");
|
182
|
+
dispatchDone(
|
183
|
+
element,
|
184
|
+
isAsync,
|
185
|
+
wrap[`run${isAsync ? "Async" : ""}`](
|
186
|
+
await fetchSource(element, wrap.io, true),
|
187
|
+
),
|
188
|
+
);
|
189
|
+
} else {
|
190
|
+
// resolve PyScriptElement to allow connectedCallback
|
191
|
+
element._wrap.resolve(wrap);
|
192
|
+
}
|
193
|
+
console.debug("[pyscript/main] PyScript Ready");
|
194
|
+
},
|
195
|
+
onWorker(_, xworker) {
|
196
|
+
assign(xworker.sync, sync);
|
197
|
+
for (const callback of main("onWorker"))
|
198
|
+
callback(_, xworker);
|
199
|
+
},
|
200
|
+
onBeforeRun(wrap, element) {
|
201
|
+
currentElement = element;
|
202
|
+
bootstrapNodeAndPlugins(
|
203
|
+
main,
|
204
|
+
wrap,
|
227
205
|
element,
|
228
|
-
|
229
|
-
wrap[`run${isAsync ? "Async" : ""}`](
|
230
|
-
await fetchSource(element, wrap.io, true),
|
231
|
-
),
|
206
|
+
"onBeforeRun",
|
232
207
|
);
|
233
|
-
}
|
234
|
-
|
235
|
-
element
|
236
|
-
|
237
|
-
|
208
|
+
},
|
209
|
+
onBeforeRunAsync(wrap, element) {
|
210
|
+
currentElement = element;
|
211
|
+
return bootstrapNodeAndPlugins(
|
212
|
+
main,
|
213
|
+
wrap,
|
214
|
+
element,
|
215
|
+
"onBeforeRunAsync",
|
216
|
+
);
|
217
|
+
},
|
218
|
+
onAfterRun(wrap, element) {
|
219
|
+
bootstrapNodeAndPlugins(
|
220
|
+
main,
|
221
|
+
wrap,
|
222
|
+
element,
|
223
|
+
"onAfterRun",
|
224
|
+
);
|
225
|
+
},
|
226
|
+
onAfterRunAsync(wrap, element) {
|
227
|
+
return bootstrapNodeAndPlugins(
|
228
|
+
main,
|
229
|
+
wrap,
|
230
|
+
element,
|
231
|
+
"onAfterRunAsync",
|
232
|
+
);
|
233
|
+
},
|
234
|
+
},
|
235
|
+
worker: {
|
236
|
+
...codeFor(worker),
|
237
|
+
// these are lazy getters that returns a composition
|
238
|
+
// of the current hooks or undefined, if no hook is present
|
239
|
+
get onReady() {
|
240
|
+
return createFunction(this, "onReady", true);
|
241
|
+
},
|
242
|
+
get onBeforeRun() {
|
243
|
+
return createFunction(this, "onBeforeRun", false);
|
244
|
+
},
|
245
|
+
get onBeforeRunAsync() {
|
246
|
+
return createFunction(this, "onBeforeRunAsync", true);
|
247
|
+
},
|
248
|
+
get onAfterRun() {
|
249
|
+
return createFunction(this, "onAfterRun", false);
|
250
|
+
},
|
251
|
+
get onAfterRunAsync() {
|
252
|
+
return createFunction(this, "onAfterRunAsync", true);
|
253
|
+
},
|
254
|
+
},
|
255
|
+
};
|
256
|
+
|
257
|
+
hooked.set(TYPE, hooks);
|
258
|
+
|
259
|
+
define(TYPE, {
|
260
|
+
config,
|
261
|
+
interpreter,
|
262
|
+
hooks,
|
263
|
+
env: `${TYPE}-script`,
|
264
|
+
version: config?.interpreter,
|
265
|
+
onerror(error, element) {
|
266
|
+
errors.set(element, error);
|
238
267
|
},
|
239
268
|
});
|
240
269
|
|
@@ -290,13 +319,14 @@ for (const [TYPE, interpreter] of TYPES) {
|
|
290
319
|
* @param {{config?: string | object, async?: boolean}} [options] optional configuration for the worker.
|
291
320
|
* @returns {Worker & {sync: ProxyHandler<object>}}
|
292
321
|
*/
|
293
|
-
|
322
|
+
function PyWorker(file, options) {
|
323
|
+
const hooks = hooked.get("py");
|
294
324
|
// this propagates pyscript worker hooks without needing a pyscript
|
295
325
|
// bootstrap + it passes arguments and enforces `pyodide`
|
296
326
|
// as the interpreter to use in the worker, as all hooks assume that
|
297
327
|
// and as `pyodide` is the only default interpreter that can deal with
|
298
328
|
// all the features we need to deliver pyscript out there.
|
299
|
-
const xworker = XWorker.call(new Hook(null,
|
329
|
+
const xworker = XWorker.call(new Hook(null, hooks), file, {
|
300
330
|
type: "pyodide",
|
301
331
|
...options,
|
302
332
|
});
|
package/src/exceptions.js
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import { assign } from "polyscript/exports";
|
2
|
+
|
1
3
|
const CLOSEBUTTON =
|
2
4
|
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='currentColor' width='12px'><path d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/></svg>";
|
3
5
|
|
@@ -87,13 +89,13 @@ export function _createAlertBanner(
|
|
87
89
|
}
|
88
90
|
|
89
91
|
const content = messageType === "html" ? "innerHTML" : "textContent";
|
90
|
-
const banner =
|
92
|
+
const banner = assign(document.createElement("div"), {
|
91
93
|
className: `alert-banner py-${level}`,
|
92
94
|
[content]: message,
|
93
95
|
});
|
94
96
|
|
95
97
|
if (level === "warning") {
|
96
|
-
const closeButton =
|
98
|
+
const closeButton = assign(document.createElement("button"), {
|
97
99
|
id: "alert-close-button",
|
98
100
|
innerHTML: CLOSEBUTTON,
|
99
101
|
});
|
package/src/fetch.js
CHANGED
package/src/hooks.js
CHANGED
@@ -1,28 +1,91 @@
|
|
1
1
|
import { typedSet } from "type-checked-collections";
|
2
|
+
import { dedent } from "polyscript/exports";
|
3
|
+
import toJSONCallback from "to-json-callback";
|
4
|
+
|
5
|
+
import stdlib from "./stdlib.js";
|
6
|
+
|
7
|
+
export const main = (name) => hooks.main[name];
|
8
|
+
export const worker = (name) => hooks.worker[name];
|
9
|
+
|
10
|
+
const code = (hooks, branch, key, lib) => {
|
11
|
+
hooks[key] = () => {
|
12
|
+
const arr = lib ? [lib] : [];
|
13
|
+
arr.push(...branch(key));
|
14
|
+
return arr.map(dedent).join("\n");
|
15
|
+
};
|
16
|
+
};
|
17
|
+
|
18
|
+
export const codeFor = (branch) => {
|
19
|
+
const hooks = {};
|
20
|
+
code(hooks, branch, `codeBeforeRun`, stdlib);
|
21
|
+
code(hooks, branch, `codeBeforeRunAsync`, stdlib);
|
22
|
+
code(hooks, branch, `codeAfterRun`);
|
23
|
+
code(hooks, branch, `codeAfterRunAsync`);
|
24
|
+
return hooks;
|
25
|
+
};
|
26
|
+
|
27
|
+
export const createFunction = (self, name) => {
|
28
|
+
const cbs = [...worker(name)];
|
29
|
+
if (cbs.length) {
|
30
|
+
const cb = toJSONCallback(
|
31
|
+
self[`_${name}`] ||
|
32
|
+
(name.endsWith("Async")
|
33
|
+
? async (wrap, xworker, ...cbs) => {
|
34
|
+
for (const cb of cbs) await cb(wrap, xworker);
|
35
|
+
}
|
36
|
+
: (wrap, xworker, ...cbs) => {
|
37
|
+
for (const cb of cbs) cb(wrap, xworker);
|
38
|
+
}),
|
39
|
+
);
|
40
|
+
const a = cbs.map(toJSONCallback).join(", ");
|
41
|
+
return Function(`return(w,x)=>(${cb})(w,x,...[${a}])`)();
|
42
|
+
}
|
43
|
+
};
|
2
44
|
|
3
45
|
const SetFunction = typedSet({ typeof: "function" });
|
4
46
|
const SetString = typedSet({ typeof: "string" });
|
5
47
|
|
6
|
-
export
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
48
|
+
export const hooks = {
|
49
|
+
main: {
|
50
|
+
/** @type {Set<function>} */
|
51
|
+
onWorker: new SetFunction(),
|
52
|
+
/** @type {Set<function>} */
|
53
|
+
onReady: new SetFunction(),
|
54
|
+
/** @type {Set<function>} */
|
55
|
+
onBeforeRun: new SetFunction(),
|
56
|
+
/** @type {Set<function>} */
|
57
|
+
onBeforeRunAsync: new SetFunction(),
|
58
|
+
/** @type {Set<function>} */
|
59
|
+
onAfterRun: new SetFunction(),
|
60
|
+
/** @type {Set<function>} */
|
61
|
+
onAfterRunAsync: new SetFunction(),
|
62
|
+
/** @type {Set<string>} */
|
63
|
+
codeBeforeRun: new SetString(),
|
64
|
+
/** @type {Set<string>} */
|
65
|
+
codeBeforeRunAsync: new SetString(),
|
66
|
+
/** @type {Set<string>} */
|
67
|
+
codeAfterRun: new SetString(),
|
68
|
+
/** @type {Set<string>} */
|
69
|
+
codeAfterRunAsync: new SetString(),
|
70
|
+
},
|
71
|
+
worker: {
|
72
|
+
/** @type {Set<function>} */
|
73
|
+
onReady: new SetFunction(),
|
74
|
+
/** @type {Set<function>} */
|
75
|
+
onBeforeRun: new SetFunction(),
|
76
|
+
/** @type {Set<function>} */
|
77
|
+
onBeforeRunAsync: new SetFunction(),
|
78
|
+
/** @type {Set<function>} */
|
79
|
+
onAfterRun: new SetFunction(),
|
80
|
+
/** @type {Set<function>} */
|
81
|
+
onAfterRunAsync: new SetFunction(),
|
82
|
+
/** @type {Set<string>} */
|
83
|
+
codeBeforeRun: new SetString(),
|
84
|
+
/** @type {Set<string>} */
|
85
|
+
codeBeforeRunAsync: new SetString(),
|
86
|
+
/** @type {Set<string>} */
|
87
|
+
codeAfterRun: new SetString(),
|
88
|
+
/** @type {Set<string>} */
|
89
|
+
codeAfterRunAsync: new SetString(),
|
90
|
+
},
|
28
91
|
};
|
package/src/plugins/error.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
// PyScript Error Plugin
|
2
2
|
import { hooks } from "../core.js";
|
3
3
|
|
4
|
-
hooks.
|
4
|
+
hooks.main.onReady.add(function override(pyScript) {
|
5
5
|
// be sure this override happens only once
|
6
|
-
hooks.
|
6
|
+
hooks.main.onReady.delete(override);
|
7
7
|
|
8
8
|
// trap generic `stderr` to propagate to it regardless
|
9
9
|
const { stderr } = pyScript.io;
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import { defineProperty } from "polyscript/exports";
|
2
|
+
|
3
|
+
// helper for all script[type="py"] out there
|
4
|
+
const before = (script) => {
|
5
|
+
defineProperty(document, "currentScript", {
|
6
|
+
configurable: true,
|
7
|
+
get: () => script,
|
8
|
+
});
|
9
|
+
};
|
10
|
+
|
11
|
+
const after = () => {
|
12
|
+
delete document.currentScript;
|
13
|
+
};
|
14
|
+
|
15
|
+
// common life-cycle handlers for any node
|
16
|
+
export default async (main, wrap, element, hook) => {
|
17
|
+
const isAsync = hook.endsWith("Async");
|
18
|
+
const isBefore = hook.startsWith("onBefore");
|
19
|
+
// make it possible to reach the current target node via Python
|
20
|
+
// or clean up for other scripts executing around this one
|
21
|
+
(isBefore ? before : after)(element);
|
22
|
+
for (const fn of main(hook)) {
|
23
|
+
if (isAsync) await fn(wrap, element);
|
24
|
+
else fn(wrap, element);
|
25
|
+
}
|
26
|
+
};
|
package/types/core.d.ts
CHANGED
@@ -1,16 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
*/
|
7
|
-
export function PyWorker(file: string, options?: {
|
8
|
-
config?: string | object;
|
9
|
-
async?: boolean;
|
10
|
-
}): Worker & {
|
11
|
-
sync: ProxyHandler<object>;
|
12
|
-
};
|
13
|
-
import sync from "./sync.js";
|
14
|
-
declare const exportedConfig: {};
|
15
|
-
import hooks from "./hooks.js";
|
16
|
-
export { exportedConfig as config, hooks };
|
1
|
+
declare const exportedPyWorker: any;
|
2
|
+
declare const exportedHooks: any;
|
3
|
+
declare const exportedConfig: any;
|
4
|
+
declare const exportedWhenDefined: any;
|
5
|
+
export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };
|