Move telepath.js into an external package

pull/6931/head
Matt Westcott 2021-02-10 13:06:02 +00:00
rodzic 56ea3feca3
commit 31a6e5b0a8
5 zmienionych plików z 7 dodań i 303 usunięć

Wyświetl plik

@ -1,3 +1,3 @@
import Telepath from '../../../utils/telepath';
import Telepath from 'telepath-unpack';
window.telepath = new Telepath();

Wyświetl plik

@ -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;

Wyświetl plik

@ -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é');
});
});

5
package-lock.json wygenerowano
Wyświetl plik

@ -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",

Wyświetl plik

@ -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": {