forked from FINAKON/HelpProject
1. Initial Commit - a boiler plate code and POC to realize the concept of context sensitive help 2. Frontend code written in ReactJS 3. Backend code written in Java, Spring Boot Framework 4. Frontend Start: pre-requisites : node, npm npm run dev ==> to start the frontend vite server 5. Backend Start: pre-requisites : java, mvn mvn spring-boot:run ==> to start the backend server 6. Visit http://localhost:5173/ for basic demo of help, press F1 in textboxes 7. Visit http://localhost:5173/editor and enter "admin123" to add/modify texts. Happy Coding !!! Thank you, Bhargava.
172 lines
4.3 KiB
JavaScript
172 lines
4.3 KiB
JavaScript
import {
|
|
VOID, PRIMITIVE,
|
|
ARRAY, OBJECT,
|
|
DATE, REGEXP, MAP, SET,
|
|
ERROR, BIGINT
|
|
} from './types.js';
|
|
|
|
const EMPTY = '';
|
|
|
|
const {toString} = {};
|
|
const {keys} = Object;
|
|
|
|
const typeOf = value => {
|
|
const type = typeof value;
|
|
if (type !== 'object' || !value)
|
|
return [PRIMITIVE, type];
|
|
|
|
const asString = toString.call(value).slice(8, -1);
|
|
switch (asString) {
|
|
case 'Array':
|
|
return [ARRAY, EMPTY];
|
|
case 'Object':
|
|
return [OBJECT, EMPTY];
|
|
case 'Date':
|
|
return [DATE, EMPTY];
|
|
case 'RegExp':
|
|
return [REGEXP, EMPTY];
|
|
case 'Map':
|
|
return [MAP, EMPTY];
|
|
case 'Set':
|
|
return [SET, EMPTY];
|
|
case 'DataView':
|
|
return [ARRAY, asString];
|
|
}
|
|
|
|
if (asString.includes('Array'))
|
|
return [ARRAY, asString];
|
|
|
|
if (asString.includes('Error'))
|
|
return [ERROR, asString];
|
|
|
|
return [OBJECT, asString];
|
|
};
|
|
|
|
const shouldSkip = ([TYPE, type]) => (
|
|
TYPE === PRIMITIVE &&
|
|
(type === 'function' || type === 'symbol')
|
|
);
|
|
|
|
const serializer = (strict, json, $, _) => {
|
|
|
|
const as = (out, value) => {
|
|
const index = _.push(out) - 1;
|
|
$.set(value, index);
|
|
return index;
|
|
};
|
|
|
|
const pair = value => {
|
|
if ($.has(value))
|
|
return $.get(value);
|
|
|
|
let [TYPE, type] = typeOf(value);
|
|
switch (TYPE) {
|
|
case PRIMITIVE: {
|
|
let entry = value;
|
|
switch (type) {
|
|
case 'bigint':
|
|
TYPE = BIGINT;
|
|
entry = value.toString();
|
|
break;
|
|
case 'function':
|
|
case 'symbol':
|
|
if (strict)
|
|
throw new TypeError('unable to serialize ' + type);
|
|
entry = null;
|
|
break;
|
|
case 'undefined':
|
|
return as([VOID], value);
|
|
}
|
|
return as([TYPE, entry], value);
|
|
}
|
|
case ARRAY: {
|
|
if (type) {
|
|
let spread = value;
|
|
if (type === 'DataView') {
|
|
spread = new Uint8Array(value.buffer);
|
|
}
|
|
else if (type === 'ArrayBuffer') {
|
|
spread = new Uint8Array(value);
|
|
}
|
|
return as([type, [...spread]], value);
|
|
}
|
|
|
|
const arr = [];
|
|
const index = as([TYPE, arr], value);
|
|
for (const entry of value)
|
|
arr.push(pair(entry));
|
|
return index;
|
|
}
|
|
case OBJECT: {
|
|
if (type) {
|
|
switch (type) {
|
|
case 'BigInt':
|
|
return as([type, value.toString()], value);
|
|
case 'Boolean':
|
|
case 'Number':
|
|
case 'String':
|
|
return as([type, value.valueOf()], value);
|
|
}
|
|
}
|
|
|
|
if (json && ('toJSON' in value))
|
|
return pair(value.toJSON());
|
|
|
|
const entries = [];
|
|
const index = as([TYPE, entries], value);
|
|
for (const key of keys(value)) {
|
|
if (strict || !shouldSkip(typeOf(value[key])))
|
|
entries.push([pair(key), pair(value[key])]);
|
|
}
|
|
return index;
|
|
}
|
|
case DATE:
|
|
return as([TYPE, value.toISOString()], value);
|
|
case REGEXP: {
|
|
const {source, flags} = value;
|
|
return as([TYPE, {source, flags}], value);
|
|
}
|
|
case MAP: {
|
|
const entries = [];
|
|
const index = as([TYPE, entries], value);
|
|
for (const [key, entry] of value) {
|
|
if (strict || !(shouldSkip(typeOf(key)) || shouldSkip(typeOf(entry))))
|
|
entries.push([pair(key), pair(entry)]);
|
|
}
|
|
return index;
|
|
}
|
|
case SET: {
|
|
const entries = [];
|
|
const index = as([TYPE, entries], value);
|
|
for (const entry of value) {
|
|
if (strict || !shouldSkip(typeOf(entry)))
|
|
entries.push(pair(entry));
|
|
}
|
|
return index;
|
|
}
|
|
}
|
|
|
|
const {message} = value;
|
|
return as([TYPE, {name: type, message}], value);
|
|
};
|
|
|
|
return pair;
|
|
};
|
|
|
|
/**
|
|
* @typedef {Array<string,any>} Record a type representation
|
|
*/
|
|
|
|
/**
|
|
* Returns an array of serialized Records.
|
|
* @param {any} value a serializable value.
|
|
* @param {{json?: boolean, lossy?: boolean}?} options an object with a `lossy` or `json` property that,
|
|
* if `true`, will not throw errors on incompatible types, and behave more
|
|
* like JSON stringify would behave. Symbol and Function will be discarded.
|
|
* @returns {Record[]}
|
|
*/
|
|
export const serialize = (value, {json, lossy} = {}) => {
|
|
const _ = [];
|
|
return serializer(!(json || lossy), !!json, new Map, _)(value), _;
|
|
};
|