kopia lustrzana https://github.com/wagtail/wagtail
Move telepath.js into an external package
rodzic
56ea3feca3
commit
31a6e5b0a8
|
@ -1,3 +1,3 @@
|
|||
import Telepath from '../../../utils/telepath';
|
||||
import Telepath from 'telepath-unpack';
|
||||
|
||||
window.telepath = new Telepath();
|
||||
|
|
|
@ -1,137 +0,0 @@
|
|||
/* eslint-disable dot-notation, no-param-reassign */
|
||||
|
||||
class Telepath {
|
||||
constructor() {
|
||||
this.constructors = {};
|
||||
}
|
||||
|
||||
register(name, constructor) {
|
||||
this.constructors[name] = constructor;
|
||||
}
|
||||
|
||||
unpack(objData) {
|
||||
const packedValuesById = {};
|
||||
this.scanForIds(objData, packedValuesById);
|
||||
const valuesById = {};
|
||||
return this.unpackWithRefs(objData, packedValuesById, valuesById);
|
||||
}
|
||||
|
||||
scanForIds(objData, packedValuesById) {
|
||||
/* descend into objData, indexing any objects with an _id in packedValuesById */
|
||||
|
||||
if (objData === null || typeof(objData) !== 'object') {
|
||||
/* primitive value - nothing to scan */
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(objData)) {
|
||||
/* scan recursively */
|
||||
objData.forEach(item => this.scanForIds(item, packedValuesById));
|
||||
return;
|
||||
}
|
||||
|
||||
/* objData is an object / dict - check for reserved key names */
|
||||
let hasReservedKeyNames = false;
|
||||
|
||||
if ('_id' in objData) {
|
||||
hasReservedKeyNames = true;
|
||||
/* index object in packedValuesById */
|
||||
packedValuesById[objData['_id']] = objData;
|
||||
}
|
||||
|
||||
if ('_type' in objData || '_val' in objData || '_ref' in objData) {
|
||||
hasReservedKeyNames = true;
|
||||
}
|
||||
|
||||
if ('_list' in objData) {
|
||||
hasReservedKeyNames = true;
|
||||
/* scan list items recursively */
|
||||
objData['_list'].forEach(item => this.scanForIds(item, packedValuesById));
|
||||
}
|
||||
|
||||
if ('_args' in objData) {
|
||||
hasReservedKeyNames = true;
|
||||
/* scan arguments recursively */
|
||||
objData['_args'].forEach(item => this.scanForIds(item, packedValuesById));
|
||||
}
|
||||
|
||||
if ('_dict' in objData) {
|
||||
hasReservedKeyNames = true;
|
||||
/* scan dict items recursively */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for (const [key, val] of Object.entries(objData['_dict'])) {
|
||||
this.scanForIds(val, packedValuesById);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasReservedKeyNames) {
|
||||
/* scan as a plain dict */
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
for (const [key, val] of Object.entries(objData)) {
|
||||
this.scanForIds(val, packedValuesById);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unpackWithRefs(objData, packedValuesById, valuesById) {
|
||||
if (objData === null || typeof(objData) !== 'object') {
|
||||
/* primitive value - return unchanged */
|
||||
return objData;
|
||||
}
|
||||
|
||||
if (Array.isArray(objData)) {
|
||||
/* unpack recursively */
|
||||
return objData.map(item => this.unpackWithRefs(item, packedValuesById, valuesById));
|
||||
}
|
||||
|
||||
/* objData is an object / dict - check for reserved key names */
|
||||
let result;
|
||||
|
||||
if ('_ref' in objData) {
|
||||
if (objData['_ref'] in valuesById) {
|
||||
/* use previously unpacked instance */
|
||||
result = valuesById[objData['_ref']];
|
||||
} else {
|
||||
/* look up packed object and unpack it; this will populate valuesById as a side effect */
|
||||
result = this.unpackWithRefs(
|
||||
packedValuesById[objData['_ref']], packedValuesById, valuesById
|
||||
);
|
||||
}
|
||||
} else if ('_val' in objData) {
|
||||
result = objData['_val'];
|
||||
} else if ('_list' in objData) {
|
||||
result = objData['_list'].map(
|
||||
item => this.unpackWithRefs(item, packedValuesById, valuesById)
|
||||
);
|
||||
} else if ('_dict' in objData) {
|
||||
result = {};
|
||||
for (const [key, val] of Object.entries(objData['_dict'])) {
|
||||
result[key] = this.unpackWithRefs(val, packedValuesById, valuesById);
|
||||
}
|
||||
} else if ('_type' in objData) {
|
||||
/* handle as a custom type */
|
||||
const constructorId = objData['_type'];
|
||||
const constructor = this.constructors[constructorId];
|
||||
/* unpack arguments recursively */
|
||||
const args = objData['_args'].map(arg => this.unpackWithRefs(arg, packedValuesById, valuesById));
|
||||
result = new constructor(...args);
|
||||
} else if ('_id' in objData) {
|
||||
throw new Error('telepath encountered object with _id but no type specified');
|
||||
} else {
|
||||
/* no reserved key names found, so unpack objData as a plain dict and return */
|
||||
result = {};
|
||||
for (const [key, val] of Object.entries(objData)) {
|
||||
result[key] = this.unpackWithRefs(val, packedValuesById, valuesById);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if ('_id' in objData) {
|
||||
valuesById[objData['_id']] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default Telepath;
|
|
@ -1,165 +0,0 @@
|
|||
/* eslint-disable dot-notation */
|
||||
|
||||
import Telepath from './telepath';
|
||||
|
||||
const telepath = new Telepath();
|
||||
|
||||
class Artist {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
telepath.register('music.Artist', Artist);
|
||||
|
||||
class Album {
|
||||
constructor(title, artists) {
|
||||
this.title = title;
|
||||
this.artists = artists;
|
||||
}
|
||||
}
|
||||
|
||||
telepath.register('music.Album', Album);
|
||||
|
||||
describe('Telepath', () => {
|
||||
it('can unpack objects', () => {
|
||||
const beyonce = telepath.unpack({ _type: 'music.Artist', _args: ['Beyoncé'] });
|
||||
expect(beyonce).toBeInstanceOf(Artist);
|
||||
expect(beyonce.name).toBe('Beyoncé');
|
||||
});
|
||||
|
||||
it('can unpack lists', () => {
|
||||
const destinysChild = telepath.unpack([
|
||||
{ _type: 'music.Artist', _args: ['Beyoncé'] },
|
||||
{ _type: 'music.Artist', _args: ['Kelly Rowland'] },
|
||||
{ _type: 'music.Artist', _args: ['Michelle Williams'] },
|
||||
]);
|
||||
expect(destinysChild.length).toBe(3);
|
||||
expect(destinysChild[0]).toBeInstanceOf(Artist);
|
||||
expect(destinysChild[0].name).toBe('Beyoncé');
|
||||
});
|
||||
|
||||
it('can unpack dicts', () => {
|
||||
const glastonbury = telepath.unpack({
|
||||
pyramid_stage: { _type: 'music.Artist', _args: ['Beyoncé'] },
|
||||
acoustic_stage: { _type: 'music.Artist', _args: ['Ed Sheeran'] },
|
||||
});
|
||||
expect(glastonbury.pyramid_stage).toBeInstanceOf(Artist);
|
||||
expect(glastonbury.pyramid_stage.name).toBe('Beyoncé');
|
||||
});
|
||||
|
||||
it('can unpack dicts in verbose form', () => {
|
||||
const profile = telepath.unpack({
|
||||
_dict: {
|
||||
_artist: { _type: 'music.Artist', _args: ['Beyoncé'] },
|
||||
_type: 'R&B',
|
||||
}
|
||||
});
|
||||
expect(profile['_artist']).toBeInstanceOf(Artist);
|
||||
expect(profile['_artist'].name).toBe('Beyoncé');
|
||||
expect(profile['_type']).toBe('R&B');
|
||||
});
|
||||
|
||||
it('can recursively unpack objects in parameters', () => {
|
||||
const dangerouslyInLove = telepath.unpack({
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
'Dangerously in Love',
|
||||
[
|
||||
{ _type: 'music.Artist', _args: ['Beyoncé'] },
|
||||
]
|
||||
]
|
||||
});
|
||||
expect(dangerouslyInLove).toBeInstanceOf(Album);
|
||||
expect(dangerouslyInLove.title).toBe('Dangerously in Love');
|
||||
expect(dangerouslyInLove.artists[0]).toBeInstanceOf(Artist);
|
||||
expect(dangerouslyInLove.artists[0].name).toBe('Beyoncé');
|
||||
});
|
||||
|
||||
it('can expand object references', () => {
|
||||
const discography = telepath.unpack([
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
'Dangerously in Love',
|
||||
[
|
||||
{ _type: 'music.Artist', _args: ['Beyoncé'], _id: 0 },
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
'Everything Is Love',
|
||||
[
|
||||
{ _ref: 0 },
|
||||
{ _type: 'music.Artist', _args: ['Jay-Z'] },
|
||||
]
|
||||
]
|
||||
},
|
||||
]);
|
||||
expect(discography[0].artists[0].name).toBe('Beyoncé');
|
||||
expect(discography[1].artists[0]).toBeInstanceOf(Artist);
|
||||
expect(discography[1].artists[0].name).toBe('Beyoncé');
|
||||
expect(discography[1].artists[1].name).toBe('Jay-Z');
|
||||
});
|
||||
|
||||
it('can expand list references', () => {
|
||||
const discography = telepath.unpack([
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
"Destiny's Child",
|
||||
{
|
||||
_list: [
|
||||
{ _type: 'music.Artist', _args: ['Beyoncé'] },
|
||||
{ _type: 'music.Artist', _args: ['Kelly Rowland'] },
|
||||
{ _type: 'music.Artist', _args: ['Michelle Williams'] },
|
||||
],
|
||||
_id: 0,
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
'Survivor',
|
||||
{ _ref: 0 },
|
||||
]
|
||||
},
|
||||
]);
|
||||
expect(discography[1].artists.length).toBe(3);
|
||||
expect(discography[1].artists[0].name).toBe('Beyoncé');
|
||||
expect(discography[1].artists).toBe(discography[0].artists);
|
||||
});
|
||||
|
||||
it('can expand primitive value references', () => {
|
||||
const discography = telepath.unpack([
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
'Dangerously in Love',
|
||||
[
|
||||
{
|
||||
_type: 'music.Artist',
|
||||
_args: [{ _val: 'Beyoncé', _id: 0 }],
|
||||
_id: 1,
|
||||
},
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
_type: 'music.Album',
|
||||
_args: [
|
||||
{ _ref: 0 },
|
||||
[
|
||||
{ _ref: 1 },
|
||||
]
|
||||
]
|
||||
},
|
||||
]);
|
||||
expect(discography[0].artists[0].name).toBe('Beyoncé');
|
||||
expect(discography[1].title).toBe('Beyoncé');
|
||||
expect(discography[1].artists[0].name).toBe('Beyoncé');
|
||||
});
|
||||
});
|
|
@ -14739,6 +14739,11 @@
|
|||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
||||
"dev": true
|
||||
},
|
||||
"telepath-unpack": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/telepath-unpack/-/telepath-unpack-0.0.1.tgz",
|
||||
"integrity": "sha512-1Fgeo+sb8xfFsjyvF1Z3zjaObifMr+irrgFD7XYrBpeSfHidoVceae0lIkLqPg3qjpzaTG/KNMkGa6QNRzIiJw=="
|
||||
},
|
||||
"terminal-link": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
"react-transition-group": "^1.1.3",
|
||||
"redux": "^4.0.0",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"telepath-unpack": "0.0.1",
|
||||
"whatwg-fetch": "^2.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
Ładowanie…
Reference in New Issue