From b57dc253bad763b62b56c870c0802661e7e8bd1e Mon Sep 17 00:00:00 2001 From: REllEK-IO Date: Wed, 8 May 2024 13:11:26 -0700 Subject: [PATCH 1/4] Temp until new approach is found --- src/index.ts | 2 +- src/model/selector.ts | 162 +++++++++++++------------------------- src/test/selector.test.ts | 8 +- 3 files changed, 61 insertions(+), 111 deletions(-) diff --git a/src/index.ts b/src/index.ts index db80050..aa1b531 100644 --- a/src/index.ts +++ b/src/index.ts @@ -113,7 +113,7 @@ export { createUnifiedKeyedSelector, createAdvancedKeys, select, - DotPath + // DotPath } from './model/selector'; export { PrincipleFunction, principle } from './model/principle'; export { createActionController$, actionController } from './model/actionController'; diff --git a/src/model/selector.ts b/src/model/selector.ts index 3fb7171..929ba86 100644 --- a/src/model/selector.ts +++ b/src/model/selector.ts @@ -4,7 +4,7 @@ This file will contain a series of selectors that can be used to engage with dif $>*/ /*<#*/ import { Action } from './action'; -import { Concept, Concepts, createConcept } from './concept'; +import { Concept, Concepts } from './concept'; /** * Will have such be a list of state keys separated by spaces until someone yells at me to change this. @@ -19,121 +19,40 @@ export type KeyedSelector = { setSelector?: SelectorFunction }; /** - * For usage outside of the Axium, or when subscribed to other Axiums + * Will create a new KeyedSelector based on a concept name comparison during runtime, mainly used for external usage + * @param keys - type string - Format is 'key0.key1.key3' for deep nested key values + * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ -export const createConceptKeyedSelector = - >(conceptName: string, keys: DotPath, setKeys?: (number|string)[]): KeyedSelector => { - const selectorBase = [conceptName, ...keys.split('.')]; - if (setKeys) { - return { - conceptName, - conceptSemaphore: -1, - keys: conceptName + '.' + keys, - selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, - setKeys, - setSelector: setCreation(setKeys, setKeys.length - 1, setKeys.length) - }; - } +export const createConceptKeyedSelector = (conceptName: string, keys: string, setKeys?: (number|string)[]): KeyedSelector => { + const selectorBase = [conceptName, ...keys.split('.')]; + if (setKeys) { return { conceptName, conceptSemaphore: -1, keys: conceptName + '.' + keys, selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, - setKeys + setKeys, + setSelector: setCreation(setKeys, setKeys.length - 1, setKeys.length) }; + } + return { + conceptName, + conceptSemaphore: -1, + keys: conceptName + '.' + keys, + selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, + setKeys }; +}; /** - * This will update a concepts KeyedSelector to its currently unified concept. - * @Note Use this in place of createUnifiedSelector if you find yourself needing to lock deep values. - */ -export const updateUnifiedKeyedSelector = - (concepts: Concepts, semaphore: number, keyedSelector: KeyedSelector): KeyedSelector | undefined => { - if (concepts[semaphore]) { - const selectorBase = keyedSelector.keys.split('.'); - selectorBase[0] = concepts[semaphore].name; - const selector = creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction; - if (keyedSelector.setKeys) { - return { - conceptName: concepts[semaphore].name, - conceptSemaphore: semaphore, - selector, - keys: selectorBase.join('.'), - setKeys: keyedSelector.setKeys, - setSelector: keyedSelector.setSelector - }; - } - return { - conceptName: concepts[semaphore].name, - conceptSemaphore: semaphore, - selector, - keys: selectorBase.join('.') - }; - } else { - return undefined; - } - }; - -type Key = string | number | symbol; - -type Join = L extends - | string - | number - ? R extends string | number - ? `${L}.${R}` - : L - : R extends string | number - ? R - : undefined; - -type Union< - L extends unknown | undefined, - R extends unknown | undefined -> = L extends undefined - ? R extends undefined - ? undefined - : R - : R extends undefined - ? L - : L | R; - -// Use this type to define object types you want to skip (no path-scanning) -type ObjectsToIgnore = { new(...parms: any[]): any } | Date | Array - -type ValidObject = T extends object - ? T extends ObjectsToIgnore - ? false & 1 - : T - : false & 1; - -export type DotPath< - T extends object, - Prev extends Key | undefined = undefined, - Path extends Key | undefined = undefined, - PrevTypes extends object = T -> = string & - { - [K in keyof T]: - // T[K] is a type already checked? - T[K] extends PrevTypes | T - // Return all previous paths. - ? Union, Join> - : // T[K] is an object?. - Required[K] extends ValidObject[K]> - ? // Continue extracting - DotPath[K], Union, Join, PrevTypes | T> - : // Return all previous paths, including current key. - Union, Join>; - }[keyof T]; -/** - * Will create a new KeyedSelector during runtime, for usage within your principles. - * @Note Will want to expand this later, so that we can select into objects and arrays. - * This would allow us to lock parts of such in later revisions, not an immediate concern. + * Will create a new KeyedSelector during runtime, for usage throughout Stratimux + * @param keys - type string - Format is 'key0.key1.key3' for deep nested key values + * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ -export const createUnifiedKeyedSelector = ( +export const createUnifiedKeyedSelector = ( concepts: Concepts, semaphore: number, - keys: DotPath, + keys: string, setKeys?: (number | string)[] ): KeyedSelector | undefined => { const concept = concepts[semaphore]; @@ -164,6 +83,37 @@ export const createUnifiedKeyedSelector = ( return undefined; }; +/** + * This will update a concepts KeyedSelector to its currently unified concept. + * @Note Use this in place of createUnifiedSelector if you find yourself needing to lock deep values. + */ +export const updateUnifiedKeyedSelector = + (concepts: Concepts, semaphore: number, keyedSelector: KeyedSelector): KeyedSelector | undefined => { + if (concepts[semaphore]) { + const selectorBase = keyedSelector.keys.split('.'); + selectorBase[0] = concepts[semaphore].name; + const selector = creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction; + if (keyedSelector.setKeys) { + return { + conceptName: concepts[semaphore].name, + conceptSemaphore: semaphore, + selector, + keys: selectorBase.join('.'), + setKeys: keyedSelector.setKeys, + setSelector: keyedSelector.setSelector + }; + } + return { + conceptName: concepts[semaphore].name, + conceptSemaphore: semaphore, + selector, + keys: selectorBase.join('.') + }; + } else { + return undefined; + } + }; + const recordReturn = (key: string, previous: SelectorFunction) => { return (obj: Record) => { if (obj[key] !== undefined) { @@ -326,12 +276,12 @@ export function selectConcept(concepts: Concepts, name: string): Concept | undef /** * Advanced functionality, set a custom key path that may include array indexes. - * @example createAdvancedKeys('some', 1, 'once', 2, 'me', 7, 'world', 4) : some.1.once.2.m.7.world.4 + * @example createAdvancedKeys(['some', 1, 'once', 2, 'me', 7, 'world', 4]) : some.1.once.2.m.7.world.4 * @param arr a series of keys that points to your targeted slice * @returns DotPath */ -export function createAdvancedKeys(arr: unknown[]): DotPath { - return arr.join('.') as DotPath; +export function createAdvancedKeys(arr: unknown[]): string { + return arr.join('.') as string; } //createConceptKeyedSelector<{something: unknown}>('something', 'something.1' as DotPath<{something:unknown}>); diff --git a/src/test/selector.test.ts b/src/test/selector.test.ts index ade2000..232187d 100644 --- a/src/test/selector.test.ts +++ b/src/test/selector.test.ts @@ -52,11 +52,11 @@ test('Axium Unified Selector Test', (done) => { }, else: boolean[] } - type Deeper = { + type DeepNested = { anything : SomeDeepObject, bool: boolean } - const obj: Deeper = { + const obj: DeepNested = { anything: { else: [false], something: { @@ -70,8 +70,8 @@ test('Axium Unified Selector Test', (done) => { const concepts: Concepts = { 0: experiment }; - const selector = select.createUnifiedKeyedSelector(concepts, 0, 'anything.something.somethingArray', [10, 9, 8, 7]); - const conceptSelector = select.createConceptKeyedSelector(experimentName, 'anything.something.somethingElse'); + const selector = select.createUnifiedKeyedSelector(concepts, 0, 'anything.something.somethingArray', [10, 9, 8, 7]); + const conceptSelector = select.createConceptKeyedSelector(experimentName, 'anything.something.somethingElse'); if (selector) { const slices = select.set(concepts, selector); console.log('CHECK SLICES', slices); From 259696c173db3f56f6e00432a6a0388b8c61f1de Mon Sep 17 00:00:00 2001 From: REllEK-IO Date: Wed, 8 May 2024 13:46:42 -0700 Subject: [PATCH 2/4] Checkpoint --- src/test/selector.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/selector.test.ts b/src/test/selector.test.ts index 232187d..77c4ac8 100644 --- a/src/test/selector.test.ts +++ b/src/test/selector.test.ts @@ -4,11 +4,10 @@ $>*/ /*<#*/ import { createAxium } from '../model/axium'; import { Concepts } from '../model/concept'; -import { createUnifiedKeyedSelector, select, selectPayload, selectSlice, selectState } from '../model/selector'; +import { select, selectPayload, selectSlice, selectState } from '../model/selector'; import { CounterState, createCounterConcept, counterName } from '../concepts/counter/counter.concept'; import { counterSelectCount } from '../concepts/counter/counter.selector'; import { CounterSetCountPayload, counterSetCount } from '../concepts/counter/qualities/setCount.quality'; -import { AxiumState } from '../concepts/axium/axium.concept'; import { createExperimentConcept, experimentName } from '../concepts/experiment/experiment.concept'; test('Axium Selector Test', (done) => { From a0e2927cd571ca8cac1c6585275b6e0680c61eec Mon Sep 17 00:00:00 2001 From: REllEK-IO Date: Thu, 9 May 2024 09:57:02 -0700 Subject: [PATCH 3/4] Patch Restored DotPath v0.1.63 --- README.md | 4 +- package.json | 2 +- src/index.ts | 4 +- src/model/dotPath.ts | 183 ++++++++++++++++++++++++++++++++++++++ src/model/selector.ts | 37 ++++---- src/test/selector.test.ts | 4 +- 6 files changed, 212 insertions(+), 22 deletions(-) create mode 100644 src/model/dotPath.ts diff --git a/README.md b/README.md index 3c2a4c3..1506e33 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,9 @@ When in doubt simplify. * [Unified Turing Machine](https://github.com/Phuire-Research/Stratimux/blob/main/The-Unified-Turing-Machine.md) - The governing concept for this entire framework. ## Change Log ![Tests](https://github.com/Phuire-Research/Stratimux/actions/workflows/node.js.yml/badge.svg) -### **BREAKING** Strong Fast Lock Step v0.1.62 +### Patch v0.1.62 5/09/2024 +* Restored DotPath, a type used in the selector creators used to guide the creation of a dot path string. +### **BREAKING** Strong Fast Lock Step v0.1.62 5/08/2024 * Devised a means to ensure a lock step execution of incoming actions * Due to each stage being ran once regardless of their selector being changed, some plans may receive the wrong value if not determining if that stage has been ran for the first time. See priority.test.ts for the example: if (changes.length > 0) {//} * This also impacted the *axiumWaitForOpenThenIterate* helper function, but now works as intended via no longer checking for the latest lastStrategy change. diff --git a/package.json b/package.json index 501dde1..835c1f5 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stratimux", "license": "GPL-3.0", - "version": "0.1.62", + "version": "0.1.63", "description": "Unified Turing Machine", "main": "dist/index.js", "module": "dist/index.mjs", diff --git a/src/index.ts b/src/index.ts index aa1b531..ebd84ad 100644 --- a/src/index.ts +++ b/src/index.ts @@ -113,8 +113,10 @@ export { createUnifiedKeyedSelector, createAdvancedKeys, select, - // DotPath } from './model/selector'; +export type { + DotPath +} from './model/dotPath'; export { PrincipleFunction, principle } from './model/principle'; export { createActionController$, actionController } from './model/actionController'; export type { dispatchOptions, Staging, UnifiedSubject, StagePlanner, NamedStagePlanner } from './model/stagePlanner'; diff --git a/src/model/dotPath.ts b/src/model/dotPath.ts new file mode 100644 index 0000000..cf366d5 --- /dev/null +++ b/src/model/dotPath.ts @@ -0,0 +1,183 @@ +/*<$ +For the asynchronous graph programming framework Stratimux, define the DotPath model file. +$>*/ +/*<#*/ +type Key = string | number | symbol; + +type Join = L extends + | string + | number + ? R extends string | number + ? `${L}.${R}` + : L + : R extends string | number + ? R + : undefined; + +type Union< + L extends unknown | undefined, + R extends unknown | undefined +> = L extends undefined + ? R extends undefined + ? undefined + : R + : R extends undefined + ? L + : L | R; + +// Use this type to define object types you want to skip (no path-scanning) +type ObjectsToIgnore = { new(...parms: any[]): any } | Date | Array + +type ValidObject = T extends object + ? T extends ObjectsToIgnore + ? false & 1 + : T + : false & 1; + +export type DotPath< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + // T[K] is a type already checked? + T[K] extends PrevTypes | T + // Return all previous paths. + ? Union, Join> + : // T[K] is an object?. + Required[K] extends ValidObject[K]> + ? // Continue extracting + DotPathOne[K], Union, Join, PrevTypes | T> + : // Return all previous paths, including current key. + Union, Join>; + }[keyof T]; + +type DotPathOne< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathTwo[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +type DotPathTwo< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathThree[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +type DotPathThree< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathFour[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +type DotPathFour< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathFive[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +type DotPathFive< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathSix[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +type DotPathSix< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + DotPathSevenEnd[K], Union, Join, PrevTypes | T> + : + Union, Join>; + }[keyof T]; + +// Beyond this point will trigger TS excessively deep error or circular reference. +type DotPathSevenEnd< + T extends object, + Prev extends Key | undefined = undefined, + Path extends Key | undefined = undefined, + PrevTypes extends object = T +> = string & + { + [K in keyof T]: + T[K] extends PrevTypes | T + ? Union, Join> + : + Required[K] extends ValidObject[K]> + ? + Union, Join> + : + Union, Join>; + }[keyof T]; +/*#>*/ \ No newline at end of file diff --git a/src/model/selector.ts b/src/model/selector.ts index 929ba86..0e7988f 100644 --- a/src/model/selector.ts +++ b/src/model/selector.ts @@ -5,6 +5,7 @@ $>*/ /*<#*/ import { Action } from './action'; import { Concept, Concepts } from './concept'; +import { DotPath } from './dotPath'; /** * Will have such be a list of state keys separated by spaces until someone yells at me to change this. @@ -18,41 +19,43 @@ export type KeyedSelector = { setKeys?: (number | string)[] setSelector?: SelectorFunction }; + /** * Will create a new KeyedSelector based on a concept name comparison during runtime, mainly used for external usage * @param keys - type string - Format is 'key0.key1.key3' for deep nested key values * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ -export const createConceptKeyedSelector = (conceptName: string, keys: string, setKeys?: (number|string)[]): KeyedSelector => { - const selectorBase = [conceptName, ...keys.split('.')]; - if (setKeys) { +export const createConceptKeyedSelector = + (conceptName: string, keys: DotPath, setKeys?: (number|string)[]): KeyedSelector => { + const selectorBase = [conceptName, ...keys.split('.')]; + if (setKeys) { + return { + conceptName, + conceptSemaphore: -1, + keys: conceptName + '.' + keys, + selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, + setKeys, + setSelector: setCreation(setKeys, setKeys.length - 1, setKeys.length) + }; + } return { conceptName, conceptSemaphore: -1, keys: conceptName + '.' + keys, selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, - setKeys, - setSelector: setCreation(setKeys, setKeys.length - 1, setKeys.length) + setKeys }; - } - return { - conceptName, - conceptSemaphore: -1, - keys: conceptName + '.' + keys, - selector: creation(selectorBase, selectorBase.length - 1, selectorBase.length) as SelectorFunction, - setKeys }; -}; /** * Will create a new KeyedSelector during runtime, for usage throughout Stratimux * @param keys - type string - Format is 'key0.key1.key3' for deep nested key values * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ -export const createUnifiedKeyedSelector = ( +export const createUnifiedKeyedSelector = ( concepts: Concepts, semaphore: number, - keys: string, + keys: DotPath, setKeys?: (number | string)[] ): KeyedSelector | undefined => { const concept = concepts[semaphore]; @@ -280,8 +283,8 @@ export function selectConcept(concepts: Concepts, name: string): Concept | undef * @param arr a series of keys that points to your targeted slice * @returns DotPath */ -export function createAdvancedKeys(arr: unknown[]): string { - return arr.join('.') as string; +export function createAdvancedKeys(arr: unknown[]): DotPath { + return arr.join('.') as DotPath; } //createConceptKeyedSelector<{something: unknown}>('something', 'something.1' as DotPath<{something:unknown}>); diff --git a/src/test/selector.test.ts b/src/test/selector.test.ts index 77c4ac8..6ae2ef3 100644 --- a/src/test/selector.test.ts +++ b/src/test/selector.test.ts @@ -69,8 +69,8 @@ test('Axium Unified Selector Test', (done) => { const concepts: Concepts = { 0: experiment }; - const selector = select.createUnifiedKeyedSelector(concepts, 0, 'anything.something.somethingArray', [10, 9, 8, 7]); - const conceptSelector = select.createConceptKeyedSelector(experimentName, 'anything.something.somethingElse'); + const selector = select.createUnifiedKeyedSelector(concepts, 0, 'anything.something.somethingArray', [10, 9, 8, 7]); + const conceptSelector = select.createConceptKeyedSelector(experimentName, 'anything.something.somethingElse'); if (selector) { const slices = select.set(concepts, selector); console.log('CHECK SLICES', slices); From 026f75634f53f6c8732e9e800179749e48edd6a5 Mon Sep 17 00:00:00 2001 From: REllEK-IO Date: Thu, 9 May 2024 09:59:13 -0700 Subject: [PATCH 4/4] Patch Restored DotPath v0.1.63 --- src/model/selector.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/model/selector.ts b/src/model/selector.ts index 0e7988f..ae0e1a0 100644 --- a/src/model/selector.ts +++ b/src/model/selector.ts @@ -26,7 +26,7 @@ export type KeyedSelector = { * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ export const createConceptKeyedSelector = - (conceptName: string, keys: DotPath, setKeys?: (number|string)[]): KeyedSelector => { + >(conceptName: string, keys: DotPath, setKeys?: (number|string)[]): KeyedSelector => { const selectorBase = [conceptName, ...keys.split('.')]; if (setKeys) { return { @@ -52,7 +52,7 @@ export const createConceptKeyedSelector = * @param keys - type string - Format is 'key0.key1.key3' for deep nested key values * Originally used a DotPath parameter to ease the developer experience, but recent versions made the approach unfeasible */ -export const createUnifiedKeyedSelector = ( +export const createUnifiedKeyedSelector = >( concepts: Concepts, semaphore: number, keys: DotPath,