@neurodevs/ndx-native 0.0.1

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 (67) hide show
  1. package/.nvmrc +1 -0
  2. package/.vscode/launch.json +58 -0
  3. package/.vscode/settings.json +67 -0
  4. package/.vscode/tasks.json +130 -0
  5. package/LICENSE +21 -0
  6. package/README.md +2 -0
  7. package/build/.spruce/settings.json +11 -0
  8. package/build/__tests__/AbstractPackageTest.d.ts +7 -0
  9. package/build/__tests__/AbstractPackageTest.js +14 -0
  10. package/build/__tests__/AbstractPackageTest.js.map +1 -0
  11. package/build/__tests__/impl/LabrecorderAdapter.test.d.ts +30 -0
  12. package/build/__tests__/impl/LabrecorderAdapter.test.js +164 -0
  13. package/build/__tests__/impl/LabrecorderAdapter.test.js.map +1 -0
  14. package/build/__tests__/impl/LiblslAdapter.test.d.ts +84 -0
  15. package/build/__tests__/impl/LiblslAdapter.test.js +750 -0
  16. package/build/__tests__/impl/LiblslAdapter.test.js.map +1 -0
  17. package/build/__tests__/impl/LibxdfAdapter.test.d.ts +45 -0
  18. package/build/__tests__/impl/LibxdfAdapter.test.js +243 -0
  19. package/build/__tests__/impl/LibxdfAdapter.test.js.map +1 -0
  20. package/build/consts.d.ts +11 -0
  21. package/build/consts.js +21 -0
  22. package/build/consts.js.map +1 -0
  23. package/build/impl/LabrecorderAdapter.d.ts +30 -0
  24. package/build/impl/LabrecorderAdapter.js +69 -0
  25. package/build/impl/LabrecorderAdapter.js.map +1 -0
  26. package/build/impl/LiblslAdapter.d.ts +172 -0
  27. package/build/impl/LiblslAdapter.js +360 -0
  28. package/build/impl/LiblslAdapter.js.map +1 -0
  29. package/build/impl/LibxdfAdapter.d.ts +92 -0
  30. package/build/impl/LibxdfAdapter.js +130 -0
  31. package/build/impl/LibxdfAdapter.js.map +1 -0
  32. package/build/index.d.ts +14 -0
  33. package/build/index.js +18 -0
  34. package/build/index.js.map +1 -0
  35. package/build/lib/handleError.d.ts +8 -0
  36. package/build/lib/handleError.js +25 -0
  37. package/build/lib/handleError.js.map +1 -0
  38. package/build/testDoubles/Labrecorder/FakeLabrecorder.d.ts +15 -0
  39. package/build/testDoubles/Labrecorder/FakeLabrecorder.js +26 -0
  40. package/build/testDoubles/Labrecorder/FakeLabrecorder.js.map +1 -0
  41. package/build/testDoubles/Liblsl/FakeLiblsl.d.ts +57 -0
  42. package/build/testDoubles/Liblsl/FakeLiblsl.js +140 -0
  43. package/build/testDoubles/Liblsl/FakeLiblsl.js.map +1 -0
  44. package/build/testDoubles/Libxdf/FakeLibxdf.d.ts +13 -0
  45. package/build/testDoubles/Libxdf/FakeLibxdf.js +25 -0
  46. package/build/testDoubles/Libxdf/FakeLibxdf.js.map +1 -0
  47. package/build/testDoubles/Libxdf/SpyLibxdf.d.ts +6 -0
  48. package/build/testDoubles/Libxdf/SpyLibxdf.js +10 -0
  49. package/build/testDoubles/Libxdf/SpyLibxdf.js.map +1 -0
  50. package/eslint.config.mjs +3 -0
  51. package/package.json +84 -0
  52. package/src/.spruce/settings.json +11 -0
  53. package/src/__tests__/AbstractPackageTest.ts +16 -0
  54. package/src/__tests__/impl/LabrecorderAdapter.test.ts +197 -0
  55. package/src/__tests__/impl/LiblslAdapter.test.ts +907 -0
  56. package/src/__tests__/impl/LibxdfAdapter.test.ts +290 -0
  57. package/src/consts.ts +21 -0
  58. package/src/impl/LabrecorderAdapter.ts +100 -0
  59. package/src/impl/LiblslAdapter.ts +616 -0
  60. package/src/impl/LibxdfAdapter.ts +227 -0
  61. package/src/index.ts +26 -0
  62. package/src/lib/handleError.ts +24 -0
  63. package/src/testDoubles/Labrecorder/FakeLabrecorder.ts +37 -0
  64. package/src/testDoubles/Liblsl/FakeLiblsl.ts +204 -0
  65. package/src/testDoubles/Libxdf/FakeLibxdf.ts +33 -0
  66. package/src/testDoubles/Libxdf/SpyLibxdf.ts +13 -0
  67. package/tsconfig.json +28 -0
