Skip to content

Commit c78d131

Browse files
committed
feat(packages): implement logger for node and browser packages
1 parent 74d083d commit c78d131

18 files changed

+160
-71
lines changed

packages/browser/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"prepublishOnly": "pnpm build"
5050
},
5151
"dependencies": {
52+
"@stenodb/logger": "workspace:^0.0.0",
5253
"@stenodb/utils": "workspace:3.0.0",
5354
"class-transformer": "0.5.1"
5455
},

packages/browser/src/adapter/WebStorage.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { parseData } from '@stenodb/utils'
2-
import { plainToClass } from 'class-transformer'
1+
import { dataTransformer, entityTransformer } from '@stenodb/utils'
32
import type { Steno } from '../types.js'
3+
import type { BaseLogger } from '@stenodb/logger'
4+
import type { DataTransformer, EntityTransformer } from '@stenodb/utils'
45

56
export class BrowserStorage<T> {
67
name: string
78
storage: Storage
8-
entity: Steno.Entity<T>
9+
logger: BaseLogger
10+
11+
entityTransformer: EntityTransformer<T>
12+
dataTransformer: DataTransformer<T>
913

1014
data: T | null = null
1115
initialData: T | null = null
@@ -18,34 +22,32 @@ export class BrowserStorage<T> {
1822
) {
1923
this.name = name
2024
this.storage = storage
21-
this.entity = entity
25+
this.entityTransformer = entityTransformer(entity)
26+
this.dataTransformer = dataTransformer(this.entityTransformer)
2227

2328
if (initialData) {
2429
this.initialData = initialData
2530
}
2631
}
2732

28-
plainData(data: T | string | null = this.data): T | null {
29-
if (!data) return null
30-
31-
const parsedData =
32-
typeof data === 'string' ? parseData<T>(data).toJSON() : data
33-
34-
return plainToClass(this.entity, parsedData)
33+
registerLogger(logger: BaseLogger): void {
34+
this.logger = logger
3535
}
3636

3737
read(): void {
3838
const data = this.storage.getItem(this.name)
39-
this.data = data ? this.plainData(data) : null
39+
this.data = this.dataTransformer.toJSON(data)
40+
this.logger.info('Read data:', this.data)
4041
}
4142

4243
write(): void {
43-
this.storage.setItem(this.name, parseData(this.data).toString())
44+
this.storage.setItem(this.name, this.dataTransformer.toString(this.data))
45+
this.logger.info('Write data:', this.data)
4446
}
4547

4648
reset(): void {
4749
if (!this.initialData) return
48-
this.data = plainToClass(this.entity, this.initialData)
50+
this.data = this.entityTransformer(this.initialData)
4951
this.write()
5052
}
5153

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
import { StorageProvider } from './StorageProvider.js'
22
import type { Steno } from '../types.js'
3+
import type { CreateLogger } from '@stenodb/logger'
34

45
export class BrowserProvider {
6+
#options: Steno.BrowserProviderOptions
7+
#logger: CreateLogger
8+
9+
constructor(options: Steno.BrowserProviderOptions) {
10+
this.#options = options
11+
this.#logger = options.logger
12+
}
13+
14+
private registerAdapterModules<T>(adapter: Steno.BrowserAdapter<T>) {
15+
if (!this.#logger) return
16+
const logger = this.#logger(adapter.name)
17+
adapter.registerLogger(logger)
18+
}
19+
520
create<T>(adapter: Steno.BrowserAdapter<T>): StorageProvider<T> {
21+
this.registerAdapterModules(adapter)
622
return new StorageProvider(adapter)
723
}
824
}

packages/browser/src/provider/StorageProvider.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ export class StorageProvider<T> extends BaseProvider<T> {
1414

1515
if (!this.data) {
1616
this.reset()
17-
} else {
18-
this.data = this.#adapter.plainData()
1917
}
2018

2119
return this.data

packages/browser/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import type { LocalStorage } from './adapter/LocalStorage.js'
22
import type { SessionStorage } from './adapter/SessionStorage.js'
33
import type { StorageProvider } from './provider/StorageProvider.js'
4+
import type { CreateLogger } from '@stenodb/logger'
45
import type { ClassConstructor } from 'class-transformer'
56

67
export namespace Steno {
78
export type Entity<T> = ClassConstructor<T>
89
export type BrowserAdapter<T> = LocalStorage<T> | SessionStorage<T>
910
export type BrowserProvider<T> = StorageProvider<T>
11+
12+
export interface BrowserProviderOptions {
13+
logger?: CreateLogger
14+
}
1015
}

packages/node/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"prepublishOnly": "pnpm build"
4747
},
4848
"dependencies": {
49+
"@stenodb/logger": "workspace:^0.0.0",
4950
"@stenodb/utils": "workspace:3.0.0",
5051
"class-transformer": "0.5.1",
5152
"steno": "3.0.0"

packages/node/src/adapter/AsyncAdapter.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { readFile } from 'node:fs/promises'
2-
import { parseData } from '@stenodb/utils'
32
import { BaseAdapter } from './BaseAdapter.js'
43
import type { Steno } from '../types.js'
54

@@ -11,27 +10,43 @@ export class AsyncAdapter<T> extends BaseAdapter<T> {
1110
async read(): Promise<void> {
1211
try {
1312
const file = await readFile(this.filePath, 'utf-8')
14-
this.data = this.plainData(file)
13+
this.data = this.dataTransformer.toJSON(file)
14+
this.logger.info('Read data from file', this.data)
1515
} catch (err) {
16-
console.log(err)
16+
if (!this.data) {
17+
await this.reset()
18+
}
19+
20+
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
21+
this.logger.error('Failed to read data from file', err)
22+
}
1723
}
1824
}
1925

2026
async write(): Promise<void> {
21-
await this.writer.write(parseData(this.data).toString())
27+
await this.writer.write(this.dataTransformer.toString(this.data))
28+
this.logger.info('Write data to file', this.data)
2229
}
2330

2431
async reset(): Promise<void> {
25-
if (!this.initialData) return
32+
if (!this.initialData) {
33+
this.logger.warn('No initial data to reset to')
34+
return
35+
}
2636

2737
try {
2838
await this.directory
29-
.createTemporaryFile(this.fileName, this.data)
39+
.createTemporaryFile(
40+
this.fileName,
41+
this.dataTransformer.toString(this.data)
42+
)
3043
?.writeAsync()
31-
this.data = this.initialData
44+
this.data = this.dataTransformer.toJSON(this.initialData)
3245
await this.write()
3346
} catch (err) {
34-
console.log(err)
47+
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
48+
this.logger.error('Failed to read data from file', err)
49+
}
3550
}
3651
}
3752

packages/node/src/adapter/BaseAdapter.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
1-
import { parseData } from '@stenodb/utils'
2-
import { plainToClass } from 'class-transformer'
1+
import { BaseLogger } from '@stenodb/logger'
2+
import { dataTransformer, entityTransformer } from '@stenodb/utils'
33
import { Writer } from 'steno'
44
import type { DirectoryProvider } from '../provider/DirectoryProvider.js'
55
import type { Steno } from '../types.js'
6+
import type { DataTransformer, EntityTransformer } from '@stenodb/utils'
67

78
export class BaseAdapter<T> {
89
fileName: string
9-
entity: Steno.Entity<T>
10+
filePath: string
11+
12+
entityTransformer: EntityTransformer<T>
13+
dataTransformer: DataTransformer<T>
1014

1115
directory: DirectoryProvider
12-
filePath: string
16+
logger: BaseLogger
1317
writer: Writer
1418

1519
data: T | null = null
1620
initialData: T | null = null
1721

1822
constructor(fileName: string, entity: Steno.Entity<T>, initialData?: T) {
1923
this.fileName = fileName
20-
this.entity = entity
24+
this.entityTransformer = entityTransformer(entity)
25+
this.dataTransformer = dataTransformer(this.entityTransformer)
2126

2227
if (initialData) {
2328
this.initialData = initialData
2429
}
2530
}
2631

27-
plainData(data: T | string | null = this.data): T | null {
28-
if (!data) return null
29-
30-
const parsedData =
31-
typeof data === 'string' ? parseData<T>(data).toJSON() : data
32-
33-
return plainToClass(this.entity, parsedData)
32+
registerLogger(logger: BaseLogger): void {
33+
this.logger = logger
3434
}
3535

3636
registerDirectory(directory: DirectoryProvider): void {

packages/node/src/adapter/SyncAdapter.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { readFileSync } from 'node:fs'
2-
import { parseData } from '@stenodb/utils'
32
import { BaseAdapter } from './BaseAdapter.js'
43
import type { Steno } from '../types.js'
54

@@ -11,25 +10,43 @@ export class SyncAdapter<T> extends BaseAdapter<T> {
1110
read(): void {
1211
try {
1312
const file = readFileSync(this.filePath, 'utf-8')
14-
this.data = this.plainData(file)
13+
this.data = this.dataTransformer.toJSON(file)
14+
this.logger.info('Read data from file', this.data)
1515
} catch (err) {
16-
console.log(err)
16+
if (!this.data) {
17+
this.reset()
18+
}
19+
20+
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
21+
this.logger.error('Failed to read data from file', err)
22+
}
1723
}
1824
}
1925

2026
write(): void {
21-
this.writer.write(parseData(this.data).toString())
27+
this.writer.write(this.dataTransformer.toString(this.data))
28+
this.logger.info('Write data to file', this.data)
2229
}
2330

2431
reset(): void {
25-
if (!this.initialData) return
32+
if (!this.initialData) {
33+
this.logger.warn('No initial data to reset to')
34+
return
35+
}
2636

2737
try {
28-
this.directory.createTemporaryFile(this.fileName, this.data)?.write()
29-
this.data = this.initialData
38+
this.directory
39+
.createTemporaryFile(
40+
this.fileName,
41+
this.dataTransformer.toString(this.data)
42+
)
43+
?.write()
44+
this.data = this.dataTransformer.toJSON(this.initialData)
3045
this.write()
3146
} catch (err) {
32-
throw err
47+
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
48+
this.logger.error('Failed to read data from file', err)
49+
}
3350
}
3451
}
3552

packages/node/src/provider/AsyncProvider.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ export class AsyncProvider<T> extends BaseProvider<T> {
1414

1515
if (!this.data) {
1616
await this.reset()
17-
} else {
18-
this.data = this.#adapter.plainData()
1917
}
2018

2119
return this.data

packages/node/src/provider/DirectoryProvider.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { mkdir, readFile, rmSync } from 'node:fs'
22
import { join } from 'node:path'
3-
import { parseData } from '@stenodb/utils'
43
import { Writer } from 'steno'
54

65
export class DirectoryProvider {
@@ -37,17 +36,15 @@ export class DirectoryProvider {
3736
return join(this.temporaryPath, `${filename}-${Date.now()}.json`)
3837
}
3938

40-
createTemporaryFile<T>(filename: string, data: T | string | null) {
39+
createTemporaryFile<T>(filename: string, data: string) {
4140
if (!data) return
4241

4342
const file = this.temporaryFilePath(filename)
4443
const writer = new Writer(file)
45-
const parsedData =
46-
typeof data === 'string' ? data : parseData(data).toString()
4744

4845
return {
49-
write: () => writer.write(parsedData),
50-
writeAsync: async () => await writer.write(parsedData)
46+
write: () => writer.write(data),
47+
writeAsync: async () => await writer.write(data)
5148
}
5249
}
5350
}

packages/node/src/provider/NodeProvider.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@ import type { Steno } from '../types.js'
77

88
export class NodeProvider {
99
#directory: DirectoryProvider
10+
#options: Steno.NodeProviderOptions | undefined
1011

11-
constructor(path: string) {
12+
constructor(path: string, options?: Steno.NodeProviderOptions) {
1213
this.#directory = new DirectoryProvider(path)
14+
this.#options = options
1315
}
1416

15-
private registerDirectory<T>(adapter: Steno.NodeAdapter<T>) {
17+
private registerAdapterModules<T>(adapter: Steno.NodeAdapter<T>): void {
1618
adapter.registerDirectory(this.#directory)
19+
20+
if (this.#options?.logger) {
21+
const logger = this.#options.logger(adapter.fileName)
22+
adapter.registerLogger(logger)
23+
}
1724
}
1825

1926
create<T>(adapter: SyncAdapter<T>): SyncProvider<T>
@@ -31,12 +38,12 @@ export class NodeProvider {
3138
}
3239

3340
createSync<T>(adapter: SyncAdapter<T>): SyncProvider<T> {
34-
this.registerDirectory(adapter)
41+
this.registerAdapterModules(adapter)
3542
return new SyncProvider(adapter)
3643
}
3744

3845
createAsync<T>(adapter: AsyncAdapter<T>): AsyncProvider<T> {
39-
this.registerDirectory(adapter)
46+
this.registerAdapterModules(adapter)
4047
return new AsyncProvider(adapter)
4148
}
4249
}

packages/node/src/provider/SyncProvider.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ export class SyncProvider<T> extends BaseProvider<T> {
1414

1515
if (!this.data) {
1616
this.reset()
17-
} else {
18-
this.data = this.#adapter.plainData()
1917
}
2018

2119
return this.data

packages/node/src/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ import type { AsyncAdapter } from './adapter/AsyncAdapter.js'
22
import type { SyncAdapter } from './adapter/SyncAdapter.js'
33
import type { AsyncProvider } from './provider/AsyncProvider.js'
44
import type { SyncProvider } from './provider/SyncProvider.js'
5+
import type { CreateLogger } from '@stenodb/logger'
56
import type { ClassConstructor } from 'class-transformer'
67

78
export namespace Steno {
89
export type Entity<T> = ClassConstructor<T>
910
export type NodeAdapter<T> = AsyncAdapter<T> | SyncAdapter<T>
1011
export type NodeProvider<T> = AsyncProvider<T> | SyncProvider<T>
12+
13+
export interface NodeProviderOptions {
14+
logger?: CreateLogger
15+
}
1116
}

packages/utils/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"prepublishOnly": "pnpm build"
1616
},
1717
"dependencies": {
18+
"class-transformer": "0.5.1",
1819
"json-difference": "1.9.1"
1920
},
2021
"devDependencies": {

0 commit comments

Comments
 (0)