tinybase 2.1.0 → 2.2.0-beta.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.
Files changed (105) hide show
  1. package/bin/cli.js +2 -0
  2. package/lib/checkpoints.d.ts +0 -2
  3. package/lib/checkpoints.js +1 -1
  4. package/lib/checkpoints.js.gz +0 -0
  5. package/lib/debug/checkpoints.d.ts +0 -2
  6. package/lib/debug/checkpoints.js +4 -2
  7. package/lib/debug/indexes.d.ts +0 -2
  8. package/lib/debug/indexes.js +2 -1
  9. package/lib/debug/metrics.d.ts +0 -2
  10. package/lib/debug/metrics.js +2 -1
  11. package/lib/debug/queries.d.ts +0 -2
  12. package/lib/debug/relationships.d.ts +0 -2
  13. package/lib/debug/relationships.js +2 -1
  14. package/lib/debug/store.d.ts +1 -1
  15. package/lib/debug/store.js +12 -13
  16. package/lib/debug/tinybase.js +14 -14
  17. package/lib/debug/tools.d.ts +290 -0
  18. package/lib/debug/tools.js +955 -0
  19. package/lib/es6/checkpoints.d.ts +0 -2
  20. package/lib/es6/checkpoints.js +1 -1
  21. package/lib/es6/checkpoints.js.gz +0 -0
  22. package/lib/es6/indexes.d.ts +0 -2
  23. package/lib/es6/metrics.d.ts +0 -2
  24. package/lib/es6/queries.d.ts +0 -2
  25. package/lib/es6/relationships.d.ts +0 -2
  26. package/lib/es6/store.d.ts +1 -1
  27. package/lib/es6/store.js +1 -1
  28. package/lib/es6/store.js.gz +0 -0
  29. package/lib/es6/tinybase.js +1 -1
  30. package/lib/es6/tinybase.js.gz +0 -0
  31. package/lib/es6/tools.d.ts +290 -0
  32. package/lib/es6/tools.js +1 -0
  33. package/lib/es6/tools.js.gz +0 -0
  34. package/lib/indexes.d.ts +0 -2
  35. package/lib/metrics.d.ts +0 -2
  36. package/lib/queries.d.ts +0 -2
  37. package/lib/relationships.d.ts +0 -2
  38. package/lib/store.d.ts +1 -1
  39. package/lib/store.js +1 -1
  40. package/lib/store.js.gz +0 -0
  41. package/lib/tinybase.js +1 -1
  42. package/lib/tinybase.js.gz +0 -0
  43. package/lib/tools.d.ts +290 -0
  44. package/lib/tools.js +1 -0
  45. package/lib/tools.js.gz +0 -0
  46. package/lib/umd/checkpoints.d.ts +0 -2
  47. package/lib/umd/checkpoints.js +1 -1
  48. package/lib/umd/checkpoints.js.gz +0 -0
  49. package/lib/umd/common.js +1 -1
  50. package/lib/umd/common.js.gz +0 -0
  51. package/lib/umd/indexes.d.ts +0 -2
  52. package/lib/umd/indexes.js +1 -1
  53. package/lib/umd/indexes.js.gz +0 -0
  54. package/lib/umd/metrics.d.ts +0 -2
  55. package/lib/umd/metrics.js +1 -1
  56. package/lib/umd/metrics.js.gz +0 -0
  57. package/lib/umd/persisters.js +1 -1
  58. package/lib/umd/persisters.js.gz +0 -0
  59. package/lib/umd/queries.d.ts +0 -2
  60. package/lib/umd/queries.js +1 -1
  61. package/lib/umd/queries.js.gz +0 -0
  62. package/lib/umd/relationships.d.ts +0 -2
  63. package/lib/umd/relationships.js +1 -1
  64. package/lib/umd/relationships.js.gz +0 -0
  65. package/lib/umd/store.d.ts +1 -1
  66. package/lib/umd/store.js +1 -1
  67. package/lib/umd/store.js.gz +0 -0
  68. package/lib/umd/tinybase.js +1 -1
  69. package/lib/umd/tinybase.js.gz +0 -0
  70. package/lib/umd/tools.d.ts +290 -0
  71. package/lib/umd/tools.js +1 -0
  72. package/lib/umd/tools.js.gz +0 -0
  73. package/lib/umd/ui-react.js +1 -1
  74. package/lib/umd/ui-react.js.gz +0 -0
  75. package/lib/umd-es6/checkpoints.d.ts +0 -2
  76. package/lib/umd-es6/checkpoints.js +1 -1
  77. package/lib/umd-es6/checkpoints.js.gz +0 -0
  78. package/lib/umd-es6/common.js +1 -1
  79. package/lib/umd-es6/common.js.gz +0 -0
  80. package/lib/umd-es6/indexes.d.ts +0 -2
  81. package/lib/umd-es6/indexes.js +1 -1
  82. package/lib/umd-es6/indexes.js.gz +0 -0
  83. package/lib/umd-es6/metrics.d.ts +0 -2
  84. package/lib/umd-es6/metrics.js +1 -1
  85. package/lib/umd-es6/metrics.js.gz +0 -0
  86. package/lib/umd-es6/persisters.js +1 -1
  87. package/lib/umd-es6/persisters.js.gz +0 -0
  88. package/lib/umd-es6/queries.d.ts +0 -2
  89. package/lib/umd-es6/queries.js +1 -1
  90. package/lib/umd-es6/queries.js.gz +0 -0
  91. package/lib/umd-es6/relationships.d.ts +0 -2
  92. package/lib/umd-es6/relationships.js +1 -1
  93. package/lib/umd-es6/relationships.js.gz +0 -0
  94. package/lib/umd-es6/store.d.ts +1 -1
  95. package/lib/umd-es6/store.js +1 -1
  96. package/lib/umd-es6/store.js.gz +0 -0
  97. package/lib/umd-es6/tinybase.js +1 -1
  98. package/lib/umd-es6/tinybase.js.gz +0 -0
  99. package/lib/umd-es6/tools.d.ts +290 -0
  100. package/lib/umd-es6/tools.js +1 -0
  101. package/lib/umd-es6/tools.js.gz +0 -0
  102. package/lib/umd-es6/ui-react.js +1 -1
  103. package/lib/umd-es6/ui-react.js.gz +0 -0
  104. package/package.json +36 -27
  105. package/readme.md +12 -12
