Skip to content

Commit 36dfdc4

Browse files
authored
Merge pull request #31 from cuthbertLab/airbnb-base
Update deps and to 1.2
2 parents 97ae91e + e6a02bd commit 36dfdc4

16 files changed

Lines changed: 6153 additions & 3434 deletions

.eslintignore

Lines changed: 0 additions & 1 deletion
This file was deleted.

.eslintrc.json

Lines changed: 0 additions & 72 deletions
This file was deleted.

README.md

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
jsonpickleJS
2-
============
1+
# jsonpickleJS
32

43
Javascript reinterpretation of Python jsonpickle to allow reading and (to a lesser extent)
54
writing JSON objects
65

7-
Copyright (c) 2014 Michael Scott Cuthbert and cuthbertLab.
6+
Copyright © 2014-25 Michael Scott Asato Cuthbert.
87
Released under the BSD (3-clause) license. See LICENSE.
98

10-
Python to Javascript and Back
11-
==============================
9+
# Pre-class-based system (Closing down)
10+
11+
Note for 2025+: This system depends on legacy style functions that behave like objects.
12+
To use with modern Javascript you will need to assign all classes to globalThis (window, global).
13+
For this reason, v1.2 will be the last version of jsonpickleJS. Using custom decoders in JSON.parse
14+
is probably the best solution going forward in the modern world.
15+
16+
# Python to Javascript and Back
1217
Python has a remarkable number of ways (for a language that believes there's only one way to do it)
1318
to transfer data between itself and Javascript, most obviously with the
1419
``json.dump()``/``json.dumps()`` calls, which work well on specifically created data, especially
@@ -31,22 +36,21 @@ namespace, such as ``window``, in the Javascript. For instance, if you have a c
3136
``window.myobject.Thing`` in Javascript. The object, and any subobjects, will be created as closely
3237
as possible in Javascript.
3338

34-
The reverse is also possible, with some caveats. Since Javascript doesn't (until ECMAScript 6) have
35-
the concept of named classes, each object will need to have a marker somewhere on it saying what
39+
The reverse is also possible, with some caveats. Since Javascript didn't (until ECMAScript 6) have
40+
the concept of named classes, each object needed to have a marker somewhere on it saying what
3641
Python object it should convert back to. The marker is
3742
``o[jsonpickle.tags.PY_CLASS] = 'fully.qualified.ClassName'``.
3843
It may be possible in the future to use ``instanceof``
3944
through the entire Global namespace to figure out what something is, but that seems rather dangerous
4045
and inefficient (A project for later).
4146

42-
Limitations
43-
===========
47+
# Limitations
4448
Remember that Javascript does not have tuples, so all tuple objects are changed to lists.
49+
4550
Namedtuples behave the same way, I believe. Dicts and Objects are identical in Javascript (both
4651
a blessing and a curse).
4752

48-
Security
49-
========
53+
# Security
5054
Pickle, jsonpickle, and jsonpickleJS all raise important security considerations you must be
5155
aware of. You will be loading data directly into Python or Javascript with no checks on what the
5256
data contains. Only load data you have personally produced if you want to be safe. In Javascript,
@@ -60,15 +64,68 @@ data, but anyone with JS programming experience can inject other data into your
6064
Be safe: be cautious going from Python to Javascript and NEVER accept Javascript-produced
6165
jsonpickle data from the net into your Python program in any sort of open environment.
6266

63-
Usage
64-
=====
65-
See the source code of: testUnpickle.html to see how to use it. JsonpickleJS follows the AMD
66-
moduleloader standard, so set the ``src=""`` attribute in the ``<script>`` to an AMD loader
67-
such as ``//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.14/require.min.js``
68-
(or the included local version in ``jsonpickleJS/ext/require/require.js``) and
69-
the ``data-main`` attribute to ``jsonpickleJS/main`` (no ``.js``). Then call
70-
``var o = jsonpickle.decode(jsonStr)`` to get the Python object back as a JS object named ``o``.
71-
72-
See the cuthbertLab/music21 and cuthbertLab/music21j projects and especially the ``.show('vexflow')``
73-
component for an example of how jsonpickleJS can be extremely useful for projects that have
74-
parallel data structures between Python and Javascript.
67+
# Usage
68+
69+
You can use `jsonpickleJS` in modern JavaScript environments with either
70+
ES Modules or traditional `<script>` tags.
71+
72+
---
73+
74+
### ES Module (Modern usage)
75+
76+
```js
77+
// be sure jsonpickle is in your package.json and installed.
78+
79+
// # in python:
80+
// import jsonpickle
81+
// jsonStr = jsonpickle.encode(my_object)
82+
83+
import jsonpickle from 'jsonpickle';
84+
85+
const obj = jsonpickle.decode(jsonStr);
86+
// `obj` is now a JavaScript version of the original Python object
87+
// with proper classes.
88+
```
89+
90+
---
91+
92+
### `<script>` Tag (Legacy/global usage)
93+
94+
```html
95+
<script src="build/jsonpickle.min.js"></script>
96+
<script>
97+
const obj = jsonpickle.decode(jsonStr);
98+
console.log(obj);
99+
</script>
100+
```
101+
102+
This works without any build system. The `jsonpickle` global will be available automatically.
103+
104+
105+
### Example
106+
107+
You can find a working example in [`testUnpickle.html`](./testUnpickle.html).
108+
109+
110+
### Background
111+
112+
`jsonpickleJS` allows you to **decode Python-style JSON strings** into rich JavaScript objects.
113+
It’s especially useful for projects that mirror data structures across Python and JavaScript.
114+
115+
One real-world use case:
116+
Older versions of [`music21`](https://github.com/cuthbertLab/music21) and
117+
[`music21j`](https://github.com/cuthbertLab/music21j) use `jsonpickleJS` to render complex
118+
musical objects in the browser — such as using `.show('vexflow')` in music21 to visualize
119+
music sent from Python into JavaScript.
120+
121+
# Building
122+
Run once:
123+
```
124+
% npm install
125+
```
126+
127+
Then:
128+
129+
```
130+
% npm run build
131+
```

build/jsonpickle.min.js

Lines changed: 2 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*!
2+
*
3+
* jsonpickle.js 1.2.0 built on 2025-08-06
4+
* Copyright (c) 2013–2025 Michael Scott Asato Cuthbert. BSD License
5+
*
6+
* http://github.com/cuthbertLab/jsonpickleJS
7+
*
8+
*/

build/jsonpickle.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

eslint.config.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import globals from 'globals';
2+
import { configs } from 'eslint-config-airbnb-extended/legacy';
3+
4+
export default [
5+
...configs.base.recommended,
6+
{
7+
ignores: ['build/*', 'node_modules/*'],
8+
languageOptions: {
9+
ecmaVersion: 'latest',
10+
sourceType: 'module',
11+
globals: {
12+
...globals.browser,
13+
},
14+
},
15+
rules: {
16+
'array-bracket-spacing': ['off'],
17+
'arrow-parens': ['off'],
18+
'brace-style': ['off'],
19+
'camelcase': ['off'],
20+
'class-methods-use-this': ['off'],
21+
'comma-dangle': ['error', {
22+
'arrays': 'only-multiline',
23+
'objects': 'always-multiline',
24+
'imports': 'always-multiline',
25+
'exports': 'always-multiline',
26+
'functions': 'ignore',
27+
}],
28+
'curly': ['error', 'all'],
29+
'dot-location': ['error', 'property'],
30+
'dot-notation': ['error'],
31+
'indent': ['error', 4],
32+
'import/extensions': ['off'],
33+
'import/prefer-default-export': ['off'],
34+
'import/no-named-as-default': ['off'],
35+
'import/no-named-as-default-member': ['off'],
36+
'import/no-unresolved': ['off'],
37+
'import/no-extraneous-dependencies': ['off'],
38+
'max-len': ['off'],
39+
'new-cap': ['off'],
40+
'no-case-declarations': ['error'],
41+
'no-console': ['off'],
42+
'no-continue': ['off'],
43+
'no-confusing-arrow': ['off'],
44+
'no-else-return': ['off'],
45+
'no-lonely-if': ['off'],
46+
'no-mixed-operators': ['off'],
47+
'no-multi-spaces': ['off'],
48+
'no-multiple-empty-lines': ['error', { 'max': 3 }],
49+
'no-param-reassign': ['off'],
50+
'no-plusplus': ['error', { 'allowForLoopAfterthoughts': true }],
51+
'no-restricted-syntax': [
52+
2,
53+
'DebuggerStatement',
54+
'LabeledStatement',
55+
'WithStatement'
56+
],
57+
'no-shadow': ['off'],
58+
'no-trailing-spaces': ['off'],
59+
'no-use-before-define': ['off'],
60+
'no-underscore-dangle': ['off'],
61+
'no-unused-vars': [
62+
'error',
63+
{
64+
args: 'none',
65+
caughtErrors: 'none',
66+
varsIgnorePattern: '^i$|^j$|^unused|^junk|^counter|^_',
67+
}
68+
],
69+
'object-curly-spacing': ['off'],
70+
'object-property-newline': ['off'],
71+
'operator-linebreak': ['error', 'before'],
72+
'padded-blocks': ['off'],
73+
'prefer-destructuring': ['off'],
74+
'prefer-template': ['off'],
75+
'quote-props': ['off'],
76+
'radix': ['off'],
77+
'space-infix-ops': ['off'],
78+
'spaced-comment': ['off'],
79+
'strict': ['error', 'global'],
80+
'yoda': ['error', 'never', { 'exceptRange': true }],
81+
},
82+
},
83+
];

js/index.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22
* jsonpickleJS -- interpretation of python jsonpickle in Javascript
33
* index.js -- main loader -- this should be the only file that most users care about.
44
*
5-
* Copyright (c) 2014-19 Michael Scott Cuthbert and cuthbertLab
5+
* Copyright (c) 2014-25 Michael Scott Cuthbert and cuthbertLab
66
*/
7-
import 'regenerator-runtime/runtime';
8-
97
import * as unpickler from './unpickler.js';
108
import * as pickler from './pickler.js';
119
import * as util from './util.js';
1210
import { tags } from './tags.js';
1311
import { handlers } from './handlers.js';
1412

1513
// noinspection JSUnusedGlobalSymbols
16-
export { pickler, unpickler, util, tags, handlers };
14+
export {
15+
pickler, unpickler, util, tags, handlers,
16+
};
1717

1818
export function encode(
19-
value, unpicklable=true, make_refs=true,
20-
keys=false, max_depth, backend
19+
value,
20+
unpicklable=true,
21+
make_refs=true,
22+
keys=false,
23+
max_depth=undefined,
24+
backend=undefined,
2125
) {
2226
const options = {
2327
unpicklable,

js/pickler.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import * as util from './util';
2-
import { handlers } from './handlers';
3-
import { tags } from './tags';
1+
import * as util from './util.js';
2+
import { handlers } from './handlers.js';
3+
import { tags } from './tags.js';
44

55
export function encode(value, options) {
66
const params = {
@@ -51,6 +51,7 @@ export class Pickler {
5151
this._objs = [];
5252
this._seen = [];
5353
}
54+
5455
reset() {
5556
this._objs = [];
5657
this._depth = -1;
@@ -60,13 +61,15 @@ export class Pickler {
6061
_push() {
6162
this._depth += 1;
6263
}
64+
6365
_pop(value) {
6466
this._depth -= 1;
6567
if (this._depth === -1) {
6668
this.reset();
6769
}
6870
return value;
6971
}
72+
7073
_mkref(obj) {
7174
const found_id = this._get_id_in_objs(obj);
7275
// console.log(found_id);
@@ -81,6 +84,7 @@ export class Pickler {
8184
this._objs.push(obj);
8285
return true;
8386
}
87+
8488
_get_id_in_objs(obj) {
8589
const objLength = this._objs.length;
8690
// console.log('sought obj', obj);

0 commit comments

Comments
 (0)