diff --git a/.gitignore b/.gitignore index b73e485..86b0437 100644 --- a/.gitignore +++ b/.gitignore @@ -118,8 +118,9 @@ venv.bak/ # Rope project settings .ropeproject -# VS Code Files +# IDE Files .vscode/ +.idea/ # mkdocs documentation /site diff --git a/pyscriptjs/.eslintrc.js b/pyscriptjs/.eslintrc.js new file mode 100644 index 0000000..6853e5c --- /dev/null +++ b/pyscriptjs/.eslintrc.js @@ -0,0 +1,46 @@ +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'], + extraFileExtensions: ['.svelte'], + }, + env: { + es6: true, + browser: true, + }, + overrides: [ + { + files: ['*.svelte'], + processor: 'svelte3/svelte3', + }, + ], + settings: { + 'svelte3/typescript': require('typescript'), + // ignore style tags in Svelte because of Tailwind CSS + // See https://github.com/sveltejs/eslint-plugin-svelte3/issues/70 + 'svelte3/ignore-styles': () => true, + }, + plugins: ['svelte3', '@typescript-eslint'], + ignorePatterns: ['node_modules'], + rules: { + 'no-prototype-builtins': 'warn', + '@typescript-eslint/no-unused-vars': 'warn', + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-unsafe-assignment': 'warn', + '@typescript-eslint/no-unsafe-argument': 'warn', + '@typescript-eslint/no-unsafe-member-access': 'warn', + '@typescript-eslint/no-unsafe-call': 'warn', + '@typescript-eslint/no-unsafe-return': 'warn', + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/restrict-plus-operands': 'warn', + '@typescript-eslint/no-empty-function': 'warn', + }, +}; \ No newline at end of file diff --git a/pyscriptjs/.prettierignore b/pyscriptjs/.prettierignore new file mode 100644 index 0000000..55ec36d --- /dev/null +++ b/pyscriptjs/.prettierignore @@ -0,0 +1,6 @@ +build +node_modules + + +# Ignore all HTML files +*.html \ No newline at end of file diff --git a/pyscriptjs/.prettierrc.js b/pyscriptjs/.prettierrc.js new file mode 100644 index 0000000..bafc660 --- /dev/null +++ b/pyscriptjs/.prettierrc.js @@ -0,0 +1,13 @@ +module.exports = { + arrowParens: 'avoid', + bracketSameLine: true, + singleQuote: true, + printWidth: 120, + plugins: ['prettier-plugin-svelte'], + semi: true, + svelteSortOrder: 'options-styles-scripts-markup', + svelteStrictMode: false, + svelteIndentScriptAndStyle: true, + tabWidth: 4, + trailingComma: 'all', +} \ No newline at end of file diff --git a/pyscriptjs/package-lock.json b/pyscriptjs/package-lock.json index 30e4ade..018b045 100644 --- a/pyscriptjs/package-lock.json +++ b/pyscriptjs/package-lock.json @@ -275,6 +275,23 @@ "w3c-keyname": "^2.2.4" } }, + "@eslint/eslintrc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.2.tgz", + "integrity": "sha512-lTVWHs7O2hjBFZunXTZYnYqtB9GakA1lnxIf+gKq2nY5gxkkNi/lQvveW6t8gFdOHTg6nG50Xs95PrLqVpcaLg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, "@fortawesome/fontawesome-common-types": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.1.tgz", @@ -288,6 +305,23 @@ "@fortawesome/fontawesome-common-types": "6.1.1" } }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@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 + }, "@lezer/common": { "version": "0.15.12", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz", @@ -410,6 +444,12 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "dev": true }, + "@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": "17.0.23", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", @@ -446,12 +486,131 @@ "@types/node": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz", + "integrity": "sha512-fapGzoxilCn3sBtC6NtXZX6+P/Hef7VDbyfGqTTpzYydwhlkevB+0vE0EnmHPVTVSy68GUncyJ/2PcrFBeCo5Q==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/type-utils": "5.20.0", + "@typescript-eslint/utils": "5.20.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/parser": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.20.0.tgz", + "integrity": "sha512-UWKibrCZQCYvobmu3/N8TWbEeo/EPQbS41Ux1F9XqPzGuV7pfg6n50ZrFo6hryynD8qOTTfLHtHjjdQtxJ0h/w==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", + "debug": "^4.3.2" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.20.0.tgz", + "integrity": "sha512-h9KtuPZ4D/JuX7rpp1iKg3zOH0WNEa+ZIXwpW/KWmEFDxlA/HSfCMhiyF1HS/drTICjIbpA6OqkAhrP/zkCStg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.20.0.tgz", + "integrity": "sha512-WxNrCwYB3N/m8ceyoGCgbLmuZwupvzN0rE8NBuwnl7APgjv24ZJIjkNzoFBXPRCGzLNkoU/WfanW0exvp/+3Iw==", + "dev": true, + "requires": { + "@typescript-eslint/utils": "5.20.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.20.0.tgz", + "integrity": "sha512-+d8wprF9GyvPwtoB4CxBAR/s0rpP25XKgnOvMf/gMXYDvlUC3rPFHupdTQ/ow9vn7UDe5rX02ovGYQbv/IUCbg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.20.0.tgz", + "integrity": "sha512-36xLjP/+bXusLMrT9fMMYy1KJAGgHhlER2TqpUVDYUQg4w0q/NW/sg4UGAgVwAqb8V4zYg43KMUpM8vV2lve6w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/visitor-keys": "5.20.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/utils": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.20.0.tgz", + "integrity": "sha512-lHONGJL1LIO12Ujyx8L8xKbwWSkoUKFSO+0wDAqGXiudWB2EO7WEUT+YZLtVbmOmSllAjLb9tpoIPwpRe5Tn6w==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.20.0", + "@typescript-eslint/types": "5.20.0", + "@typescript-eslint/typescript-estree": "5.20.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "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" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.20.0.tgz", + "integrity": "sha512-1flRpNF+0CAQkMNlTJ6L/Z5jiODG/e5+7mk6XwtPOUS3UrTz3UOiAg9jG2VtKsWI6rZQfy4C6a232QNRZTRGlg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.20.0", + "eslint-visitor-keys": "^3.0.0" + } + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "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 + }, "acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", @@ -469,6 +628,24 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "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-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": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -499,6 +676,12 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, + "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 + }, "autoprefixer": { "version": "10.4.4", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz", @@ -732,6 +915,17 @@ "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" }, + "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" + } + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -750,6 +944,21 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "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" + } + }, + "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.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -785,12 +994,30 @@ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", "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" + } + }, "dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", "dev": true }, + "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" + } + }, "electron-to-chromium": { "version": "1.4.103", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.103.tgz", @@ -824,12 +1051,215 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "eslint": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.14.0.tgz", + "integrity": "sha512-3/CE4aJX7LNEiE3i6FeodHmI/38GZtWCsAtsymScmzYapx8q1nVVb+eLcLSzATmCPXw5pT4TqVs1E0OmxAd9tw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.2.2", + "@humanwhocodes/config-array": "^0.9.2", + "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.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "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", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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 + }, + "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 + }, + "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" + } + }, + "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 + }, + "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" + } + } + } + }, + "eslint-plugin-svelte3": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte3/-/eslint-plugin-svelte3-3.4.1.tgz", + "integrity": "sha512-7p59WG8qV8L6wLdl4d/c3mdjkgVglQCdv5XOTk/iNPBKXuuV+Q0eFP5Wa6iJd/G2M1qR3BkLPEzaANOqKAZczw==", + "dev": true + }, + "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" + } + }, + "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.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + } + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "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" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, "estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "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 + }, + "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.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -843,6 +1273,18 @@ "micromatch": "^4.0.4" } }, + "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": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -852,6 +1294,15 @@ "reusify": "^1.0.4" } }, + "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", @@ -861,6 +1312,33 @@ "to-regex-range": "^5.0.1" } }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, "fraction.js": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", @@ -897,6 +1375,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "get-port": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", @@ -925,6 +1409,29 @@ "is-glob": "^4.0.1" } }, + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "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.9", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", @@ -970,6 +1477,12 @@ "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", "dev": true }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -980,6 +1493,12 @@ "resolve-from": "^4.0.0" } }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1070,6 +1589,12 @@ "@types/estree": "*" } }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, "jest-worker": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", @@ -1118,6 +1643,18 @@ "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": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -1133,6 +1670,16 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==" }, + "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" + } + }, "lilconfig": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", @@ -1174,12 +1721,27 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "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 + }, "lodash.topath": { "version": "4.5.2", "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz", "integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=", "dev": true }, + "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" + } + }, "magic-string": { "version": "0.25.9", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", @@ -1263,12 +1825,24 @@ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==" }, + "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 + }, "nanoid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", "dev": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node-emoji": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", @@ -1317,6 +1891,20 @@ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true }, + "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" + } + }, "opts": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz", @@ -1350,6 +1938,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "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", @@ -1438,12 +2032,36 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "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.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", + "dev": true + }, + "prettier-plugin-svelte": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-2.7.0.tgz", + "integrity": "sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==", + "dev": true + }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "purgecss": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz", @@ -1504,6 +2122,12 @@ } } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "require-relative": { "version": "0.8.7", "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", @@ -1682,6 +2306,15 @@ "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==" }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, "serialize-javascript": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", @@ -1691,6 +2324,21 @@ "randombytes": "^2.1.0" } }, + "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 + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -1733,6 +2381,12 @@ "tinydate": "^1.0.0" } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "sorcery": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.10.0.tgz", @@ -1781,6 +2435,15 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "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-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -1790,6 +2453,12 @@ "min-indent": "^1.0.0" } }, + "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.0", "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", @@ -2036,6 +2705,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "tinydate": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", @@ -2081,6 +2756,38 @@ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "dev": true }, + "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-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": "4.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.3.tgz", @@ -2093,17 +2800,47 @@ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true }, + "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" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "w3c-keyname": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz", "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw==" }, + "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 + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -2121,6 +2858,12 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/pyscriptjs/package.json b/pyscriptjs/package.json index ec97fbd..d1f39de 100644 --- a/pyscriptjs/package.json +++ b/pyscriptjs/package.json @@ -5,15 +5,26 @@ "build": "NODE_ENV=production rollup -c", "dev": "rollup -c -w", "start": "sirv public --no-clear --port 8080", - "validate": "svelte-check" + "validate": "svelte-check", + "format:check": "prettier --check './src/**/*.{js,svelte,html,ts}'", + "format": "prettier --write './src/**/*.{js,svelte,html,ts}'", + "lint": "eslint './src/**/*.{js,svelte,html,ts}'", + "lint:fix": "eslint --fix './src/**/*.{js,svelte,html,ts}'", + "xprelint": "npm run format" }, "devDependencies": { "@rollup/plugin-commonjs": "^17.0.0", "@rollup/plugin-node-resolve": "^11.0.0", "@rollup/plugin-typescript": "^8.1.0", "@tsconfig/svelte": "^1.0.0", + "@typescript-eslint/eslint-plugin": "^5.20.0", + "@typescript-eslint/parser": "^5.20.0", "autoprefixer": "^10.2.3", + "eslint": "^8.14.0", + "eslint-plugin-svelte3": "^3.4.1", "postcss": "^8.2.4", + "prettier": "^2.6.2", + "prettier-plugin-svelte": "^2.7.0", "rollup": "^2.3.4", "rollup-plugin-css-only": "^3.1.0", "rollup-plugin-livereload": "^2.0.0", diff --git a/pyscriptjs/src/App.svelte b/pyscriptjs/src/App.svelte index 7122ca7..781adc7 100644 --- a/pyscriptjs/src/App.svelte +++ b/pyscriptjs/src/App.svelte @@ -1,81 +1,84 @@ - - + + - + diff --git a/pyscriptjs/src/Tailwind.svelte b/pyscriptjs/src/Tailwind.svelte index aedc87d..b7fa654 100644 --- a/pyscriptjs/src/Tailwind.svelte +++ b/pyscriptjs/src/Tailwind.svelte @@ -2,4 +2,4 @@ @tailwind base; @tailwind components; @tailwind utilities; - \ No newline at end of file + diff --git a/pyscriptjs/src/components/base.ts b/pyscriptjs/src/components/base.ts index 877745d..113beaa 100644 --- a/pyscriptjs/src/components/base.ts +++ b/pyscriptjs/src/components/base.ts @@ -1,4 +1,4 @@ -import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, mode } from '../stores'; +import { componentDetailsNavOpen, loadedEnvironments, mode, pyodideLoaded } from '../stores'; import { guidGenerator } from '../utils'; // Premise used to connect to the first available pyodide interpreter let pyodideReadyPromise; @@ -7,7 +7,7 @@ let currentMode; let Element; pyodideLoaded.subscribe(value => { - pyodideReadyPromise = value; + pyodideReadyPromise = value; }); loadedEnvironments.subscribe(value => { environments = value; @@ -15,17 +15,17 @@ loadedEnvironments.subscribe(value => { let propertiesNavOpen; componentDetailsNavOpen.subscribe(value => { - propertiesNavOpen = value; + propertiesNavOpen = value; }); mode.subscribe(value => { - currentMode = value; + currentMode = value; }); // TODO: use type declaractions type PyodideInterface = { - registerJsModule(name: string, module: object): void -} + registerJsModule(name: string, module: object): void; +}; export class BaseEvalElement extends HTMLElement { shadow: ShadowRoot; @@ -37,142 +37,136 @@ export class BaseEvalElement extends HTMLElement { outputElement: HTMLElement; errorElement: HTMLElement; theme: string; - + constructor() { super(); - + // attach shadow so we can preserve the element original innerHtml content - this.shadow = this.attachShadow({ mode: 'open'}); + this.shadow = this.attachShadow({ mode: 'open' }); this.wrapper = document.createElement('slot'); this.shadow.appendChild(this.wrapper); } addToOutput(s: string) { - this.outputElement.innerHTML += "
"+s+"
"; + this.outputElement.innerHTML += '
' + s + '
'; this.outputElement.hidden = false; - } - - postEvaluate(){ - } - checkId(){ - if (!this.id) - this.id = this.constructor.name+"-"+guidGenerator(); + postEvaluate() {} + + checkId() { + if (!this.id) this.id = this.constructor.name + '-' + guidGenerator(); } - getSourceFromElement(): string{ - return ""; + getSourceFromElement(): string { + return ''; } - async getSourceFromFile(s: string): Promise{ - let pyodide = await pyodideReadyPromise; - let response = await fetch(s); + async getSourceFromFile(s: string): Promise { + const pyodide = await pyodideReadyPromise; + const response = await fetch(s); this.code = await response.text(); return this.code; - } + } protected async _register_esm(pyodide: PyodideInterface): Promise { - const imports: {[key: string]: unknown} = {} - + const imports: { [key: string]: unknown } = {}; + for (const node of document.querySelectorAll("script[type='importmap']")) { - const importmap = (() => { - try { - return JSON.parse(node.textContent) - } catch { - return null + const importmap = (() => { + try { + return JSON.parse(node.textContent); + } catch { + return null; + } + })(); + + if (importmap?.imports == null) continue; + + for (const [name, url] of Object.entries(importmap.imports)) { + if (typeof name != 'string' || typeof url != 'string') continue; + + try { + // XXX: pyodide doesn't like Module(), failing with + // "can't read 'name' of undefined" at import time + imports[name] = { ...(await import(url)) }; + } catch { + console.error(`failed to fetch '${url}' for '${name}'`); + } } - })() - - if (importmap?.imports == null) - continue - - for (const [name, url] of Object.entries(importmap.imports)) { - if (typeof name != "string" || typeof url != "string") - continue - - try { - // XXX: pyodide doesn't like Module(), failing with - // "can't read 'name' of undefined" at import time - imports[name] = {...await import(url)} - } catch { - console.error(`failed to fetch '${url}' for '${name}'`) - } - } } - - pyodide.registerJsModule("esm", imports) + + pyodide.registerJsModule('esm', imports); } async evaluate(): Promise { console.log('evaluate'); - let pyodide = await pyodideReadyPromise; + const pyodide = await pyodideReadyPromise; let source: string; let output; try { - // @ts-ignore - if (this.source){ + if (this.source) { source = await this.getSourceFromFile(this.source); - }else{ + } else { source = this.getSourceFromElement(); } await this._register_esm(pyodide); - if (source.includes("asyncio")){ - await pyodide.runPythonAsync(`output_manager.change("`+this.outputElement.id+`", "`+this.errorElement.id+`")`); + if (source.includes('asyncio')) { + await pyodide.runPythonAsync( + `output_manager.change("` + this.outputElement.id + `", "` + this.errorElement.id + `")`, + ); output = await pyodide.runPythonAsync(source); - await pyodide.runPythonAsync(`output_manager.revert()`) - }else{ - output = pyodide.runPython(`output_manager.change("`+this.outputElement.id+`", "`+this.errorElement.id+`")`); + await pyodide.runPythonAsync(`output_manager.revert()`); + } else { + output = pyodide.runPython( + `output_manager.change("` + this.outputElement.id + `", "` + this.errorElement.id + `")`, + ); output = pyodide.runPython(source); - pyodide.runPython(`output_manager.revert()`) + pyodide.runPython(`output_manager.revert()`); } - if (output !== undefined){ - if (Element === undefined){ + if (output !== undefined) { + if (Element === undefined) { Element = pyodide.globals.get('Element'); } const out = Element(this.outputElement.id); - // @ts-ignore - out.write.callKwargs(output, { append : true}); + out.write.callKwargs(output, { append: true }); - this.outputElement.hidden = false; + this.outputElement.hidden = false; this.outputElement.style.display = 'block'; } - this.postEvaluate() - + this.postEvaluate(); } catch (err) { - if (Element === undefined){ + if (Element === undefined) { Element = pyodide.globals.get('Element'); } const out = Element(this.errorElement.id); - // @ts-ignore - out.write.callKwargs(err, { append : true}); + out.write.callKwargs(err, { append: true }); this.errorElement.hidden = false; this.errorElement.style.display = 'block'; - } - } // end evaluate + } + } // end evaluate - async eval(source: string): Promise { + async eval(source: string): Promise { let output; - let pyodide = await pyodideReadyPromise; - - try{ + const pyodide = await pyodideReadyPromise; + + try { output = await pyodide.runPythonAsync(source); - if (output !== undefined){ console.log(output); } + if (output !== undefined) { + console.log(output); + } } catch (err) { console.log(err); } } // end eval - } +} - - - function createWidget(name: string, code: string, klass: string){ - - class CustomWidget extends HTMLElement{ +function createWidget(name: string, code: string, klass: string) { + class CustomWidget extends HTMLElement { shadow: ShadowRoot; wrapper: HTMLElement; @@ -183,13 +177,13 @@ export class BaseEvalElement extends HTMLElement { proxyClass: any; constructor() { - super(); - - // attach shadow so we can preserve the element original innerHtml content - this.shadow = this.attachShadow({ mode: 'open'}); - - this.wrapper = document.createElement('slot'); - this.shadow.appendChild(this.wrapper); + super(); + + // attach shadow so we can preserve the element original innerHtml content + this.shadow = this.attachShadow({ mode: 'open' }); + + this.wrapper = document.createElement('slot'); + this.shadow.appendChild(this.wrapper); } connectedCallback() { @@ -207,19 +201,19 @@ export class BaseEvalElement extends HTMLElement { }, 2000); } - async registerWidget(){ - let pyodide = await pyodideReadyPromise; + async registerWidget() { + const pyodide = await pyodideReadyPromise; console.log('new widget registered:', this.name); pyodide.globals.set(this.id, this.proxy); } async eval(source: string): Promise { let output; - let pyodide = await pyodideReadyPromise; - try{ + const pyodide = await pyodideReadyPromise; + try { output = await pyodide.runPythonAsync(source); this.proxyClass = pyodide.globals.get(this.klass); - if (output !== undefined){ + if (output !== undefined) { console.log(output); } } catch (err) { @@ -227,10 +221,10 @@ export class BaseEvalElement extends HTMLElement { } } } - let xPyWidget = customElements.define(name, CustomWidget); - } + const xPyWidget = customElements.define(name, CustomWidget); +} - export class PyWidget extends HTMLElement { +export class PyWidget extends HTMLElement { shadow: ShadowRoot; name: string; klass: string; @@ -240,43 +234,45 @@ export class BaseEvalElement extends HTMLElement { theme: string; source: string; code: string; - + constructor() { super(); - + // attach shadow so we can preserve the element original innerHtml content - this.shadow = this.attachShadow({ mode: 'open'}); - + this.shadow = this.attachShadow({ mode: 'open' }); + this.wrapper = document.createElement('slot'); this.shadow.appendChild(this.wrapper); if (this.hasAttribute('src')) { - this.source = this.getAttribute('src'); + this.source = this.getAttribute('src'); } if (this.hasAttribute('name')) { - this.name = this.getAttribute('name'); + this.name = this.getAttribute('name'); } if (this.hasAttribute('klass')) { - this.klass = this.getAttribute('klass'); + this.klass = this.getAttribute('klass'); } - } + } connectedCallback() { - if (this.id === undefined){ - throw new ReferenceError(`No id specified for component. Components must have an explicit id. Please use id="" to specify your component id.`) - return; - } + if (this.id === undefined) { + throw new ReferenceError( + `No id specified for component. Components must have an explicit id. Please use id="" to specify your component id.`, + ); + return; + } - let mainDiv = document.createElement('div'); - mainDiv.id = this.id + '-main'; - this.appendChild(mainDiv); - console.log('reading source') - this.getSourceFromFile(this.source).then((code:string) => { - this.code = code; - createWidget(this.name, code, this.klass); - }); + const mainDiv = document.createElement('div'); + mainDiv.id = this.id + '-main'; + this.appendChild(mainDiv); + console.log('reading source'); + this.getSourceFromFile(this.source).then((code: string) => { + this.code = code; + createWidget(this.name, code, this.klass); + }); } initOutErr(): void { @@ -287,42 +283,42 @@ export class BaseEvalElement extends HTMLElement { if (!this.hasAttribute('output-mode')) { this.setAttribute('output-mode', 'append'); } - }else{ - if (this.hasAttribute('std-out')){ + } else { + if (this.hasAttribute('std-out')) { this.outputElement = document.getElementById(this.getAttribute('std-out')); - }else{ + } else { // In this case neither output or std-out have been provided so we need // to create a new output div to output to this.outputElement = document.createElement('div'); - this.outputElement.classList.add("output"); + this.outputElement.classList.add('output'); this.outputElement.hidden = true; - this.outputElement.id = this.id + "-" + this.getAttribute("exec-id"); + this.outputElement.id = this.id + '-' + this.getAttribute('exec-id'); } - if (this.hasAttribute('std-err')){ + if (this.hasAttribute('std-err')) { this.outputElement = document.getElementById(this.getAttribute('std-err')); - }else{ + } else { this.errorElement = this.outputElement; } } } - async getSourceFromFile(s: string): Promise{ - let pyodide = await pyodideReadyPromise; - let response = await fetch(s); + async getSourceFromFile(s: string): Promise { + const pyodide = await pyodideReadyPromise; + const response = await fetch(s); return await response.text(); } - + async eval(source: string): Promise { let output; - let pyodide = await pyodideReadyPromise; - try{ + const pyodide = await pyodideReadyPromise; + try { output = await pyodide.runPythonAsync(source); - if (output !== undefined){ + if (output !== undefined) { console.log(output); } } catch (err) { console.log(err); } } - } +} diff --git a/pyscriptjs/src/components/pybox.ts b/pyscriptjs/src/components/pybox.ts index acd27e5..124360f 100644 --- a/pyscriptjs/src/components/pybox.ts +++ b/pyscriptjs/src/components/pybox.ts @@ -5,65 +5,62 @@ export class PyBox extends HTMLElement { wrapper: HTMLElement; theme: string; widths: Array; - + constructor() { super(); - + // attach shadow so we can preserve the element original innerHtml content - this.shadow = this.attachShadow({ mode: 'open'}); - + this.shadow = this.attachShadow({ mode: 'open' }); + this.wrapper = document.createElement('slot'); this.shadow.appendChild(this.wrapper); - } - + } connectedCallback() { - let mainDiv = document.createElement('div'); - addClasses(mainDiv, ["flex", "mx-8"]) - - // Hack: for some reason when moving children, the editor box duplicates children - // meaning that we end up with 2 editors, if there's a inside the - // so, if we have more than 2 children with the cm-editor class, we remove one of them - while (this.childNodes.length > 0) { - console.log(this.firstChild); - if ( this.firstChild.nodeName == "PY-REPL" ){ - // in this case we need to remove the child and craete a new one from scratch - let replDiv = document.createElement('div'); - // we need to put the new repl inside a div so that if the repl has auto-generate true - // it can replicate itself inside that constrained div - replDiv.appendChild(this.firstChild.cloneNode()); - mainDiv.appendChild(replDiv); - this.firstChild.remove(); - } - else{ - if ( this.firstChild.nodeName != "#text" ){ - mainDiv.appendChild(this.firstChild); - }else{ - this.firstChild.remove() - } - } - } + const mainDiv = document.createElement('div'); + addClasses(mainDiv, ['flex', 'mx-8']); - // now we need to set widths - this.widths = [] - if (this.hasAttribute('widths')) { - for (let w of this.getAttribute('widths').split(";")) { - this.widths.push(`w-${w}`); + // Hack: for some reason when moving children, the editor box duplicates children + // meaning that we end up with 2 editors, if there's a inside the + // so, if we have more than 2 children with the cm-editor class, we remove one of them + while (this.childNodes.length > 0) { + console.log(this.firstChild); + if (this.firstChild.nodeName == 'PY-REPL') { + // in this case we need to remove the child and craete a new one from scratch + const replDiv = document.createElement('div'); + // we need to put the new repl inside a div so that if the repl has auto-generate true + // it can replicate itself inside that constrained div + replDiv.appendChild(this.firstChild.cloneNode()); + mainDiv.appendChild(replDiv); + this.firstChild.remove(); + } else { + if (this.firstChild.nodeName != '#text') { + mainDiv.appendChild(this.firstChild); + } else { + this.firstChild.remove(); + } + } } - }else{ - for (let el of mainDiv.childNodes) { - this.widths.push(`w-1/${mainDiv.childNodes.length}`); + + // now we need to set widths + this.widths = []; + if (this.hasAttribute('widths')) { + for (const w of this.getAttribute('widths').split(';')) { + this.widths.push(`w-${w}`); + } + } else { + for (const el of mainDiv.childNodes) { + this.widths.push(`w-1/${mainDiv.childNodes.length}`); + } } - } - for (let i in this.widths) { - // @ts-ignore - addClasses(mainDiv.childNodes[parseInt(i)], [this.widths[i], 'mx-4']); - } + this.widths.forEach((width, index)=>{ + const node: ChildNode = mainDiv.childNodes[index]; + addClasses(node, [width, 'mx-4']) - this.appendChild(mainDiv); - console.log('py-box connected'); + }) + + this.appendChild(mainDiv); + console.log('py-box connected'); } - } - - \ No newline at end of file +} diff --git a/pyscriptjs/src/components/pybutton.ts b/pyscriptjs/src/components/pybutton.ts index 426b537..ad54f9b 100644 --- a/pyscriptjs/src/components/pybutton.ts +++ b/pyscriptjs/src/components/pybutton.ts @@ -10,47 +10,47 @@ export class PyButton extends BaseEvalElement { mount_name: string; constructor() { super(); - + if (this.hasAttribute('label')) { - this.label = this.getAttribute('label'); + this.label = this.getAttribute('label'); } - } + } connectedCallback() { - this.code = htmlDecode(this.innerHTML); - this.mount_name = this.id.split("-").join("_"); - this.innerHTML = ''; - - let mainDiv = document.createElement('button'); - mainDiv.innerHTML = this.label; - addClasses(mainDiv, ["p-2", "text-white", "bg-blue-600", "border", "border-blue-600", "rounded"]); - - mainDiv.id = this.id; - this.id = `${this.id}-container`; + this.code = htmlDecode(this.innerHTML); + this.mount_name = this.id.split('-').join('_'); + this.innerHTML = ''; - this.appendChild(mainDiv); - this.code = this.code.split("self").join(this.mount_name); - let registrationCode = `${this.mount_name} = Element("${ mainDiv.id }")`; - if (this.code.includes("def on_focus")){ - this.code = this.code.replace("def on_focus", `def on_focus_${this.mount_name}`); - registrationCode += `\n${this.mount_name}.element.onfocus = on_focus_${this.mount_name}` - } + const mainDiv = document.createElement('button'); + mainDiv.innerHTML = this.label; + addClasses(mainDiv, ['p-2', 'text-white', 'bg-blue-600', 'border', 'border-blue-600', 'rounded']); - if (this.code.includes("def on_click")){ - this.code = this.code.replace("def on_click", `def on_click_${this.mount_name}`); - registrationCode += `\n${this.mount_name}.element.onclick = on_click_${this.mount_name}` - } - - // now that we appended and the element is attached, lets connect with the event handlers - // defined for this widget - setTimeout(() => { - this.eval(this.code).then(() => { - this.eval(registrationCode).then(() => { - console.log('registered handlers'); - }); - }); - }, 4000); - - console.log('py-button connected'); + mainDiv.id = this.id; + this.id = `${this.id}-container`; + + this.appendChild(mainDiv); + this.code = this.code.split('self').join(this.mount_name); + let registrationCode = `${this.mount_name} = Element("${mainDiv.id}")`; + if (this.code.includes('def on_focus')) { + this.code = this.code.replace('def on_focus', `def on_focus_${this.mount_name}`); + registrationCode += `\n${this.mount_name}.element.onfocus = on_focus_${this.mount_name}`; + } + + if (this.code.includes('def on_click')) { + this.code = this.code.replace('def on_click', `def on_click_${this.mount_name}`); + registrationCode += `\n${this.mount_name}.element.onclick = on_click_${this.mount_name}`; + } + + // now that we appended and the element is attached, lets connect with the event handlers + // defined for this widget + setTimeout(() => { + this.eval(this.code).then(() => { + this.eval(registrationCode).then(() => { + console.log('registered handlers'); + }); + }); + }, 4000); + + console.log('py-button connected'); } - } +} diff --git a/pyscriptjs/src/components/pyenv.ts b/pyscriptjs/src/components/pyenv.ts index c2f964c..ec924f8 100644 --- a/pyscriptjs/src/components/pyenv.ts +++ b/pyscriptjs/src/components/pyenv.ts @@ -9,68 +9,65 @@ let environments; let currentMode; pyodideLoaded.subscribe(value => { - pyodideReadyPromise = value; + pyodideReadyPromise = value; }); loadedEnvironments.subscribe(value => { - environments = value; + environments = value; }); mode.subscribe(value => { - currentMode = value; + currentMode = value; }); export class PyEnv extends HTMLElement { - shadow: ShadowRoot; - wrapper: HTMLElement; - code: string; - environment: any; + shadow: ShadowRoot; + wrapper: HTMLElement; + code: string; + environment: any; - constructor() { - super(); + constructor() { + super(); - this.shadow = this.attachShadow({ mode: 'open'}); - this.wrapper = document.createElement('slot'); - } + this.shadow = this.attachShadow({ mode: 'open' }); + this.wrapper = document.createElement('slot'); + } - connectedCallback() { - this.code = this.innerHTML; - this.innerHTML = ''; + connectedCallback() { + this.code = this.innerHTML; + this.innerHTML = ''; - let env = []; - let paths = []; + const env = []; + const paths = []; - this.environment = jsyaml.load(this.code); - if (this.environment === undefined) - return + this.environment = jsyaml.load(this.code); + if (this.environment === undefined) return; - for (let entry of this.environment) { - if (typeof entry == "string" ){ - env.push(entry); - } - else if (entry.hasOwnProperty('paths')){ - for (let path of entry.paths) { - paths.push(path); + for (const entry of this.environment) { + if (typeof entry == 'string') { + env.push(entry); + } else if (entry.hasOwnProperty('paths')) { + for (const path of entry.paths) { + paths.push(path); + } + } } - } - } - async function loadEnv() { - let pyodide = await pyodideReadyPromise; - await loadPackage(env, pyodide); - console.log("enviroment loaded") - } + async function loadEnv() { + const pyodide = await pyodideReadyPromise; + await loadPackage(env, pyodide); + console.log('enviroment loaded'); + } - async function loadPaths() { - let pyodide = await pyodideReadyPromise; - for (let singleFile of paths) { - await loadFromFile(singleFile, pyodide); - } - console.log("paths loaded") + async function loadPaths() { + const pyodide = await pyodideReadyPromise; + for (const singleFile of paths) { + await loadFromFile(singleFile, pyodide); + } + console.log('paths loaded'); + } + addInitializer(loadEnv); + addInitializer(loadPaths); + console.log('enviroment loading...', env); } - addInitializer(loadEnv); - addInitializer(loadPaths); - console.log("enviroment loading...", env) - - } } diff --git a/pyscriptjs/src/components/pyinputbox.ts b/pyscriptjs/src/components/pyinputbox.ts index 58fec14..9fbc73e 100644 --- a/pyscriptjs/src/components/pyinputbox.ts +++ b/pyscriptjs/src/components/pyinputbox.ts @@ -9,46 +9,44 @@ export class PyInputBox extends BaseEvalElement { label: string; mount_name: string; constructor() { - super(); + super(); - if (this.hasAttribute('label')) { - this.label = this.getAttribute('label'); - } + if (this.hasAttribute('label')) { + this.label = this.getAttribute('label'); + } } connectedCallback() { - this.code = htmlDecode(this.innerHTML); - this.mount_name = this.id.split("-").join("_"); - this.innerHTML = ''; - - let mainDiv = document.createElement('input'); - mainDiv.type = "text"; - addClasses(mainDiv, ["border", "flex-1", "w-full", "mr-3", "border-gray-300", "p-2", "rounded"]); + this.code = htmlDecode(this.innerHTML); + this.mount_name = this.id.split('-').join('_'); + this.innerHTML = ''; - mainDiv.id = this.id; - this.id = `${this.id}-container`; - this.appendChild(mainDiv); + const mainDiv = document.createElement('input'); + mainDiv.type = 'text'; + addClasses(mainDiv, ['border', 'flex-1', 'w-full', 'mr-3', 'border-gray-300', 'p-2', 'rounded']); - // now that we appended and the element is attached, lets connect with the event handlers - // defined for this widget - this.appendChild(mainDiv); - this.code = this.code.split("self").join(this.mount_name); - let registrationCode = `${this.mount_name} = Element("${ mainDiv.id }")`; - if (this.code.includes("def on_keypress")){ - this.code = this.code.replace("def on_keypress", `def on_keypress_${this.mount_name}`); - registrationCode += `\n${this.mount_name}.element.onkeypress = on_keypress_${this.mount_name}` - } + mainDiv.id = this.id; + this.id = `${this.id}-container`; + this.appendChild(mainDiv); - // TODO: For now we delay execution to allow pyodide to load but in the future this - // should really wait for it to load.. - setTimeout(() => { - this.eval(this.code).then(() => { - this.eval(registrationCode).then(() => { - console.log('registered handlers'); - }); - }); + // now that we appended and the element is attached, lets connect with the event handlers + // defined for this widget + this.appendChild(mainDiv); + this.code = this.code.split('self').join(this.mount_name); + let registrationCode = `${this.mount_name} = Element("${mainDiv.id}")`; + if (this.code.includes('def on_keypress')) { + this.code = this.code.replace('def on_keypress', `def on_keypress_${this.mount_name}`); + registrationCode += `\n${this.mount_name}.element.onkeypress = on_keypress_${this.mount_name}`; + } + + // TODO: For now we delay execution to allow pyodide to load but in the future this + // should really wait for it to load.. + setTimeout(() => { + this.eval(this.code).then(() => { + this.eval(registrationCode).then(() => { + console.log('registered handlers'); + }); + }); }, 4000); } - } - - \ No newline at end of file +} diff --git a/pyscriptjs/src/components/pyrepl.ts b/pyscriptjs/src/components/pyrepl.ts index 621d224..beedbd1 100644 --- a/pyscriptjs/src/components/pyrepl.ts +++ b/pyscriptjs/src/components/pyrepl.ts @@ -1,12 +1,11 @@ -import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup" -import { python } from "@codemirror/lang-python" -// @ts-ignore -import { StateCommand, Compartment } from '@codemirror/state'; -import { keymap, ViewUpdate } from "@codemirror/view"; -import { defaultKeymap } from "@codemirror/commands"; -import { oneDarkTheme } from "@codemirror/theme-one-dark"; +import { basicSetup, EditorState, EditorView } from '@codemirror/basic-setup'; +import { python } from '@codemirror/lang-python'; +import { Compartment, StateCommand } from '@codemirror/state'; +import { keymap } from '@codemirror/view'; +import { defaultKeymap } from '@codemirror/commands'; +import { oneDarkTheme } from '@codemirror/theme-one-dark'; -import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode } from '../stores'; +import { componentDetailsNavOpen, currentComponentDetails, loadedEnvironments, mode, pyodideLoaded } from '../stores'; import { addClasses } from '../utils'; import { BaseEvalElement } from './base'; @@ -16,7 +15,7 @@ let environments; let currentMode; pyodideLoaded.subscribe(value => { - pyodideReadyPromise = value; + pyodideReadyPromise = value; }); loadedEnvironments.subscribe(value => { environments = value; @@ -24,216 +23,230 @@ loadedEnvironments.subscribe(value => { let propertiesNavOpen; componentDetailsNavOpen.subscribe(value => { - propertiesNavOpen = value; + propertiesNavOpen = value; }); mode.subscribe(value => { - currentMode = value; + currentMode = value; }); +const languageConf = new Compartment(); -const languageConf = new Compartment - -function createCmdHandler(el){ +function createCmdHandler(el) { // Creates a codemirror cmd handler that calls the el.evaluate when an event // triggers that specific cmd - const toggleCheckbox:StateCommand = ({ state, dispatch }) => { - return el.evaluate(state) - } - return toggleCheckbox + const toggleCheckbox: StateCommand = ({ state, dispatch }) => { + return el.evaluate(state); + }; + return toggleCheckbox; } - export class PyRepl extends BaseEvalElement { editor: EditorView; editorNode: HTMLElement; - + constructor() { super(); - + // add an extra div where we can attach the codemirror editor this.editorNode = document.createElement('div'); - addClasses(this.editorNode, ["editor-box"]) + addClasses(this.editorNode, ['editor-box']); this.shadow.appendChild(this.wrapper); - } - + } connectedCallback() { - this.checkId() - this.code = this.innerHTML; - this.innerHTML = ''; + this.checkId(); + this.code = this.innerHTML; + this.innerHTML = ''; - let extensions = [ - basicSetup, - languageConf.of(python()), - keymap.of([ + const extensions = [ + basicSetup, + languageConf.of(python()), + keymap.of([ ...defaultKeymap, - { key: "Ctrl-Enter", run: createCmdHandler(this) }, - { key: "Shift-Enter", run: createCmdHandler(this) } - ]), + { key: 'Ctrl-Enter', run: createCmdHandler(this) }, + { key: 'Shift-Enter', run: createCmdHandler(this) }, + ]), - // Event listener function that is called every time an user types something on this editor - // EditorView.updateListener.of((v:ViewUpdate) => { - // if (v.docChanged) { - // console.log(v.changes); + // Event listener function that is called every time an user types something on this editor + // EditorView.updateListener.of((v:ViewUpdate) => { + // if (v.docChanged) { + // console.log(v.changes); + + // } + // }) + ]; - // } - // }) - ]; - if (!this.hasAttribute('theme')) { - this.theme = this.getAttribute('theme'); - if (this.theme == 'dark'){ - extensions.push(oneDarkTheme); - } - } - - let startState = EditorState.create({ - doc: this.code.trim(), - extensions: extensions - }) - - this.editor = new EditorView({ - state: startState, - parent: this.editorNode - }) - - let mainDiv = document.createElement('div'); - addClasses(mainDiv, ["parentBox", "group", "flex", "flex-col", "mt-2", "border-2", "border-gray-200", "rounded-lg", "mx-8"]) - // add Editor to main PyScript div - - // Butons DIV - var eDiv = document.createElement('div'); - addClasses(eDiv, "buttons-box opacity-0 group-hover:opacity-100 relative top-0 right-0 flex flex-row-reverse space-x-reverse space-x-4 font-mono text-white text-sm font-bold leading-6 dev-buttons-group".split(" ")) - eDiv.setAttribute("role", "group"); - - // Play Button - this.btnRun = document.createElement('button'); - this.btnRun.innerHTML = ''; - let buttonClasses = ["mr-2", "block", "py-2", "px-4", "rounded-full"]; - addClasses(this.btnRun, buttonClasses); - addClasses(this.btnRun, ["bg-green-500"]) - eDiv.appendChild(this.btnRun); - - this.btnRun.onclick = wrap(this); - - function wrap(el: any){ - async function evaluatePython() { - el.evaluate() - } - return evaluatePython; - } - - // Settings button - this.btnConfig = document.createElement('button'); - this.btnConfig.innerHTML = ''; - this.btnConfig.onclick = function toggleNavBar(evt){ - console.log('clicked'); - componentDetailsNavOpen.set(!propertiesNavOpen); - - currentComponentDetails.set([ - {key: "auto-generate", value: true}, - {key:"output", value: "default"}, - {key: "source", value: "self"}, - {key: "output-mode", value: "clear"} - ]) - } - - addClasses(this.btnConfig, buttonClasses); - addClasses(this.btnConfig, ["bg-blue-500"]) - eDiv.appendChild(this.btnConfig); - - - mainDiv.appendChild(eDiv); - mainDiv.appendChild(this.editorNode); - - if (!this.id){ - console.log("WARNING: define with an id. should always have an id. More than one on a page won't work otherwise!") - } - - if (!this.hasAttribute('exec-id')) { - this.setAttribute("exec-id", "1"); - } - - if (!this.hasAttribute('root')) { - this.setAttribute("root", this.id); - } - - if (this.hasAttribute('output')) { - this.errorElement = this.outputElement = document.getElementById(this.getAttribute('output')); - - // in this case, the default output-mode is append, if hasn't been specified - if (!this.hasAttribute('output-mode')) { - this.setAttribute('output-mode', 'append'); - } - }else{ - if (this.hasAttribute('std-out')){ - this.outputElement = document.getElementById(this.getAttribute('std-out')); - }else{ - // In this case neither output or std-out have been provided so we need - // to create a new output div to output to - this.outputElement = document.createElement('div'); - this.outputElement.classList.add("output"); - this.outputElement.hidden = true; - this.outputElement.id = this.id + "-" + this.getAttribute("exec-id"); - - // add the output div id if there's not output pre-defined - mainDiv.appendChild(this.outputElement); + this.theme = this.getAttribute('theme'); + if (this.theme == 'dark') { + extensions.push(oneDarkTheme); + } } - if (this.hasAttribute('std-err')){ - this.errorElement = document.getElementById(this.getAttribute('std-err')); - }else{ - this.errorElement = this.outputElement; + const startState = EditorState.create({ + doc: this.code.trim(), + extensions: extensions, + }); + + this.editor = new EditorView({ + state: startState, + parent: this.editorNode, + }); + + const mainDiv = document.createElement('div'); + addClasses(mainDiv, [ + 'parentBox', + 'group', + 'flex', + 'flex-col', + 'mt-2', + 'border-2', + 'border-gray-200', + 'rounded-lg', + 'mx-8', + ]); + // add Editor to main PyScript div + + // Butons DIV + const eDiv = document.createElement('div'); + addClasses( + eDiv, + 'buttons-box opacity-0 group-hover:opacity-100 relative top-0 right-0 flex flex-row-reverse space-x-reverse space-x-4 font-mono text-white text-sm font-bold leading-6 dev-buttons-group'.split( + ' ', + ), + ); + eDiv.setAttribute('role', 'group'); + + // Play Button + this.btnRun = document.createElement('button'); + this.btnRun.innerHTML = + ''; + const buttonClasses = ['mr-2', 'block', 'py-2', 'px-4', 'rounded-full']; + addClasses(this.btnRun, buttonClasses); + addClasses(this.btnRun, ['bg-green-500']); + eDiv.appendChild(this.btnRun); + + this.btnRun.onclick = wrap(this); + + function wrap(el: any) { + async function evaluatePython() { + await el.evaluate(); + } + + return evaluatePython; } - } + // Settings button + this.btnConfig = document.createElement('button'); + this.btnConfig.innerHTML = + ''; + this.btnConfig.onclick = function toggleNavBar(evt) { + console.log('clicked'); + componentDetailsNavOpen.set(!propertiesNavOpen); - this.appendChild(mainDiv); - this.editor.focus(); - console.log('connected'); + currentComponentDetails.set([ + { key: 'auto-generate', value: true }, + { key: 'output', value: 'default' }, + { key: 'source', value: 'self' }, + { key: 'output-mode', value: 'clear' }, + ]); + }; + + addClasses(this.btnConfig, buttonClasses); + addClasses(this.btnConfig, ['bg-blue-500']); + eDiv.appendChild(this.btnConfig); + + mainDiv.appendChild(eDiv); + mainDiv.appendChild(this.editorNode); + + if (!this.id) { + console.log( + 'WARNING: define with an id. should always have an id. More than one on a page won\'t work otherwise!', + ); + } + + if (!this.hasAttribute('exec-id')) { + this.setAttribute('exec-id', '1'); + } + + if (!this.hasAttribute('root')) { + this.setAttribute('root', this.id); + } + + if (this.hasAttribute('output')) { + this.errorElement = this.outputElement = document.getElementById(this.getAttribute('output')); + + // in this case, the default output-mode is append, if hasn't been specified + if (!this.hasAttribute('output-mode')) { + this.setAttribute('output-mode', 'append'); + } + } else { + if (this.hasAttribute('std-out')) { + this.outputElement = document.getElementById(this.getAttribute('std-out')); + } else { + // In this case neither output or std-out have been provided so we need + // to create a new output div to output to + this.outputElement = document.createElement('div'); + this.outputElement.classList.add('output'); + this.outputElement.hidden = true; + this.outputElement.id = this.id + '-' + this.getAttribute('exec-id'); + + // add the output div id if there's not output pre-defined + mainDiv.appendChild(this.outputElement); + } + + if (this.hasAttribute('std-err')) { + this.errorElement = document.getElementById(this.getAttribute('std-err')); + } else { + this.errorElement = this.outputElement; + } + } + + this.appendChild(mainDiv); + this.editor.focus(); + console.log('connected'); } addToOutput(s: string) { - this.outputElement.innerHTML += "
"+s+"
"; + this.outputElement.innerHTML += '
' + s + '
'; this.outputElement.hidden = false; - } + } postEvaluate(): void { + this.outputElement.hidden = false; + this.outputElement.style.display = 'block'; - this.outputElement.hidden = false; - this.outputElement.style.display = 'block'; + if (this.hasAttribute('auto-generate')) { + const nextExecId = parseInt(this.getAttribute('exec-id')) + 1; + const newPyRepl = document.createElement('py-repl'); + newPyRepl.setAttribute('root', this.getAttribute('root')); + newPyRepl.id = this.getAttribute('root') + '-' + nextExecId.toString(); + newPyRepl.setAttribute('auto-generate', null); + if (this.hasAttribute('output')) { + newPyRepl.setAttribute('output', this.getAttribute('output')); + } + if (this.hasAttribute('std-out')) { + newPyRepl.setAttribute('std-out', this.getAttribute('std-out')); + } + if (this.hasAttribute('std-err')) { + newPyRepl.setAttribute('std-err', this.getAttribute('std-err')); + } - if (this.hasAttribute('auto-generate')) { - let nextExecId = parseInt(this.getAttribute('exec-id')) + 1; - const newPyRepl = document.createElement("py-repl"); - newPyRepl.setAttribute('root', this.getAttribute('root')); - newPyRepl.id = this.getAttribute('root') + "-" + nextExecId.toString(); - newPyRepl.setAttribute('auto-generate', null); - if (this.hasAttribute('output')){ - newPyRepl.setAttribute('output', this.getAttribute('output')); + newPyRepl.setAttribute('exec-id', nextExecId.toString()); + this.parentElement.appendChild(newPyRepl); } - if (this.hasAttribute('std-out')){ - newPyRepl.setAttribute('std-out', this.getAttribute('std-out')); - } - if (this.hasAttribute('std-err')){ - newPyRepl.setAttribute('std-err', this.getAttribute('std-err')); - } - - newPyRepl.setAttribute('exec-id', nextExecId.toString()); - this.parentElement.appendChild(newPyRepl); - } } getSourceFromElement(): string { - const sourceStrings = [`output_manager.change("`+this.outputElement.id+`")`, - ...this.editor.state.doc.toString().split("\n")]; - return sourceStrings.join('\n') + const sourceStrings = [ + `output_manager.change("` + this.outputElement.id + `")`, + ...this.editor.state.doc.toString().split('\n'), + ]; + return sourceStrings.join('\n'); } - render(){ - console.log('rendered'); - + render() { + console.log('rendered'); } - } - +} diff --git a/pyscriptjs/src/components/pyscript.ts b/pyscriptjs/src/components/pyscript.ts index 8b7aacc..61267e6 100644 --- a/pyscriptjs/src/components/pyscript.ts +++ b/pyscriptjs/src/components/pyscript.ts @@ -1,12 +1,19 @@ -import {EditorState, EditorView, basicSetup} from "@codemirror/basic-setup" -import { python } from "@codemirror/lang-python" -// @ts-ignore +import { EditorState } from '@codemirror/basic-setup'; +import { python } from '@codemirror/lang-python'; import { StateCommand } from '@codemirror/state'; -import { keymap, ViewUpdate } from "@codemirror/view"; -import { defaultKeymap } from "@codemirror/commands"; -import { oneDarkTheme } from "@codemirror/theme-one-dark"; +import { keymap } from '@codemirror/view'; +import { defaultKeymap } from '@codemirror/commands'; +import { oneDarkTheme } from '@codemirror/theme-one-dark'; -import { pyodideLoaded, loadedEnvironments, componentDetailsNavOpen, currentComponentDetails, mode, addToScriptsQueue, addInitializer, addPostInitializer } from '../stores'; +import { + addInitializer, + addPostInitializer, + addToScriptsQueue, + componentDetailsNavOpen, + loadedEnvironments, + mode, + pyodideLoaded, +} from '../stores'; import { addClasses, htmlDecode } from '../utils'; import { BaseEvalElement } from './base'; @@ -17,7 +24,7 @@ let currentMode; let handlersCollected = false; pyodideLoaded.subscribe(value => { - pyodideReadyPromise = value; + pyodideReadyPromise = value; }); loadedEnvironments.subscribe(value => { environments = value; @@ -25,240 +32,233 @@ loadedEnvironments.subscribe(value => { let propertiesNavOpen; componentDetailsNavOpen.subscribe(value => { - propertiesNavOpen = value; + propertiesNavOpen = value; }); mode.subscribe(value => { - currentMode = value; + currentMode = value; }); -function createCmdHandler(el){ +function createCmdHandler(el) { // Creates a codemirror cmd handler that calls the el.evaluate when an event // triggers that specific cmd - const toggleCheckbox:StateCommand = ({ state, dispatch }) => { - return el.evaluate(state) - } - return toggleCheckbox + const toggleCheckbox: StateCommand = ({ state, dispatch }) => { + return el.evaluate(state); + }; + return toggleCheckbox; } // TODO: use type declaractions type PyodideInterface = { - registerJsModule(name: string, module: object): void -} + registerJsModule(name: string, module: object): void; +}; // TODO: This should be used as base for generic scripts that need exectutoin // from PyScript to initializers, etc... class Script { - source: string; - state: string; - output: string; - - constructor(source: string, output: string) { - this.output = output; - this.source = source; - this.state = 'waiting'; - } - - async evaluate() { - console.log('evaluate'); - let pyodide = await pyodideReadyPromise; - // debugger - try { - // @ts-ignore - // let source = this.editor.state.doc.toString(); - let output; - if (this.source.includes("asyncio")){ - output = await pyodide.runPythonAsync(this.source); - }else{ - output = pyodide.runPython(this.source); - } + source: string; + state: string; + output: string; - if (this.output){ - // this.editorOut.innerHTML = s; - } - // if (output !== undefined){ - // this.addToOutput(output); - // } + constructor(source: string, output: string) { + this.output = output; + this.source = source; + this.state = 'waiting'; + } - - } catch (err) { - console.log("OOOPS, this happened: " + err); - // this.addToOutput(err); - } - } + async evaluate() { + console.log('evaluate'); + const pyodide = await pyodideReadyPromise; + // debugger + try { + // let source = this.editor.state.doc.toString(); + let output; + if (this.source.includes('asyncio')) { + output = await pyodide.runPythonAsync(this.source); + } else { + output = pyodide.runPython(this.source); + } + + if (this.output) { + // this.editorOut.innerHTML = s; + } + // if (output !== undefined){ + // this.addToOutput(output); + // } + } catch (err) { + console.log('OOOPS, this happened: ', err); + // this.addToOutput(err); + } + } } export class PyScript extends BaseEvalElement { - constructor() { super(); - + // add an extra div where we can attach the codemirror editor this.shadow.appendChild(this.wrapper); - } + } connectedCallback() { - this.checkId() + this.checkId(); this.code = this.innerHTML; this.innerHTML = ''; - let startState = EditorState.create({ - doc: this.code, - extensions: [ - keymap.of([ + const startState = EditorState.create({ + doc: this.code, + extensions: [ + keymap.of([ ...defaultKeymap, - { key: "Ctrl-Enter", run: createCmdHandler(this) }, - { key: "Shift-Enter", run: createCmdHandler(this) } - ]), - oneDarkTheme, - python(), - // Event listener function that is called every time an user types something on this editor - // EditorView.updateListener.of((v:ViewUpdate) => { - // if (v.docChanged) { - // console.log(v.changes); + { key: 'Ctrl-Enter', run: createCmdHandler(this) }, + { key: 'Shift-Enter', run: createCmdHandler(this) }, + ]), + oneDarkTheme, + python(), + // Event listener function that is called every time an user types something on this editor + // EditorView.updateListener.of((v:ViewUpdate) => { + // if (v.docChanged) { + // console.log(v.changes); - // } - // }) - ] - }) - - let mainDiv = document.createElement('div'); - addClasses(mainDiv, ["parentBox", "flex", "flex-col", 'mx-8']) - // add Editor to main PyScript div - + // } + // }) + ], + }); - if (this.hasAttribute('output')) { - this.errorElement = this.outputElement = document.getElementById(this.getAttribute('output')); + const mainDiv = document.createElement('div'); + addClasses(mainDiv, ['parentBox', 'flex', 'flex-col', 'mx-8']); + // add Editor to main PyScript div - // in this case, the default output-mode is append, if hasn't been specified - if (!this.hasAttribute('output-mode')) { - this.setAttribute('output-mode', 'append'); - } - }else{ - if (this.hasAttribute('std-out')){ - this.outputElement = document.getElementById(this.getAttribute('std-out')); - }else{ - // In this case neither output or std-out have been provided so we need - // to create a new output div to output to + if (this.hasAttribute('output')) { + this.errorElement = this.outputElement = document.getElementById(this.getAttribute('output')); - // Let's check if we have an id first and create one if not - this.outputElement = document.createElement('div'); - const exec_id = this.getAttribute("exec-id"); - this.outputElement.id = this.id + (exec_id ? "-"+exec_id : ""); + // in this case, the default output-mode is append, if hasn't been specified + if (!this.hasAttribute('output-mode')) { + this.setAttribute('output-mode', 'append'); + } + } else { + if (this.hasAttribute('std-out')) { + this.outputElement = document.getElementById(this.getAttribute('std-out')); + } else { + // In this case neither output or std-out have been provided so we need + // to create a new output div to output to - // add the output div id if there's not output pre-defined - mainDiv.appendChild(this.outputElement); + // Let's check if we have an id first and create one if not + this.outputElement = document.createElement('div'); + const exec_id = this.getAttribute('exec-id'); + this.outputElement.id = this.id + (exec_id ? '-' + exec_id : ''); + + // add the output div id if there's not output pre-defined + mainDiv.appendChild(this.outputElement); + } + + if (this.hasAttribute('std-err')) { + this.outputElement = document.getElementById(this.getAttribute('std-err')); + } else { + this.errorElement = this.outputElement; + } } - if (this.hasAttribute('std-err')){ - this.outputElement = document.getElementById(this.getAttribute('std-err')); - }else{ - this.errorElement = this.outputElement; + if (currentMode == 'edit') { + // TODO: We need to build a plan for this + this.appendChild(mainDiv); + } else { + this.appendChild(mainDiv); + addToScriptsQueue(this); } - } - if (currentMode=="edit"){ - // TODO: We need to build a plan for this - this.appendChild(mainDiv); - }else{ - this.appendChild(mainDiv); - addToScriptsQueue(this); - } + console.log('connected'); - console.log('connected'); - - if (this.hasAttribute('src')) { - this.source = this.getAttribute('src'); - } + if (this.hasAttribute('src')) { + this.source = this.getAttribute('src'); + } } protected async _register_esm(pyodide: PyodideInterface): Promise { - for (const node of document.querySelectorAll("script[type='importmap']")) { - const importmap = (() => { - try { - return JSON.parse(node.textContent) - } catch { - return null - } - })() + for (const node of document.querySelectorAll("script[type='importmap']")) { + const importmap = (() => { + try { + return JSON.parse(node.textContent); + } catch { + return null; + } + })(); - if (importmap?.imports == null) - continue + if (importmap?.imports == null) continue; - for (const [name, url] of Object.entries(importmap.imports)) { - if (typeof name != "string" || typeof url != "string") - continue + for (const [name, url] of Object.entries(importmap.imports)) { + if (typeof name != 'string' || typeof url != 'string') continue; - let exports: object - try { - // XXX: pyodide doesn't like Module(), failing with - // "can't read 'name' of undefined" at import time - exports = {...await import(url)} - } catch { - console.warn(`failed to fetch '${url}' for '${name}'`) - continue - } + let exports: object; + try { + // XXX: pyodide doesn't like Module(), failing with + // "can't read 'name' of undefined" at import time + exports = { ...(await import(url)) }; + } catch { + console.warn(`failed to fetch '${url}' for '${name}'`); + continue; + } - pyodide.registerJsModule(name, exports) + pyodide.registerJsModule(name, exports); + } } - } } getSourceFromElement(): string { - return htmlDecode(this.code); + return htmlDecode(this.code); } - } +} /** Initialize all elements with py-onClick handlers attributes */ async function initHandlers() { - console.log('Collecting nodes...'); - let pyodide = await pyodideReadyPromise; - let matches : NodeListOf = document.querySelectorAll('[pys-onClick]'); - let output; - let source; - for (var el of matches) { - let handlerCode = el.getAttribute('pys-onClick'); - source = `Element("${ el.id }").element.onclick = ${ handlerCode }`; - output = await pyodide.runPythonAsync(source); + console.log('Collecting nodes...'); + const pyodide = await pyodideReadyPromise; + let matches: NodeListOf = document.querySelectorAll('[pys-onClick]'); + let output; + let source; + for (const el of matches) { + const handlerCode = el.getAttribute('pys-onClick'); + source = `Element("${el.id}").element.onclick = ${handlerCode}`; + output = await pyodide.runPythonAsync(source); - // TODO: Should we actually map handlers in JS instaed of Python? - // el.onclick = (evt: any) => { - // console.log("click"); - // new Promise((resolve, reject) => { - // setTimeout(() => { - // console.log('Inside') - // }, 300); - // }).then(() => { - // console.log("resolved") - // }); - // // let handlerCode = el.getAttribute('pys-onClick'); - // // pyodide.runPython(handlerCode); - // } - } - handlersCollected = true; + // TODO: Should we actually map handlers in JS instaed of Python? + // el.onclick = (evt: any) => { + // console.log("click"); + // new Promise((resolve, reject) => { + // setTimeout(() => { + // console.log('Inside') + // }, 300); + // }).then(() => { + // console.log("resolved") + // }); + // // let handlerCode = el.getAttribute('pys-onClick'); + // // pyodide.runPython(handlerCode); + // } + } + handlersCollected = true; - matches = document.querySelectorAll('[pys-onKeyDown]'); - for (var el of matches) { - let handlerCode = el.getAttribute('pys-onKeyDown'); - source = `Element("${ el.id }").element.addEventListener("keydown", ${ handlerCode })`; - output = await pyodide.runPythonAsync(source); - } + matches = document.querySelectorAll('[pys-onKeyDown]'); + for (const el of matches) { + const handlerCode = el.getAttribute('pys-onKeyDown'); + source = `Element("${el.id}").element.addEventListener("keydown", ${handlerCode})`; + output = await pyodide.runPythonAsync(source); + } } /** Mount all elements with attribute py-mount into the Python namespace */ async function mountElements() { - console.log('Collecting nodes to be mounted into python namespace...'); - let pyodide = await pyodideReadyPromise; - let matches : NodeListOf = document.querySelectorAll('[py-mount]'); - let output; - let source = ""; - for (var el of matches) { - let mountName = el.getAttribute('py-mount'); - if (!mountName){ - mountName = el.id.split("-").join("_"); + console.log('Collecting nodes to be mounted into python namespace...'); + const pyodide = await pyodideReadyPromise; + const matches: NodeListOf = document.querySelectorAll('[py-mount]'); + let output; + let source = ''; + for (const el of matches) { + let mountName = el.getAttribute('py-mount'); + if (!mountName) { + mountName = el.id.split('-').join('_'); + } + source += `\n${mountName} = Element("${el.id}")`; } - source += `\n${ mountName } = Element("${ el.id }")`; - } - await pyodide.runPythonAsync(source); + await pyodide.runPythonAsync(source); } addInitializer(mountElements); addPostInitializer(initHandlers); diff --git a/pyscriptjs/src/components/pytitle.ts b/pyscriptjs/src/components/pytitle.ts index de4890c..444ff53 100644 --- a/pyscriptjs/src/components/pytitle.ts +++ b/pyscriptjs/src/components/pytitle.ts @@ -2,33 +2,31 @@ import { BaseEvalElement } from './base'; import { addClasses, ltrim, htmlDecode } from '../utils'; export class PyTitle extends BaseEvalElement { - shadow: ShadowRoot; - wrapper: HTMLElement; - theme: string; - widths: Array; - label: string; - mount_name: string; - constructor() { - super(); + shadow: ShadowRoot; + wrapper: HTMLElement; + theme: string; + widths: Array; + label: string; + mount_name: string; + constructor() { + super(); } - connectedCallback() { - this.label = htmlDecode(this.innerHTML); - this.mount_name = this.id.split("-").join("_"); - this.innerHTML = ''; + connectedCallback() { + this.label = htmlDecode(this.innerHTML); + this.mount_name = this.id.split('-').join('_'); + this.innerHTML = ''; - let mainDiv = document.createElement('div'); - let divContent = document.createElement('h1') + const mainDiv = document.createElement('div'); + const divContent = document.createElement('h1'); - addClasses(mainDiv, ["text-center", "w-full", "mb-8"]); - addClasses(divContent, ["text-3xl", "font-bold", "text-gray-800", "uppercase", "tracking-tight"]); - divContent.innerHTML = this.label; + addClasses(mainDiv, ['text-center', 'w-full', 'mb-8']); + addClasses(divContent, ['text-3xl', 'font-bold', 'text-gray-800', 'uppercase', 'tracking-tight']); + divContent.innerHTML = this.label; - mainDiv.id = this.id; - this.id = `${this.id}-container`; - mainDiv.appendChild(divContent); - this.appendChild(mainDiv); - } + mainDiv.id = this.id; + this.id = `${this.id}-container`; + mainDiv.appendChild(divContent); + this.appendChild(mainDiv); + } } - - \ No newline at end of file diff --git a/pyscriptjs/src/interpreter.ts b/pyscriptjs/src/interpreter.ts index ceab6ab..8459b07 100644 --- a/pyscriptjs/src/interpreter.ts +++ b/pyscriptjs/src/interpreter.ts @@ -1,11 +1,9 @@ -import { getLastPath } from "./utils"; +import { getLastPath } from './utils'; -// @ts-nocheck -// @ts-ignore let pyodideReadyPromise; let pyodide; -let additional_definitions = ` +const additional_definitions = ` from js import document, setInterval, console, setTimeout import micropip import time @@ -413,19 +411,18 @@ class OutputManager: pyscript = PyScript() output_manager = OutputManager() -` +`; -let loadInterpreter = async function(): Promise { - console.log("creating pyodide runtime"); - /* @ts-ignore */ +const loadInterpreter = async function (): Promise { + console.log('creating pyodide runtime'); pyodide = await loadPyodide({ - stdout: console.log, - stderr: console.log - }); + stdout: console.log, + stderr: console.log, + }); // now that we loaded, add additional convenience fuctions - console.log("loading micropip"); - await pyodide.loadPackage("micropip"); + console.log('loading micropip'); + await pyodide.loadPackage('micropip'); console.log('loading pyscript module'); // await pyodide.runPythonAsync(` // from pyodide.http import pyfetch @@ -437,31 +434,36 @@ let loadInterpreter = async function(): Promise { // `) // let pkg = pyodide.pyimport("pyscript"); - console.log("creating additional definitions"); - let output = pyodide.runPython(additional_definitions); - console.log("done setting up environment"); - /* @ts-ignore */ + console.log('creating additional definitions'); + const output = pyodide.runPython(additional_definitions); + console.log('done setting up environment'); return pyodide; -} +}; -let loadPackage = async function(package_name: string[] | string, runtime: any): Promise { - let micropip = pyodide.globals.get('micropip'); - await micropip.install(package_name) - micropip.destroy() -} +const loadPackage = async function (package_name: string[] | string, runtime: any): Promise { + const micropip = pyodide.globals.get('micropip'); + await micropip.install(package_name); + micropip.destroy(); +}; -let loadFromFile = async function(s: string, runtime: any): Promise { - let filename = getLastPath(s); - await runtime.runPythonAsync(` +const loadFromFile = async function (s: string, runtime: any): Promise { + const filename = getLastPath(s); + await runtime.runPythonAsync( + ` from pyodide.http import pyfetch - response = await pyfetch("`+s+`") + response = await pyfetch("` + + s + + `") content = await response.bytes() - with open("`+filename+`", "wb") as f: + with open("` + + filename + + `", "wb") as f: f.write(content) - `) + `, + ); - runtime.pyimport(filename.replace(".py", "")); -} + runtime.pyimport(filename.replace('.py', '')); +}; -export {loadInterpreter, pyodideReadyPromise, loadPackage, loadFromFile} +export { loadInterpreter, pyodideReadyPromise, loadPackage, loadFromFile }; diff --git a/pyscriptjs/src/main.ts b/pyscriptjs/src/main.ts index 321a79e..9f8badf 100644 --- a/pyscriptjs/src/main.ts +++ b/pyscriptjs/src/main.ts @@ -1,26 +1,25 @@ -import App from "./App.svelte"; +import App from './App.svelte'; -import { PyScript } from "./components/pyscript"; -import { PyRepl } from "./components/pyrepl"; -import { PyEnv } from "./components/pyenv"; -import { PyBox } from "./components/pybox"; -import { PyButton } from "./components/pybutton"; -import { PyTitle } from "./components/pytitle"; -import { PyInputBox } from "./components/pyinputbox"; -import { PyWidget } from "./components/base"; - -let xPyScript = customElements.define('py-script', PyScript); -let xPyRepl = customElements.define('py-repl', PyRepl); -let xPyEnv = customElements.define('py-env', PyEnv); -let xPyBox = customElements.define('py-box', PyBox); -let xPyButton = customElements.define('py-button', PyButton); -let xPyTitle = customElements.define('py-title', PyTitle); -let xPyInputBox = customElements.define('py-inputbox', PyInputBox); -let xPyWidget = customElements.define('py-register-widget', PyWidget); +import { PyScript } from './components/pyscript'; +import { PyRepl } from './components/pyrepl'; +import { PyEnv } from './components/pyenv'; +import { PyBox } from './components/pybox'; +import { PyButton } from './components/pybutton'; +import { PyTitle } from './components/pytitle'; +import { PyInputBox } from './components/pyinputbox'; +import { PyWidget } from './components/base'; +const xPyScript = customElements.define('py-script', PyScript); +const xPyRepl = customElements.define('py-repl', PyRepl); +const xPyEnv = customElements.define('py-env', PyEnv); +const xPyBox = customElements.define('py-box', PyBox); +const xPyButton = customElements.define('py-button', PyButton); +const xPyTitle = customElements.define('py-title', PyTitle); +const xPyInputBox = customElements.define('py-inputbox', PyInputBox); +const xPyWidget = customElements.define('py-register-widget', PyWidget); const app = new App({ - target: document.body, + target: document.body, }); export default app; diff --git a/pyscriptjs/src/stores.ts b/pyscriptjs/src/stores.ts index 77bfa75..e4151a4 100644 --- a/pyscriptjs/src/stores.ts +++ b/pyscriptjs/src/stores.ts @@ -1,12 +1,11 @@ import { writable } from 'svelte/store'; - export const pyodideLoaded = writable({ - loaded: false, - premise: null + loaded: false, + premise: null, }); -export const loadedEnvironments = writable([{}]) +export const loadedEnvironments = writable([{}]); export const DEFAULT_MODE = 'play'; export const navBarOpen = writable(false); @@ -14,43 +13,43 @@ export const componentsNavOpen = writable(false); export const componentDetailsNavOpen = writable(false); export const mainDiv = writable(null); export const currentComponentDetails = writable([]); -export const mode = writable(DEFAULT_MODE) -export const scriptsQueue = writable([]) -export const initializers = writable([]) -export const postInitializers = writable([]) +export const mode = writable(DEFAULT_MODE); +export const scriptsQueue = writable([]); +export const initializers = writable([]); +export const postInitializers = writable([]); let scriptsQueue_ = []; let initializers_ = []; let postInitializers_ = []; scriptsQueue.subscribe(value => { - scriptsQueue_ = value; + scriptsQueue_ = value; }); -export const addToScriptsQueue = (script) => { - scriptsQueue.set([...scriptsQueue_, script]); +export const addToScriptsQueue = script => { + scriptsQueue.set([...scriptsQueue_, script]); }; scriptsQueue.subscribe(value => { - scriptsQueue_ = value; + scriptsQueue_ = value; }); initializers.subscribe(value => { - initializers_ = value; + initializers_ = value; }); -export const addInitializer = (initializer) => { - console.log("adding initializer", initializer); - initializers.set([...initializers_, initializer]); - console.log("adding initializer", initializer); +export const addInitializer = initializer => { + console.log('adding initializer', initializer); + initializers.set([...initializers_, initializer]); + console.log('adding initializer', initializer); }; postInitializers.subscribe(value => { - postInitializers_ = value; + postInitializers_ = value; }); -export const addPostInitializer = (initializer) => { - console.log("adding post initializer", initializer); - postInitializers.set([...postInitializers_, initializer]); - console.log("adding post initializer", initializer); +export const addPostInitializer = initializer => { + console.log('adding post initializer', initializer); + postInitializers.set([...postInitializers_, initializer]); + console.log('adding post initializer', initializer); }; diff --git a/pyscriptjs/src/utils.ts b/pyscriptjs/src/utils.ts index cdcd1c7..6873396 100644 --- a/pyscriptjs/src/utils.ts +++ b/pyscriptjs/src/utils.ts @@ -1,44 +1,40 @@ - -function addClasses(element: HTMLElement, classes: Array){ - for (let entry of classes) { - element.classList.add(entry); +function addClasses(element: HTMLElement, classes: Array) { + for (const entry of classes) { + element.classList.add(entry); } } const getLastPath = function (str) { - return str.split('\\').pop().split('/').pop(); -} + return str.split('\\').pop().split('/').pop(); +}; function htmlDecode(input) { - var doc = new DOMParser().parseFromString(input, "text/html"); - return ltrim(doc.documentElement.textContent); + const doc = new DOMParser().parseFromString(input, 'text/html'); + return ltrim(doc.documentElement.textContent); } function ltrim(code: string): string { - const lines = code.split("\n") - if (lines.length == 0) - return code + const lines = code.split('\n'); + if (lines.length == 0) return code; - const lengths = lines - .filter((line) => line.trim().length != 0) - .map((line) => { - const [prefix] = line.match(/^\s*/) - return prefix.length - }) + const lengths = lines + .filter(line => line.trim().length != 0) + .map(line => { + const [prefix] = line.match(/^\s*/); + return prefix.length; + }); - const k = Math.min(...lengths) + const k = Math.min(...lengths); - if (k != 0) - return lines.map((line) => line.substring(k)).join("\n") - else - return code + if (k != 0) return lines.map(line => line.substring(k)).join('\n'); + else return code; } function guidGenerator(): string { - var S4 = function(): string { - return (((1+Math.random())*0x10000)|0).toString(16).substring(1); - }; - return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4()); + const S4 = function (): string { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); + }; + return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4(); } -export {addClasses, getLastPath, ltrim, htmlDecode, guidGenerator} +export { addClasses, getLastPath, ltrim, htmlDecode, guidGenerator };