Skip to content

Commit

Permalink
feat: v1 updates (#32)
Browse files Browse the repository at this point in the history
* refactor: minor changes to specs

* docs: add jsdoc comments

* fix: make set store private

* 1.0.0

* chore: remove redundant @types/rimraf package

* chore: update README
  • Loading branch information
BatuhanW committed Dec 29, 2023
1 parent 70a37a3 commit 3704d19
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Maintainability](https://api.codeclimate.com/v1/badges/4315aa36678fe4181b77/maintainability)](https://codeclimate.com/github/BatuhanW/haf/maintainability)
[![Test Coverage](https://api.codeclimate.com/v1/badges/4315aa36678fe4181b77/test_coverage)](https://codeclimate.com/github/BatuhanW/haf/test_coverage)

Haf is a fully typed 🔒, cross-platform, persistent 💾 config ⚙️ solution for your NodeJS projects with a great developer experience!
Haf is a fully typed 🔒, cross-platform, persistent 💾 JSON storage ⚙️ solution for your NodeJS projects with a great developer experience!

- ✏️ Auto-completed dot-notation suggestions as you type when you try to get()/set()/delete()/reset() data from the store.
- ✅ The type of the value you get() from the store is correctly inferred. So you always know what you'll get().
Expand Down
15 changes: 2 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "@batuhanw/haf",
"version": "0.2.0",
"version": "1.0.0",
"engines": {
"node": ">=16"
},
"description": "Fully typed, modern, cross-platform persistent config solution for NodeJS projects",
"description": "Fully typed, modern, cross-platform persistent JSON storage solution for NodeJS projects.",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
Expand Down Expand Up @@ -46,7 +46,6 @@
"@types/fs-extra": "^11.0.4",
"@types/jest": "^29.5.11",
"@types/node": "^18.19.3",
"@types/rimraf": "^4.0.5",
"@typescript-eslint/eslint-plugin": "^6.16.0",
"@typescript-eslint/parser": "^6.16.0",
"eslint": "^8.56.0",
Expand Down
46 changes: 24 additions & 22 deletions spec/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ describe('Haf', () => {
});

it('appends string', () => {
haf.append('favoriteToys', 'socks');
haf.append('favoriteToys', 'socks', 'ball');

expect(haf.get('favoriteToys')).toEqual(['toilet paper', 'socks']);
expect(haf.get('favoriteToys')).toEqual(['toilet paper', 'socks', 'ball']);
});

it('appends number', () => {
Expand Down Expand Up @@ -284,35 +284,37 @@ describe('Haf', () => {
});

describe('delete()', () => {
const defaultSchema = {
age: 2,
appearance: {
eyeColor: 'brown',
hairColor: {
primary: 'white',
otherColors: ['pink'],
},
birthMarks: ['head'],
},
favoriteToys: ['socks', 'toilet_paper'],
hasPuppies: false,
luckyNumbers: [4, 2],
name: 'Pop',
vaccines: [
{ name: 'rabies', date: '2020-01-22', next: { date: '2020-07-22' } },
{ name: 'parasite', date: '2020-01-22' },
],
};

beforeEach(() => {
haf = new Haf({
name: 'pop',
defaultSchema: {
age: 2,
appearance: {
eyeColor: 'brown',
hairColor: {
primary: 'white',
otherColors: ['pink'],
},
birthMarks: ['head'],
},
favoriteToys: ['socks', 'toilet_paper'],
hasPuppies: false,
luckyNumbers: [4, 2],
name: 'Pop',
vaccines: [
{ name: 'rabies', date: '2020-01-22', next: { date: '2020-07-22' } },
{ name: 'parasite', date: '2020-01-22' },
],
},
defaultSchema,
});
});

it('undefined', () => {
haf.delete('sterilizedAt');

expect(haf.get('sterilizedAt')).toBeUndefined();
expect(haf.store).toEqual({ ...defaultSchema, sterilizedAt: undefined });
});
});

Expand Down
102 changes: 101 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,34 @@ import { getStorePath } from './get-store-path';
import type { FlattenedWithDotNotation, OptionalKeysOf, StringKeysOf, ArrayKeysOf } from './types';

interface HafConfig<Schema> {
/**
* @description name of the store file.
* @required
*/
name: string;
/**
* @description extension of the store file.
* @optional
* @default haf
* @file /path/to/store/storeName.**haf**
*/
extension?: string;
/**
* @description default JSON object to use when initializing the store.
* @optional
* @default {}
*/
defaultSchema?: Partial<Schema>;
/**
* @description directory for the store file.
* @default checks the environment variables in the following order:
* - process.env.CONFIG_DIR // unix
* - process.env.XDG_CONFIG_HOME // unix
* - process.env.LOCALAPPDATA // windows
* fallback:
* - os.homedir() + '/.config'
* @optional
*/
storeDir?: string;
}

Expand All @@ -31,18 +56,63 @@ class Haf<Schema, FlattenedSchema = FlattenedWithDotNotation<Schema>> {
return readJsonSync(this.storePath);
}

set store(schema: Schema | Partial<Schema>) {
private set store(schema: Schema | Partial<Schema>) {
writeJsonSync(this.storePath, schema);
}

/**
* @description returns the value at the provided path.
* @param path
* @example
* ```typescript
* const haf = new Haf<DogSchema>({
* name: 'dog',
* defaultSchema: {
* name: 'Popita'
* }
* })
*
* haf.get('name') // Popita
* ```
*/
get<Path extends StringKeysOf<FlattenedSchema>>(path: Path): FlattenedSchema[Path] {
return this._get(path);
}

/**
* @description sets the value to the provided path.
* @param path
* @param value
* @example
* ```typescript
* const haf = new Haf<DogSchema>({
* name: 'dog',
* })
*
* haf.set('name', 'Popita')
* ```
*/
set<Path extends StringKeysOf<FlattenedSchema>>(path: Path, value: FlattenedSchema[Path]): void {
this._set(path, value);
}

/**
* @description appends the provided values to the array at the provided path.
* @param path
* @param ...values
* @example
* ```typescript
* const haf = new Haf<DogSchema>({
* name: 'dog',
* })
*
* haf.set('favoriteToys', ['ball', 'bone'])
*
* haf.append('favoriteToys', 'socks', 'toilet paper')
*
* haf.get('favoriteToys') // ['ball', 'bone', 'socks', 'toilet paper']
* ```
*/
append<
Path extends ArrayKeysOf<FlattenedSchema>,
Values extends Extract<FlattenedSchema[Path], unknown[]>,
Expand All @@ -54,10 +124,37 @@ class Haf<Schema, FlattenedSchema = FlattenedWithDotNotation<Schema>> {
this._set(path, existingValues);
}

/**
* @description sets the value of the provided path to undefined.
*/
delete(path: OptionalKeysOf<FlattenedSchema>): void {
this._set(path, undefined);
}

/**
* @description resets the store to defaultSchema values. Sets fields to undefined if not provided in defaultSchema.
* @param path optional path to reset. if not provided, the entire store will be reset.
* @example
* ```typescript
* const haf = new Haf<DogSchema>({
* name: 'dog',
* defaultSchema: {
* name: 'pop',
* });
*
* haf.set('name', 'pup');
*
* haf.reset('name');
*
* haf.get('name'); // pop
*
* haf.set('age', 3)
*
* haf.reset('age')
*
* haf.get('age') // undefined
* ```
*/
reset(path?: StringKeysOf<FlattenedSchema>): void {
if (typeof path === 'undefined') {
this.store = this.defaultSchema;
Expand All @@ -70,6 +167,9 @@ class Haf<Schema, FlattenedSchema = FlattenedWithDotNotation<Schema>> {
this._set(path, defaultValue);
}

/**
* @description removes the store file from the file system.
*/
nuke(): void {
removeSync(this.storePath);
}
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type FlattenedWithDotNotation<Schema, Prefix = null> =
[K in string & keyof Schema as AddPrefix<K, Prefix>]: Schema[K];
} /* then, for each sub-object, recurse */ & IntersectValuesOf<{
// see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html#key-remapping-in-mapped-types
// Since Array type also satisfies `object`, excluding it before starting recursion for `object` type.
[K in string & keyof Schema as AddPrefix<K, Prefix>]: Schema[K] extends Array<any>
? never
: Schema[K] extends object
Expand Down

0 comments on commit 3704d19

Please sign in to comment.