Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support non-primitive values #154

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
"debounce-fn": "^4.0.0",
"dot-prop": "^6.0.1",
"env-paths": "^2.2.1",
"is-plain-obj": "^3.0.0",
"json-schema-typed": "^7.0.3",
"modify-values": "^1.0.1",
"onetime": "^5.1.2",
"pkg-up": "^3.1.0",
"semver": "^7.3.5"
Expand Down
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ console.log(config.get('foo'));
config.delete('unicorn');
console.log(config.get('unicorn'));
//=> undefined

// Store non-primitive values
store.set('date', new Date());
console.log(store.get('date') instanceof Date);
//=> true
```

Or [create a subclass](https://github.com/sindresorhus/electron-store/blob/main/index.js).
Expand Down
36 changes: 34 additions & 2 deletions source/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {isDeepStrictEqual} from 'util';
import fs = require('fs');
import path = require('path');
import v8 = require('v8');
import crypto = require('crypto');
import assert = require('assert');
import {EventEmitter} from 'events';
Expand All @@ -13,9 +14,12 @@ import ajvFormats from 'ajv-formats';
import debounceFn = require('debounce-fn');
import semver = require('semver');
import onetime = require('onetime');
import isPlainObject = require('is-plain-obj');
import modifyValues = require('modify-values');
import {JSONSchema} from 'json-schema-typed';
import {Deserialize, Migrations, OnDidChangeCallback, Options, Serialize, Unsubscribe, Schema, OnDidAnyChangeCallback} from './types';

const {serialize, deserialize} = v8;
const encryptionAlgorithm = 'aes-256-cbc';

const createPlainObject = <T = unknown>(): T => {
Expand All @@ -26,6 +30,8 @@ const isExist = <T = unknown>(data: T): boolean => {
return data !== undefined && data !== null;
};

const isObject = (value: unknown): boolean => typeof value === 'object' && value !== null;

let parentDir = '';
try {
// Prevent caching of this module so module.parent is always accurate.
Expand Down Expand Up @@ -425,8 +431,34 @@ class Conf<T extends Record<string, any> = Record<string, unknown>> implements I
return () => this.events.removeListener('change', onChange);
}

private readonly _deserialize: Deserialize<T> = value => JSON.parse(value);
private readonly _serialize: Serialize<T> = value => JSON.stringify(value, undefined, '\t');
private readonly _deserialize: Deserialize<T> = value => JSON.parse(
value,
(_, value) => {
if (typeof value === 'string' && value.startsWith(INTERNAL_KEY)) {
return deserialize(Buffer.from(value.slice(INTERNAL_KEY.length), 'base64'));
}

return value;
}
);

private readonly _serialize: Serialize<T> = value => JSON.stringify(
value,
(_, value) => {
if (isPlainObject(value)) {
return modifyValues(value, value => {
if (isObject(value) && !Array.isArray(value) && !isPlainObject(value)) {
return INTERNAL_KEY + serialize(value).toString('base64');
}

return value;
});
}

return value;
},
'\t'
);

private _validate(data: T | unknown): void {
if (!this.#validator) {
Expand Down
5 changes: 5 additions & 0 deletions source/modify-values.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module 'modify-values' {
declare function modifyValues<KeyType extends PropertyKey, ValueType, ReturnValueType>(object: Record<KeyType, ValueType>, transformer: (value: ValueType, key: KeyType) => ReturnValueType): Record<KeyType, ReturnValueType>;

export = modifyValues;
}
5 changes: 5 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ test('.set() - invalid key', t => {
}, {message: 'Expected `key` to be of type `string` or `object`, got number'});
});

test('.set() - with non-primitive value', t => {
t.context.config.set('baz.boo', new Date());
t.true(t.context.config.get('baz.boo') instanceof Date, 'expected an instance of `Date`');
});

test('.has()', t => {
t.context.config.set('foo', fixture);
t.context.config.set('baz.boo', fixture);
Expand Down