@jseeio/jsee 0.2.3 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,15 +1,16 @@
1
1
  {
2
2
  "name": "@jseeio/jsee",
3
- "version": "0.2.3",
3
+ "version": "0.2.7",
4
4
  "description": "",
5
5
  "main": "dist/jsee.js",
6
6
  "private": false,
7
7
  "scripts": {
8
- "build-dev": "webpack --mode=development --progress",
9
- "build": "webpack --mode=production --progress && npx webpack --mode=production --progress --env RUNTIME",
10
- "watch": "nodemon --watch . --ignore dist --ext vue,js,css,html --exec 'npm run build-dev'",
11
- "prepublishOnly": "npm run build",
12
- "test": "tape test.js | faucet"
8
+ "build-dev": "webpack --mode=development --progress --stats-children --env DEVELOPMENT",
9
+ "build": "webpack --mode=production --progress && webpack --mode=production --progress --env RUNTIME",
10
+ "watch": "nodemon --watch . --ignore dist --ext vue,js,css,html --exec 'npm run build-dev && npm test'",
11
+ "prepublishOnly": "npm run build && npm test",
12
+ "test": "jest test.js --detectOpenHandles",
13
+ "test-head": "HEADLESS=false npm test"
13
14
  },
14
15
  "author": "Anton Zemlyansky",
15
16
  "license": "MIT",
@@ -31,10 +32,14 @@
31
32
  "@babel/preset-env": "^7.16.5",
32
33
  "babel-loader": "^8.2.3",
33
34
  "css-loader": "^6.5.1",
35
+ "http-server": "^14.0.0",
36
+ "jest": "^27.4.5",
37
+ "jest-puppeteer": "^6.0.3",
34
38
  "node-sass": "^7.0.0",
35
39
  "nodemon": "^2.0.15",
36
- "puppeteer": "^1.12.2",
40
+ "puppeteer": "^1.20.0",
37
41
  "sass-loader": "^12.4.0",
42
+ "source-map-loader": "^3.0.0",
38
43
  "style-loader": "^3.3.1",
39
44
  "tape": "^4.9.1",
40
45
  "terser-webpack-plugin": "^5.3.0",
package/src/app.js CHANGED
@@ -20,12 +20,7 @@ const components = {
20
20
  const filtrex = require('filtrex')
21
21
  const JsonViewer = require('vue3-json-viewer').default
22
22
 
23
- function log () {
24
- console.log(`[Vue]`, ...arguments)
25
- }
26
-
27
23
  function resetInputs (inputs) {
28
- log('Resetting inputs...')
29
24
  inputs.forEach(input => {
30
25
  if (input.default) {
31
26
  input.value = input.default
@@ -65,7 +60,14 @@ function resetInputs (inputs) {
65
60
  })
66
61
  }
67
62
 
68
- function createVueApp (env, dataInit, mountedCallback) {
63
+ function createVueApp (env, mountedCallback, logMain) {
64
+ function log () {
65
+ logMain('[Vue]', ...arguments)
66
+ }
67
+
68
+ // Vue's data is based on schema
69
+ const dataInit = env.schema
70
+
69
71
  // Reset input values to default ones
70
72
  resetInputs(dataInit.inputs)
71
73
 
@@ -73,6 +75,11 @@ function createVueApp (env, dataInit, mountedCallback) {
73
75
  dataInit.outputs = []
74
76
  }
75
77
 
78
+ // Flag that shows if data was changed from initial conditions
79
+ dataInit.dataChanged = false
80
+ // Flag for autorun feedback
81
+ dataInit.clickRun = false
82
+
76
83
  function len(s) {
77
84
  return s.length;
78
85
  }
@@ -142,8 +149,9 @@ function createVueApp (env, dataInit, mountedCallback) {
142
149
  deep: true,
143
150
  immediate: false,
144
151
  handler (v) {
152
+ this.dataChanged = true // Used in the reset button
145
153
  if (this.model.autorun) {
146
- env.run()
154
+ this.run()
147
155
  }
148
156
  }
149
157
  }
@@ -158,9 +166,16 @@ function createVueApp (env, dataInit, mountedCallback) {
158
166
  },
159
167
  reset () {
160
168
  resetInputs(this.inputs)
169
+ this.$nextTick(() => {
170
+ this.dataChanged = false
171
+ })
161
172
  },
162
173
  run () {
174
+ this.clickRun = true
163
175
  env.run()
176
+ setTimeout(() => {
177
+ this.clickRun = false
178
+ }, 150)
164
179
  },
165
180
  notify (msg) {
166
181
  env.notify(msg)
package/src/utils.js ADDED
@@ -0,0 +1,52 @@
1
+ function getModelFuncJS (model, target, log=console.log) {
2
+ switch (model.type) {
3
+ case 'class':
4
+ log('Init class')
5
+ const modelClass = new target()
6
+ return (...a) => {
7
+ return modelClass[model.method || 'predict'](...a)
8
+ }
9
+ case 'async-init':
10
+ // TODO: Test this
11
+ log('Function with async init')
12
+ return target().then(m => {
13
+ log('> Async init resolved: ', m)
14
+ return m
15
+ })
16
+ default:
17
+ log('Init function')
18
+ return target
19
+ }
20
+ }
21
+
22
+ function getModelFuncAPI (model, log=console.log) {
23
+ switch (model.type) {
24
+ case 'get':
25
+ return (data) => {
26
+ const query = new URLSearchParams(data).toString()
27
+ const finalURL = model.url +'?' + query
28
+ log('Sending GET request to:', finalURL)
29
+ const resPromise = fetch(finalURL)
30
+ .then(response => response.json())
31
+ return resPromise
32
+ }
33
+ case 'post':
34
+ return (data) => {
35
+ log('Sending POST request to', this.schema.model.url)
36
+ const resPromise = fetch(this.schema.model.url, {
37
+ method: 'POST',
38
+ headers: {
39
+ 'Accept': 'application/json',
40
+ 'Content-Type': 'application/json'
41
+ },
42
+ body: JSON.stringify(data)
43
+ }).then(response => response.json())
44
+ return resPromise
45
+ }
46
+ }
47
+ }
48
+
49
+ module.exports = {
50
+ getModelFuncJS,
51
+ getModelFuncAPI
52
+ }
package/src/worker.js CHANGED
@@ -1,11 +1,55 @@
1
+ const utils = require('./utils')
2
+
1
3
  function log () {
2
4
  const args = Array.prototype.slice.call(arguments);
3
5
  args.unshift('[Worker]')
4
- console.log(args)
5
6
  postMessage({_status: 'log', _log: args})
6
7
  }
7
8
 
9
+ function initTF (model) {
10
+ throw new Error('Tensorflow in worker (not implemented)')
11
+ }
12
+
13
+ function initPython (model) {
14
+ throw new Error('Python in worker (not implemented)')
15
+ }
16
+
17
+ function initJS (model) {
18
+ log('Init JS')
19
+ this.container = model.container
20
+
21
+ if (model.code) {
22
+ log('Load code as a string')
23
+ // https://github.com/altbdoor/blob-worker/blob/master/blobWorker.js
24
+ importScripts(URL.createObjectURL(new Blob([model.code], { type: 'text/javascript' })))
25
+ } else if (model.url) {
26
+ log('Load script from URL:', model.url)
27
+ importScripts(model.url)
28
+ } else {
29
+ log('No script provided')
30
+ }
31
+
32
+
33
+ // Related:
34
+ // https://stackoverflow.com/questions/37711603/javascript-es6-class-definition-not-accessible-in-window-global
35
+ const target = model.type === 'class'
36
+ ? eval(model.name)
37
+ : this[model.name]
38
+ // Need promise here in case of async init
39
+ Promise.resolve(utils.getModelFuncJS(model, target, log))
40
+ .then(m => {
41
+ postMessage({_status: 'loaded'})
42
+ this.modelFunc = m
43
+ })
44
+ }
45
+
46
+ function initAPI (model) {
47
+ log('Init API')
48
+ this.modelFunc = utils.getModelFuncAPI(model, log)
49
+ }
50
+
8
51
  onmessage = function (e) {
52
+
9
53
  var data = e.data
10
54
  log('Received message of type:', typeof data)
11
55
 
@@ -14,67 +58,30 @@ onmessage = function (e) {
14
58
  INIT MESSAGE
15
59
  */
16
60
  let model = data
61
+ log('Init...')
17
62
 
18
- if (model.type === 'py') {
19
- // Python with Pyodide
20
- importScripts('https://pyodide.cdn.iodide.io/pyodide.js')
21
- // Check when all's loaded
22
- /*
23
- TODO: Implement same loaded as port
24
- let pyCheck = setInterval(() => {
25
- if (self.pyodide && self.pyodide.runPythonAsync && this.model && this.model.length) {
26
- console.log('[Worker] Pyodide lib and model loaded. Try running to preload all imports')
27
- self.pyodide.runPythonAsync(this.model, () => {})
28
- .then((res) => {
29
- postMessage({_status: 'loaded'})
30
- })
31
- .catch((err) => {
32
- postMessage({_status: 'loaded'})
33
- })
34
- clearInterval(pyCheck)
35
- }
36
- }, 500)
37
- */
38
- } else {
39
- // Javascript
40
- this.container = model.container
41
-
42
- if (model.code) {
43
- log('Load code from schema')
44
- // https://github.com/altbdoor/blob-worker/blob/master/blobWorker.js
45
- importScripts(URL.createObjectURL(new Blob([model.code], { type: 'text/javascript' })))
46
- } else if (model.url) {
47
- log('Load script from URL:', model.url)
48
- importScripts(model.url)
49
- } else {
50
- log('No script provided')
51
- }
52
-
53
- if (model.type === 'class') {
54
- log('[Worker] Init class')
55
- // this.modelFunc = (new this[model.name]())[model.method || 'predict']
56
-
57
- const modelClass = new this[model.name]()
58
- this.modelFunc = (...a) => {
59
- return modelClass[model.method || 'predict'](...a)
60
- }
61
- } else if (model.type === 'async-init') {
62
- log('Init function with promise')
63
- log(this[model.name])
64
- this[model.name]().then((m) => {
65
- log('Async init resolved: ', m)
66
- this.modelFunc = m
67
- })
68
- } else {
69
- log('Init function')
70
- this.modelFunc = this[model.name]
71
- }
72
-
73
- postMessage({_status: 'loaded'})
63
+ switch (model.type) {
64
+ case 'tf':
65
+ initTF(model)
66
+ break
67
+ case 'py':
68
+ initPython(model)
69
+ break
70
+ case 'function':
71
+ case 'class':
72
+ case 'async-init':
73
+ case 'async-function':
74
+ initJS(model)
75
+ break
76
+ case 'get':
77
+ case 'post':
78
+ initAPI(model)
79
+ break
74
80
  }
75
81
  } else {
76
82
  /*
77
- CALL MESSAGE
83
+ :w
84
+ CALL MESSAGE
78
85
  */
79
86
  var res
80
87
  if (typeof this.modelFunc === 'string') {
@@ -26,6 +26,7 @@
26
26
  justify-content: center;
27
27
  }
28
28
 
29
+
29
30
  .card-header {
30
31
  box-shadow: none;
31
32
  border-bottom: 1px solid #ececec;
@@ -50,6 +51,73 @@
50
51
  background-color: whitesmoke;
51
52
  }
52
53
  }
54
+
55
+ .card-footer {
56
+ /* background: linear-gradient(62deg, rgba(0,171,209,1) 0%, rgba(0,209,178,1) 100%); */
57
+ background: linear-gradient(90deg, #4395d0 0%, #00d1b2 100%);
58
+ }
59
+
60
+ .card-footer.reset {
61
+ background: linear-gradient(90deg, #ff577f 0%, #4395d0 50%, #00d1b2 100%);
62
+ }
63
+
64
+ .card-footer .button {
65
+ background: none;
66
+ padding: .75rem 1.5rem;
67
+ border: none !important;
68
+ border-radius: .25rem !important;
69
+ font-size: 14px;
70
+ font-weight: 400;
71
+ }
72
+
73
+ .reset-button {
74
+ justify-content: left;
75
+ }
76
+
77
+ .reset-button:hover {
78
+ background-color: transparent !important;
79
+ background: linear-gradient(90deg, #ff3a56 0%, #fff0 80%);
80
+ box-shadow: -5px 0px 5px -2px #fd4c7e30;
81
+ }
82
+
83
+ .card-footer .run-button {
84
+ border-left: 1px dashed white;
85
+ justify-content: right;
86
+ }
87
+
88
+ .card-footer .run-button:hover,{
89
+ background-color: transparent !important;
90
+ background: linear-gradient(270deg, #02dbb2 0%, #fff0 80%);
91
+ box-shadow: 5px 0px 5px -2px #48ffd43b;
92
+ }
93
+
94
+ .card-footer .run-button.running .run-icon {
95
+ color: #016c5c !important;
96
+ }
97
+
98
+ .field {
99
+ margin-bottom: 5px;
100
+ }
101
+
102
+ .input, .textarea, .select select {
103
+ border-color: #e8e8e8;
104
+ border-top-left-radius: 0;
105
+ }
106
+
107
+ .input:focus, .textarea:focus, .select select:focus, .is-focused.input, .is-focused.textarea, .select select.is-focused, .input:active, .textarea:active, .select select:active, .is-active.input, .is-active.textarea, .select select.is-active {
108
+ border-color: #7ab8e6;
109
+ box-shadow: 0 0 0 0.125em rgba(72, 139, 199, 0.25);
110
+ }
111
+
112
+ #inputs .field > label:first-child {
113
+ background: #f2f2f2;
114
+ padding: 1px 5px;
115
+ margin-top: 2px;
116
+ display: inline-block;
117
+ border-top-left-radius: 5px;
118
+ border-top-right-radius: 5px;
119
+ }
120
+
53
121
  }
54
122
  </style>
55
123
  <template>
@@ -73,21 +141,22 @@
73
141
  <pre v-if="$parent.model.debug">{{ $parent.inputs }}</pre>
74
142
  <!-- <button class="button is-primary" id="run"><span>▸</span>&nbsp;&nbsp;Run</button> -->
75
143
  </div>
76
- <footer class="card-footer">
144
+ <footer class="card-footer" v-bind:class="{ reset: $parent.dataChanged }">
77
145
  <button
78
146
  v-on:click="$parent.reset()"
79
- v-if="$parent.inputs && $parent.inputs.length > 0"
80
- class="button icon card-footer-item is-danger is-small"
147
+ v-if="$parent.inputs && $parent.inputs.length > 0 && $parent.dataChanged"
148
+ class="button reset-button icon card-footer-item is-danger is-small"
81
149
  >
82
- <span class="has-text-danger-dark">✕</span>
150
+ <span class="rest-icon has-text-danger-dark">✕</span>
83
151
  <span>&nbsp; Reset</span>
84
152
  </button>
85
153
  <button
86
154
  v-on:click="$parent.run()"
87
- class="button icon card-footer-item is-primary is-small"
155
+ class="button run-button icon card-footer-item is-primary is-small"
156
+ v-bind:class="{ running: $parent.clickRun }"
88
157
  >
89
- <span class="has-text-primary-dark">▸</span>
90
- <span>&nbsp; Run</span>
158
+ <span>&nbsp; Run &nbsp;</span>
159
+ <span class="run-icon has-text-primary-dark">▸</span>
91
160
  </button>
92
161
  </footer>
93
162
  </div>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="card mb-5" v-if="output.value">
2
+ <div class="card mb-5" v-if="!(typeof output.value === 'undefined')">
3
3
  <header class="card-header">
4
4
  <p class="card-header-title is-size-6" v-if="output.name">
5
5
  {{ output.name }}
@@ -23,12 +23,6 @@
23
23
  <pre>{{ output.value }}</pre>
24
24
  </div>
25
25
  </div>
26
- <!--
27
- <footer class="card-footer" v-if="output.filename">
28
- <a v-on:click="save()" class="card-footer-item">Save</a>
29
- <a v-on:click="copy()" class="card-footer-item">Copy</a>
30
- </footer>
31
- -->
32
26
  </div>
33
27
  </template>
34
28
 
package/test/code.html ADDED
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ function sum (a, b) {
6
+ return a + b
7
+ }
8
+ new JSEE({
9
+ schema: {
10
+ "model": {
11
+ "name": "sum",
12
+ "type": "function",
13
+ "container": "args",
14
+ "code": sum,
15
+ "autorun": true,
16
+ "worker": false
17
+ },
18
+ "inputs": [
19
+ { "name": "a", "type": "int", "default": 100 },
20
+ { "name": "b", "type": "int", "default": 42 }
21
+ ]
22
+ }
23
+ })
24
+ </script>
25
+ </html>
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ function sum (a, b) {
6
+ return a + b
7
+ }
8
+ new JSEE({
9
+ schema: {
10
+ "model": {
11
+ "name": "sum",
12
+ "type": "function",
13
+ "container": "args",
14
+ "code": sum,
15
+ "autorun": true,
16
+ "worker": true
17
+ },
18
+ "inputs": [
19
+ { "name": "a", "type": "int", "default": 100 },
20
+ { "name": "b", "type": "int", "default": 42 }
21
+ ]
22
+ }
23
+ })
24
+ </script>
25
+ </html>
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ class Doubler {
2
+ constructor() {
3
+ this.a = 2
4
+ }
5
+ double(b) {
6
+ return this.a * b
7
+ }
8
+ }
@@ -0,0 +1,3 @@
1
+ function sum (a, b) {
2
+ return a + b
3
+ }
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ new JSEE({
6
+ schema: {
7
+ 'model': function (a, b) {
8
+ return a * b
9
+ }
10
+ },
11
+ container: 'jsee-container'
12
+ })
13
+ </script>
14
+ </html>
@@ -0,0 +1,13 @@
1
+ <!-- Minimal example -->
2
+ <html>
3
+ <div id="jsee-container">
4
+ <script src="/dist/jsee.js"></script>
5
+ <script>window.JSEE || document.write('<script src="https://cdn.jsdelivr.net/npm/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
6
+ <script>window.JSEE || document.write('<script src="https://unpkg.com/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
7
+ <script>
8
+ function mul (a, b) {
9
+ return a * b
10
+ }
11
+ new JSEE(mul, '#jsee-container')
12
+ </script>
13
+ </html>
@@ -0,0 +1,15 @@
1
+ <!-- Minimal example -->
2
+ <html>
3
+ <div id="jsee-container">
4
+ <script src="/dist/jsee.js"></script>
5
+ <script>window.JSEE || document.write('<script src="https://cdn.jsdelivr.net/npm/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
6
+ <script>window.JSEE || document.write('<script src="https://unpkg.com/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
7
+ <script>
8
+ function mul (a, b) {
9
+ return a * b
10
+ }
11
+ new JSEE({
12
+ model: mul
13
+ }, '#jsee-container')
14
+ </script>
15
+ </html>
@@ -0,0 +1,10 @@
1
+ <!-- Minimal example -->
2
+ <html>
3
+ <div id="jsee-container">
4
+ <script src="/dist/jsee.js"></script>
5
+ <script>window.JSEE || document.write('<script src="https://cdn.jsdelivr.net/npm/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
6
+ <script>window.JSEE || document.write('<script src="https://unpkg.com/@jseeio/jsee@latest/dist/jsee.runtime.js">\x3C/script>')</script>
7
+ <script>
8
+ new JSEE(function (a, b) { return a * b }, '#jsee-container')
9
+ </script>
10
+ </html>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ new JSEE({
6
+ schema: {
7
+ "model": {
8
+ "name": "div",
9
+ "code": "function div (a) { ruturn a / 2 }"
10
+ },
11
+ "inputs": [
12
+ {
13
+ "name": "a",
14
+ "type": "int",
15
+ "value": 0
16
+ }
17
+ ]
18
+ },
19
+ container: '#jsee-container'
20
+ })
21
+ </script>
22
+ </html>
@@ -0,0 +1,26 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ new JSEE({
6
+ schema: {
7
+ "model": {
8
+ "name": "sum",
9
+ "type": "function",
10
+ "container": "args",
11
+ "code": `
12
+ function sum (a, b) {
13
+ return a + b
14
+ }
15
+ `,
16
+ "autorun": true,
17
+ "worker": false
18
+ },
19
+ "inputs": [
20
+ { "name": "a", "type": "int", "default": 100 },
21
+ { "name": "b", "type": "int", "default": 42 }
22
+ ]
23
+ }
24
+ })
25
+ </script>
26
+ </html>
@@ -0,0 +1,29 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+
6
+ new JSEE({
7
+ schema: {
8
+ "model": {
9
+ "name": "sum",
10
+ "type": "function",
11
+ "container": "args",
12
+ "code": `
13
+ function sum (a, b) {
14
+ return a + b
15
+ }
16
+ `,
17
+ "autorun": true,
18
+ "worker": true
19
+ },
20
+ "inputs": [
21
+ { "name": "a", "type": "int", "default": 100 },
22
+ { "name": "b", "type": "int", "default": 42 }
23
+ ]
24
+ },
25
+ container: '#jsee-container',
26
+ verbose: false
27
+ })
28
+ </script>
29
+ </html>
@@ -0,0 +1,17 @@
1
+ {
2
+ "model": {
3
+ "name": "sum",
4
+ "type": "function",
5
+ "title": "title",
6
+ "description": "description",
7
+ "container": "args",
8
+ "url": "example-sum.js",
9
+ "autorun": true,
10
+ "worker": false
11
+ },
12
+ "inputs": [
13
+ { "name": "a", "type": "int", "default": 100 },
14
+ { "name": "b", "type": "int", "default": 42 }
15
+ ]
16
+ }
17
+