Skip to content

Commit 8c29696

Browse files
authored
Merge pull request nullstack#321 from nullstack/next
Next
2 parents 08d674e + bc48788 commit 8c29696

22 files changed

+401
-38
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Nullstack
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ Get to know the [Nullstack Contributors](https://nullstack.app/contributors)
3535

3636
## License
3737

38-
Nullstack is released under the [MIT License](https://opensource.org/licenses/MIT).
38+
Nullstack is released under the [MIT License](LICENSE).

client/instanceProxyHandler.js

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import client from './client'
2-
import { generateContext } from './context'
2+
import context, { generateContext } from './context'
33
import { generateObjectProxy } from './objectProxyHandler'
44

55
export const instanceProxies = new WeakMap()
@@ -15,8 +15,26 @@ const instanceProxyHandler = {
1515
}
1616
const { [name]: named } = {
1717
[name]: (args) => {
18-
const context = generateContext({ ...target._attributes, ...args })
19-
return target[name].call(proxy, context)
18+
const scopedContext = generateContext({ ...target._attributes, ...args })
19+
let result
20+
try {
21+
result = target[name].call(proxy, scopedContext)
22+
} catch (error) {
23+
if (context.catch) {
24+
context.catch(error)
25+
} else {
26+
throw error
27+
}
28+
return null
29+
}
30+
if (result instanceof Promise) {
31+
return new Promise((resolve, reject) => {
32+
result.then(resolve).catch((error) => {
33+
context.catch ? context.catch(error) : reject(error)
34+
})
35+
})
36+
}
37+
return result
2038
},
2139
}
2240
return named

loaders/add-source-to-node.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ module.exports = function (source) {
1313
if (path.parent.type === 'JSXAttribute') {
1414
if (path.node.name.startsWith('on')) {
1515
const element = path.findParent((p) => p.type === 'JSXOpeningElement' && p.node.attributes)
16-
const hasSource = element.node.attributes.find((a) => a.name.name === 'source')
16+
const hasSource = element.node.attributes.find((a) => {
17+
return a.type === 'JSXAttribute' && a.name.name === 'source'
18+
})
1719
if (!hasSource) {
1820
const start = element.node.attributes[0].start
1921
uniquePositions.add(start)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nullstack",
3-
"version": "0.17.4",
3+
"version": "0.17.5",
44
"description": "Full Stack Javascript Components for one-dev armies",
55
"main": "nullstack.js",
66
"author": "Mortaro",

plugins/bindable.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function transform({ node, environment }) {
99
const object = node.attributes.bind.object ?? {}
1010
const property = node.attributes.bind.property
1111
if (node.type === 'textarea') {
12-
node.children = [object[property]]
12+
node.children = [object[property] ?? '']
1313
} else if (node.type === 'input' && node.attributes.type === 'checkbox') {
1414
node.attributes.checked = object[property]
1515
} else {

server/printError.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import context from './context'
2+
13
export default function (error) {
4+
if (context.catch) {
5+
context.catch(error)
6+
}
27
const lines = error.stack.split(`\n`)
38
let initiator = lines.find((line) => line.indexOf('Proxy') > -1)
49
if (initiator) {

server/reqres.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,20 @@
1-
const reqres = {}
1+
class ReqRes {
2+
3+
request = null
4+
response = null
5+
6+
set(request, response) {
7+
this.request = request
8+
this.response = response
9+
}
10+
11+
clear() {
12+
this.request = null
13+
this.response = null
14+
}
15+
16+
}
17+
18+
const reqres = new ReqRes()
19+
220
export default reqres

server/server.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ for (const method of ['get', 'post', 'put', 'patch', 'delete', 'all']) {
4040
server[method] = function (...args) {
4141
if (typeof args[1] === 'function' && args[1].name === '_invoke') {
4242
return original(args[0], bodyParser.text({ limit: server.maximumPayloadSize }), async (request, response) => {
43+
reqres.set(request, response)
4344
const params = {}
4445
for (const key of Object.keys(request.params)) {
4546
params[key] = extractParamValue(request.params[key])
@@ -48,14 +49,17 @@ for (const method of ['get', 'post', 'put', 'patch', 'delete', 'all']) {
4849
params[key] = extractParamValue(request.query[key])
4950
}
5051
if (request.method !== 'GET') {
51-
Object.assign(params, deserialize(request.body))
52+
const payload = typeof request.body === 'object' ? JSON.stringify(request.body) : request.body
53+
Object.assign(params, deserialize(payload))
5254
}
5355
try {
5456
const subcontext = generateContext({ request, response, ...params })
5557
const result = await args[1](subcontext)
58+
reqres.clear()
5659
response.json(result)
5760
} catch (error) {
5861
printError(error)
62+
reqres.clear()
5963
response.status(500).json({})
6064
}
6165
})
@@ -224,6 +228,7 @@ server.start = function () {
224228

225229
server.all(`/${prefix}/:hash/:methodName.json`, async (request, response) => {
226230
const payload = request.method === 'GET' ? request.query.payload : request.body
231+
reqres.set(request, response)
227232
const args = deserialize(payload)
228233
const { hash, methodName } = request.params
229234
const [invokerHash, boundHash] = hash.split('-')
@@ -241,12 +246,15 @@ server.start = function () {
241246
try {
242247
const subcontext = generateContext({ request, response, ...args })
243248
const result = await method.call(boundKlass, subcontext)
249+
reqres.clear()
244250
response.json({ result })
245251
} catch (error) {
246252
printError(error)
253+
reqres.clear()
247254
response.status(500).json({})
248255
}
249256
} else {
257+
reqres.clear()
250258
response.status(404).json({})
251259
}
252260
})
@@ -255,21 +263,23 @@ server.start = function () {
255263
if (request.originalUrl.split('?')[0].indexOf('.') > -1) {
256264
return next()
257265
}
258-
reqres.request = request
259-
reqres.response = response
266+
reqres.set(request, response)
260267
const scope = await prerender(request, response)
261268
if (!response.headersSent) {
262269
const status = scope.context.page.status
263270
const html = template(scope)
264-
reqres.request = null
265-
reqres.response = null
271+
reqres.clear()
266272
response.status(status).send(html)
267273
} else {
268-
reqres.request = null
269-
reqres.response = null
274+
reqres.clear()
270275
}
271276
})
272277

278+
server.use((error, _request, response, _next) => {
279+
printError(error)
280+
response.status(500).json({})
281+
})
282+
273283
if (!server.less) {
274284
if (!server.port) {
275285
console.info('\x1b[31mServer port is not defined!\x1b[0m')

tests/client.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import Nullstack from 'nullstack'
22

33
import Application from './src/Application'
4+
import CatchError from './src/CatchError.njs'
45
import vueable from './src/plugins/vueable'
56

67
Nullstack.use(vueable)
@@ -12,4 +13,11 @@ context.start = function () {
1213
setTimeout(() => (context.startTimedValue = true), 1000)
1314
}
1415

16+
context.catch = async function (error) {
17+
CatchError.logError({ message: error.message })
18+
if (context.environment.development) {
19+
console.error(error)
20+
}
21+
}
22+
1523
export default context

0 commit comments

Comments
 (0)