Skip to content

Commit

Permalink
Run mocha tests in browser. Small fixes for Chrome and Firefox. Avoid…
Browse files Browse the repository at this point in the history
… str, as it is a reserved keyword in Python.
  • Loading branch information
EmileSonneveld committed Feb 22, 2023
1 parent a3d9aaa commit 60ace2b
Show file tree
Hide file tree
Showing 14 changed files with 176 additions and 118 deletions.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ This string happens to be legitimate JavaScript and can be parsed back with `eva
Like JSON, but supporting Sets, Maps, Dates, circular references and more.

```js
const str = serialize(source, opts={})
eval(str) // gives back the object!
const codeStr = serialize(source, opts={})
eval(codeStr) // gives back the object!
```

serializes an object to JavaScript
Expand All @@ -22,7 +22,7 @@ const serialize = require('serialize-to-js')
const reusedObject = { key: 'value' }
reusedObject.cyclicSelf = reusedObject
const obj = {
str: 'hello world!',
s: 'hello world!',
num: 3.1415,
bool: true,
nil: null,
Expand All @@ -43,7 +43,7 @@ This gives the following string as result:
```js
(function(){
const root = {
str: "hello world!",
s: "hello world!",
num: 3.1415,
bool: true,
nil: null,
Expand Down Expand Up @@ -80,7 +80,7 @@ This gives the following string as result:
})()
```

You can parse this results with `eval(str)` to get back a real JS object.
You can parse this results with `eval(codeStr)` to get back a real JS object.

Take a look to [the tests](test/index.test.js) for more examples.

Expand Down Expand Up @@ -122,5 +122,7 @@ See [LICENSE][] for more info.

```
npm install
path=%CD%/node_modules/.bin;%path%
SET NODE_OPTIONS=--openssl-legacy-provider
node_modules\.bin\webpack
```
29 changes: 29 additions & 0 deletions mocha.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mocha Tests</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="node_modules/mocha/mocha.css" />
<script type="module" src="node_modules/chai/chai.js"></script>
<script type="module" src="node_modules/acorn/dist/acorn.js"></script>
</head>
<body>
<div id="mocha"></div>

<script src="node_modules/chai/chai.js"></script>
<script src="node_modules/mocha/mocha.js"></script>
<script class="mocha-init">
mocha.setup('bdd');
mocha.checkLeaks();
</script>
<script type="module" src="test/call.test.js"></script>
<script type="module" src="test/custom-eval.test.js"></script>
<script type="module" src="test/index.test.js"></script>
<script type="module" src="test/search.test.js"></script>
<script type="module" src="test/serialize-javascript.js"></script>
<script type="module" class="mocha-exec">
mocha.run();
</script>
</body>
</html>
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"author": "EmileSonneveld <[email protected]>",
"main": "lib",
"module": "src",
"type": "module",
"directories": {
"lib": "lib",
"test": "test"
Expand Down Expand Up @@ -63,9 +64,9 @@
"@babel/cli": "^7.8.3",
"@babel/core": "^7.8.3",
"@babel/preset-env": "^7.8.3",
"chai": "^4.1.0",
"chai": "^4.3.7",
"eslint": "^8.19.0",
"mocha": "^7.0.1",
"mocha": "^7.2.0",
"nyc": "^15.0.0",
"rimraf": "^3.0.0",
"webpack": "5.38.1",
Expand Down
15 changes: 8 additions & 7 deletions src/custom-eval.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
let acorn = require("acorn");
const utils = require("../src/internal/utils");
import utils from './internal/utils.js'
const isBrowser = (typeof window !== 'undefined')

if (!isBrowser) {
// hacky import to work in browser and node
globalThis["acorn"] = (await import('../node_modules/acorn/dist/acorn.js')).default
}
const world = utils.world
world.acorn = acorn


// derived from https://blog.bitsrc.io/build-a-js-interpreter-in-javascript-using-acorn-as-a-parser-5487bb53390c
function CustomEval(str) {
export function CustomEval(str) {
// Attach metadata to objects with Map, because wrapping the objects is way to invasive.
const purelyInterpreted = new Map()
function isPurelyInterpreted(value){
Expand Down Expand Up @@ -287,7 +292,3 @@ function CustomEval(str) {
return ret
}
world.CustomEval = CustomEval

module.exports = {
CustomEval,
}
16 changes: 7 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@

'use strict'

const customEval = require('./custom-eval')
const utils = require('./internal/utils')
const world = utils.world
const Ref = require('./internal/reference')
const search = require('./search')
import utils from './internal/utils.js'
import Ref from './internal/reference.js'
import {search} from './search.js'

class ObjectIsDirectlyLinkableError extends Error {
constructor(message, directLink) {
Expand All @@ -33,7 +31,7 @@ class ObjectIsDirectlyLinkableError extends Error {
* @param {*} [opts.space]
* @return {String} serialized representation of `source`
*/
function serialize(src, opts = null) {
export function serialize(src, opts = null) {
if (src === "magic value that will resort to globalThis object") {
src = globalThis;
}
Expand Down Expand Up @@ -518,10 +516,10 @@ function slog(src, opts = null) {
}
}

module.exports = {
export default {
serialize,
slog,
}
// store globally:
world.serialize = serialize
world.slog = slog
utils.world.serialize = serialize
utils.world.slog = slog
4 changes: 2 additions & 2 deletions src/internal/reference.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

'use strict'

const utils = require('./utils')
import utils from './utils.js'

const safeKeyRegex = /^[a-zA-Z$_][a-zA-Z$_0-9]*$/

Expand Down Expand Up @@ -91,4 +91,4 @@ Ref.prototype = {

}

module.exports = Ref
export default Ref
33 changes: 17 additions & 16 deletions src/internal/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,26 @@ const UNICODE_CHARS = {
'\u2029': '\\u2029'
}

function safeString(str) {
return str.replace(UNSAFE_CHARS_REGEXP, (unsafeChar) => {
function safeString(s) {
return s.replace(UNSAFE_CHARS_REGEXP, (unsafeChar) => {
return UNICODE_CHARS[unsafeChar]
})
}

function unsafeString(str) {
str = str.replace(CHARS_REGEXP, (unsafeChar) => UNICODE_CHARS[unsafeChar])
return str
function unsafeString(s) {
s = s.replace(CHARS_REGEXP, (unsafeChar) => UNICODE_CHARS[unsafeChar])
return s
}

function quote(str, opts) {
function quote(s, opts) {
const fn = opts.unsafe ? unsafeString : safeString
return str ? `"${fn(str)}"` : '""'
return s ? `"${fn(s)}"` : '""'
}

function saferFunctionString(str, opts) {
function saferFunctionString(s, opts) {
return opts.unsafe
? str
: str.replace(/(<\/?)([a-z][^>]*?>)/ig, (m, m1, m2) => safeString(m1) + m2)
? s
: s.replace(/(<\/?)([a-z][^>]*?>)/ig, (m, m1, m2) => safeString(m1) + m2)
}

function isObject(arg) {
Expand Down Expand Up @@ -137,7 +137,8 @@ function isSimpleGetter(func, propName) {
}
if (functContent.indexOf(' [native code] ') !== -1) {
// This test could be narrowed down
if (func.name === 'bound fetch') {
if (func.name === 'bound fetch'
|| func.name === 'bound ') { // When running search.test.js in Chrome
return false;
}
// 'window.test = "value"' adds a getter and setter to 'window'
Expand Down Expand Up @@ -187,15 +188,15 @@ function escapeRegExp(string) {
}

if (!String.prototype.replaceAll) {
String.prototype.replaceAll = function (str, newStr) {
String.prototype.replaceAll = function (s, newStr) {

// If a regex pattern
if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') {
return this.replace(str, newStr);
if (Object.prototype.toString.call(s).toLowerCase() === '[object regexp]') {
return this.replace(s, newStr);
}

// If a string
return this.replace(new RegExp(escapeRegExp(str), 'g'), newStr);
return this.replace(new RegExp(escapeRegExp(s), 'g'), newStr);
};
}

Expand All @@ -221,7 +222,7 @@ if (typeof URL === 'undefined') {
world.URL = require('url').URL
}

module.exports = {
export default {
safeString,
unsafeString,
quote,
Expand Down
18 changes: 10 additions & 8 deletions src/search.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use strict'

const utils = require('./internal/utils')
const world = utils.world
const Ref = require('./internal/reference')
import utils from './internal/utils.js'
import Ref from './internal/reference.js'

/**
* Figuratively search a needle in the haystack.
Expand All @@ -11,7 +10,7 @@ const Ref = require('./internal/reference')
* @param {*} needle
* @param {*} opts
*/
function search(needle, opts = null) {
export function search(needle, opts = null) {
opts = {
returnValue: false,
root: globalThis,
Expand Down Expand Up @@ -41,7 +40,7 @@ function search(needle, opts = null) {
for (const key in descs) {
if (Object.prototype.hasOwnProperty.call(descs, key)) {
const propDesc = descs[key]
if (propDesc.get && !(utils.isSimpleGetter(propDesc.get) || (propDesc.get + '').indexOf(' [native code] ') !== -1)) {
if (propDesc.get && !(utils.isSimpleGetter(propDesc.get) || (propDesc.get + '').indexOf(' [native code]') !== -1)) {
continue
}
let access = Ref.isSafeKey(key) ? `.${key}` : `[${utils.quote(key, opts)}]`;
Expand All @@ -53,6 +52,9 @@ function search(needle, opts = null) {
source = child;
child = child();
}
if(child == null) {
continue
}

try {
// noinspection BadExpressionStatementJS
Expand All @@ -65,7 +67,7 @@ function search(needle, opts = null) {
if (child === needle ||
(child
&& child.toString // avoid "TypeError: Cannot convert object to primitive value"
&& (utils.isSimpleGetter(child.toString) || (child.toString + '').indexOf(' [native code] ') !== -1)
&& (utils.isSimpleGetter(child.toString) || (child.toString + '').indexOf(' [native code]') !== -1)
&& !(child.length === 1) // avoid '(['a'] == 'a')===true' weirdness
&& child == needle // sloppy compare can be handy for '5'==5
)
Expand Down Expand Up @@ -106,9 +108,9 @@ function search(needle, opts = null) {
console.log(results.join("\n"))
}

module.exports = {
export default {
search,
}

// store globally:
world.search = search
utils.world.search = search
19 changes: 11 additions & 8 deletions test/call.test.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
/* eslint no-new-func: off */
'use strict'

const assert = require('assert')
const src = require('../src')
const {search} = require('../src/search')
const {expect} = require("chai");
const {createReadStream} = require("fs");
const path = require("path");
const utils = require("../src/internal/utils");
import {serialize} from '../src/index.js';
import utils from '../src/internal/utils.js'
const world = utils.world
const serialize = src.serialize

const isBrowser = (typeof window !== 'undefined')

if (!isBrowser) {
// hacky import to work in browser and node
globalThis["chai"] = (await import('../node_modules/chai/chai.js')).default
}
const assert = chai.assert
const expect = chai.expect

// Call requires the arguments to be passed in one-by-one, and apply takes the arguments as an array.

Expand Down
22 changes: 14 additions & 8 deletions test/custom-eval.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@

// npm run test test/custom-eval.test.js

const assert = require('assert')
const src = require('../src')
const {search} = require('../src/search')
const {expect} = require("chai");
const {createReadStream} = require("fs");
const path = require("path");
const {CustomEval} = require("../src/custom-eval");
const serialize = src.serialize
import {serialize} from '../src/index.js';
import {CustomEval} from '../src/custom-eval.js'
import utils from '../src/internal/utils.js'

const isBrowser = (typeof window !== 'undefined')

if (!isBrowser) {
// hacky import to work in browser and node
globalThis["chai"] = (await import('../node_modules/chai/chai.js')).default
globalThis["acorn"] = (await import('../node_modules/acorn/dist/acorn.js')).default
}
const assert = chai.assert
const expect = chai.expect


describe("customEval test", () => {
it("simple math", () => {
Expand Down
Loading

0 comments on commit 60ace2b

Please sign in to comment.