@@ -0,0 +1,227 @@
1
+ import fs from 'fs'
2
+ import {
3
+ MangledNameExtractor,
4
+ MangledNameMap,
5
+ } from '@neurodevs/node-mangled-names'
6
+ import { DataType, define, FieldType, FuncObj, open } from 'ffi-rs'
7
+
8
+ export default class LibxdfAdapter implements Libxdf {
9
+ public static Class?: LibxdfConstructor
10
+ public static ffiRsOpen = open
11
+ public static ffiRsDefine = define
12
+ private static readonly loadXdfName = 'load_xdf_to_json'
13
+ private static unmangledNames = [this.loadXdfName]
14
+
15
+ protected bindings!: LibxdfBindings
16
+ private libxdfPath: string
17
+ private mangledNameMap: MangledNameMap
18
+
19
+ protected constructor(libxdfPath: string, mangledNameMap: MangledNameMap) {
20
+ this.libxdfPath = libxdfPath
21
+ this.mangledNameMap = mangledNameMap
22
+
23
+ this.tryToLoadBindings()
24
+ }
25
+
26
+ public static async Create(
27
+ libxdfPath: string,
28
+ throwIfPathNotExists = true
29
+ ) {
30
+ if (throwIfPathNotExists && !fs.existsSync(libxdfPath)) {
31
+ throw new Error(this.generateFailedMessage(libxdfPath))
32
+ }
33
+
34
+ const mangledNameMap = await this.loadMangledNameMap(libxdfPath)
35
+ return new (this.Class ?? this)(libxdfPath, mangledNameMap)
36
+ }
37
+
38
+ private tryToLoadBindings() {
39
+ try {
40
+ this.bindings = this.loadBindings()
41
+ } catch (err: unknown) {
42
+ this.throwFailedToLoadLiblsl(err)
43
+ }
44
+ }
45
+
46
+ private loadBindings() {
47
+ this.openLibxdf()
48
+ return this.defineBindings()
49
+ }
50
+
51
+ private openLibxdf() {
52
+ LibxdfAdapter.ffiRsOpen({
53
+ library: 'xdf',
54
+ path: this.libxdfPath,
55
+ })
56
+ }
57
+
58
+ private defineBindings() {
59
+ const funcs = this.unmangledNames.reduce((acc, name) => {
60
+ const mangledName = this.mangledNameMap[name].slice(1)
61
+
62
+ // @ts-ignore
63
+ acc[mangledName] = {
64
+ library: 'xdf',
65
+ retType: DataType.String,
66
+ paramsType: [DataType.String],
67
+ }
68
+ return acc
69
+ }, {})
70
+
71
+ return LibxdfAdapter.ffiRsDefine(funcs)
72
+ }
73
+
74
+ private throwFailedToLoadLiblsl(err: unknown) {
75
+ throw new Error(this.generateFailedMessage(err))
76
+ }
77
+
78
+ private generateFailedMessage(err: unknown) {
79
+ return `
80
+ ${LibxdfAdapter.generateFailedMessage(this.libxdfPath)}
81
+ \n ${err}
82
+ \n
83
+ `
84
+ }
85
+
86
+ public loadXdf(path: string) {
87
+ const mangledName = this.mangledNameMap[this.loadXdfName].slice(1)
88
+ const mangledFunc = this.bindings[mangledName]
89
+
90
+ const serializedData = mangledFunc([path])
91
+ const parsedData = JSON.parse(serializedData) as LibxdfFile
92
+
93
+ if (!parsedData.events) {
94
+ parsedData.events = []
95
+ }
96
+
97
+ const mappedStreams = parsedData.streams.map((stream) => ({
98
+ id: stream.stream_id,
99
+ name: stream.stream_info.stream_name,
100
+ type: stream.stream_info.stream_type,
101
+ channelCount: stream.stream_info.channel_count,
102
+ channelFormat: stream.stream_info.channel_format,
103
+ nominalSampleRateHz: stream.stream_info.nominal_srate,
104
+ data: stream.time_series,
105
+ timestamps: stream.time_stamps,
106
+ }))
107
+
108
+ const mappedEvents = parsedData.events.map((event) => ({
109
+ name: event.event_name,
110
+ timestamp: event.event_timestamp,
111
+ streamId: event.stream_id,
112
+ }))
113
+
114
+ return {
115
+ path,
116
+ streams: mappedStreams,
117
+ events: mappedEvents,
118
+ }
119
+ }
120
+
121
+ private get unmangledNames() {
122
+ return LibxdfAdapter.unmangledNames
123
+ }
124
+
125
+ private get loadXdfName() {
126
+ return LibxdfAdapter.loadXdfName
127
+ }
128
+
129
+ private static generateFailedMessage(libxdfPath: string) {
130
+ return `
131
+ \n -----------------------------------
132
+ \n Failed to load libxdf! Tried to load from:
133
+ \n ${libxdfPath}
134
+ \n Instructions to save your day (on MacOS):
135
+ \n 1. git clone https://github.com/neurodevs/libxdf.git
136
+ \n 2. cd libxdf && cmake -S . -B build && cmake --build build
137
+ \n 3. sudo cp build/libxdf.dylib /opt/local/lib/
138
+ \n 4. Try whatever you were doing again!
139
+ \n Modify step 3 for your OS if you are not on MacOS.
140
+ \n Check the official repo for OS-specific instructions:
141
+ \n https://github.com/xdf-modules/libxdf
142
+ \n If you're still unsure, ask an LLM with this error and your OS.
143
+ \n You could also post an issue on the repo:
144
+ \n https://github.com/neurodevs/node-xdf/issues
145
+ \n Good luck!
146
+ \n @ericthecurious
147
+ \n -----------------------------------
148
+ `
149
+ }
150
+
151
+ private static async loadMangledNameMap(libxdfPath: string) {
152
+ const extractor = this.MangledNameExtractor()
153
+ return await extractor.extract(libxdfPath, this.unmangledNames)
154
+ }
155
+
156
+ private static MangledNameExtractor() {
157
+ return MangledNameExtractor.Create()
158
+ }
159
+ }
160
+
161
+ export interface Libxdf {
162
+ loadXdf(path: string): XdfFile
163
+ }
164
+
165
+ export type LibxdfConstructor = new (
166
+ libxdfPath: string,
167
+ mangledNameMap: MangledNameMap
168
+ ) => Libxdf
169
+
170
+ export type LibxdfBindings = Record<string, (path: string[]) => string>
171
+
172
+ export type LibxdfStatusCode = 0 | Exclude<number, 0>
173
+
174
+ export type FfiRsDefineOptions = FuncObj<
175
+ FieldType,
176
+ boolean | undefined,
177
+ boolean | undefined
178
+ >
179
+
180
+ export interface XdfFile {
181
+ path: string
182
+ streams: XdfStream[]
183
+ events: XdfEvent[]
184
+ }
185
+
186
+ export interface XdfStream {
187
+ id: number
188
+ name: string
189
+ type: string
190
+ channelCount: number
191
+ channelFormat: string
192
+ nominalSampleRateHz: number
193
+ data: number[][]
194
+ timestamps: number[]
195
+ }
196
+
197
+ export interface XdfEvent {
198
+ name: string
199
+ timestamp: number
200
+ streamId: number
201
+ }
202
+
203
+ export interface LibxdfFile {
204
+ streams: LibxdfStream[]
205
+ events: LibxdfEvent[]
206
+ }
207
+
208
+ export interface LibxdfStream {
209
+ stream_id: number
210
+ stream_info: LibxdfStreamInfo
211
+ time_series: number[][]
212
+ time_stamps: number[]
213
+ }
214
+
215
+ export interface LibxdfStreamInfo {
216
+ channel_count: number
217
+ channel_format: string
218
+ nominal_srate: number
219
+ stream_name: string
220
+ stream_type: string
221
+ }
222
+
223
+ export interface LibxdfEvent {
224
+ stream_id: number
225
+ event_name: string
226
+ event_timestamp: number
227
+ }
package/src/index.ts ADDED
@@ -0,0 +1,26 @@
1
+ // Labrecorder
2
+
3
+ export { default as LabrecorderAdapter } from './impl/LabrecorderAdapter.js'
4
+ export * from './impl/LabrecorderAdapter.js'
5
+
6
+ export { default as FakeLabrecorder } from './testDoubles/Labrecorder/FakeLabrecorder.js'
7
+ export * from './testDoubles/Labrecorder/FakeLabrecorder.js'
8
+
9
+ // Liblsl
10
+
11
+ export { default as LiblslAdapter } from './impl/LiblslAdapter.js'
12
+ export * from './impl/LiblslAdapter.js'
13
+
14
+ export { default as FakeLiblsl } from './testDoubles/Liblsl/FakeLiblsl.js'
15
+ export * from './testDoubles/Liblsl/FakeLiblsl.js'
16
+
17
+ // Libxdf
18
+
19
+ export { default as LibxdfAdapter } from './impl/LibxdfAdapter.js'
20
+ export * from './impl/LibxdfAdapter.js'
21
+
22
+ export { default as FakeLibxdf } from './testDoubles/Libxdf/FakeLibxdf.js'
23
+ export * from './testDoubles/Libxdf/FakeLibxdf.js'
24
+
25
+ export { default as SpyLibxdf } from './testDoubles/Libxdf/SpyLibxdf.js'
26
+ export * from './testDoubles/Libxdf/SpyLibxdf.js'
@@ -0,0 +1,24 @@
1
+ export default function handleError(errorCode: number) {
2
+ switch (errorCode) {
3
+ case 0:
4
+ return
5
+ case -1:
6
+ throw new Error(`The liblsl operation failed due to a timeout!`)
7
+ case -2:
8
+ throw new Error(`The liblsl stream has been lost!`)
9
+ case -3:
10
+ throw new Error(`A liblsl argument was incorrectly specified!`)
11
+ case -4:
12
+ throw new Error(`An internal liblsl error has occurred!`)
13
+ default:
14
+ throw new Error(`An unknown liblsl error has occurred!`)
15
+ }
16
+ }
17
+
18
+ export enum LslErrorCode {
19
+ Ok = 0,
20
+ Timeout = -1,
21
+ Lost = -2,
22
+ BadArgument = -3,
23
+ InternalError = -4,
24
+ }
@@ -0,0 +1,37 @@
1
+ import { RecordingHandle, Labrecorder } from '../../impl/LabrecorderAdapter.js'
2
+
3
+ export default class FakeLabrecorder implements Labrecorder {
4
+ public static constructorCalls: string[] = []
5
+
6
+ public static createRecordingCalls: {
7
+ filename: string
8
+ watchFor: string[]
9
+ }[] = []
10
+
11
+ public static stopRecordingCalls: RecordingHandle[] = []
12
+ public static deleteRecordingCalls: RecordingHandle[] = []
13
+
14
+ public constructor(labrecorderPath: string) {
15
+ FakeLabrecorder.constructorCalls.push(labrecorderPath)
16
+ }
17
+
18
+ public createRecording(filename: string, watchFor: string[]) {
19
+ FakeLabrecorder.createRecordingCalls.push({ filename, watchFor })
20
+ return {} as RecordingHandle
21
+ }
22
+
23
+ public stopRecording(recording: RecordingHandle) {
24
+ FakeLabrecorder.stopRecordingCalls.push(recording)
25
+ }
26
+
27
+ public deleteRecording(recording: RecordingHandle) {
28
+ FakeLabrecorder.deleteRecordingCalls.push(recording)
29
+ }
30
+
31
+ public static resetTestDouble() {
32
+ this.constructorCalls = []
33
+ this.createRecordingCalls = []
34
+ this.stopRecordingCalls = []
35
+ this.deleteRecordingCalls = []
36
+ }
37
+ }
@@ -0,0 +1,204 @@
1
+ import generateId from '@neurodevs/generate-id'
2
+
3
+ import {
4
+ OutletHandle,
5
+ InfoHandle,
6
+ CreateStreamInfoOptions,
7
+ AppendChannelsToStreamInfoOptions,
8
+ CreateOutletOptions,
9
+ PushSampleFloatTimestampOptions,
10
+ PushSampleStringTimestampOptions,
11
+ Liblsl,
12
+ CreateInletOptions,
13
+ DestroyInletOptions,
14
+ InletHandle,
15
+ FlushInletOptions,
16
+ PullChunkOptions,
17
+ PullSampleOptions,
18
+ DestroyStreamInfoOptions,
19
+ ResolveByPropOptions,
20
+ DestroyOutletOptions,
21
+ OpenStreamOptions,
22
+ CloseStreamOptions,
23
+ GetChannelCountOptions,
24
+ } from 'impl/LiblslAdapter.js'
25
+
26
+ export default class FakeLiblsl implements Liblsl {
27
+ public static fakeInfoHandles: InfoHandle[] = []
28
+
29
+ public static fakeSamples: Float32Array[] = [
30
+ new Float32Array([1, 2, 3]),
31
+ new Float32Array([4, 5, 6]),
32
+ ]
33
+
34
+ public static fakeChunks: Float32Array[] = [
35
+ new Float32Array([1, 2, 3, 4, 5, 6]),
36
+ new Float32Array([1, 2, 3, 4, 5, 6]),
37
+ ]
38
+
39
+ public static fakeTimestamps: Float64Array[] = [
40
+ new Float64Array([7, 8]),
41
+ new Float64Array([7, 8]),
42
+ ]
43
+
44
+ public static fakeChannelCount = 3
45
+ public static fakeErrorCode = 0
46
+
47
+ public liblslPath: string = generateId()
48
+
49
+ public fakeSamples = FakeLiblsl.fakeSamples.slice()
50
+ public fakeChunks = FakeLiblsl.fakeChunks.slice()
51
+ public fakeTimestamps = FakeLiblsl.fakeTimestamps.slice()
52
+
53
+ public outletHandle: OutletHandle = {} as OutletHandle
54
+ public infoHandle: InfoHandle = {} as InfoHandle
55
+
56
+ public lastCreateStreamInfoOptions?: CreateStreamInfoOptions
57
+ public lastAppendChannelsToStreamInfoOptions?: AppendChannelsToStreamInfoOptions
58
+ public lastDestroyStreamInfoOptions?: DestroyStreamInfoOptions
59
+ public lastResolveByPropOptions?: ResolveByPropOptions
60
+ public lastGetChannelCountOptions?: GetChannelCountOptions
61
+
62
+ public lastCreateOutletOptions?: CreateOutletOptions
63
+ public lastPushSampleFloatTimestampOptions?: PushSampleFloatTimestampOptions
64
+ public lastPushSampleStringTimestampOptions?: PushSampleStringTimestampOptions
65
+ public lastDestroyOutletOptions?: DestroyOutletOptions
66
+
67
+ public lastCreateInletOptions?: CreateInletOptions
68
+ public lastOpenStreamOptions?: OpenStreamOptions
69
+ public lastCloseStreamOptions?: CloseStreamOptions
70
+ public lastPullSampleOptions?: PullSampleOptions
71
+ public lastPullChunkOptions?: PullChunkOptions
72
+ public lastFlushInletOptions?: FlushInletOptions
73
+ public lastDestroyInletOptions?: DestroyInletOptions
74
+
75
+ public createStreamInfoHitCount = 0
76
+ public createOutletHitCount = 0
77
+ public destroyOutletHitCount = 0
78
+ public createInletHitCount = 0
79
+ public flushInletHitCount = 0
80
+ public destroyInletHitCount = 0
81
+ public localClockHitCount = 0
82
+ public pushSampleStringTimestampHitCount = 0
83
+
84
+ public createStreamInfo(options: CreateStreamInfoOptions) {
85
+ this.createStreamInfoHitCount++
86
+ this.lastCreateStreamInfoOptions = options
87
+ return this.infoHandle
88
+ }
89
+
90
+ public appendChannelsToStreamInfo(
91
+ options: AppendChannelsToStreamInfoOptions
92
+ ) {
93
+ this.lastAppendChannelsToStreamInfoOptions = options
94
+ }
95
+
96
+ public getChannelCount(options: GetChannelCountOptions) {
97
+ this.lastGetChannelCountOptions = options
98
+ return FakeLiblsl.fakeChannelCount
99
+ }
100
+
101
+ public destroyStreamInfo(options: DestroyStreamInfoOptions) {
102
+ this.lastDestroyStreamInfoOptions = options
103
+ }
104
+
105
+ public async resolveByProp(options: ResolveByPropOptions) {
106
+ this.lastResolveByPropOptions = options
107
+ return FakeLiblsl.fakeInfoHandles
108
+ }
109
+
110
+ public pushSampleFloatTimestamp(options: PushSampleFloatTimestampOptions) {
111
+ this.lastPushSampleFloatTimestampOptions = options
112
+ return FakeLiblsl.fakeErrorCode
113
+ }
114
+
115
+ public pushSampleStringTimestamp(
116
+ options: PushSampleStringTimestampOptions
117
+ ) {
118
+ this.lastPushSampleStringTimestampOptions = options
119
+ this.pushSampleStringTimestampHitCount++
120
+ return FakeLiblsl.fakeErrorCode
121
+ }
122
+
123
+ public createOutlet(options: CreateOutletOptions) {
124
+ this.createOutletHitCount++
125
+ this.lastCreateOutletOptions = options
126
+ return this.outletHandle
127
+ }
128
+
129
+ public destroyOutlet(options: DestroyOutletOptions) {
130
+ this.destroyOutletHitCount++
131
+ this.lastDestroyOutletOptions = options
132
+ }
133
+
134
+ public createInlet(options: CreateInletOptions) {
135
+ this.createInletHitCount++
136
+ this.lastCreateInletOptions = options
137
+ return {} as InletHandle
138
+ }
139
+
140
+ public async openStream(options: OpenStreamOptions) {
141
+ this.lastOpenStreamOptions = options
142
+ }
143
+
144
+ public async closeStream(options: CloseStreamOptions) {
145
+ this.lastCloseStreamOptions = options
146
+ }
147
+
148
+ public pullSample(options: PullSampleOptions) {
149
+ this.lastPullSampleOptions = options
150
+
151
+ const sample = this.fakeSamples.shift()
152
+
153
+ if (sample) {
154
+ return 1
155
+ }
156
+
157
+ return 0
158
+ }
159
+
160
+ public pullChunk(options: PullChunkOptions) {
161
+ this.lastPullChunkOptions = options
162
+
163
+ const chunk = this.fakeChunks.shift()
164
+ const timestamps = this.fakeTimestamps.shift()
165
+
166
+ if (chunk && timestamps) {
167
+ return 1
168
+ }
169
+
170
+ return 0
171
+ }
172
+
173
+ public flushInlet(options: FlushInletOptions) {
174
+ this.flushInletHitCount++
175
+ this.lastFlushInletOptions = options
176
+ }
177
+
178
+ public destroyInlet(options: DestroyInletOptions) {
179
+ this.destroyInletHitCount++
180
+ this.lastDestroyInletOptions = options
181
+ }
182
+
183
+ public localClock() {
184
+ this.localClockHitCount++
185
+ return new Date().getTime()
186
+ }
187
+
188
+ public resetTestDouble() {
189
+ this.lastCreateStreamInfoOptions = undefined
190
+ this.lastAppendChannelsToStreamInfoOptions = undefined
191
+ this.lastCreateOutletOptions = undefined
192
+ this.lastPushSampleFloatTimestampOptions = undefined
193
+ this.lastPushSampleStringTimestampOptions = undefined
194
+
195
+ this.createStreamInfoHitCount = 0
196
+ this.destroyOutletHitCount = 0
197
+ this.localClockHitCount = 0
198
+ this.pushSampleStringTimestampHitCount = 0
199
+
200
+ this.fakeSamples = FakeLiblsl.fakeSamples.slice()
201
+ this.fakeChunks = FakeLiblsl.fakeChunks.slice()
202
+ this.fakeTimestamps = FakeLiblsl.fakeTimestamps.slice()
203
+ }
204
+ }
@@ -0,0 +1,33 @@
1
+ import { MangledNameMap } from '@neurodevs/node-mangled-names'
2
+
3
+ import { Libxdf, XdfFile } from '../../impl/LibxdfAdapter.js'
4
+
5
+ export default class FakeLibxdf implements Libxdf {
6
+ public static libxdfPath?: string
7
+ public static loadXdfCalls: string[] = []
8
+ public static mangledNameMap: MangledNameMap
9
+ public static fakeXdfFile: XdfFile = { path: '', streams: [], events: [] }
10
+
11
+ public constructor(libxdfPath: string, mangledNameMap: MangledNameMap) {
12
+ FakeLibxdf.libxdfPath = libxdfPath
13
+ FakeLibxdf.mangledNameMap = mangledNameMap
14
+ }
15
+
16
+ public loadXdf(path: string) {
17
+ FakeLibxdf.loadXdfCalls.push(path)
18
+ return this.fakeXdfFile
19
+ }
20
+
21
+ public get mangledNameMap() {
22
+ return FakeLibxdf.mangledNameMap
23
+ }
24
+
25
+ public get fakeXdfFile() {
26
+ return FakeLibxdf.fakeXdfFile
27
+ }
28
+
29
+ public static resetTestDouble() {
30
+ FakeLibxdf.libxdfPath = undefined
31
+ FakeLibxdf.loadXdfCalls = []
32
+ }
33
+ }
@@ -0,0 +1,13 @@
1
+ import { MangledNameMap } from '@neurodevs/node-mangled-names'
2
+
3
+ import LibxdfAdapter from '../../impl/LibxdfAdapter.js'
4
+
5
+ export default class SpyLibxdf extends LibxdfAdapter {
6
+ public constructor(libxdfPath: string, mangledNameMap: MangledNameMap) {
7
+ super(libxdfPath, mangledNameMap)
8
+ }
9
+
10
+ public getBindings() {
11
+ return this.bindings
12
+ }
13
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "nodenext",
4
+ "moduleResolution": "nodenext",
5
+ "target": "ES2022",
6
+ "lib": ["ES2022"],
7
+ "types": ["node"],
8
+ "baseUrl": "src",
9
+ "outDir": "build",
10
+ "sourceMap": false,
11
+ "strict": true,
12
+ "noImplicitAny": true,
13
+ "noImplicitReturns": true,
14
+ "noUnusedLocals": true,
15
+ "forceConsistentCasingInFileNames": true,
16
+ "declaration": true,
17
+ "skipLibCheck": true,
18
+ "esModuleInterop": true,
19
+ "moduleDetection": "force",
20
+ "allowJs": true,
21
+ "resolveJsonModule": true,
22
+ "experimentalDecorators": true
23
+ },
24
+ "include": [
25
+ "src/*.ts",
26
+ "src/**/*.ts"
27
+ ]
28
+ }