sliftutils 0.86.0 → 0.88.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/builders/setup.ts CHANGED
@@ -78,7 +78,7 @@ async function main() {
78
78
  let packageJsonPath = path.join(targetDir, "package.json");
79
79
  if (fs.existsSync(packageJsonPath)) {
80
80
  console.log("\nUpdating package.json scripts...");
81
- updatePackageJson(packageJsonPath);
81
+ await updatePackageJson(packageJsonPath);
82
82
  } else {
83
83
  console.warn("\nNo package.json found in target directory");
84
84
  }
@@ -136,7 +136,7 @@ function replaceImports(content: string, importMappings: { [key: string]: string
136
136
  return processedLines.join("\n");
137
137
  }
138
138
 
139
- function updatePackageJson(packageJsonPath: string) {
139
+ async function updatePackageJson(packageJsonPath: string) {
140
140
  let packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
141
141
 
142
142
  // Read our current package.json to get the type script
@@ -191,8 +191,22 @@ function updatePackageJson(packageJsonPath: string) {
191
191
  }
192
192
  }
193
193
 
194
+ let needsYarnInstall = false;
195
+
196
+ // ALSO, add socket-function, if it doesn't have it already. This fixes intelliSense, for socket-function, which has a lot of useful utilities related to caching.
197
+ if (!packageJson.dependencies?.["socket-function"]) {
198
+ packageJson.dependencies = packageJson.dependencies || {};
199
+ packageJson.dependencies["socket-function"] = "*";
200
+ needsYarnInstall = true;
201
+ }
202
+
194
203
  fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, undefined, 4) + "\n", "utf8");
195
204
  console.log(" package.json updated");
205
+
206
+ if (needsYarnInstall) {
207
+ console.log(" Needs yarn install");
208
+ await execSync("yarn install", { cwd: path.dirname(packageJsonPath), stdio: "inherit" });
209
+ }
196
210
  }
197
211
 