@@ -0,0 +1,955 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_STRING = '';
3
+ const STRING = getTypeOf(EMPTY_STRING);
4
+ const BOOLEAN = getTypeOf(true);
5
+ const NUMBER = getTypeOf(0);
6
+ const TYPE = 'type';
7
+ const DEFAULT = 'default';
8
+
9
+ const arrayEvery = (array, cb) => array.every(cb);
10
+ const arraySort = (array, sorter) => array.sort(sorter);
11
+ const arrayForEach = (array, cb) => array.forEach(cb);
12
+ const arrayMap = (array, cb) => array.map(cb);
13
+ const arrayLength = (array) => array.length;
14
+ const arrayIsEmpty = (array) => arrayLength(array) == 0;
15
+ const arrayPush = (array, ...values) => array.push(...values);
16
+ const arrayPop = (array) => array.pop();
17
+ const arrayUnshift = (array, ...values) => array.unshift(...values);
18
+ const arrayShift = (array) => array.shift();
19
+
20
+ const jsonParse = JSON.parse;
21
+ const isFiniteNumber = isFinite;
22
+ const isUndefined = (thing) => thing == void 0;
23
+ const ifNotUndefined = (value, then, otherwise) =>
24
+ isUndefined(value) ? otherwise?.() : then(value);
25
+ const isTypeStringOrBoolean = (type) => type == STRING || type == BOOLEAN;
26
+ const isString = (thing) => getTypeOf(thing) == STRING;
27
+ const isArray = (thing) => Array.isArray(thing);
28
+
29
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
30
+ const collValues = (coll) => [...(coll?.values() ?? [])];
31
+ const collForEach = (coll, cb) => coll?.forEach(cb);
32
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
33
+
34
+ const mapNew = (entries) => new Map(entries);
35
+ const mapGet = (map, key) => map?.get(key);
36
+ const mapForEach = (map, cb) =>
37
+ collForEach(map, (value, key) => cb(key, value));
38
+ const mapMap = (coll, cb) =>
39
+ arrayMap([...(coll?.entries() ?? [])], ([key, value]) => cb(value, key));
40
+ const mapSet = (map, key, value) =>
41
+ isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
42
+ const mapEnsure = (map, key, getDefaultValue) => {
43
+ if (!collHas(map, key)) {
44
+ mapSet(map, key, getDefaultValue());
45
+ }
46
+ return mapGet(map, key);
47
+ };
48
+
49
+ const setNew = (entryOrEntries) =>
50
+ new Set(
51
+ isArray(entryOrEntries) || isUndefined(entryOrEntries)
52
+ ? entryOrEntries
53
+ : [entryOrEntries],
54
+ );
55
+ const setAdd = (set, value) => set?.add(value);
56
+
57
+ const pairNew = (value) => [value, value];
58
+ const pairNewMap = () => [mapNew(), mapNew()];
59
+
60
+ const NON_ALPHANUMERIC = /[^A-Za-z0-9]+/;
61
+ const JSDOC = /^( *)\/\*\* *(.*?) *\*\/$/gm;
62
+ const substr = (str, start, end) => str.substring(start, end);
63
+ const upper = (str) => str.toUpperCase();
64
+ const lower = (str) => str.toLowerCase();
65
+ const mapUnique = (map, id, value, index = 1) => {
66
+ const uniqueId = `${id}${index == 1 ? '' : index}`;
67
+ if (collHas(map, uniqueId)) {
68
+ return mapUnique(map, id, value, index + 1);
69
+ } else {
70
+ mapSet(map, uniqueId, value);
71
+ return uniqueId;
72
+ }
73
+ };
74
+ const formatJsDoc = (file) =>
75
+ file.replace(JSDOC, (_, indent, text) => {
76
+ const lineLength = 77 - length(indent);
77
+ return `${indent}/**
78
+ ${text.replace(
79
+ new RegExp(`([^\\n]{1,${lineLength}})(\\s|$)`, 'g'),
80
+ `${indent} * $1
81
+ `,
82
+ )}${indent} */`;
83
+ });
84
+ const length = (str) => str.length;
85
+ const join = (str, sep = EMPTY_STRING) => str.join(sep);
86
+ const camel = (str, firstCap = 0) =>
87
+ join(
88
+ arrayMap(
89
+ str.split(NON_ALPHANUMERIC),
90
+ (word, w) =>
91
+ (w > 0 || firstCap ? upper : lower)(substr(word, 0, 1)) +
92
+ substr(word, 1),
93
+ ),
94
+ );
95
+ const snake = (str) => upper(join(str.split(NON_ALPHANUMERIC), '_'));
96
+ const comment = (doc) => `/** ${doc}. */`;
97
+ const getCodeFunctions = () => {
98
+ const allImports = pairNewMap();
99
+ const types = mapNew();
100
+ const methods = mapNew();
101
+ const constants = mapNew();
102
+ const build = (...lines) => {
103
+ const allLines = [];
104
+ const handleLine = (line) =>
105
+ isArray(line)
106
+ ? arrayForEach(line, handleLine)
107
+ : arrayPush(allLines, line);
108
+ arrayForEach(lines, handleLine);
109
+ return allLines.join('\n');
110
+ };
111
+ const addImport = (location, source, ...items) =>
112
+ arrayForEach(items, (item) =>
113
+ setAdd(mapEnsure(allImports[location], source, setNew), item),
114
+ );
115
+ const addType = (name, body = '', doc = '') =>
116
+ mapUnique(types, name, [body, doc]);
117
+ const updateType = (name, body, doc) => mapSet(types, name, [body, doc]);
118
+ const addMethod = (name, parameters, returnType, body, doc, generic = '') =>
119
+ mapUnique(methods, name, [parameters, returnType, body, doc, generic]);
120
+ const addFunction = (name, parameters, body) =>
121
+ mapUnique(
122
+ constants,
123
+ name,
124
+ isArray(body)
125
+ ? [`(${parameters}) => {`, body, '}']
126
+ : [`(${parameters}) => ${body}`],
127
+ );
128
+ const addConstant = (name, body) =>
129
+ mapGet(constants, name) === body ? name : mapUnique(constants, name, body);
130
+ const getImports = (location) => [
131
+ ...arraySort(
132
+ mapMap(
133
+ allImports[location],
134
+ (items, source) =>
135
+ `import {${join(
136
+ arraySort(collValues(items)),
137
+ ', ',
138
+ )}} from '${source}';`,
139
+ ),
140
+ ),
141
+ EMPTY_STRING,
142
+ ];
143
+ const getTypes = () =>
144
+ mapMap(types, ([body, doc], name) => [
145
+ comment(doc),
146
+ `export type ${name} = ${body};`,
147
+ EMPTY_STRING,
148
+ ]);
149
+ const getMethods = (location) =>
150
+ mapMap(methods, ([parameters, returnType, body, doc, generic], name) => {
151
+ const lines = location
152
+ ? [`${name}: ${generic}(${parameters}): ${returnType} => ${body},`]
153
+ : [`${name}${generic}(${parameters}): ${returnType};`];
154
+ if (!location) {
155
+ arrayUnshift(lines, comment(doc));
156
+ }
157
+ arrayPush(lines, EMPTY_STRING);
158
+ return lines;
159
+ });
160
+ const getConstants = () =>
161
+ mapMap(constants, (body, name) => {
162
+ body = isArray(body) ? body : [body];
163
+ arrayPush(body, `${arrayPop(body)};`);
164
+ return [`const ${name} = ${arrayShift(body)}`, body, EMPTY_STRING];
165
+ });
166
+ return [
167
+ build,
168
+ addImport,
169
+ addType,
170
+ updateType,
171
+ addMethod,
172
+ addFunction,
173
+ addConstant,
174
+ getImports,
175
+ getTypes,
176
+ getMethods,
177
+ getConstants,
178
+ ];
179
+ };
180
+
181
+ const object = Object;
182
+ const objIds = object.keys;
183
+ const objFreeze = object.freeze;
184
+ const objGet = (obj, id) => ifNotUndefined(obj, (obj2) => obj2[id]);
185
+ const objHas = (obj, id) => !isUndefined(objGet(obj, id));
186
+ const objForEach = (obj, cb) =>
187
+ arrayForEach(object.entries(obj), ([id, value]) => cb(value, id));
188
+ const objIsEmpty = (obj) => arrayIsEmpty(objIds(obj));
189
+
190
+ const getCellType = (cell) => {
191
+ const type = getTypeOf(cell);
192
+ return isTypeStringOrBoolean(type) || (type == NUMBER && isFiniteNumber(cell))
193
+ ? type
194
+ : void 0;
195
+ };
196
+
197
+ const getCreateFunction = (getFunction) => {
198
+ const getFunctionsByStore = /* @__PURE__ */ new WeakMap();
199
+ return (store) => {
200
+ if (!getFunctionsByStore.has(store)) {
201
+ getFunctionsByStore.set(store, getFunction(store));
202
+ }
203
+ return getFunctionsByStore.get(store);
204
+ };
205
+ };
206
+
207
+ const THE_STORE = 'the Store';
208
+ const REPRESENTS = 'Represents';
209
+ const THE_CONTENT_OF = 'the content of';
210
+ const THE_CONTENT_OF_THE_STORE = `${THE_CONTENT_OF} ${THE_STORE}`;
211
+ const THE_SPECIFIED_ROW = 'the specified Row';
212
+ const REGISTERS_A_LISTENER = 'Registers a listener that will be called';
213
+ const storeMethod = (method, parameters = '', cast = '') =>
214
+ `store.${method}(${parameters})${cast ? ` as ${cast}` : ''}`;
215
+ const fluentStoreMethod = (method, parameters = '') =>
216
+ `fluent(() => ${storeMethod(method, parameters)})`;
217
+ const getIdsDoc = (idsNoun, parentNoun, sorted = 0) =>
218
+ `Gets ${
219
+ sorted ? 'sorted, paginated' : 'the'
220
+ } Ids of the ${idsNoun}s in ${parentNoun}`;
221
+ const getForEachDoc = (childNoun, parentNoun) =>
222
+ `Calls a function for each ${childNoun} in ${parentNoun}`;
223
+ const getHasDoc = (childNoun, parentNoun = THE_STORE) =>
224
+ `Gets whether ${childNoun} exists in ${parentNoun}`;
225
+ const getCallbackDoc = (takes) => `A function that takes ${takes}`;
226
+ const getListenerDoc = (childNoun, parentNoun, pluralChild = 0) =>
227
+ `${REGISTERS_A_LISTENER} whenever ${childNoun} in ${parentNoun} change` +
228
+ (pluralChild ? '' : 's');
229
+ const getVerb = (verb = 0) =>
230
+ verb == 1
231
+ ? 'Sets'
232
+ : verb == 2
233
+ ? 'Sets part of'
234
+ : verb == 3
235
+ ? 'Deletes'
236
+ : 'Gets';
237
+ const getStoreApi = (schema, module) => {
238
+ if (objIsEmpty(schema)) {
239
+ return pairNew('// store has no inferable schema');
240
+ }
241
+ const moduleName = camel(module);
242
+ const storeType = camel(module, 1);
243
+ const storeInstance = camel(storeType);
244
+ const returnStore = `return ${storeInstance};`;
245
+ const tablesTypes = [];
246
+ const tableIdTypes = [];
247
+ const tableCallbackArgTypes = [];
248
+ const getCellChangeArgTypes = [];
249
+ const cellListenerArgTypes = [];
250
+ const allCellIdType = [];
251
+ const schemaLines = [];
252
+ const storeListener = (method, beforeParameters = '', afterParameters = '') =>
253
+ `store.${method}(${
254
+ beforeParameters ? `${beforeParameters}, ` : ''
255
+ }proxy(listener)${afterParameters ? `, ${afterParameters}` : ''})`;
256
+ const [
257
+ build,
258
+ addImport,
259
+ addType,
260
+ updateType,
261
+ addMethod,
262
+ addFunction,
263
+ addConstant,
264
+ getImports,
265
+ getTypes,
266
+ getMethods,
267
+ getConstants,
268
+ ] = getCodeFunctions();
269
+ addImport(
270
+ 0,
271
+ 'tinybase',
272
+ 'CellChange',
273
+ 'ChangedCells',
274
+ 'Id',
275
+ 'IdOrNull',
276
+ 'Ids',
277
+ 'InvalidCells',
278
+ 'Json',
279
+ 'Store',
280
+ );
281
+ addImport(
282
+ 1,
283
+ 'tinybase',
284
+ 'ChangedCells',
285
+ 'Id',
286
+ 'IdOrNull',
287
+ 'Ids',
288
+ 'InvalidCells',
289
+ 'Json',
290
+ 'Store',
291
+ 'createStore',
292
+ );
293
+ addFunction('fluent', 'actions: () => Store', ['actions();', returnStore]);
294
+ addFunction(
295
+ 'proxy',
296
+ `listener: any`,
297
+ `(_: Store, ...args: any[]) => listener(${storeInstance}, ...args)`,
298
+ );
299
+ const TYPE2 = addConstant(snake(TYPE), `'${TYPE}'`);
300
+ const DEFAULT2 = addConstant(snake(DEFAULT), `'${DEFAULT}'`);
301
+ const tablesType = addType('Tables');
302
+ const tableIdType = addType('TableId');
303
+ const tableCallbackType = addType('TableCallback');
304
+ const getCellChangeType = addType('GetCellChange');
305
+ const tablesListenerType = addType(
306
+ 'TablesListener',
307
+ `(${storeInstance}: ${storeType}, getCellChange: ${getCellChangeType} | undefined) => void`,
308
+ `A function for listening to changes to ${THE_CONTENT_OF_THE_STORE}`,
309
+ );
310
+ const tableIdsListenerType = addType(
311
+ 'TableIdsListener',
312
+ `(${storeInstance}: ${storeType}) => void`,
313
+ `A function for listening to changes to Table Ids in ${THE_STORE}`,
314
+ );
315
+ const tableListenerType = addType(
316
+ 'TableListener',
317
+ `(${storeInstance}: ${storeType}, tableId: ${tableIdType}, getCellChange: ${getCellChangeType} | undefined) => void`,
318
+ `A function for listening to changes to a Table in ${THE_STORE}`,
319
+ );
320
+ const rowIdsListenerType = addType(
321
+ 'RowIdsListener',
322
+ `(${storeInstance}: ${storeType}, tableId: ${tableIdType}) => void`,
323
+ `A function for listening to changes to Row Ids in ${THE_STORE}`,
324
+ );
325
+ const rowListenerType = addType(
326
+ 'RowListener',
327
+ `(${storeInstance}: ${storeType}, tableId: ${tableIdType}, rowId: Id, getCellChange: ${getCellChangeType} | undefined) => void`,
328
+ `A function for listening to changes to a Row in ${THE_STORE}`,
329
+ );
330
+ const cellIdsListenerType = addType(
331
+ 'CellIdsListener',
332
+ `(${storeInstance}: ${storeType}, tableId: ${tableIdType}, rowId: Id) => void`,
333
+ `A function for listening to changes to Cell Ids in ${THE_STORE}`,
334
+ );
335
+ const cellListenerType = addType('CellListener');
336
+ const invalidCellListenerType = addType(
337
+ 'InvalidCellListener',
338
+ `(${storeInstance}: ${storeType}, tableId: Id, rowId: Id, cellId: Id, invalidCells: any[]) => void;`,
339
+ `A function for listening to invalid Cell changes`,
340
+ );
341
+ const transactionListenerType = addType(
342
+ 'TransactionListener',
343
+ `(${storeInstance}: ${storeType}, cellsTouched: boolean) => void;`,
344
+ `A function for listening to the completion of a transaction`,
345
+ );
346
+ addImport(
347
+ 1,
348
+ `./${moduleName}.d`,
349
+ storeType,
350
+ `create${storeType} as create${storeType}Decl`,
351
+ tablesType,
352
+ tableIdType,
353
+ tableCallbackType,
354
+ tablesListenerType,
355
+ tableIdsListenerType,
356
+ tableListenerType,
357
+ rowIdsListenerType,
358
+ rowListenerType,
359
+ cellIdsListenerType,
360
+ cellListenerType,
361
+ invalidCellListenerType,
362
+ transactionListenerType,
363
+ );
364
+ const getStoreContentDoc = (verb = 0) =>
365
+ `${getVerb(verb)} ${THE_CONTENT_OF_THE_STORE}`;
366
+ addMethod(
367
+ `hasTables`,
368
+ '',
369
+ BOOLEAN,
370
+ storeMethod('hasTables'),
371
+ getHasDoc('any Table'),
372
+ );
373
+ addMethod(
374
+ `getTables`,
375
+ '',
376
+ tablesType,
377
+ storeMethod('getTables'),
378
+ getStoreContentDoc(),
379
+ );
380
+ addMethod(
381
+ `setTables`,
382
+ `tables: ${tablesType}`,
383
+ storeType,
384
+ fluentStoreMethod('setTables', 'tables'),
385
+ getStoreContentDoc(1),
386
+ );
387
+ addMethod(
388
+ `delTables`,
389
+ '',
390
+ storeType,
391
+ fluentStoreMethod('delTables'),
392
+ getStoreContentDoc(3),
393
+ );
394
+ addMethod(
395
+ `getTableIds`,
396
+ '',
397
+ `${tableIdType}[]`,
398
+ storeMethod('getTableIds', '', `${tableIdType}[]`),
399
+ getIdsDoc('Table', THE_STORE),
400
+ );
401
+ addMethod(
402
+ 'forEachTable',
403
+ `tableCallback: ${tableCallbackType}`,
404
+ 'void',
405
+ storeMethod('forEachTable', 'tableCallback as any'),
406
+ getForEachDoc('Table', THE_STORE),
407
+ );
408
+ const mapCellTypes = mapNew();
409
+ objForEach(schema, (cellSchemas, tableId) => {
410
+ const table = camel(tableId, 1);
411
+ const TABLE_ID = addConstant(snake(tableId), `'${tableId}'`);
412
+ const getCellsTypes = [];
413
+ const setCellsTypes = [];
414
+ const cellIdTypes = [];
415
+ const cellCallbackArgTypes = [];
416
+ const tableDoc = `the '${tableId}' Table`;
417
+ const rowDoc = `${THE_SPECIFIED_ROW} in ${tableDoc}`;
418
+ const tableContentDoc = `${THE_CONTENT_OF} ${tableDoc}`;
419
+ const getTableContentDoc = (verb = 0) =>
420
+ `${getVerb(verb)} ${THE_CONTENT_OF} ${tableDoc}`;
421
+ const getRowContentDoc = (verb = 0) =>
422
+ `${getVerb(verb)} ${THE_CONTENT_OF} ${rowDoc}`;
423
+ const getRowTypeDoc = (set = 0) =>
424
+ `${REPRESENTS} a Row when ${set ? 's' : 'g'}etting ${tableContentDoc}`;
425
+ const tableType = addType(
426
+ `${table}Table`,
427
+ `{[rowId: Id]: ${table}Row}`,
428
+ `${REPRESENTS} ${tableDoc}`,
429
+ );
430
+ const rowType = addType(`${table}Row`);
431
+ const rowWhenSetType = addType(`${table}RowWhenSet`);
432
+ const cellIdType = addType(`${table}CellId`);
433
+ const cellCallbackType = addType(`${table}CellCallback`);
434
+ const rowCallbackType = addType(`${table}RowCallback`);
435
+ addImport(
436
+ 1,
437
+ `./${moduleName}.d`,
438
+ tableType,
439
+ rowType,
440
+ rowWhenSetType,
441
+ cellIdType,
442
+ cellCallbackType,
443
+ rowCallbackType,
444
+ );
445
+ addMethod(
446
+ `has${table}Table`,
447
+ '',
448
+ BOOLEAN,
449
+ storeMethod('hasTable', TABLE_ID),
450
+ getHasDoc(tableDoc),
451
+ );
452
+ addMethod(
453
+ `get${table}Table`,
454
+ '',
455
+ tableType,
456
+ storeMethod('getTable', TABLE_ID, tableType),
457
+ getTableContentDoc(),
458
+ );
459
+ addMethod(
460
+ `set${table}Table`,
461
+ `table: ${tableType}`,
462
+ storeType,
463
+ fluentStoreMethod('setTable', `${TABLE_ID}, table`),
464
+ getTableContentDoc(1),
465
+ );
466
+ addMethod(
467
+ `del${table}Table`,
468
+ '',
469
+ storeType,
470
+ fluentStoreMethod('delTable', TABLE_ID),
471
+ getTableContentDoc(3),
472
+ );
473
+ addMethod(
474
+ `get${table}RowIds`,
475
+ '',
476
+ 'Ids',
477
+ storeMethod('getRowIds', TABLE_ID),
478
+ getIdsDoc('Row', tableDoc),
479
+ );
480
+ addMethod(
481
+ `get${table}SortedRowIds`,
482
+ `cellId?: ${cellIdType}, descending?: boolean, offset?: number, limit?: number`,
483
+ 'Ids',
484
+ storeMethod(
485
+ 'getSortedRowIds',
486
+ `${TABLE_ID}, cellId, descending, offset, limit`,
487
+ ),
488
+ getIdsDoc('Row', tableDoc, 1),
489
+ );
490
+ addMethod(
491
+ `forEach${table}Row`,
492
+ `rowCallback: ${rowCallbackType}`,
493
+ 'void',
494
+ storeMethod('forEachRow', `${TABLE_ID}, rowCallback as any`),
495
+ getForEachDoc('Row', tableDoc),
496
+ );
497
+ addMethod(
498
+ `has${table}Row`,
499
+ 'rowId: Id',
500
+ BOOLEAN,
501
+ storeMethod('hasRow', `${TABLE_ID}, rowId`),
502
+ getHasDoc(THE_SPECIFIED_ROW, tableDoc),
503
+ );
504
+ addMethod(
505
+ `get${table}Row`,
506
+ 'rowId: Id',
507
+ rowType,
508
+ storeMethod('getRow', `${TABLE_ID}, rowId`, rowType),
509
+ getRowContentDoc(),
510
+ );
511
+ addMethod(
512
+ `set${table}Row`,
513
+ `rowId: Id, row: ${rowWhenSetType}`,
514
+ storeType,
515
+ fluentStoreMethod('setRow', `${TABLE_ID}, rowId, row`),
516
+ getRowContentDoc(1),
517
+ );
518
+ addMethod(
519
+ `add${table}Row`,
520
+ `row: ${rowWhenSetType}`,
521
+ 'Id | undefined',
522
+ storeMethod('addRow', `${TABLE_ID}, row`),
523
+ `Adds a new Row to ${tableDoc}`,
524
+ );
525
+ addMethod(
526
+ `set${table}PartialRow`,
527
+ `rowId: Id, partialRow: ${rowWhenSetType}`,
528
+ storeType,
529
+ fluentStoreMethod('setPartialRow', `${TABLE_ID}, rowId, partialRow`),
530
+ getRowContentDoc(2),
531
+ );
532
+ addMethod(
533
+ `del${table}Row`,
534
+ `rowId: Id`,
535
+ storeType,
536
+ fluentStoreMethod('delRow', `${TABLE_ID}, rowId`),
537
+ getRowContentDoc(3),
538
+ );
539
+ addMethod(
540
+ `get${table}CellIds`,
541
+ 'rowId: Id',
542
+ `${cellIdType}[]`,
543
+ storeMethod('getCellIds', `${TABLE_ID}, rowId`, `${cellIdType}[]`),
544
+ getIdsDoc('Cell', rowDoc),
545
+ );
546
+ addMethod(
547
+ `forEach${table}Cell`,
548
+ `rowId: Id, cellCallback: ${cellCallbackType}`,
549
+ 'void',
550
+ storeMethod('forEachCell', `${TABLE_ID}, rowId, cellCallback as any`),
551
+ getForEachDoc('Cell', rowDoc),
552
+ );
553
+ arrayPush(schemaLines, `[${TABLE_ID}]: {`);
554
+ objForEach(cellSchemas, (cellSchema, cellId) => {
555
+ const cell = camel(cellId, 1);
556
+ const CELL_ID = addConstant(snake(cellId), `'${cellId}'`);
557
+ const type = cellSchema[TYPE];
558
+ const defaulted = objHas(cellSchema, DEFAULT);
559
+ const defaultValue = cellSchema[DEFAULT];
560
+ const cellDoc = `the '${cellId}' Cell`;
561
+ const getCellContentDoc = (verb = 0) =>
562
+ `${getVerb(verb)} ${cellDoc} for ${rowDoc}`;
563
+ arrayPush(
564
+ schemaLines,
565
+ `[${CELL_ID}]: {[${TYPE2}]: ${addConstant(snake(type), `'${type}'`)}${
566
+ defaulted
567
+ ? `, [${DEFAULT2}]: ${
568
+ isString(defaultValue)
569
+ ? addConstant(snake(defaultValue), `'${defaultValue}'`)
570
+ : defaultValue
571
+ }`
572
+ : ''
573
+ }},`,
574
+ );
575
+ arrayPush(getCellsTypes, `'${cellId}'${defaulted ? '' : '?'}: ${type};`);
576
+ arrayPush(setCellsTypes, `'${cellId}'?: ${type};`);
577
+ arrayPush(cellIdTypes, `'${cellId}'`);
578
+ arrayPush(cellCallbackArgTypes, `[cellId: '${cellId}', cell: ${type}]`);
579
+ arrayPush(
580
+ cellListenerArgTypes,
581
+ `[${storeInstance}: ${storeType}, tableId: '${tableId}', rowId: Id, cellId: '${cellId}', newCell: ${type} | undefined, oldCell: ${type} | undefined, getCellChange: ${getCellChangeType} | undefined]`,
582
+ );
583
+ const mapCellType = `Map${camel(type, 1)}`;
584
+ mapSet(mapCellTypes, type, mapCellType);
585
+ addMethod(
586
+ `has${table}${cell}Cell`,
587
+ 'rowId: Id',
588
+ BOOLEAN,
589
+ storeMethod('hasCell', `${TABLE_ID}, rowId, ${CELL_ID}`),
590
+ getHasDoc(cellDoc, rowDoc),
591
+ );
592
+ const returnCellType = `${type}${defaulted ? '' : ' | undefined'}`;
593
+ addMethod(
594
+ `get${table}${cell}Cell`,
595
+ 'rowId: Id',
596
+ returnCellType,
597
+ storeMethod(
598
+ 'getCell',
599
+ `${TABLE_ID}, rowId, ${CELL_ID}`,
600
+ returnCellType,
601
+ ),
602
+ getCellContentDoc(),
603
+ );
604
+ addMethod(
605
+ `set${table}${cell}Cell`,
606
+ `rowId: Id, cell: ${type} | ${mapCellType}`,
607
+ storeType,
608
+ fluentStoreMethod(
609
+ 'setCell',
610
+ `${TABLE_ID}, rowId, ${CELL_ID}, cell as any`,
611
+ ),
612
+ getCellContentDoc(1),
613
+ );
614
+ addMethod(
615
+ `del${table}${cell}Cell`,
616
+ `rowId: Id`,
617
+ storeType,
618
+ fluentStoreMethod('delCell', `${TABLE_ID}, rowId, ${CELL_ID}`),
619
+ getCellContentDoc(3),
620
+ );
621
+ });
622
+ arrayPush(schemaLines, `},`);
623
+ arrayPush(tablesTypes, `'${tableId}'?: ${tableType};`);
624
+ arrayPush(tableIdTypes, `'${tableId}'`);
625
+ arrayPush(
626
+ tableCallbackArgTypes,
627
+ `[tableId: '${tableId}', forEachRow: (rowCallback: ${rowCallbackType}) => void]`,
628
+ );
629
+ arrayPush(
630
+ getCellChangeArgTypes,
631
+ `[tableId: '${tableId}', rowId: Id, cellId: ${cellIdType}]`,
632
+ );
633
+ arrayPush(allCellIdType, cellIdType);
634
+ updateType(rowType, `{${join(getCellsTypes, ' ')}}`, getRowTypeDoc());
635
+ updateType(
636
+ rowWhenSetType,
637
+ `{${join(setCellsTypes, ' ')}}`,
638
+ getRowTypeDoc(1),
639
+ );
640
+ updateType(
641
+ cellIdType,
642
+ join(cellIdTypes, ' | '),
643
+ `A Cell Id for ${tableDoc}`,
644
+ );
645
+ updateType(
646
+ cellCallbackType,
647
+ `(...[cellId, cell]: ${join(cellCallbackArgTypes, ' | ')}) => void`,
648
+ getCallbackDoc(`a Cell Id and value from a Row in ${tableDoc}`),
649
+ );
650
+ updateType(
651
+ rowCallbackType,
652
+ `(rowId: Id, forEachCell: (cellCallback: ${cellCallbackType}) => void) => void`,
653
+ getCallbackDoc(`a Row Id from ${tableDoc}, and a Cell iterator`),
654
+ );
655
+ });
656
+ addMethod(
657
+ 'getJson',
658
+ '',
659
+ 'Json',
660
+ storeMethod('getJson'),
661
+ `Gets a a string serialization ${THE_CONTENT_OF_THE_STORE}`,
662
+ );
663
+ addMethod(
664
+ 'setJson',
665
+ 'json: Json',
666
+ storeType,
667
+ fluentStoreMethod('setJson', 'json'),
668
+ `Sets ${THE_CONTENT_OF_THE_STORE} from a serialized string`,
669
+ );
670
+ addMethod(
671
+ 'transaction',
672
+ 'actions: () => Return, doRollback?: (changedCells: ChangedCells, invalidCells: InvalidCells) => boolean',
673
+ 'Return',
674
+ storeMethod('transaction', 'actions, doRollback'),
675
+ 'Execute a transaction to make multiple mutations',
676
+ '<Return>',
677
+ );
678
+ addMethod(
679
+ 'startTransaction',
680
+ '',
681
+ storeType,
682
+ fluentStoreMethod('startTransaction'),
683
+ 'Explicitly starts a transaction',
684
+ );
685
+ addMethod(
686
+ 'finishTransaction',
687
+ 'doRollback?: (changedCells: ChangedCells, invalidCells: InvalidCells) => boolean,',
688
+ storeType,
689
+ fluentStoreMethod('finishTransaction', 'doRollback'),
690
+ 'Explicitly finishes a transaction',
691
+ );
692
+ addMethod(
693
+ 'addTablesListener',
694
+ `listener: ${tablesListenerType}, mutator?: boolean`,
695
+ 'Id',
696
+ storeListener('addTablesListener', '', 'mutator'),
697
+ `${REGISTERS_A_LISTENER} whenever ${THE_CONTENT_OF_THE_STORE} changes`,
698
+ );
699
+ addMethod(
700
+ 'addTableIdsListener',
701
+ `listener: ${tableIdsListenerType}, mutator?: boolean`,
702
+ 'Id',
703
+ storeListener('addTableIdsListener', '', 'mutator'),
704
+ getListenerDoc('the Table Ids', THE_STORE, 1),
705
+ );
706
+ addMethod(
707
+ 'addTableListener',
708
+ `tableId: ${tableIdType} | null, listener: ${tableListenerType}, mutator?: boolean`,
709
+ 'Id',
710
+ storeListener('addTableListener', 'tableId', 'mutator'),
711
+ getListenerDoc('a Table', THE_STORE),
712
+ );
713
+ addMethod(
714
+ 'addRowIdsListener',
715
+ `tableId: ${tableIdType} | null, listener: ${rowIdsListenerType}, mutator?: boolean`,
716
+ 'Id',
717
+ storeListener('addRowIdsListener', 'tableId', 'mutator'),
718
+ getListenerDoc('the Row Ids', 'a Table', 1),
719
+ );
720
+ addMethod(
721
+ 'addRowListener',
722
+ `tableId: ${tableIdType} | null, rowId: IdOrNull, listener: ${rowListenerType}, mutator?: boolean`,
723
+ 'Id',
724
+ storeListener('addRowListener', 'tableId, rowId', 'mutator'),
725
+ getListenerDoc('a Row', 'a Table'),
726
+ );
727
+ addMethod(
728
+ 'addCellIdsListener',
729
+ `tableId: ${tableIdType} | null, rowId: IdOrNull, listener: ${cellIdsListenerType}, mutator?: boolean`,
730
+ 'Id',
731
+ storeListener('addCellIdsListener', 'tableId, rowId', 'mutator'),
732
+ getListenerDoc('the Cell Ids', 'a Row', 1),
733
+ );
734
+ addMethod(
735
+ 'addCellListener',
736
+ `tableId: ${tableIdType} | null, rowId: IdOrNull, cellId: ${join(
737
+ allCellIdType,
738
+ ' | ',
739
+ )} | null, listener: ${cellListenerType}, mutator?: boolean`,
740
+ 'Id',
741
+ storeListener('addCellListener', 'tableId, rowId, cellId', 'mutator'),
742
+ getListenerDoc('a Cell', 'a Row'),
743
+ );
744
+ addMethod(
745
+ 'addInvalidCellListener',
746
+ `tableId: IdOrNull, rowId: IdOrNull, cellId: IdOrNull, listener: ${invalidCellListenerType}, mutator?: boolean`,
747
+ 'Id',
748
+ storeListener('addCellListener', 'tableId, rowId, cellId', 'mutator'),
749
+ `${REGISTERS_A_LISTENER} whenever an invalid Cell change was attempted`,
750
+ );
751
+ addMethod(
752
+ 'addWillFinishTransactionListener',
753
+ `listener: ${transactionListenerType}`,
754
+ 'Id',
755
+ storeListener('addWillFinishTransactionListener'),
756
+ `${REGISTERS_A_LISTENER} just before the end of the transaction`,
757
+ );
758
+ addMethod(
759
+ 'addDidFinishTransactionListener',
760
+ `listener: ${transactionListenerType}`,
761
+ 'Id',
762
+ storeListener('addDidFinishTransactionListener'),
763
+ `${REGISTERS_A_LISTENER} just after the end of the transaction`,
764
+ );
765
+ addMethod(
766
+ 'callListener',
767
+ 'listenerId: Id',
768
+ storeType,
769
+ fluentStoreMethod('callListener', 'listenerId'),
770
+ 'Manually provoke a listener to be called',
771
+ );
772
+ addMethod(
773
+ 'delListener',
774
+ 'listenerId: Id',
775
+ storeType,
776
+ fluentStoreMethod('delListener', 'listenerId'),
777
+ `Remove a listener that was previously added to ${THE_STORE}`,
778
+ );
779
+ addMethod(
780
+ 'getStore',
781
+ '',
782
+ 'Store',
783
+ 'store',
784
+ 'Gets the underlying Store object',
785
+ );
786
+ updateType(
787
+ tablesType,
788
+ `{${join(tablesTypes, ' ')}}`,
789
+ `${REPRESENTS} ${THE_CONTENT_OF_THE_STORE}`,
790
+ );
791
+ updateType(
792
+ tableIdType,
793
+ join(tableIdTypes, ' | '),
794
+ `A Table Id in ${THE_STORE}`,
795
+ );
796
+ updateType(
797
+ tableCallbackType,
798
+ `(...[tableId, rowCallback]: ${join(
799
+ tableCallbackArgTypes,
800
+ ' | ',
801
+ )}) => void`,
802
+ getCallbackDoc('a Table Id, and a Row iterator'),
803
+ );
804
+ updateType(
805
+ getCellChangeType,
806
+ `(...[tableId, rowId, cellId]: ${join(
807
+ getCellChangeArgTypes,
808
+ ' | ',
809
+ )}) => CellChange`,
810
+ `A function that returns information about any Cell's changes during a transaction`,
811
+ );
812
+ updateType(
813
+ cellListenerType,
814
+ `(...[${storeInstance}, tableId, rowId, cellId, newCell, oldCell, getCellChange]: ${join(
815
+ cellListenerArgTypes,
816
+ ' | ',
817
+ )}) => void`,
818
+ `A function for listening to changes to a Cell in ${THE_STORE}`,
819
+ );
820
+ mapForEach(mapCellTypes, (type, mapCellType) =>
821
+ addType(
822
+ mapCellType,
823
+ `(cell: ${type} | undefined) => ${type}`,
824
+ `Takes a ${type} Cell value and returns another`,
825
+ ),
826
+ );
827
+ addImport(1, `./${moduleName}.d`, ...collValues(mapCellTypes));
828
+ addConstant('store', ['createStore().setSchema({', ...schemaLines, '})']);
829
+ addConstant(storeInstance, ['{', ...getMethods(1), '}']);
830
+ return [
831
+ build(
832
+ ...getImports(0),
833
+ ...getTypes(),
834
+ `export interface ${storeType} {`,
835
+ ...getMethods(0),
836
+ `}`,
837
+ '',
838
+ comment(`Creates a ${storeType} object`),
839
+ `export function create${storeType}(): ${storeType};`,
840
+ ),
841
+ build(
842
+ ...getImports(1),
843
+ `export const create${storeType}: typeof create${storeType}Decl = () => {`,
844
+ ...getConstants(),
845
+ `return Object.freeze(${storeInstance});`,
846
+ `};`,
847
+ ),
848
+ ];
849
+ };
850
+
851
+ const prettierConfig = {
852
+ parser: 'typescript',
853
+ singleQuote: true,
854
+ trailingComma: 'all',
855
+ bracketSpacing: false,
856
+ jsdocSingleLineComment: false,
857
+ };
858
+ const createTools = getCreateFunction((store) => {
859
+ const getStoreStats = (detail) => {
860
+ let totalTables = 0;
861
+ let totalRows = 0;
862
+ let totalCells = 0;
863
+ const tables = {};
864
+ store.forEachTable((tableId, forEachRow) => {
865
+ totalTables++;
866
+ let tableRows = 0;
867
+ let tableCells = 0;
868
+ const rows = {};
869
+ forEachRow((rowId, forEachCell) => {
870
+ tableRows++;
871
+ let rowCells = 0;
872
+ forEachCell(() => rowCells++);
873
+ tableCells += rowCells;
874
+ if (detail) {
875
+ rows[rowId] = {rowCells};
876
+ }
877
+ });
878
+ totalRows += tableRows;
879
+ totalCells += tableCells;
880
+ if (detail) {
881
+ tables[tableId] = {tableRows, tableCells, rows};
882
+ }
883
+ });
884
+ return {
885
+ totalTables,
886
+ totalRows,
887
+ totalCells,
888
+ jsonLength: length(store.getJson()),
889
+ ...(detail ? {detail: {tables}} : {}),
890
+ };
891
+ };
892
+ const getStoreSchema = () => {
893
+ const schema = jsonParse(store.getSchemaJson());
894
+ if (
895
+ !objIsEmpty(schema) ||
896
+ arrayEvery(store.getTableIds(), (tableId) => {
897
+ const rowIds = store.getRowIds(tableId);
898
+ const cellsMeta = mapNew();
899
+ if (
900
+ arrayEvery(rowIds, (rowId) =>
901
+ arrayEvery(store.getCellIds(tableId, rowId), (cellId) => {
902
+ const value = store.getCell(tableId, rowId, cellId);
903
+ const cellMeta = mapEnsure(cellsMeta, cellId, () => [
904
+ getCellType(value),
905
+ mapNew(),
906
+ [0],
907
+ 0,
908
+ ]);
909
+ const [type, values, [maxCount]] = cellMeta;
910
+ const count = mapEnsure(values, value, () => 0) + 1;
911
+ if (count > maxCount) {
912
+ cellMeta[2] = [count, value];
913
+ }
914
+ mapSet(values, value, count);
915
+ cellMeta[3]++;
916
+ return type == getCellType(value);
917
+ }),
918
+ )
919
+ ) {
920
+ schema[tableId] = {};
921
+ collForEach(cellsMeta, ([type, , [, maxValue], count], cellId) => {
922
+ schema[tableId][cellId] = {
923
+ [TYPE]: type,
924
+ ...(count == arrayLength(rowIds) ? {[DEFAULT]: maxValue} : {}),
925
+ };
926
+ });
927
+ return 1;
928
+ }
929
+ })
930
+ ) {
931
+ return schema;
932
+ }
933
+ return {};
934
+ };
935
+ const getStoreApi$1 = (module) => getStoreApi(getStoreSchema(), module);
936
+ const getPrettyStoreApi = async (module) => {
937
+ const files = getStoreApi$1(module);
938
+ try {
939
+ const {format} = await import('prettier');
940
+ return arrayMap(files, (file) =>
941
+ formatJsDoc(format(file, prettierConfig)),
942
+ );
943
+ } catch {}
944
+ return files;
945
+ };
946
+ const tools = {
947
+ getStoreStats,
948
+ getStoreSchema,
949
+ getStoreApi: getStoreApi$1,
950
+ getPrettyStoreApi,
951
+ };
952
+ return objFreeze(tools);
953
+ });
954
+
955
+ export {createTools};