Skip to content

Conversation

@SimenB
Copy link
Member

@SimenB SimenB commented May 19, 2017

I tried this:

diff --git i/index.js w/index.js
index ff80f46..923d310 100644
--- i/index.js
+++ w/index.js
@@ -306,7 +306,7 @@ function buildObject (schema, code, name, externalSchema, fullSchema) {
     // Using obj.key !== undefined instead of obj.hasOwnProperty(prop) for perf reasons,
     // see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
     code += `
-      if (obj.${key} !== undefined) {
+      if (obj['${key}'] !== undefined) {
         json += '${$asString(key)}:'
       `
 
@@ -392,6 +392,7 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema) {
   var code = ''
   var funcName
   const type = schema.type
+  const value = `obj['${key.substring(1)}']`
   switch (type) {
     case 'null':
       code += `
@@ -400,36 +401,36 @@ function nested (laterCode, name, key, schema, externalSchema, fullSchema) {
       break
     case 'string':
       code += `
-        json += $asString(obj${key})
+        json += $asString(${value})
       `
       break
     case 'integer':
       code += `
-        json += $asInteger(obj${key})
+        json += $asInteger(${value})
       `
       break
     case 'number':
       code += `
-        json += $asNumber(obj${key})
+        json += $asNumber(${value})
       `
       break
     case 'boolean':
       code += `
-        json += $asBoolean(obj${key})
+        json += $asBoolean(${value})
       `
       break
     case 'object':
       funcName = (name + key).replace(/[-.\[\]]/g, '') // eslint-disable-line
       laterCode = buildObject(schema, laterCode, funcName, externalSchema, fullSchema)
       code += `
-        json += ${funcName}(obj${key})
+        json += ${funcName}(${value})
       `
       break
     case 'array':
       funcName = (name + key).replace(/[-.\[\]]/g, '') // eslint-disable-line
       laterCode = buildArray(schema, laterCode, funcName, externalSchema, fullSchema)
       code += `
-        json += ${funcName}(obj${key})
+        json += ${funcName}(${value})
       `
       break
     default:

The top part worked fine, it failed a bunch of tests with the second one, though

@mcollina
Copy link
Member

mcollina commented May 19, 2017

I think you should have an helper that spits out key.substring(1) if key starts with @. It should work

I think the problem you are encountering is because the same logic works for both object and arrays.

@SimenB
Copy link
Member Author

SimenB commented May 19, 2017

Wouldn't this be a problem for all keys not being Aa-Zz?

@mcollina
Copy link
Member

@SimenB very probably.

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

I'm a bit stuck here... Why is key prefixed with . anyways? And is there a perf hit for doing obj['key'] instead of obj.key? I've pushed what I had locally, would love some guidance on how to fix it.

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

@mcollina I made it green at least. Not too happy with the implementation though... Ideas?

@SimenB SimenB changed the title Add failing test case for #33 Allow non alpha keys May 20, 2017
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should use the dot notation wherever possible. It should be faster.

Is this impacting benchmarks anyhow?

// see https://github.com/mcollina/fast-json-stringify/pull/3 for discussion.
code += `
if (obj.${key} !== undefined) {
if (obj['${key}'] !== undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you use the same accessor here?

Copy link
Member Author

@SimenB SimenB May 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accessor is in the nested function, not up here.

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

Benchmarks (on [email protected]):
Master:

JSON.stringify array x 3,666 ops/sec ±1.84% (81 runs sampled)
fast-json-stringify array x 2,337 ops/sec ±2.16% (83 runs sampled)
JSON.stringify long string x 14,201 ops/sec ±1.55% (80 runs sampled)
fast-json-stringify long string x 13,621 ops/sec ±1.90% (82 runs sampled)
JSON.stringify short string x 5,156,172 ops/sec ±1.87% (83 runs sampled)
fast-json-stringify short string x 12,075,130 ops/sec ±1.79% (81 runs sampled)
JSON.stringify obj x 1,729,733 ops/sec ±1.71% (79 runs sampled)
fast-json-stringify obj x 2,308,956 ops/sec ±2.22% (81 runs sampled)

This branch:

JSON.stringify array x 3,595 ops/sec ±2.19% (80 runs sampled)
fast-json-stringify array x 2,336 ops/sec ±2.11% (81 runs sampled)
JSON.stringify long string x 13,642 ops/sec ±1.65% (84 runs sampled)
fast-json-stringify long string x 13,699 ops/sec ±2.62% (84 runs sampled)
JSON.stringify short string x 4,928,457 ops/sec ±1.86% (78 runs sampled)
fast-json-stringify short string x 11,600,544 ops/sec ±1.71% (84 runs sampled)
JSON.stringify obj x 1,775,965 ops/sec ±2.34% (79 runs sampled)
fast-json-stringify obj x 2,309,468 ops/sec ±2.29% (82 runs sampled)

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

It could have been interesting to pass the generated code through a minifier, which would remove the brackets if they're unnecessary (uglilfy does this). Not sure if you want that dep, though...

image

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

I tested it out (because why not). Result

JSON.stringify array x 4,008 ops/sec ±1.64% (87 runs sampled)
fast-json-stringify array x 2,520 ops/sec ±2.12% (85 runs sampled)
JSON.stringify long string x 14,634 ops/sec ±1.31% (88 runs sampled)
fast-json-stringify long string x 14,446 ops/sec ±1.53% (85 runs sampled)
JSON.stringify short string x 5,382,246 ops/sec ±1.83% (82 runs sampled)
fast-json-stringify short string x 12,582,489 ops/sec ±2.26% (86 runs sampled)
JSON.stringify obj x 1,741,939 ops/sec ±1.57% (87 runs sampled)
fast-json-stringify obj x 2,404,493 ops/sec ±2.52% (80 runs sampled)

Diff:

diff --git i/index.js w/index.js
index ff80f46..d51febb 100644
--- i/index.js
+++ w/index.js
@@ -1,6 +1,7 @@
 'use strict'
 
 const fastSafeStringify = require('fast-safe-stringify')
+const uglify = require('uglify-es')
 
 let isLong
 try {
@@ -74,10 +75,16 @@ function build (schema, options) {
     ;
     return ${main}
   `
+
+  const uglified = uglify.minify(code, {parse: {bare_returns: true}})
+
+  if (uglified.error) {
+    throw uglified.error
+  }
   if (schema.additionalProperties === true) {
-    return (new Function('fastSafeStringify', code))(fastSafeStringify)
+    return (new Function('fastSafeStringify', uglified.code))(fastSafeStringify)
   }
-  return (new Function(code))()
+  return (new Function(uglified.code))()
 }
 
 function $asNull () {
diff --git i/package.json w/package.json
index 5ebd8a8..0fb85b9 100644
--- i/package.json
+++ w/package.json
@@ -32,6 +32,7 @@
     "tap": "^10.3.0"
   },
   "dependencies": {
-    "fast-safe-stringify": "^1.1.11"
+    "fast-safe-stringify": "^1.1.11",
+    "uglify-es": "^3.0.9"
   }
 }

Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Regarding uglify, I'm definitely +1, as the numbers look nice. I would like to have that but avoid a direct dependency to uglify, as this module is tight and nice. Would you like to send a PR?

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

How would we pass it through a minimizer without depending on the minimizer? Try to require it in case it's available?

@mcollina
Copy link
Member

mcollina commented May 20, 2017 via email

@SimenB
Copy link
Member Author

SimenB commented May 20, 2017

Cool, PR sent 😄

Will you be able to merge and release this and #35 by Monday?

@mcollina mcollina merged commit b4d8301 into fastify:master May 21, 2017
@SimenB SimenB deleted the weird-keys branch May 21, 2017 10:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants