Skip to content

Commit

Permalink
feat: test new state parser
Browse files Browse the repository at this point in the history
  • Loading branch information
juanfran committed Mar 14, 2024
1 parent 92a2645 commit ecb2295
Show file tree
Hide file tree
Showing 3 changed files with 205 additions and 1 deletion.
1 change: 1 addition & 0 deletions libs/plugins-data-parser/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { parse, getSelectedUuids } from './lib/utils';
export * from './lib/models';
export { getPartialState } from './lib/utils/parse-state';
199 changes: 199 additions & 0 deletions libs/plugins-data-parser/src/lib/utils/parse-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { toCamelCase } from './object.util';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type UknowCljs = any;

declare global {
const cljs: UknowCljs;
const app: UknowCljs;
}

const PATH_SEPARATOR = '/' as const;

function getPath(path: string): UknowCljs[] {
if (path === 'root') {
return [];
}
return path
.slice(5)
.split(PATH_SEPARATOR)
.map((it) => {
if (it.startsWith('#')) {
return cljs.core.uuid(it.slice(1));
} else if (it.startsWith(':')) {
return cljs.core.keyword(it.slice(1));
} else if (it.startsWith('!')) {
return parseInt(it.slice(1), 10);
} else {
return it;
}
});
}

const expandableTable = {
'app:datetime': false,
'cljs:uuid': false,
'cljs:keyword': false,
'cljs:symbol': false,
'js:date': false,
'js:boolean': false,
'js:function': false,
'js:number': false,
'js:string': false,
'js:undefined': false,
'js:null': false,
'unkwnown:unknown': false,
'cljs:vector': true,
'cljs:list': true,
'cljs:map': true,
'cljs:set': true,
'js:array': true,
'js:object': true,
} as const;

function isCljsArray(key: string) {
const valid = ['cljs:vector', 'cljs:list', 'cljs:set'];

return valid.includes(key);
}

const valueTable = {
'app:datetime': (value: unknown) => cljs.core.str(value),
'cljs:uuid': (value: unknown) => cljs.core.name(value),
'cljs:keyword': (value: unknown) => cljs.core.name(value),
'js:date': (value: unknown) => (value as Date).toISOString(),
};

function isTypeExpandable(type: keyof typeof expandableTable) {
return expandableTable[type];
}

function getType(value: unknown) {
const typeTable = {
'app:datetime': app.util.time.datetime_QMARK_,
'cljs:uuid': cljs.core.uuid_QMARK_,
'cljs:keyword': cljs.core.keyword_QMARK_,
'cljs:vector': cljs.core.vector_QMARK_,
'cljs:list': cljs.core.list_QMARK_,
'cljs:map': cljs.core.map_QMARK_,
'cljs:set': cljs.core.set_QMARK_,
'cljs:symbol': cljs.core.symbol_QMARK_,
'js:date': (value: unknown) => value instanceof Date,
'js:array': (value: unknown) => Array.isArray(value),
'js:boolean': (value: unknown) => typeof value === 'boolean',
'js:function': (value: unknown) => typeof value === 'function',
'js:number': (value: unknown) => typeof value === 'number',
'js:string': (value: unknown) => typeof value === 'string',
'js:undefined': (value: unknown) => typeof value === 'undefined',
'js:null': (value: unknown) => value === null,
'js:object': (value: unknown) =>
typeof value === 'object' &&
value !== null &&
value.toString() === '[object Object]',
};

for (const [type, fn] of Object.entries(typeTable)) {
if (fn(value)) return type as keyof typeof typeTable;
}

return 'unknown:unknown' as keyof typeof typeTable;
}

function getKeyName(key: string | number) {
if (cljs.core.uuid_QMARK_(key)) {
return '#' + cljs.core.name(key);
} else if (cljs.core.keyword_QMARK_(key)) {
return ':' + cljs.core.name(key);
} else if (typeof key === 'string') {
return key;
} else if (typeof key === 'number') {
return `!${key}`;
}

return key;
}

function getValue(value: unknown, type: string): unknown {
return type in valueTable
? valueTable[type as keyof typeof valueTable](value)
: value;
}

export function getPartialState(path: string, state: UknowCljs) {
// const state = cljs.core.deref(app.main.store.state);
const statePath = getPath(path);
const data = cljs.core.get_in(state, statePath);
const type = getType(data);
const isArray = isCljsArray(type);
const isExpandable = isTypeExpandable(type);

const map: Record<string, unknown> = {};
const list: unknown[] = [];

function addEntry(
childPath: string,
propName: string | number,
repValue: unknown,
isExpandable: boolean
) {
if (isArray) {
list.push(isExpandable ? getPartialState(childPath, state) : repValue);
} else {
if (isExpandable) {
Object.defineProperty(map, propName, {
get() {
return getPartialState(childPath, state);
},
configurable: true,
enumerable: true,
});
} else {
map[propName] = repValue;
}
}
}

if (isExpandable) {
if (type.startsWith('cljs:')) {
const cljsData = cljs.core.clj__GT_js(cljs.core.to_array(data));

cljsData.forEach((entry: unknown, index: number) => {
if (cljs.core.map_entry_QMARK_(entry)) {
const key = cljs.core.first(entry);
const name = getKeyName(key);
const value = cljs.core.nth(entry, 1);
const valueType = getType(value);
const repValue = getValue(value, valueType);
const isExpandable = isTypeExpandable(valueType);
const childPath = path + PATH_SEPARATOR + name;
const propName = name.startsWith(':')
? toCamelCase(name.slice(1))
: name;

addEntry(childPath, propName, repValue, isExpandable);

return;
} else {
const valueType = getType(entry);
const repValue = getValue(entry, valueType);
const isExpandable = isTypeExpandable(valueType);
const childPath = path + PATH_SEPARATOR + getKeyName(index);

addEntry(childPath, index, repValue, isExpandable);

return;
}
});
} else if (type.startsWith('js:')) {
Object.entries(data).forEach(([key, value]) => {
map[key] = value;
});
}

return isArray ? list : map;
}

const repValue = getValue(data, type);

return repValue;
}
6 changes: 5 additions & 1 deletion libs/plugins-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import './lib/plugin-modal';

import { ɵloadPlugin } from './lib/load-plugin';
import { setFileState, setPageState, setSelection, setTheme } from './lib/api';
import { getSelectedUuids } from 'plugins-parser';
import { getPartialState, getSelectedUuids } from 'plugins-parser';

repairIntrinsics({
evalTaming: 'unsafeEval',
Expand All @@ -18,6 +18,10 @@ export function initialize(api: any) {
console.log(api);

/* eslint-disable */
(globalThis as any).getPartialState = (path: string) => {
return getPartialState(path, api.getState());
};

api.addListener('plugin-page', 'page', (page: any) => {
console.log('Page Changed:', page);

Expand Down

0 comments on commit ecb2295

Please sign in to comment.