198
212
  main().catch(error => {
package/index.d.ts CHANGED
@@ -127,6 +127,8 @@ declare module "sliftutils/misc/random" {
127
127
 
128
128
  declare module "sliftutils/misc/types" {
129
129
  export declare function isDefined<T>(value: T | undefined | null): value is T;
130
+ export declare function freezeObject(value: unknown): unknown;
131
+ export declare function deepFreezeObject(value: unknown): void;
130
132
 
131
133
  }
132
134
 
@@ -658,6 +660,12 @@ declare module "sliftutils/storage/DiskCollection" {
658
660
  writeDelay?: number | undefined;
659
661
  cbor?: boolean | undefined;
660
662
  noPrompt?: boolean | undefined;
663
+ freeze?: "deep" | "shallow" | undefined;
664
+ beforeWrite?: ((update: {
665
+ newValue: T;
666
+ key: string;
667
+ collection: DiskCollection<T>;
668
+ }) => void) | undefined;
661
669
  } | undefined);
662
670
  transactionStorage: TransactionStorage | undefined;
663
671
  initStorage(): Promise<IStorage<T>>;
@@ -969,6 +977,7 @@ declare module "sliftutils/storage/StorageObservable" {
969
977
  import { IStorage, IStorageSync } from "./IStorage";
970
978
  export declare class StorageSync<T> implements IStorageSync<T> {
971
979
  storage: IStorage<T>;
980
+ private config?;
972
981
  cached: import("mobx").ObservableMap<string, T | undefined>;
973
982
  infoCached: import("mobx").ObservableMap<string, {
974
983
  size: number;
@@ -978,7 +987,14 @@ declare module "sliftutils/storage/StorageObservable" {
978
987
  synced: {
979
988
  keySeqNum: number;
980
989
  };
981
- constructor(storage: IStorage<T>);
990
+ constructor(storage: IStorage<T>, config?: {
991
+ freeze?: "deep" | "shallow" | undefined;
992
+ beforeWrite?: ((update: {
993
+ newValue: T;
994
+ key: string;
995
+ collection: StorageSync<T>;
996
+ }) => void) | undefined;
997
+ } | undefined);
982
998
  get(key: string): T | undefined;
983
999
  set(key: string, value: T): void;
984
1000
  remove(key: string): void;
package/misc/types.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export declare function isDefined<T>(value: T | undefined | null): value is T;
2
+ export declare function freezeObject(value: unknown): unknown;
3
+ export declare function deepFreezeObject(value: unknown): void;
package/misc/types.ts CHANGED
@@ -1,3 +1,24 @@
1
1
  export function isDefined<T>(value: T | undefined | null): value is T {
2
2
  return value !== undefined && value !== null;
3
+ }
4
+
5
+
6
+ export function freezeObject(value: unknown) {
7
+ if (!value) return value;
8
+ Object.freeze(value);
9
+ }
10
+
11
+ export function deepFreezeObject(value: unknown) {
12
+ if (!value) return;
13
+ if (typeof value !== "object") return;
14
+ if (Object.isFrozen(value)) return;
15
+
16
+ Object.freeze(value);
17
+
18
+ Object.getOwnPropertyNames(value).forEach(prop => {
19
+ const propValue = (value as any)[prop];
20
+ if (propValue && typeof propValue === "object") {
21
+ deepFreezeObject(propValue);
22
+ }
23
+ });
3
24
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sliftutils",
3
- "version": "0.86.0",
3
+ "version": "0.88.0",
4
4
  "main": "index.js",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -10,6 +10,12 @@ export declare class DiskCollection<T> implements IStorageSync<T> {
10
10
  writeDelay?: number | undefined;
11
11
  cbor?: boolean | undefined;
12
12
  noPrompt?: boolean | undefined;
13
+ freeze?: "deep" | "shallow" | undefined;
14
+ beforeWrite?: ((update: {
15
+ newValue: T;
16
+ key: string;
17
+ collection: DiskCollection<T>;
18
+ }) => void) | undefined;
13
19
  } | undefined);
14
20
  transactionStorage: TransactionStorage | undefined;
15
21
  initStorage(): Promise<IStorage<T>>;
@@ -18,6 +18,9 @@ export class DiskCollection<T> implements IStorageSync<T> {
18
18
  writeDelay?: number;
19
19
  cbor?: boolean;
20
20
  noPrompt?: boolean;
21
+ freeze?: "shallow" | "deep";
22
+ // May mutate newValue in order to change what will be written
23
+ beforeWrite?: (update: { newValue: T; key: string; collection: DiskCollection<T> }) => void;
21
24
  }
22
25
  ) {
23
26
  }
@@ -41,7 +44,11 @@ export class DiskCollection<T> implements IStorageSync<T> {
41
44
  private synced = new StorageSync(
42
45
  new PendingStorage(`Collection (${this.collectionName})`,
43
46
  new DelayedStorage<T>(this.baseStorage)
44
- )
47
+ ),
48
+ {
49
+ freeze: this.config?.freeze,
50
+ beforeWrite: this.config?.beforeWrite && ((update) => this.config!.beforeWrite!({ ...update, collection: this })),
51
+ }
45
52
  );
46
53
 
47
54
  public get(key: string): T | undefined {
@@ -1,6 +1,7 @@
1
1
  import { IStorage, IStorageSync } from "./IStorage";
2
2
  export declare class StorageSync<T> implements IStorageSync<T> {
3
3
  storage: IStorage<T>;
4
+ private config?;
4
5
  cached: import("mobx").ObservableMap<string, T | undefined>;
5
6
  infoCached: import("mobx").ObservableMap<string, {
6
7
  size: number;
@@ -10,7 +11,14 @@ export declare class StorageSync<T> implements IStorageSync<T> {
10
11
  synced: {
11
12
  keySeqNum: number;
12
13
  };
13
- constructor(storage: IStorage<T>);
14
+ constructor(storage: IStorage<T>, config?: {
15
+ freeze?: "deep" | "shallow" | undefined;
16
+ beforeWrite?: ((update: {
17
+ newValue: T;
18
+ key: string;
19
+ collection: StorageSync<T>;
20
+ }) => void) | undefined;
21
+ } | undefined);
14
22
  get(key: string): T | undefined;
15
23
  set(key: string, value: T): void;
16
24
  remove(key: string): void;
@@ -1,5 +1,5 @@
1
1
  import { observable } from "mobx";
2
- import { isDefined } from "../misc/types";
2
+ import { deepFreezeObject, freezeObject, isDefined } from "../misc/types";
3
3
  import { IStorage, IStorageSync } from "./IStorage";
4
4
 
5
5
  // NOTE: At around 500K values (depending on their size to some degree), this will take about 2 minutes to load. But once it does it will be fast. So... keep that in mind. I recommend not exceeding 100K
@@ -11,7 +11,11 @@ export class StorageSync<T> implements IStorageSync<T> {
11
11
  keySeqNum: 0,
12
12
  }, undefined, { deep: false });
13
13
 
14
- constructor(public storage: IStorage<T>) {
14
+ constructor(public storage: IStorage<T>, private config?: {
15
+ freeze?: "shallow" | "deep";
16
+ // May mutate newValue in order to change what will be written
17
+ beforeWrite?: (update: { newValue: T; key: string; collection: StorageSync<T> }) => void;
18
+ }) {
15
19
  storage.watchResync?.(async () => {
16
20
  // NOTE: If there's multiple tabs open, this'll trigger a lot, so we can't just clear all the values, as that'll cause a render where nothing's loaded.
17
21
  this.loadedKeys = false;
@@ -33,6 +37,9 @@ export class StorageSync<T> implements IStorageSync<T> {
33
37
  return this.cached.get(key);
34
38
  }
35
39
  public set(key: string, value: T): void {
40
+ if (this.config?.beforeWrite) {
41
+ this.config.beforeWrite({ newValue: value, key, collection: this });
42
+ }
36
43
  if (!this.keys.has(key)) {
37
44
  this.keys.add(key);
38
45
  this.synced.keySeqNum++;
@@ -79,7 +86,12 @@ export class StorageSync<T> implements IStorageSync<T> {
79
86
  let value = this.cached.get(key);
80
87
  if (value === undefined) {
81
88
  value = await this.storage.get(key);
82
- if (this.cached.get(key) === undefined) {
89
+ if (value !== undefined && this.cached.get(key) === undefined) {
90
+ if (this.config?.freeze === "shallow") {
91
+ freezeObject(value);
92
+ } else if (this.config?.freeze === "deep") {
93
+ deepFreezeObject(value);
94
+ }
83
95
  this.cached.set(key, value);
84
96
  }
85
97
  }
@@ -401,26 +401,20 @@ export class TransactionStorage implements IStorage<Buffer> {
401
401
  this.cache.delete(entry.key);
402
402
  } else {
403
403
  if (!anyChanged && !initialLoad) {
404
- let prev = this.cache.get(entry.key);
405
- if (!prev) {
406
- anyChanged = true;
407
- } else {
408
- if (!prev.value) {
409
- if (entry.value) {
410
- anyChanged = true;
411
- }
412
- } else {
413
- if (!entry.value) {
414
- anyChanged = true;
415
- } else {
416
- // Both values, so... it might not have changed
417
- if (!prev.value.equals(entry.value)) {
418
- anyChanged = true;
419
- }
420
- }
404
+ const hasChanged = () => {
405
+ let prev = this.cache.get(entry.key);
406
+ if (!prev) {
407
+ return true;
421
408
  }
422
- }
409
+ if (!!prev.value !== !!entry.value) return true;
410
+ if (prev.value && entry.value && !prev.value.equals(entry.value)) {
411
+ return true;
412
+ }
413
+ return false;
414
+ };
415
+ anyChanged = hasChanged() || anyChanged;
423
416
  }
417
+
424
418
  this.cache.set(entry.key, entry);
425
419
  }
426
420
  }
@@ -13,24 +13,6 @@ export class ExamplePage extends preact.Component {
13
13
  count: 0,
14
14
  });
15
15
 
16
- onKeyDown = (e: KeyboardEvent) => {
17
- // Skip if the current target is an ipnut
18
- if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) {
19
- return;
20
- }
21
- let hotkeySelector = `[data-hotkey="${e.code}"]`;
22
- let elements = document.querySelectorAll(hotkeySelector);
23
- for (let element of elements) {
24
- (element as HTMLElement).click();
25
- }
26
- };
27
- componentDidMount(): void {
28
- document.addEventListener("keydown", this.onKeyDown);
29
- }
30
- componentWillUnmount(): void {
31
- document.removeEventListener("keydown", this.onKeyDown);
32
- }
33
-
34
16
  render() {
35
17
  return (
36
18
  <div className={css.pad2(20)}>