├── .demo ├── async-component.js └── jqvm-loader │ ├── .gitignore │ ├── compile.js │ ├── component-a.html │ ├── index.html │ ├── index.js │ ├── package-lock.json │ ├── package.json │ └── webpack.config.js ├── .gitignore ├── .npmignore ├── README.md ├── README_zh.md ├── index.html ├── jqvm.png ├── loader.js ├── package-lock.json ├── package.json ├── src ├── async.js ├── index.js ├── jqvm.js ├── router.js ├── store.js └── utils.js ├── webpack.config.js └── webpack.dev.config.js /.demo/async-component.js: -------------------------------------------------------------------------------- 1 | const template = ` 2 |
3 |
{{title}}
4 |
{{content}}
5 |
6 | ` 7 | export default $(template) 8 | .vm(() => ({ title: 'Title', content: 'Content' })) 9 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist.js 3 | component-a.js 4 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/compile.js: -------------------------------------------------------------------------------- 1 | const { compile } = require('../../loader') 2 | const fs = require('fs') 3 | 4 | const content = fs.readFileSync(__dirname + '/component-a.html').toString() 5 | const output = compile(content, { $: 'jQuery' }) 6 | fs.writeFileSync(__dirname + '/component-a.js', output) 7 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/component-a.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 | 21 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/index.js: -------------------------------------------------------------------------------- 1 | import ComponentA from './component-a.html' 2 | 3 | import jQuery from 'jquery' 4 | import { useJQuery } from 'jqvm' 5 | 6 | const $ = useJQuery(jQuery) 7 | 8 | $('#app').vm({}) 9 | .component('comp-a', ComponentA) 10 | .mount() 11 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jqvm-loader", 3 | "version": "1.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@discoveryjs/json-ext": { 8 | "version": "0.5.3", 9 | "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", 10 | "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==" 11 | }, 12 | "@types/eslint": { 13 | "version": "7.2.13", 14 | "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", 15 | "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", 16 | "requires": { 17 | "@types/estree": "*", 18 | "@types/json-schema": "*" 19 | } 20 | }, 21 | "@types/eslint-scope": { 22 | "version": "3.7.0", 23 | "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", 24 | "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", 25 | "requires": { 26 | "@types/eslint": "*", 27 | "@types/estree": "*" 28 | } 29 | }, 30 | "@types/estree": { 31 | "version": "0.0.47", 32 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", 33 | "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==" 34 | }, 35 | "@types/json-schema": { 36 | "version": "7.0.7", 37 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", 38 | "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==" 39 | }, 40 | "@types/node": { 41 | "version": "15.12.2", 42 | "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", 43 | "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==" 44 | }, 45 | "@webassemblyjs/ast": { 46 | "version": "1.11.0", 47 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", 48 | "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", 49 | "requires": { 50 | "@webassemblyjs/helper-numbers": "1.11.0", 51 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0" 52 | } 53 | }, 54 | "@webassemblyjs/floating-point-hex-parser": { 55 | "version": "1.11.0", 56 | "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", 57 | "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==" 58 | }, 59 | "@webassemblyjs/helper-api-error": { 60 | "version": "1.11.0", 61 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", 62 | "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==" 63 | }, 64 | "@webassemblyjs/helper-buffer": { 65 | "version": "1.11.0", 66 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", 67 | "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==" 68 | }, 69 | "@webassemblyjs/helper-numbers": { 70 | "version": "1.11.0", 71 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", 72 | "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", 73 | "requires": { 74 | "@webassemblyjs/floating-point-hex-parser": "1.11.0", 75 | "@webassemblyjs/helper-api-error": "1.11.0", 76 | "@xtuc/long": "4.2.2" 77 | } 78 | }, 79 | "@webassemblyjs/helper-wasm-bytecode": { 80 | "version": "1.11.0", 81 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", 82 | "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==" 83 | }, 84 | "@webassemblyjs/helper-wasm-section": { 85 | "version": "1.11.0", 86 | "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", 87 | "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", 88 | "requires": { 89 | "@webassemblyjs/ast": "1.11.0", 90 | "@webassemblyjs/helper-buffer": "1.11.0", 91 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0", 92 | "@webassemblyjs/wasm-gen": "1.11.0" 93 | } 94 | }, 95 | "@webassemblyjs/ieee754": { 96 | "version": "1.11.0", 97 | "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", 98 | "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", 99 | "requires": { 100 | "@xtuc/ieee754": "^1.2.0" 101 | } 102 | }, 103 | "@webassemblyjs/leb128": { 104 | "version": "1.11.0", 105 | "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", 106 | "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", 107 | "requires": { 108 | "@xtuc/long": "4.2.2" 109 | } 110 | }, 111 | "@webassemblyjs/utf8": { 112 | "version": "1.11.0", 113 | "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", 114 | "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==" 115 | }, 116 | "@webassemblyjs/wasm-edit": { 117 | "version": "1.11.0", 118 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", 119 | "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", 120 | "requires": { 121 | "@webassemblyjs/ast": "1.11.0", 122 | "@webassemblyjs/helper-buffer": "1.11.0", 123 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0", 124 | "@webassemblyjs/helper-wasm-section": "1.11.0", 125 | "@webassemblyjs/wasm-gen": "1.11.0", 126 | "@webassemblyjs/wasm-opt": "1.11.0", 127 | "@webassemblyjs/wasm-parser": "1.11.0", 128 | "@webassemblyjs/wast-printer": "1.11.0" 129 | } 130 | }, 131 | "@webassemblyjs/wasm-gen": { 132 | "version": "1.11.0", 133 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", 134 | "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", 135 | "requires": { 136 | "@webassemblyjs/ast": "1.11.0", 137 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0", 138 | "@webassemblyjs/ieee754": "1.11.0", 139 | "@webassemblyjs/leb128": "1.11.0", 140 | "@webassemblyjs/utf8": "1.11.0" 141 | } 142 | }, 143 | "@webassemblyjs/wasm-opt": { 144 | "version": "1.11.0", 145 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", 146 | "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", 147 | "requires": { 148 | "@webassemblyjs/ast": "1.11.0", 149 | "@webassemblyjs/helper-buffer": "1.11.0", 150 | "@webassemblyjs/wasm-gen": "1.11.0", 151 | "@webassemblyjs/wasm-parser": "1.11.0" 152 | } 153 | }, 154 | "@webassemblyjs/wasm-parser": { 155 | "version": "1.11.0", 156 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", 157 | "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", 158 | "requires": { 159 | "@webassemblyjs/ast": "1.11.0", 160 | "@webassemblyjs/helper-api-error": "1.11.0", 161 | "@webassemblyjs/helper-wasm-bytecode": "1.11.0", 162 | "@webassemblyjs/ieee754": "1.11.0", 163 | "@webassemblyjs/leb128": "1.11.0", 164 | "@webassemblyjs/utf8": "1.11.0" 165 | } 166 | }, 167 | "@webassemblyjs/wast-printer": { 168 | "version": "1.11.0", 169 | "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", 170 | "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", 171 | "requires": { 172 | "@webassemblyjs/ast": "1.11.0", 173 | "@xtuc/long": "4.2.2" 174 | } 175 | }, 176 | "@webpack-cli/configtest": { 177 | "version": "1.0.4", 178 | "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", 179 | "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==" 180 | }, 181 | "@webpack-cli/info": { 182 | "version": "1.3.0", 183 | "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", 184 | "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", 185 | "requires": { 186 | "envinfo": "^7.7.3" 187 | } 188 | }, 189 | "@webpack-cli/serve": { 190 | "version": "1.5.1", 191 | "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz", 192 | "integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==" 193 | }, 194 | "@xtuc/ieee754": { 195 | "version": "1.2.0", 196 | "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", 197 | "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" 198 | }, 199 | "@xtuc/long": { 200 | "version": "4.2.2", 201 | "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", 202 | "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" 203 | }, 204 | "acorn": { 205 | "version": "8.3.0", 206 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz", 207 | "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==" 208 | }, 209 | "ajv": { 210 | "version": "6.12.6", 211 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 212 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 213 | "requires": { 214 | "fast-deep-equal": "^3.1.1", 215 | "fast-json-stable-stringify": "^2.0.0", 216 | "json-schema-traverse": "^0.4.1", 217 | "uri-js": "^4.2.2" 218 | } 219 | }, 220 | "ajv-keywords": { 221 | "version": "3.5.2", 222 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", 223 | "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" 224 | }, 225 | "browserslist": { 226 | "version": "4.16.6", 227 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", 228 | "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", 229 | "requires": { 230 | "caniuse-lite": "^1.0.30001219", 231 | "colorette": "^1.2.2", 232 | "electron-to-chromium": "^1.3.723", 233 | "escalade": "^3.1.1", 234 | "node-releases": "^1.1.71" 235 | } 236 | }, 237 | "buffer-from": { 238 | "version": "1.1.1", 239 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 240 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 241 | }, 242 | "caniuse-lite": { 243 | "version": "1.0.30001236", 244 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001236.tgz", 245 | "integrity": "sha512-o0PRQSrSCGJKCPZcgMzl5fUaj5xHe8qA2m4QRvnyY4e1lITqoNkr7q/Oh1NcpGSy0Th97UZ35yoKcINPoq7YOQ==" 246 | }, 247 | "chrome-trace-event": { 248 | "version": "1.0.3", 249 | "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", 250 | "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" 251 | }, 252 | "clone-deep": { 253 | "version": "4.0.1", 254 | "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", 255 | "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", 256 | "requires": { 257 | "is-plain-object": "^2.0.4", 258 | "kind-of": "^6.0.2", 259 | "shallow-clone": "^3.0.0" 260 | } 261 | }, 262 | "colorette": { 263 | "version": "1.2.2", 264 | "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", 265 | "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" 266 | }, 267 | "commander": { 268 | "version": "2.20.3", 269 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 270 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" 271 | }, 272 | "cross-spawn": { 273 | "version": "7.0.3", 274 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 275 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 276 | "requires": { 277 | "path-key": "^3.1.0", 278 | "shebang-command": "^2.0.0", 279 | "which": "^2.0.1" 280 | } 281 | }, 282 | "electron-to-chromium": { 283 | "version": "1.3.752", 284 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.752.tgz", 285 | "integrity": "sha512-2Tg+7jSl3oPxgsBsWKh5H83QazTkmWG/cnNwJplmyZc7KcN61+I10oUgaXSVk/NwfvN3BdkKDR4FYuRBQQ2v0A==" 286 | }, 287 | "enhanced-resolve": { 288 | "version": "5.8.2", 289 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", 290 | "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", 291 | "requires": { 292 | "graceful-fs": "^4.2.4", 293 | "tapable": "^2.2.0" 294 | } 295 | }, 296 | "envinfo": { 297 | "version": "7.8.1", 298 | "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", 299 | "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" 300 | }, 301 | "es-module-lexer": { 302 | "version": "0.4.1", 303 | "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", 304 | "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==" 305 | }, 306 | "escalade": { 307 | "version": "3.1.1", 308 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 309 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" 310 | }, 311 | "eslint-scope": { 312 | "version": "5.1.1", 313 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", 314 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", 315 | "requires": { 316 | "esrecurse": "^4.3.0", 317 | "estraverse": "^4.1.1" 318 | } 319 | }, 320 | "esrecurse": { 321 | "version": "4.3.0", 322 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 323 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 324 | "requires": { 325 | "estraverse": "^5.2.0" 326 | }, 327 | "dependencies": { 328 | "estraverse": { 329 | "version": "5.2.0", 330 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", 331 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" 332 | } 333 | } 334 | }, 335 | "estraverse": { 336 | "version": "4.3.0", 337 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", 338 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" 339 | }, 340 | "events": { 341 | "version": "3.3.0", 342 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", 343 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" 344 | }, 345 | "execa": { 346 | "version": "5.1.1", 347 | "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", 348 | "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", 349 | "requires": { 350 | "cross-spawn": "^7.0.3", 351 | "get-stream": "^6.0.0", 352 | "human-signals": "^2.1.0", 353 | "is-stream": "^2.0.0", 354 | "merge-stream": "^2.0.0", 355 | "npm-run-path": "^4.0.1", 356 | "onetime": "^5.1.2", 357 | "signal-exit": "^3.0.3", 358 | "strip-final-newline": "^2.0.0" 359 | } 360 | }, 361 | "fast-deep-equal": { 362 | "version": "3.1.3", 363 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 364 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 365 | }, 366 | "fast-json-stable-stringify": { 367 | "version": "2.1.0", 368 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 369 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 370 | }, 371 | "fastest-levenshtein": { 372 | "version": "1.0.12", 373 | "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", 374 | "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" 375 | }, 376 | "find-up": { 377 | "version": "4.1.0", 378 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 379 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 380 | "requires": { 381 | "locate-path": "^5.0.0", 382 | "path-exists": "^4.0.0" 383 | } 384 | }, 385 | "function-bind": { 386 | "version": "1.1.1", 387 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 388 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 389 | }, 390 | "get-stream": { 391 | "version": "6.0.1", 392 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", 393 | "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" 394 | }, 395 | "glob-to-regexp": { 396 | "version": "0.4.1", 397 | "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", 398 | "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" 399 | }, 400 | "graceful-fs": { 401 | "version": "4.2.6", 402 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", 403 | "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" 404 | }, 405 | "has": { 406 | "version": "1.0.3", 407 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 408 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 409 | "requires": { 410 | "function-bind": "^1.1.1" 411 | } 412 | }, 413 | "has-flag": { 414 | "version": "4.0.0", 415 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 416 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 417 | }, 418 | "human-signals": { 419 | "version": "2.1.0", 420 | "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", 421 | "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" 422 | }, 423 | "import-local": { 424 | "version": "3.0.2", 425 | "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", 426 | "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", 427 | "requires": { 428 | "pkg-dir": "^4.2.0", 429 | "resolve-cwd": "^3.0.0" 430 | } 431 | }, 432 | "interpret": { 433 | "version": "2.2.0", 434 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", 435 | "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" 436 | }, 437 | "is-core-module": { 438 | "version": "2.4.0", 439 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", 440 | "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", 441 | "requires": { 442 | "has": "^1.0.3" 443 | } 444 | }, 445 | "is-plain-object": { 446 | "version": "2.0.4", 447 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 448 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 449 | "requires": { 450 | "isobject": "^3.0.1" 451 | } 452 | }, 453 | "is-stream": { 454 | "version": "2.0.0", 455 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", 456 | "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" 457 | }, 458 | "isexe": { 459 | "version": "2.0.0", 460 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 461 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 462 | }, 463 | "isobject": { 464 | "version": "3.0.1", 465 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 466 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" 467 | }, 468 | "jest-worker": { 469 | "version": "27.0.2", 470 | "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", 471 | "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", 472 | "requires": { 473 | "@types/node": "*", 474 | "merge-stream": "^2.0.0", 475 | "supports-color": "^8.0.0" 476 | } 477 | }, 478 | "jquery": { 479 | "version": "3.6.0", 480 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", 481 | "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" 482 | }, 483 | "jqvm": { 484 | "version": "4.1.6", 485 | "resolved": "https://registry.npmjs.org/jqvm/-/jqvm-4.1.6.tgz", 486 | "integrity": "sha512-OMMDKKbsfmHHbwWqq0FtGqxdeSR/VGnoKjHMMuE0W26Vr2F1QoxEEDAeaTqzYniExT2aGLJn2Un5rSeGe1Fv6g==", 487 | "requires": { 488 | "jquery": "^3.6.0", 489 | "scopex": "^3.0.2", 490 | "ts-fns": "^10.3.2" 491 | } 492 | }, 493 | "json-parse-better-errors": { 494 | "version": "1.0.2", 495 | "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", 496 | "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" 497 | }, 498 | "json-schema-traverse": { 499 | "version": "0.4.1", 500 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 501 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 502 | }, 503 | "kind-of": { 504 | "version": "6.0.3", 505 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 506 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" 507 | }, 508 | "loader-runner": { 509 | "version": "4.2.0", 510 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", 511 | "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" 512 | }, 513 | "locate-path": { 514 | "version": "5.0.0", 515 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 516 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 517 | "requires": { 518 | "p-locate": "^4.1.0" 519 | } 520 | }, 521 | "merge-stream": { 522 | "version": "2.0.0", 523 | "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", 524 | "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" 525 | }, 526 | "mime-db": { 527 | "version": "1.48.0", 528 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", 529 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" 530 | }, 531 | "mime-types": { 532 | "version": "2.1.31", 533 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", 534 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", 535 | "requires": { 536 | "mime-db": "1.48.0" 537 | } 538 | }, 539 | "mimic-fn": { 540 | "version": "2.1.0", 541 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 542 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 543 | }, 544 | "neo-async": { 545 | "version": "2.6.2", 546 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 547 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" 548 | }, 549 | "node-releases": { 550 | "version": "1.1.73", 551 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", 552 | "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" 553 | }, 554 | "npm-run-path": { 555 | "version": "4.0.1", 556 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", 557 | "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", 558 | "requires": { 559 | "path-key": "^3.0.0" 560 | } 561 | }, 562 | "onetime": { 563 | "version": "5.1.2", 564 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 565 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 566 | "requires": { 567 | "mimic-fn": "^2.1.0" 568 | } 569 | }, 570 | "p-limit": { 571 | "version": "3.1.0", 572 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 573 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 574 | "requires": { 575 | "yocto-queue": "^0.1.0" 576 | } 577 | }, 578 | "p-locate": { 579 | "version": "4.1.0", 580 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 581 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 582 | "requires": { 583 | "p-limit": "^2.2.0" 584 | }, 585 | "dependencies": { 586 | "p-limit": { 587 | "version": "2.3.0", 588 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 589 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 590 | "requires": { 591 | "p-try": "^2.0.0" 592 | } 593 | } 594 | } 595 | }, 596 | "p-try": { 597 | "version": "2.2.0", 598 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 599 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" 600 | }, 601 | "path-exists": { 602 | "version": "4.0.0", 603 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 604 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 605 | }, 606 | "path-key": { 607 | "version": "3.1.1", 608 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 609 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 610 | }, 611 | "path-parse": { 612 | "version": "1.0.7", 613 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 614 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" 615 | }, 616 | "pkg-dir": { 617 | "version": "4.2.0", 618 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 619 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 620 | "requires": { 621 | "find-up": "^4.0.0" 622 | } 623 | }, 624 | "punycode": { 625 | "version": "2.1.1", 626 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 627 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 628 | }, 629 | "randombytes": { 630 | "version": "2.1.0", 631 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", 632 | "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", 633 | "requires": { 634 | "safe-buffer": "^5.1.0" 635 | } 636 | }, 637 | "rechoir": { 638 | "version": "0.7.0", 639 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", 640 | "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", 641 | "requires": { 642 | "resolve": "^1.9.0" 643 | } 644 | }, 645 | "resolve": { 646 | "version": "1.20.0", 647 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", 648 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", 649 | "requires": { 650 | "is-core-module": "^2.2.0", 651 | "path-parse": "^1.0.6" 652 | } 653 | }, 654 | "resolve-cwd": { 655 | "version": "3.0.0", 656 | "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", 657 | "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", 658 | "requires": { 659 | "resolve-from": "^5.0.0" 660 | } 661 | }, 662 | "resolve-from": { 663 | "version": "5.0.0", 664 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", 665 | "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" 666 | }, 667 | "safe-buffer": { 668 | "version": "5.2.1", 669 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 670 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 671 | }, 672 | "schema-utils": { 673 | "version": "3.0.0", 674 | "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", 675 | "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", 676 | "requires": { 677 | "@types/json-schema": "^7.0.6", 678 | "ajv": "^6.12.5", 679 | "ajv-keywords": "^3.5.2" 680 | } 681 | }, 682 | "scopex": { 683 | "version": "3.0.2", 684 | "resolved": "https://registry.npmjs.org/scopex/-/scopex-3.0.2.tgz", 685 | "integrity": "sha512-yFlUEL6m/VxncnoBdldlKOAN/f2+zcm/3SR5z3Guseh/ayIygbhK5vw18LLENOYDVaYktvUPS28Bk+xNMqUQ8w==" 686 | }, 687 | "serialize-javascript": { 688 | "version": "5.0.1", 689 | "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", 690 | "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", 691 | "requires": { 692 | "randombytes": "^2.1.0" 693 | } 694 | }, 695 | "shallow-clone": { 696 | "version": "3.0.1", 697 | "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", 698 | "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", 699 | "requires": { 700 | "kind-of": "^6.0.2" 701 | } 702 | }, 703 | "shebang-command": { 704 | "version": "2.0.0", 705 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 706 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 707 | "requires": { 708 | "shebang-regex": "^3.0.0" 709 | } 710 | }, 711 | "shebang-regex": { 712 | "version": "3.0.0", 713 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 714 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 715 | }, 716 | "signal-exit": { 717 | "version": "3.0.3", 718 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", 719 | "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" 720 | }, 721 | "source-list-map": { 722 | "version": "2.0.1", 723 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", 724 | "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" 725 | }, 726 | "source-map": { 727 | "version": "0.6.1", 728 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 729 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 730 | }, 731 | "source-map-support": { 732 | "version": "0.5.19", 733 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", 734 | "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", 735 | "requires": { 736 | "buffer-from": "^1.0.0", 737 | "source-map": "^0.6.0" 738 | } 739 | }, 740 | "strip-final-newline": { 741 | "version": "2.0.0", 742 | "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", 743 | "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" 744 | }, 745 | "supports-color": { 746 | "version": "8.1.1", 747 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", 748 | "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", 749 | "requires": { 750 | "has-flag": "^4.0.0" 751 | } 752 | }, 753 | "tapable": { 754 | "version": "2.2.0", 755 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", 756 | "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==" 757 | }, 758 | "terser": { 759 | "version": "5.7.0", 760 | "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", 761 | "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==", 762 | "requires": { 763 | "commander": "^2.20.0", 764 | "source-map": "~0.7.2", 765 | "source-map-support": "~0.5.19" 766 | }, 767 | "dependencies": { 768 | "source-map": { 769 | "version": "0.7.3", 770 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", 771 | "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" 772 | } 773 | } 774 | }, 775 | "terser-webpack-plugin": { 776 | "version": "5.1.3", 777 | "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.3.tgz", 778 | "integrity": "sha512-cxGbMqr6+A2hrIB5ehFIF+F/iST5ZOxvOmy9zih9ySbP1C2oEWQSOUS+2SNBTjzx5xLKO4xnod9eywdfq1Nb9A==", 779 | "requires": { 780 | "jest-worker": "^27.0.2", 781 | "p-limit": "^3.1.0", 782 | "schema-utils": "^3.0.0", 783 | "serialize-javascript": "^5.0.1", 784 | "source-map": "^0.6.1", 785 | "terser": "^5.7.0" 786 | } 787 | }, 788 | "ts-fns": { 789 | "version": "10.3.2", 790 | "resolved": "https://registry.npmjs.org/ts-fns/-/ts-fns-10.3.2.tgz", 791 | "integrity": "sha512-8OtNhaovuSgQloSmMZ2AKFXch0Zum5Cglv/GBeT63GE6RS3CNcoMVa460CF0ABx9uCeBPlncWOB7o2K6idvvTw==" 792 | }, 793 | "uri-js": { 794 | "version": "4.4.1", 795 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 796 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 797 | "requires": { 798 | "punycode": "^2.1.0" 799 | } 800 | }, 801 | "v8-compile-cache": { 802 | "version": "2.3.0", 803 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", 804 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==" 805 | }, 806 | "watchpack": { 807 | "version": "2.2.0", 808 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", 809 | "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", 810 | "requires": { 811 | "glob-to-regexp": "^0.4.1", 812 | "graceful-fs": "^4.1.2" 813 | } 814 | }, 815 | "webpack": { 816 | "version": "5.38.1", 817 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", 818 | "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", 819 | "requires": { 820 | "@types/eslint-scope": "^3.7.0", 821 | "@types/estree": "^0.0.47", 822 | "@webassemblyjs/ast": "1.11.0", 823 | "@webassemblyjs/wasm-edit": "1.11.0", 824 | "@webassemblyjs/wasm-parser": "1.11.0", 825 | "acorn": "^8.2.1", 826 | "browserslist": "^4.14.5", 827 | "chrome-trace-event": "^1.0.2", 828 | "enhanced-resolve": "^5.8.0", 829 | "es-module-lexer": "^0.4.0", 830 | "eslint-scope": "5.1.1", 831 | "events": "^3.2.0", 832 | "glob-to-regexp": "^0.4.1", 833 | "graceful-fs": "^4.2.4", 834 | "json-parse-better-errors": "^1.0.2", 835 | "loader-runner": "^4.2.0", 836 | "mime-types": "^2.1.27", 837 | "neo-async": "^2.6.2", 838 | "schema-utils": "^3.0.0", 839 | "tapable": "^2.1.1", 840 | "terser-webpack-plugin": "^5.1.1", 841 | "watchpack": "^2.2.0", 842 | "webpack-sources": "^2.3.0" 843 | } 844 | }, 845 | "webpack-cli": { 846 | "version": "4.7.2", 847 | "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz", 848 | "integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==", 849 | "requires": { 850 | "@discoveryjs/json-ext": "^0.5.0", 851 | "@webpack-cli/configtest": "^1.0.4", 852 | "@webpack-cli/info": "^1.3.0", 853 | "@webpack-cli/serve": "^1.5.1", 854 | "colorette": "^1.2.1", 855 | "commander": "^7.0.0", 856 | "execa": "^5.0.0", 857 | "fastest-levenshtein": "^1.0.12", 858 | "import-local": "^3.0.2", 859 | "interpret": "^2.2.0", 860 | "rechoir": "^0.7.0", 861 | "v8-compile-cache": "^2.2.0", 862 | "webpack-merge": "^5.7.3" 863 | }, 864 | "dependencies": { 865 | "commander": { 866 | "version": "7.2.0", 867 | "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", 868 | "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" 869 | } 870 | } 871 | }, 872 | "webpack-merge": { 873 | "version": "5.8.0", 874 | "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", 875 | "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", 876 | "requires": { 877 | "clone-deep": "^4.0.1", 878 | "wildcard": "^2.0.0" 879 | } 880 | }, 881 | "webpack-sources": { 882 | "version": "2.3.0", 883 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", 884 | "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", 885 | "requires": { 886 | "source-list-map": "^2.0.1", 887 | "source-map": "^0.6.1" 888 | } 889 | }, 890 | "which": { 891 | "version": "2.0.2", 892 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 893 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 894 | "requires": { 895 | "isexe": "^2.0.0" 896 | } 897 | }, 898 | "wildcard": { 899 | "version": "2.0.0", 900 | "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", 901 | "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" 902 | }, 903 | "yocto-queue": { 904 | "version": "0.1.0", 905 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 906 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" 907 | } 908 | } 909 | } 910 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jqvm-loader", 3 | "version": "1.1.0", 4 | "description": "", 5 | "main": "jqvm-loader.js", 6 | "scripts": { 7 | "build": "webpack" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "jqvm": "^4.1.6", 13 | "webpack": "^5.38.1", 14 | "webpack-cli": "^4.7.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.demo/jqvm-loader/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'none', 3 | target: 'web', 4 | entry: __dirname + '/index.js', 5 | output: { 6 | path: __dirname, 7 | filename: 'dist.js', 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.html$/, 13 | loader: __dirname + '/../../loader.js', 14 | options: { 15 | // $: 'jQuery', 16 | } 17 | }, 18 | ], 19 | }, 20 | externals: { 21 | jquery: 'jQuery', 22 | jqvm: true, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | webpack.config.js 2 | webpack.dev.config.js 3 | jqvm.png 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

jqvm

2 |

The world's easiest reactive frontend view-model framework based on jQuery.

3 | 4 |
5 |
6 |
7 | 8 |

9 | 10 |
11 |
12 |
13 |
14 | 15 | [中文文档](./README_zh.md) 16 | [English](./README.md) 17 | 18 | ## :hear_no_evil: What's all the jQvm? 19 | 20 | JQvm is a library, a jQuery plugin, a frontend reactive view-model framework, which helps JavaScript developers who are familiar with jQuery code more quickly. Boring with React, Vue? Want to taste reactive programming in frontend? Believe me, if you have learned jQuery, you can setup a small application in 10 seconds! 21 | 22 | ## :rocket: Install 23 | 24 | ``` 25 | npm i jqvm 26 | ``` 27 | 28 | With modules system. 29 | 30 | ```js 31 | import jQuery from 'jquery' 32 | import { useJQuery } from 'jqvm' 33 | 34 | const $ = useJQuery(jQuery) 35 | ``` 36 | 37 | You can use cdn of unpkg. 38 | 39 | ```html 40 | 41 | 42 | ``` 43 | 44 | ## :zap: Fast implementation 45 | 46 | There is a small [demo](https://unpkg.com/jqvm/index.html), you can try it online. 47 | 48 | **step 1: template** 49 | 50 | You should define your template in your html. 51 | 52 | ```html 53 | 54 | 55 | 58 | ``` 59 | 60 | **step 2: initialize** 61 | 62 | You should create scripts like this: 63 | 64 | ```html 65 | 66 | 67 | 68 | 73 | ``` 74 | 75 | Or 76 | 77 | ```js 78 | import jQuery from 'jquery' 79 | import { useJQuery } from 'jqvm' 80 | 81 | const $ = useJQuery(jQuery) 82 | $('#app') 83 | .vm({ title: 'Default Title' }) 84 | .mount() 85 | ``` 86 | 87 | **step 3: bind event listeners** 88 | 89 | Unlike vue.js, you should must bind event listeners in script, not in template. 90 | 91 | ```html 92 | 100 | ``` 101 | 102 | Here, you call the `on` method and pass a action function to change `state`, and the view will be rerendered. 103 | 104 | ## :tada: API 105 | 106 | ### Exports 107 | 108 | ```js 109 | import { 110 | component, 111 | directive, 112 | filter, 113 | View, 114 | useJQuery, 115 | createStore, 116 | createAsyncComponent, 117 | } from 'jqvm' 118 | ``` 119 | 120 | Or in browser: 121 | 122 | ```js 123 | const { 124 | component, 125 | directive, 126 | filter, 127 | View, 128 | useJQuery, 129 | createStore, 130 | createAsyncComponent, 131 | } = window.jqvm 132 | ``` 133 | 134 | - component(name:string, compile:function, affect:function): global component register function 135 | - directive(name:string, compile:function, affect:function): global directive register function 136 | - filter(name:string, formatter:function): global filter register function 137 | - View: view constructor 138 | - useJQuery: you can use another version jquery by invoke this 139 | 140 | ### $.fn.vm 141 | 142 | JQVM is a jQuery plugin first at all, you should use code like this: 143 | 144 | ```js 145 | const view = $('#app').vm(initState) 146 | ``` 147 | 148 | JQVM will treat html string in #app as template, so, it is recommended to use `template` tag to define template. 149 | 150 | The return value is a `view` object which has methods: 151 | 152 | - on(event, selector?, action): bind an action, notice that action function is different from jQuery.fn.on callback function, I will detail later 153 | - once(event, selector?, action): refer to jQuery's `one` 154 | - off(event, selector?, action?): unbind listener which is bound by `on` 155 | - mount(el?): mount view into DOM 156 | - unmount(): unmount view from DOM, `vm` is unusable until you invoke `mount` again 157 | - destroy(): unmount and clear bound actions, after you destroy, you can mount again, but actions should be bound again 158 | - update(nextState?): rerender, you can pass new state into `update()`, the new state will be merge into old state like react setState does. 159 | - find(selector): same as `$.fn.find`, select elements in view container 160 | - component(name, compile, affect): register component only for this vm 161 | - directive(name, compile, affect): register directive only for this vm 162 | - filter(name, formatter): register formatter only for this vm 163 | - fn(name, action?, patch?): register a function on `view`, when you not pass `func`, it means you want to get the function, `action` is the same usage as `on` 164 | 165 | The `mount` method can receive a selector or a jquery element. 166 | 167 | ```js 168 | const template = ` 169 | 172 | ` 173 | $(template) 174 | .vm({ title: 'xxx' }) 175 | .mount('div#app') // mount view to div#app 176 | ``` 177 | 178 | When selector is passed into `mount`, the view will be rendered in the target element (replace with innerHTML). If selector is not passed, you should select a element in DOM and the view will be rendered after the selected element (as the beginning code does). 179 | 180 | `fn` define a new function on view: 181 | 182 | ```js 183 | $(..).vm({ .. }) 184 | .fn('fnName', (state, ...args) => (e) => { 185 | ... 186 | }) 187 | .fn('doSome', (state) => (xx) => { 188 | ... 189 | }, true) 190 | .on('click', '.some', function() { 191 | this.doSome('xx') 192 | }) 193 | ``` 194 | 195 | Now, let's look into `action` detail. 196 | 197 | ```js 198 | // a function which return a inner function 199 | // state: the current state in vm 200 | // ...args: those bind on fn in template 201 | function action(state, ...args) { 202 | const view = this // you can do like `view.unmount()` 203 | 204 | state.some = 'next' // `some` should be exisiting in state, and this will trigger rerendering later 205 | // if `some` is not in state, you should MUST use `state.$set('some', 'next') 206 | // async works, i.e. setTimeout(() => state.some = 'next', 1000) 207 | // if you change some instances which is not a plain object, you should invoke `view.update()` manually, 208 | // i.e. `state.myIns.name = 'new name'; view.update()` 209 | 210 | // handle function which is put into jQuery.fn.on as you did like `$('#app').on('click', handle)` 211 | // handle function is optional, when you do not return handle function, action will still be invoked when the event happens, but you have no idea to receive DOM event 212 | return function handle(e) { 213 | const el = this 214 | const $el = $(this) 215 | } 216 | } 217 | 218 | view.on('click', '.some', action) 219 | ``` 220 | 221 | No matter you use `fn` in view or to a component by `@`, the `action` function is the same structure. 222 | 223 | ```html 224 | 225 | 226 | 232 | ``` 233 | 234 | Inside events: 235 | 236 | - $mount: when you invoke `view.mount()` this event will be triggered 237 | - $unmount: when you invoke `view.unmount()` 238 | - $render: when inner content rendered 239 | - $change: when state change 240 | 241 | ```js 242 | $('#app') 243 | .vm({ name: 'some' }) 244 | .on('$mount', state => { 245 | state.name = 'new name' 246 | }) 247 | .mount() 248 | ``` 249 | 250 | The changing of `state` object you receive in action function will trigger rerendering. 251 | And the scope in template is `state`, so when you write a `{{title}}` syntax in template, you are calling `state.title` in fact. 252 | `state` is only available in `on` action functions. 253 | 254 | *You should always change `state` instead of changing DOM to trigger UI changing. You should not change DOM in `action` function unless you know what you are doing!* 255 | 256 | It is created from `initState` which is received by `$('#app').vm(initState)`, `initState` can be one of: 257 | 258 | - object: a normal object which is used to be vm's default state. 259 | - function: which returns one of above 260 | 261 | *Notice, an instance of some class, for example `new Some()`, should not be passed in, only normal object supported.* 262 | 263 | When you pass a normal object, the original object will be changed by vm. This make it shared amoung different mounting. 264 | To prevent this, you can use a function to return an independent object in the function. 265 | 266 | ```js 267 | const view = $('#app').vm(function init() { 268 | return { title: 'xxx' } 269 | }) 270 | 271 | view.mount() 272 | view.unmount() // destory DOM 273 | view.mount() // use `init` function to generate independent initState 274 | ``` 275 | 276 | ## :dizzy: Directive 277 | 278 | You can invoke `directive` to create a new attribute. 279 | 280 | ``` 281 | directive(name:string, compile:function, affect:function) 282 | ``` 283 | 284 | - name: the tag name of the directive 285 | - compile($el, attrs): how to compile this component, should return undefined|$el|htmlstring 286 | - affect($el, attrs): do some side effects after whole template have been compiled, should return a function to abolish side effects, will be invoke after each compilation 287 | 288 | ```js 289 | const { directive } = window.jqvm 290 | 291 | directive('jq-link', function(el, attrs) { 292 | const link = attrs['jq-link'] 293 | el.attr('href', link) 294 | // if you return a string, it will be used as this tag's new content 295 | // if you do not return anthing, `el` will be used as content 296 | }) 297 | ``` 298 | 299 | ```html 300 | 303 | ``` 304 | 305 | *Notice that, `el` is a copy element in `directive` and `component`, it is not in real DOM, so you should not bind events on it, binding will not work!* 306 | 307 | Example of `affect`: 308 | 309 | ```js 310 | directive('jq-src', null, function($el, attrs) { 311 | // here $el is real DOM element referer 312 | const attr = attrs['jq-src'] 313 | const value = this.scope.interpolate(attr) 314 | $el.attr('src', value) 315 | }) 316 | ``` 317 | 318 | This is the source code of `jq-src`, by this operation, image will not be loaded when compiling, and will be loaded after insert into DOM. 319 | 320 | ```html 321 | 322 | ``` 323 | 324 | You can even bind event listeners to $el: 325 | 326 | ```js 327 | directive('jq-on-click', null, function($el, attrs) { 328 | const callback = () => console.log('click') 329 | $el.on('click', callback) 330 | return () => $el.off('click', callback) // notice, you should must return function to abolish side effects 331 | }) 332 | ``` 333 | 334 | **BuiltIn Directives** 335 | 336 | Here are builtin directives: 337 | 338 | - `jq-if="!!exp"` whehter to show this tag 339 | - `jq-class="{ 'some-class': !!exp }"` whether patch classes to tag 340 | - `jq-value="exp"` only used on `input` `select` `textarea` 341 | - `jq-disabled="!!exp"` only used on `input` `select` `textarea` `button` 342 | - `jq-checked="!!exp"` only used on `input[type=checkbox]` `input[type=radio]` 343 | - `jq-selected="!!exp"` only used on `select > option` 344 | - `jq-bind="keyPath"` two way binding, only used on `input` `select` `textarea`, when user type in, the `keyPath` value of vm will be update automaticly 345 | - `jq-src="exp"` only used on `img`, you should always use jq-src instead of `src` 346 | - `jq-repeat` print serval times 347 | - `jq-on="event:fn"` bind event callback function 348 | 349 | The `jq-repeat` usage is a little complex: 350 | 351 | ```html 352 |
353 | {{index + 1}} 354 | {{value.name}} 355 | {{value.time}} 356 |
357 | ``` 358 | 359 | Notice, `value,index` should have NO space inside, `,index` is optional. 360 | 361 | The `jq-on` directive should must work with `view.fn`, for example: 362 | 363 | ```html 364 | 365 | 366 | 371 | ``` 372 | 373 | ## :clown_face: Component 374 | 375 | You can invoke `component` to create a new tag. 376 | 377 | ``` 378 | component(name:string, view:View) 379 | ``` 380 | 381 | - name: the tag name of the component 382 | - view: another view created by $.fn.vm 383 | 384 | ```js 385 | const { component } = window.jqvm 386 | 387 | const icon = $(``) 388 | .vm(() => ({ type: 'eye' })) // notice here, you should use a function to return initState 389 | 390 | component('icon', icon) 391 | ``` 392 | 393 | You should use a function to return initState, so that the state of component is alone. 394 | 395 | Now you can use this `icon` component in template: 396 | 397 | ```html 398 | 401 | ``` 402 | 403 | When the component rendered, it will use `type="search"` to replace `type` state, so the final html is: 404 | 405 | ``` 406 | 407 | ``` 408 | 409 | **props** 410 | 411 | When you want to pass props into a component, you should know that: 412 | 413 | - `type="search"` normal string 414 | - `:type="'search'"` expression, read from state of current scope 415 | - `@change="fn"` emitter handler function, read from functions which registered by `fn` 416 | 417 | And, a very important thing: *only those properties on component's state will work (override inner state), others will have no effect, and you have no idea to get them.*. When the value of a property changes, the inner component will rerender with new value. For example: 418 | 419 | ```js 420 | const box = $(`...`).vm({ a: 1, b: 2 }) 421 | 422 | const view = $(` 423 | 424 | `) 425 | .vm(() => ({ ... })) 426 | .component('my-box', box) 427 | // :a="2" will work, and c="xxx" will not work (has no effect) 428 | ``` 429 | 430 | **emitter** 431 | 432 | Inside a component (sepcial view), you should call `view.emit` to emit a event. For example: 433 | 434 | ```js 435 | $(...).vm(() => ({ ... })) 436 | .fn('change', function(state) { 437 | return (e) => this.emit('change', e) // this -> view, emit is only in view instance 438 | }) 439 | ``` 440 | 441 | Usage: 442 | 443 | ```js 444 | this.emit(event, ...args) 445 | ``` 446 | 447 | Then you can receive the event outside: 448 | 449 | ```html 450 | 451 | ``` 452 | 453 | The handler function is an `action` function as metioned. 454 | 455 | Notice: component emitter is different from `jq-on` event. `jq-on` event is refer to DOM Event system, component emitter is just refer to a custom subscriber system. 456 | 457 | ## :bread: Filter 458 | 459 | A filter is a string formatter which used in template. 460 | 461 | ```html 462 | 465 | ``` 466 | 467 | ```js 468 | function number(value, fixed) { 469 | return value.toFixed(fixed) 470 | } 471 | 472 | view.filter('number', number) 473 | ``` 474 | 475 | The first paramter of the function is the value receive from the previous before `|`. 476 | 477 | ## Store 478 | 479 | To share state among components, you may use a store to maintain the shared state: 480 | 481 | ```js 482 | // create store and share it between two components by passing `store` into `.vm(store)` 483 | const { createStore } = window.jqvm 484 | const store = createStore({ count: 10 }) 485 | const componentA = $('{{count}}') 486 | .vm(store) 487 | const componentB = $('
count: {{count}}
') 488 | .vm(store) 489 | 490 | // using the two components 491 | 495 | 496 | $('#app').vm({}) 497 | .component('comp-a', componentA) 498 | .component('comp-b', componentB) 499 | .mount() 500 | ``` 501 | 502 | ## Async Component 503 | 504 | To split your code with unit by component, you can use `createAsyncComponent` to implement this. 505 | 506 | ``` 507 | createAsyncComponent(loader:Function, callback:Function) -> compile 508 | ``` 509 | 510 | - loader: Function to return a jQuery.Deferred or promise which contains a `then` method, a ESModule with `default` export a View instance or a View instance should be put in `then` callback 511 | - callback: invoke after the deferer resolved, you can visti `this` as current view in it 512 | 513 | Example: 514 | 515 | ```js 516 | // https://xxx/some-component.js 517 | export default $(`{{title}}`) 518 | .vm(() => ({ title: '' })) 519 | 520 | // main.js 521 | $('#app').vm(...) 522 | .component('some-component', createAsyncComponent(() => import('https://xxxx/some-component.js'))) 523 | .mount() 524 | ``` 525 | 526 | ```js 527 | // main.js 528 | $('#app').vm({ loading: true }) 529 | .component( 530 | 'my-box', 531 | createAsyncComponent( 532 | () => $.get('https://xxxx/some-component.template.html') 533 | .then((html) => $(html).vm(() => ({ title: '' }))), 534 | function() { 535 | this.update({ loading: false }) 536 | }, 537 | ), 538 | ) 539 | ``` 540 | 541 | Or you can use AMD Module system to create a single component as a module to load, so that you can split your code easily. 542 | 543 | ## :see_no_evil: License 544 | 545 | MIT. 546 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 |

jqvm

2 |

基于jQuery的超简单响应式开发框架

3 | 4 |
5 |
6 |
7 | 8 |

9 | 10 |
11 |
12 |
13 |
14 | 15 | [中文文档](./README_zh.md) 16 | [English](./README.md) 17 | 18 | ## :hear_no_evil: 什么是jQvm? 19 | 20 | jQvm是一个jQuery插件,同时也是一个MVVM响应式视图层框架。它帮助熟悉jQuery的开发者实现更便捷的开发。你可能用过其他前端框架,但是,如果你的系统是基于jQuery的老系统,那么根本没法迁移,而使用这个插件,你就既能在原有系统基础上升级,同时又享受现代响应式编程的乐趣。相信我,如果你用过jQuery,你会在10秒内学会jQvm! 21 | 22 | ## :rocket: 安装 23 | 24 | ``` 25 | npm i jqvm 26 | ``` 27 | 28 | ```js 29 | import jQuery from 'jquery' 30 | import { useJQuery } from 'jqvm' 31 | 32 | const $ = useJQuery(jQuery) 33 | ``` 34 | 35 | 或者直接使用CDN引入: 36 | 37 | ```html 38 | 39 | 40 | ``` 41 | 42 | ## :zap: 快速上手 43 | 44 | 这里有一个小[demo](https://unpkg.com/jqvm/index.html),你可以提前在线试试。 45 | 46 | **第1步:模板** 47 | 48 | 你可以在HTML中定义好模板。 49 | 50 | ```html 51 | 52 | 53 | 56 | ``` 57 | 58 | **第3步:实例化** 59 | 60 | 接下来,你需要在脚本中实例化视图。 61 | 62 | ```html 63 | 64 | 65 | 66 | 71 | ``` 72 | 73 | 或者: 74 | 75 | ```js 76 | import jQuery from 'jquery' 77 | import { useJQuery } from 'jqvm' 78 | 79 | const $ = useJQuery(jQuery) 80 | $('#app') 81 | .vm({ title: 'Default Title' }) 82 | .mount() 83 | ``` 84 | 85 | **第3步:事件监听** 86 | 87 | 你可以像使用jQuery的on一样,对视图内部的元素进行监听。 88 | 89 | ```html 90 | 98 | ``` 99 | 100 | 在这段代码里面,你用`on`方法监听了`click`事件,同时在回调函数中,直接修改`state`触发界面更新。 101 | 102 | 你也可以使用内部指令`jq-on`来完成事件监听: 103 | 104 | ```html 105 | 109 | 110 | 118 | ``` 119 | 120 | 使用内置的`jq-on`指令,再配合通过`fn`方法定义的一个内部函数,就可以完成对`button`的点击事件监听。 121 | 122 | ## :tada: API 123 | 124 | > jQvm里面有两个概念:View和VM。我们调用`$('#app').vm({ a: 1 })`时会在上下文中建立一个VM,返回的是一个View的实例。VM对开发者不可见,它有一个state作为渲染界面的数据,这个state可在事件监听或方法调用时作为函数的参数被拿到。View实例是开发者使用的主要的对象,这个view提供了一堆方法,在大部分情况下都可以被获取,具体看下文。 125 | 126 | ### 导出接口 127 | 128 | 如果你在模块系统中使用,那么如下引入需要的接口: 129 | 130 | ```js 131 | import { 132 | component, 133 | directive, 134 | filter, 135 | View, 136 | useJQuery, 137 | createStore, 138 | createAsyncComponent, 139 | } from 'jqvm' 140 | ``` 141 | 142 | 如果在浏览器中使用,可以快速的按下面的方法引入: 143 | 144 | ```js 145 | const { 146 | component, 147 | directive, 148 | filter, 149 | View, 150 | useJQuery, 151 | createStore, 152 | createAsyncComponent, 153 | } = window.jqvm 154 | ``` 155 | 156 | `jqvm`是挂载在window对象上的一个静态属性,它提供了一系列的对象给你使用。其中包含了: 157 | 158 | - component(name:string, compile:function, affect:function): 注册全局组件 159 | - directive(name:string, compile:function, affect:function): 注册全局指令 160 | - filter(name:string, formatter:function): 注册全局过滤器 161 | - View: View构造器。基本上不会用到,只会用来作为一些判断依据。 162 | - useJQuery: 你可以使用另外一个版本的jQuery,一般只在模块系统中使用 163 | - createStore: 用于创建一个store的函数 164 | - createAsyncComponent: 用于创建一个异步组件的函数 165 | 166 | ### $.fn.vm 167 | 168 | jQvm是一个jQuery插件,所以使用的时候,像其他插件一样,你可以这么用: 169 | 170 | ```js 171 | const view = $('#app').vm(initState) 172 | ``` 173 | 174 | jQvm把`#app`内部的HTML字符串当作模板,用它们来构建界面。但是,如果你直接在HMTL中写标签,会被渲染到界面上,所以,jQvm强制你用`