tauri-kargo-tools 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tauri-kargo-tools",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "description": "",
5
5
  "files": ["src"],
6
6
  "exports": { "./*": "./src/*" },
@@ -10,7 +10,7 @@ export type Type<T> =
10
10
 
11
11
  | { ref: readonly (keyof T)[]; }
12
12
 
13
-
13
+ | { struct: (keyof T); }
14
14
 
15
15
  | { arrayOf: Type<T>; }
16
16
 
@@ -19,20 +19,23 @@ export type Type<T> =
19
19
 
20
20
 
21
21
  export type Structure<T> = { [name: string]: Type<T>; };
22
- export type EntityFieldValue = number | string | boolean | { ref: string } | EntityFieldValue[]
22
+ export type EntityFieldValue = number | string | boolean | { ref: string } | EntityFieldValue[] | { [name: string]: EntityFieldValue }
23
23
  export type Entity = { [name: string]: EntityFieldValue }
24
24
  export type EntityMap = { [id: string]: Entity }
25
+ export type Api<T extends { [name: string]: Structure<T>; }> = { [action: string]: Structure<T> };
26
+ export interface World<T extends { [name: string]: Structure<T>; }, A extends Api<T>> {
27
+ def: T
28
+ api: A
29
+ }
25
30
 
26
- export function createModel<T extends { [name: string]: Structure<T>; }>(def: T): T {
27
- return def;
31
+ export function createModel<T extends { [name: string]: Structure<T>; }, A extends Api<T>>(def: T, api: A): World<T, A> {
32
+ return { def: def, api: api };
28
33
  }
29
34
 
30
35
 
31
36
 
32
37
  export class DataModel<T extends { [name: string]: Structure<T>; }> {
33
-
34
38
  def: T;
35
-
36
39
  map: { [id: string]: ModelElement<T>; } = {};
37
40
  types: { [id: string]: keyof T } = {}
38
41
  idx = 0;
@@ -45,7 +48,31 @@ export class DataModel<T extends { [name: string]: Structure<T>; }> {
45
48
  getValues(): ModelElement<T>[] {
46
49
  return Object.values(this.map)
47
50
  }
51
+ attach<K extends keyof T>(ref: Ref<T, K>) {
52
+ const value: any = this.getValue(ref.ref)
53
+ if (ref.ref && this.is(value, this.types[ref.ref] as K)) {
54
+ ref.getValue = () => value
55
+ return true
56
+ }
57
+ return false
58
+
59
+ }
60
+ getRefs<K extends keyof T>(type: K) {
61
+ const refs: Ref<T, K>[] = []
62
+ for (const [value, refValue] of this.idForModelElement.entries()) {
63
+ const tmp: any = value
64
+ if (this.types[refValue] === type) {
65
+ const ref: Ref<T, K> = { ref: refValue, getValue: () => tmp }
66
+ refs.push(ref)
67
+ }
68
+
69
+ }
48
70
 
71
+ return refs
72
+
73
+
74
+
75
+ }
49
76
  getValue(ref: string): ModelElement<T> {
50
77
  return this.map[ref];
51
78
  }
@@ -181,7 +208,9 @@ export class DataModel<T extends { [name: string]: Structure<T>; }> {
181
208
  if (this.isOptionalType(t)) {
182
209
  return v === undefined || this.checkType(t.optional, root, v, map);
183
210
  }
184
-
211
+ if (this.isStructType(t)) {
212
+ return this.checkStructure(this.def[t.struct], root, v, map)
213
+ }
185
214
  if (this.isRefType(t)) {
186
215
  // runtime minimal : { ref: "$0" }
187
216
  if (typeof v !== "object" || v === null || Array.isArray(v)) return false;
@@ -210,6 +239,9 @@ export class DataModel<T extends { [name: string]: Structure<T>; }> {
210
239
  private isRefType(x: any): x is { ref: readonly (keyof T)[] } {
211
240
  return typeof x === "object" && x !== null && Array.isArray(x.ref);
212
241
  }
242
+ private isStructType(x: any): x is { struct: (keyof T) } {
243
+ return typeof x === "object" && x !== null && typeof x.struct === "string"
244
+ }
213
245
  private isArrayOfType(x: any): x is { arrayOf: Type<T> } {
214
246
  return typeof x === "object" && x !== null && "arrayOf" in x;
215
247
  }
@@ -237,9 +269,7 @@ export class DataModel<T extends { [name: string]: Structure<T>; }> {
237
269
 
238
270
  }
239
271
 
240
- export type RefUnion<TDefs extends { [name: string]: Structure<TDefs>; }> = {
241
- [K in keyof TDefs]: Ref<TDefs, K>;
242
- }[keyof TDefs];
272
+
243
273
 
244
274
  type UnwrapOptional<V> = V extends { optional: infer O; } ? O : V;
245
275
 
@@ -267,6 +297,11 @@ type ToTsType<
267
297
 
268
298
  ? { [U in K[number]]: Ref<TDefs, U> }[K[number]]
269
299
 
300
+ : never
301
+ : V extends { struct: infer K; }
302
+
303
+ ? K extends (keyof TDefs) ? ToInterface<TDefs, K>
304
+
270
305
  : never
271
306
 
272
307
  : V extends { arrayOf: infer O; }
@@ -291,6 +326,50 @@ type ToTsType<
291
326
 
292
327
  // Matérialise une "entité" (clé de TDefs) en interface concrète
293
328
 
329
+ export type ToInterfaceForStructure<
330
+
331
+ TDefs extends { [name: string]: Structure<TDefs>; },
332
+
333
+ S extends Structure<TDefs>
334
+
335
+ > =
336
+
337
+ // Propriétés requises (pas 'optional')
338
+
339
+ {
340
+ -readonly [P in keyof S as S[P] extends { optional: any; } ? never : P]:
341
+
342
+ ToTsType<TDefs, S[P]>;
343
+
344
+ }
345
+
346
+ &
347
+
348
+ // Propriétés optionnelles ('optional')
349
+
350
+ {
351
+
352
+ -readonly [P in keyof S as S[P] extends { optional: any; } ? P : never]?:
353
+
354
+ ToTsType<TDefs, UnwrapOptional<S[P]>>;
355
+
356
+ };
357
+
358
+ export interface WorldAction<T extends { [name: string]: Structure<T>; }, A extends Api<T>, K extends keyof A> {
359
+ type: 'doAction'
360
+ op: K
361
+ value: ToInterfaceForStructure<T, A[K]>
362
+ }
363
+ type Actions<TDefs extends { [name: string]: Structure<TDefs>; }, A extends Api<TDefs>> = {
364
+
365
+ [K in keyof A]: WorldAction<TDefs, A, K>;
366
+
367
+ };
368
+ type UnionActions<TDefs extends { [name: string]: Structure<TDefs>; }, A extends Api<TDefs>> = Actions<TDefs, A>[keyof A]
369
+ export type WorldActionFonction<T extends { [name: string]: Structure<T>; }, A extends Api<T>, M extends keyof T> = (action: UnionActions<T, A>,
370
+ ref: Ref<T, M>
371
+ ) => boolean
372
+
294
373
  export type ToInterface<
295
374
 
296
375
  TDefs extends { [name: string]: Structure<TDefs>; },
@@ -489,7 +568,8 @@ export class TypeImplicationChecker<TDefs extends Def<TDefs>> {
489
568
 
490
569
  export interface DataModelReponse {
491
570
  type: 'dataModelReponse';
492
- value: any;
571
+ value: any
572
+ error: boolean
493
573
  }
494
574
  export interface RefReponse {
495
575
  type: 'refReponse';
@@ -1,4 +1,4 @@
1
- import { Ref, Structure, ToInterface, DataModel, RefUnion } from "./base";
1
+ import { Ref, Structure, ToInterface, DataModel, World, Api, ToInterfaceForStructure, WorldAction } from "./base";
2
2
  export type KeysOfType<T, V> = { [K in keyof T]-?: T[K] extends V ? K : never }[keyof T];
3
3
  export type Value = string | number | boolean | Value[]
4
4
  export interface DataModelProp<T extends { [name: string]: Structure<T>; }, K extends keyof T, F extends keyof ToInterface<T, K>> {
@@ -10,13 +10,13 @@ export interface DoAction<T extends { [name: string]: Structure<T>; }, K extends
10
10
  type: "doAction"
11
11
  }
12
12
 
13
- export class DataModelClient<T extends { [name: string]: Structure<T>; },M extends keyof T> {
14
- def: T;
13
+ export class DataModelClient<T extends { [name: string]: Structure<T>; }, M extends keyof T,A extends Api<T>> {
14
+ world: World<T,A>
15
15
  resolveDataModel: (dm: DataModel<T>) => void = () => { };
16
- resolveRefUnion: (ref: Ref<T,M>) => void = () => { };
16
+ resolveRefUnion: (ref: Ref<T, M>) => void = () => { };
17
17
 
18
- async doAction<K extends keyof T, F extends KeysOfType<ToInterface<T, K>, Value>>(dvp: DataModelProp<T, K, F>): Promise<DataModel<T>> {
19
- const setDataModelProp: DoAction<T, K, F> = { ...dvp, type: "doAction" }
18
+ async doAction<K extends keyof A>(op: K, value: ToInterfaceForStructure<T, A[K]>): Promise<DataModel<T>> {
19
+ const setDataModelProp: WorldAction<T,A,K> = { type: "doAction", op: op, value: value }
20
20
  self.postMessage(JSON.parse(JSON.stringify(setDataModelProp)))
21
21
 
22
22
  const r = new Promise<DataModel<T>>((resolve) => {
@@ -32,27 +32,27 @@ export class DataModelClient<T extends { [name: string]: Structure<T>; },M exten
32
32
  })
33
33
  return r;
34
34
  }
35
- async getSelf():Promise<Ref<T,M>> {
35
+ async getSelf(): Promise<Ref<T, M>> {
36
36
  self.postMessage({ type: "getSelf" })
37
- const r = new Promise<Ref<T,M>>((resolve) => {
37
+ const r = new Promise<Ref<T, M>>((resolve) => {
38
38
  this.resolveRefUnion = resolve;
39
39
  })
40
40
  return r;
41
41
 
42
42
 
43
43
  }
44
- constructor(def: T, type:M) {
45
- this.def = def;
44
+ constructor(world: World<T,A>, type: M) {
45
+ this.world = world
46
46
  self.addEventListener("message", (event) => {
47
47
  const data = event.data;
48
48
  if (data.type === "refReponse") {
49
49
  const refReponse = data as { type: 'refReponse', ref: string };
50
- const r = { ref: refReponse.ref } as Ref<T,M>;
50
+ const r = { ref: refReponse.ref } as Ref<T, M>;
51
51
  this.resolveRefUnion(r);
52
52
  return;
53
53
  }
54
54
  if (data.type === "dataModelReponse") {
55
- const r = new DataModel<T>(this.def)
55
+ const r = new DataModel<T>(this.world.def)
56
56
  r.init(data.value)
57
57
  this.resolveDataModel(r);
58
58
  }
@@ -1,5 +1,5 @@
1
1
  import { set } from "../container";
2
- import { Ref, Structure, ToInterface, DataModel, DataModelReponse, RefUnion } from "./base";
2
+ import { Ref, Structure, ToInterface, DataModel, DataModelReponse, World, WorldActionFonction, Api } from "./base";
3
3
  import { Value } from "./client";
4
4
 
5
5
  export interface DoAction {
@@ -12,23 +12,24 @@ export interface SimpleRef {
12
12
  ref: string
13
13
  }
14
14
 
15
- export class DataModelServer<T extends { [name: string]: Structure<T>; }> extends DataModel<T> {
16
-
17
- constructor(def: T) {
18
- super(def)
15
+ export class DataModelServer<T extends { [name: string]: Structure<T>; }, M extends keyof T,A extends Api<T>> extends DataModel<T> {
16
+ world: World<T,A>
17
+ constructor(world: World<T,A>, type: M) {
18
+ super(world.def)
19
+ this.world = world
19
20
  }
20
- process(worker: Worker, check: (setDataModelProp: DoAction) => boolean, ref:SimpleRef) {
21
+
22
+ process(worker: Worker, action: WorldActionFonction<T,A, M>, ref: Ref<T, M>) {
21
23
  worker.addEventListener("message", async (event) => {
22
24
  const data = event.data;
23
25
  if (data.type === "doAction") {
24
- const setDataModelProp = data as DoAction;
25
- if (check(setDataModelProp)) {
26
- this.initField(setDataModelProp.ref.ref, setDataModelProp.field, setDataModelProp.value);
27
- worker.postMessage(this.cloneMap());
28
- }
26
+
27
+ const error = (action( { op:data.op,value:data.value,type:"doAction"}, ref))
28
+ worker.postMessage(this.cloneMap(error));
29
+
29
30
  }
30
31
  if (data.type === "getObservation") {
31
- worker.postMessage(this.cloneMap());
32
+ worker.postMessage(this.cloneMap(false));
32
33
  }
33
34
  if (data.type === "getSelf") {
34
35
  const refReponse = { type: 'refReponse', ref: ref.ref };
@@ -37,8 +38,8 @@ export class DataModelServer<T extends { [name: string]: Structure<T>; }> extend
37
38
  })
38
39
 
39
40
  }
40
- cloneMap(): DataModelReponse {
41
- return { type: 'dataModelReponse', value: JSON.parse(JSON.stringify(this.map)) };
41
+ cloneMap(error: boolean): DataModelReponse {
42
+ return { type: 'dataModelReponse', value: JSON.parse(JSON.stringify(this.map)), error: error };
42
43
  }
43
44
 
44
45
  }
@@ -5,9 +5,20 @@ export const model = createModel({
5
5
  Cell: {
6
6
  nom: "string",
7
7
  state: "boolean",
8
+ p: { struct: "Point" }
8
9
  },
9
10
  Groupe: {
10
- state:"boolean",
11
+ state: "boolean",
11
12
  membres: { arrayOf: { ref: ["Cell"] } }
13
+ },
14
+ Point: {
15
+ x: "number",
16
+ y: "number"
17
+ }
18
+ }, {
19
+ setCell: {
20
+ ref: { ref: ["Cell"] },
21
+ value: "boolean",
22
+ p: { struct: "Point" }
12
23
  }
13
24
  })
package/src/test/index.ts CHANGED
@@ -1,29 +1,34 @@
1
1
  import * as test from "../test"
2
2
  import * as api from '../api'
3
3
  import * as schema from "../schema/base"
4
- import { DataModelServer, DoAction } from "../schema/server"
4
+ import { DataModelServer } from "../schema/server"
5
5
  import { model } from "./data-model"
6
+ interface V {
7
+ ref: schema.Ref<typeof model.def, "Cell">,
8
+ value: schema.ToInterface<typeof model.def, "Point">
9
+ }
10
+
6
11
  test.test("Test schema client server", async () => {
7
12
 
8
- const server = new DataModelServer(model)
9
- const state = server.createValue("Cell", { nom: "A", state: false })
13
+ const server = new DataModelServer(model, "Groupe")
14
+ const state = server.createValue("Cell", { nom: "A", state: false, p: { x: 45, y: 7 } })
10
15
  const groupe = server.createValue("Groupe", { membres: [state], state: false })
11
- let resolve: (b: DoAction[]) => void = () => { }
12
- const p = new Promise<DoAction[]>((r) => {
16
+ let resolve: (b: V) => void = () => { }
17
+ const p = new Promise<V>((r) => {
13
18
  resolve = r
14
19
  })
15
- const m: DoAction[] = []
20
+
16
21
  const worker = new Worker(new URL("./worker.ts", import.meta.url), { type: "module" });
17
- server.process(worker, (op) => {
18
- m.push(op)
19
- if (m.length >= 2) {
20
- resolve(m)
22
+ server.process(worker, (action, ref) => {
23
+ if (action.op === "setCell") {
24
+ resolve({ ref: action.value.ref, value: action.value.p })
21
25
  }
22
26
  return true
23
27
  }, groupe)
24
28
  const v = await p
25
- test.assertEquals(v[0].ref.ref === (state.ref as any), true)
26
- test.assertEquals(v[1].ref.ref === (groupe.ref as any), true)
29
+ test.assertEquals(v.ref.ref === (state.ref as any), true)
30
+ test.assertEquals(v.value.x, 45)
31
+ test.assertEquals(v.value.y, 7)
27
32
  worker.terminate()
28
33
 
29
34
  })
@@ -95,9 +100,9 @@ test.test("Test ast typescript ", async () => {
95
100
  const client = api.createClient();
96
101
  const config = await client.getConfig()
97
102
 
98
- const rep = config.code+"\\src\\api.ts"
103
+ const rep = config.code + "\\src\\api.ts"
99
104
 
100
- const r = await client.typescriptAst({ path: rep})
105
+ const r = await client.typescriptAst({ path: rep })
101
106
  console.log(JSON.stringify(r))
102
107
 
103
108
 
@@ -7,20 +7,21 @@ const client = new DataModelClient(model, "Groupe");
7
7
 
8
8
  (async () => {
9
9
  const dm = await client.getObservation();
10
- for (const o of dm.getValues()) {
11
- if (dm.is(o, "Groupe")) {
12
- for (const ref of o.membres) {
13
- console.log(dm.map)
14
- const tmp = await client.doAction({ ref: ref, field: "state", value: true });
15
- console.log(tmp.map)
16
- }
17
-
10
+ const selfRef = await client.getSelf();
11
+ dm.attach(selfRef)
18
12
 
19
- }
13
+ for (const ref of selfRef.getValue().membres) {
14
+ console.log(dm.map)
15
+ const tmp = await client.doAction("setCell", { ref: ref, value: false, p: ref.getValue().p });
16
+ console.log(tmp.map)
20
17
  }
21
- const selfRef = await client.getSelf();
22
18
 
23
- await client.doAction({ ref: selfRef, field: "state", value: true });
19
+
20
+
21
+
22
+
23
+
24
+
24
25
 
25
26
 
26
27
 
package/src/test.ts CHANGED
@@ -12,6 +12,8 @@
12
12
  // }
13
13
  // });
14
14
 
15
+ import { Assert, Log, Terminate } from "./types";
16
+
15
17
  type StepFn = () => void | Promise<void>;
16
18
  type TestFn = (t: { step: (name: string, fn: StepFn) => Promise<void> }) => void | Promise<void>;
17
19
 
@@ -184,7 +186,7 @@ export function deepEqual(a: unknown, b: unknown, seen = new Map<any, any>()): b
184
186
  // RegExp
185
187
  if (a instanceof RegExp || b instanceof RegExp) {
186
188
  return a instanceof RegExp && b instanceof RegExp &&
187
- a.source === b.source && a.flags === b.flags;
189
+ a.source === b.source && a.flags === b.flags;
188
190
  }
189
191
 
190
192
  // Typed arrays
@@ -315,10 +317,35 @@ function safeStringify(v: unknown, maxDepth = 10): string {
315
317
 
316
318
  // ————— Public assert —————
317
319
  export function assertEquals(actual: unknown, expected: unknown, msg?: string): void {
318
- if (deepEqual(actual, expected)) return;
320
+ if (deepEqual(actual, expected)) {
321
+ const a: Assert = { type: "assert", message: msg ?? "", value: true }
322
+ if (self) {
323
+ self.postMessage(a)
324
+ }
325
+ return;
326
+ };
319
327
  const aStr = safeStringify(actual);
320
328
  const eStr = safeStringify(expected);
321
329
  const defaultMsg = `assertEquals failed:\nExpected:\n${eStr}\nActual:\n${aStr}`;
330
+ const a: Assert = { type: "assert", message: msg ? `${msg}\n${defaultMsg}` : defaultMsg, value: false }
331
+ if (self) {
332
+ self.postMessage(a)
333
+ }
322
334
  throw new Error(msg ? `${msg}\n${defaultMsg}` : defaultMsg);
323
335
  }
336
+ export function terminate() {
337
+ if (self) {
338
+ const t: Terminate = { type: "terminate" }
339
+ self.postMessage(t)
340
+ }
341
+ }
342
+ function log(...args: (string | number)[]) {
343
+ console.log(...args)
344
+ if (self) {
345
+ const log: Log = { type: "log", message: args.length == 1 ? args[0] : args }
346
+ self.postMessage(log)
347
+ }
348
+
349
+
350
+ }
324
351
 
package/src/types.ts CHANGED
@@ -262,4 +262,16 @@ export type TypescriptAstResp = TypescriptAstOk | TypescriptAstKo;
262
262
  export interface ApiTypescriptAstRequest {
263
263
  /** Chemin relatif à `state.root` (ex: "src/main.ts") */
264
264
  path: string;
265
+ }
266
+ export interface Assert {
267
+ type:'assert'
268
+ value:boolean
269
+ message:string
270
+ }
271
+ export interface Log {
272
+ type:'log'
273
+ message:(string|number)[]|string|number
274
+ }
275
+ export interface Terminate {
276
+ type:'terminate'
265
277
  }