funkophile 0.2.4 → 1.0.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/index.ts CHANGED
@@ -1,267 +1,103 @@
1
- import chokidar from "chokidar";
2
- import { createSelector } from "reselect";
3
- import { Action, createStore, Store } from "redux";
4
- import fs from "fs";
5
- import fse from "fs-extra";
6
- import { glob } from "glob";
7
- import path from "path";
8
1
  import Promise from "bluebird";
2
+ import fse from "fs-extra";
9
3
 
10
- export default (funkophileConfig: {
11
- mode: 'build' | 'watch';
12
- initialState: any;
13
- options: {
14
- inFolder: string;
15
- outFolder: string;
16
- },
17
- encodings: Record<string, string[]>,
18
- inputs: Record<string, string>,
19
- outputs: (x: any) => any;
20
- }) => {
4
+ import { Action, Store } from "redux";
5
+ import {
6
+ IConfig,
7
+ INITIALIZE,
8
+ cleanEmptyFoldersRecursively,
9
+ logDone,
10
+ logInputKeys,
11
+ logger,
12
+ makeFinalSelector,
13
+ makePromissesArray,
14
+ newStore,
15
+ previousState,
16
+ startServing,
17
+ } from "./utils";
21
18
 
22
- Promise.config({
23
- cancellation: true,
24
- });
19
+ Promise.config({
20
+ cancellation: true,
21
+ });
25
22
 
26
- const INITIALIZE = "INITIALIZE";
27
- const UPSERT = "UPSERT";
28
- const REMOVE = "REMOVE";
29
-
30
- const previousState: any = {};
23
+ export default (funkophileConfig: IConfig) => {
31
24
  let outputPromise = Promise.resolve();
25
+ const store: Store<any, Action<string>, any> = newStore(funkophileConfig);
26
+ const finalSelector = makeFinalSelector(funkophileConfig);
32
27
 
33
- const logger = {
34
- watchError: (p: string) => console.log("\u001b[7m ! \u001b[0m" + p),
35
- watchReady: (p: string) =>
36
- console.log("\u001b[7m\u001b[36m < \u001b[0m" + p),
37
- watchAdd: (p: string) =>
38
- console.log("\u001b[7m\u001b[34m + \u001b[0m./" + p),
39
- watchChange: (p: string) =>
40
- console.log("\u001b[7m\u001b[35m * \u001b[0m" + p),
41
- watchUnlink: (p: string) =>
42
- console.log("\u001b[7m\u001b[31m - \u001b[0m./" + p),
43
- stateChange: () =>
44
- console.log("\u001b[7m\u001b[31m --- Redux state changed --- \u001b[0m"),
45
- cleaningEmptyfolder: (p: string) =>
46
- console.log("\u001b[31m\u001b[7m XXX! \u001b[0m" + p),
47
- readingFile: (p: string) => console.log("\u001b[31m <-- \u001b[0m" + p),
48
- removedFile: (p: string) =>
49
- console.log("\u001b[31m\u001b[7m ??? \u001b[0m./" + p),
50
- writingString: (p: string) => console.log("\u001b[32m --> \u001b[0m" + p),
51
- writingFunction: (p: string) => console.log("\u001b[33m ... \u001b[0m" + p),
52
- writingPromise: (p: string) => console.log("\u001b[33m ... \u001b[0m" + p),
53
- writingError: (p: string, message: string) =>
54
- console.log("\u001b[31m !!! \u001b[0m" + p + " " + message),
55
-
56
- waiting: () =>
57
- console.log(
58
- "\u001b[7m Funkophile is done for now but waiting on changes...\u001b[0m "
59
- ),
60
- done: () => console.log("\u001b[7m Funkophile is done!\u001b[0m "),
61
- };
62
-
63
- function cleanEmptyFoldersRecursively(folder: string) {
64
- var isDir = fs.statSync(folder).isDirectory();
65
- if (!isDir) {
66
- return;
67
- }
68
- var files = fs.readdirSync(folder);
69
- if (files.length > 0) {
70
- files.forEach(function (file) {
71
- var fullPath = path.join(folder, file);
72
- });
73
-
74
- // re-evaluate files; after deleting subfolder
75
- // we may have parent folder empty now
76
- files = fs.readdirSync(folder);
77
- }
78
-
79
- if (files.length == 0) {
80
- logger.cleaningEmptyfolder(folder);
81
-
82
- fs.rmdirSync(folder);
83
- return;
84
- }
28
+ if (funkophileConfig.mode === "watch") {
29
+ startServing(funkophileConfig);
85
30
  }
86
31
 
87
- const dispatchUpsert = (
88
- store: Store,
89
- key: string,
90
- file: string,
91
- encodings: Record<string, string[]>
92
- ) => {
93
-
94
- const fileType: string = path.basename(file).split(".")[1];
95
-
96
- let encoding: BufferEncoding = Object.keys(encodings).find((e) => {
97
- return encodings[e].includes(fileType);
98
- }) as BufferEncoding;
99
-
100
- logger.readingFile(file);
101
- store.dispatch({
102
- type: UPSERT,
103
- payload: {
104
- key: key,
105
- // key: path.relative(process.cwd(), key),
106
- src: file,
107
- contents: fse.readFileSync(file, encoding),
108
- },
109
- });
110
- };
32
+ // Wait for all the file watchers to check in
33
+ Promise.all(
34
+ makePromissesArray(funkophileConfig, store)
35
+ ).then(function () {
36
+ console.log(
37
+ "\u001b[32m\u001b[1m[Funkophile]\u001b[0m All input watchers are ready. Setting up store subscription..."
38
+ );
111
39
 
112
- function omit(key: string, obj: any) {
113
- const { [key]: omitted, ...rest } = obj;
114
- return rest;
115
- }
40
+ // Set up the store subscription BEFORE initializing to catch all changes
41
+ store.subscribe(() => {
42
+ const s = store.getState();
43
+ console.log(
44
+ `\u001b[36m\u001b[1m[Funkophile]\u001b[0m Store updated. initialLoad: ${s.initialLoad}, timestamp: ${s.timestamp}`
45
+ );
116
46
 
117
- const store: Store<any, Action<string>, any> = createStore(
118
- (
119
- state = {
120
- initialLoad: true,
121
- ...funkophileConfig.initialState,
122
- timestamp: Date.now(),
123
- },
124
- action,
125
- ) => {
126
- if (state === undefined) {
127
- throw new Error("Redux state is undefined. This should never happen.");
128
- }
129
- // console.log("\u001b[7m\u001b[35m ||| Redux recieved action \u001b[0m", action.type)
130
- if (!action.type.includes("@@redux")) {
131
- if (action.type === INITIALIZE) {
132
- return {
133
- ...state,
134
- initialLoad: false,
135
- timestamp: Date.now(),
136
- };
137
- } else if (action.type === UPSERT) {
138
- return {
139
- ...state,
140
- [action["payload"].key]: {
141
- // @ts-ignore
142
- ...state[action.payload.key],
143
- ...{
144
- [action["payload"].src]: action["payload"].contents,
145
- },
146
- },
147
- timestamp: Date.now(),
148
- };
149
- } else if (action.type === REMOVE) {
150
- return {
151
- ...state,
152
- [action["payload"].key]: omit(
153
- action["payload"].file,
154
- state[action["payload"].key]
155
- ),
156
- timestamp: Date.now(),
157
- };
158
- } else {
159
- console.error(
160
- "Redux was asked to handle an unknown action type: " + action.type
161
- );
162
- process.exit(-1);
163
- }
164
- // return state
47
+ // Skip processing during initial load
48
+ if (s.initialLoad) {
49
+ console.log(
50
+ "\u001b[36m\u001b[1m[Funkophile]\u001b[0m Initial load in progress, skipping processing..."
51
+ );
52
+ console.log(
53
+ "\u001b[36m\u001b[1m[Funkophile]\u001b[0m State keys during initial load:",
54
+ Object.keys(s)
55
+ );
56
+ return;
165
57
  }
166
- }
167
- );
168
58
 
169
- const finalSelector = funkophileConfig.outputs(
170
- Object.keys(funkophileConfig.inputs).reduce((mm, inputKey) => {
171
- return {
172
- ...mm,
173
- [inputKey]: createSelector([(x) => x], (root) => root[inputKey]),
174
- };
175
- }, {})
176
- );
177
-
178
- // Wait for all the file watchers to check in
179
- Promise.all(
180
- Object.keys(funkophileConfig.inputs).map((inputRuleKey) => {
181
- const p = path.resolve(
182
- `./${funkophileConfig.options.inFolder}/${
183
- funkophileConfig.inputs[inputRuleKey] || ""
184
- }`
59
+ logger.stateChange();
60
+ console.log(
61
+ "\u001b[36m\u001b[1m[Funkophile]\u001b[0m Processing state changes..."
62
+ );
63
+ console.log(
64
+ "\u001b[36m\u001b[1m[Funkophile]\u001b[0m Current state keys:",
65
+ Object.keys(s)
185
66
  );
186
67
 
187
- return new Promise((fulfill, reject) => {
68
+ let outputs;
69
+ try {
70
+ outputs = finalSelector(s);
71
+ console.log(
72
+ `\u001b[36m\u001b[1m[Funkophile]\u001b[0m Generated ${
73
+ Object.keys(outputs).length
74
+ } outputs`
75
+ );
76
+ } catch (error) {
77
+ console.error(
78
+ "\u001b[31m\u001b[1m[Funkophile]\u001b[0m FATAL: Error in output selector chain ? :"
79
+ );
80
+ console.error(" Error:", error.message);
81
+ console.error(" Stack:", error.stack);
82
+ // Don't exit the process in watch mode, just log the error and continue
188
83
  if (funkophileConfig.mode === "build") {
189
- glob(p, {})
190
- .then((files: string[]) => {
191
- files.forEach((file) => {
192
- dispatchUpsert(
193
- store,
194
- inputRuleKey,
195
- file,
196
- funkophileConfig.encodings
197
- );
198
- });
199
- })
200
- .then(() => {
201
- fulfill();
202
- });
203
- } else if (funkophileConfig.mode === "watch") {
204
- chokidar
205
- .watch(p, {})
206
- .on("error", (error) => {
207
- logger.watchError(p);
208
- })
209
- .on("ready", () => {
210
- logger.watchReady(p);
211
- fulfill();
212
- })
213
- .on("add", (p) => {
214
- logger.watchAdd(p);
215
- dispatchUpsert(
216
- store,
217
- inputRuleKey,
218
- p,
219
- funkophileConfig.encodings
220
- );
221
- })
222
- .on("change", (p) => {
223
- logger.watchChange(p);
224
- dispatchUpsert(
225
- store,
226
- inputRuleKey,
227
- p,
228
- funkophileConfig.encodings
229
- );
230
- })
231
- .on("unlink", (p) => {
232
- logger.watchUnlink(p);
233
- store.dispatch({
234
- type: REMOVE,
235
- payload: {
236
- key: inputRuleKey,
237
- file: p,
238
- },
239
- });
240
- })
241
- .on("unlinkDir", (p) => {
242
- logger.watchUnlink(p);
243
- });
244
- // .on('raw', (event, p, details) => { // internal
245
- // log('Raw event info:', event, p, details);
246
- // })
84
+ process.exit(1);
247
85
  } else {
248
- console.error(
249
- `mode should be 'watch' or 'build', not "${funkophileConfig.mode}"`
86
+ console.log(
87
+ "\u001b[33m\u001b[1m[Funkophile]\u001b[0m Continuing to watch for changes despite error..."
250
88
  );
251
- process.exit(-1);
89
+ // Reset previousState to empty to ensure we try processing again on next change
90
+ Object.keys(previousState).forEach((key) => {
91
+ delete previousState[key];
92
+ });
93
+ return;
252
94
  }
253
- });
254
- })
255
- ).then(function () {
256
- // listen for changes to the store
257
- store.subscribe(() => {
258
- const s = store.getState();
259
-
260
- logger.stateChange();
261
- const outputs = finalSelector(s);
95
+ }
262
96
 
263
97
  if (outputPromise.isPending()) {
264
- console.log("cancelling previous write!");
98
+ console.log(
99
+ "\u001b[33m\u001b[1m[Funkophile]\u001b[0m Cancelling previous write operation!"
100
+ );
265
101
  outputPromise.cancel();
266
102
  }
267
103
 
@@ -273,6 +109,9 @@ export default (funkophileConfig: {
273
109
  if (!outputs[key]) {
274
110
  const file = funkophileConfig.options.outFolder + "/" + key;
275
111
  logger.removedFile(file);
112
+ console.log(
113
+ `\u001b[31m\u001b[1m[Funkophile]\u001b[0m Removing file: ${file}`
114
+ );
276
115
 
277
116
  try {
278
117
  fse.unlinkSync("./" + file);
@@ -280,14 +119,15 @@ export default (funkophileConfig: {
280
119
  "./" + file.substring(0, file.lastIndexOf("/"))
281
120
  );
282
121
  } catch (ex) {
283
- // console.error('inner', ex.message);
284
- // throw ex;
122
+ // Log error but don't fail the entire process
123
+ console.error(
124
+ `\u001b[31m\u001b[1m[Funkophile]\u001b[0m Error removing file ${file}:`,
125
+ ex.message
126
+ );
285
127
  } finally {
286
- // console.log('finally');
287
- return;
128
+ delete previousState[key];
129
+ fulfill();
288
130
  }
289
- // delete previousState[key]
290
- // fulfill()
291
131
  } else {
292
132
  if (outputs[key] !== previousState[key]) {
293
133
  previousState[key] = outputs[key];
@@ -296,77 +136,140 @@ export default (funkophileConfig: {
296
136
  "./" + funkophileConfig.options.outFolder + "/" + key;
297
137
  const contents = outputs[key];
298
138
 
139
+ // console.log(`\u001b[32m\u001b[1m[Funkophile]\u001b[0m Writing file: ${relativeFilePath}`);
140
+
299
141
  if (typeof contents === "function") {
300
142
  logger.writingFunction(relativeFilePath);
301
143
  contents((err, res) => {
302
- fse.outputFile(relativeFilePath, res, fulfill);
303
- logger.writingString(relativeFilePath);
144
+ if (err) {
145
+ logger.writingError(relativeFilePath, err.message);
146
+ fulfill(); // Still fulfill to continue processing other files
147
+ } else {
148
+ fse.outputFile(relativeFilePath, res, (err) => {
149
+ if (err) {
150
+ logger.writingError(relativeFilePath, err.message);
151
+ fulfill(); // Still fulfill to continue processing other files
152
+ } else {
153
+ logger.writingString(relativeFilePath);
154
+ fulfill();
155
+ }
156
+ });
157
+ }
304
158
  });
305
159
  } else if (typeof contents === "string") {
306
- fse.outputFile(relativeFilePath, contents, fulfill);
307
- logger.writingString(relativeFilePath);
160
+ fse.outputFile(relativeFilePath, contents, (err) => {
161
+ if (err) {
162
+ logger.writingError(relativeFilePath, err.message);
163
+ fulfill();
164
+ } else {
165
+ logger.writingString(relativeFilePath);
166
+ fulfill();
167
+ }
168
+ });
308
169
  } else if (Buffer.isBuffer(contents)) {
309
- fse.outputFile(relativeFilePath, contents, fulfill);
310
- logger.writingString(relativeFilePath);
170
+ fse.outputFile(relativeFilePath, contents, (err) => {
171
+ if (err) {
172
+ logger.writingError(relativeFilePath, err.message);
173
+ fulfill();
174
+ } else {
175
+ logger.writingString(relativeFilePath);
176
+ fulfill();
177
+ }
178
+ });
311
179
  } else if (Array.isArray(contents)) {
312
180
  fse.outputFile(
313
181
  relativeFilePath,
314
182
  JSON.stringify(contents),
315
- fulfill
183
+ (err) => {
184
+ if (err) {
185
+ logger.writingError(relativeFilePath, err.message);
186
+ fulfill();
187
+ } else {
188
+ logger.writingString(relativeFilePath);
189
+ fulfill();
190
+ }
191
+ }
316
192
  );
317
- logger.writingString(relativeFilePath);
318
193
  } else if (typeof contents.then === "function") {
319
194
  logger.writingPromise(relativeFilePath);
320
195
  Promise.resolve(contents).then(
321
196
  function (value) {
322
197
  if (value instanceof Error) {
323
198
  logger.writingError(relativeFilePath, value.message);
199
+ fulfill();
324
200
  } else {
325
- fse.outputFile(relativeFilePath, value, fulfill);
326
- logger.writingString(relativeFilePath);
201
+ fse.outputFile(relativeFilePath, value, (err) => {
202
+ if (err) {
203
+ logger.writingError(relativeFilePath, err.message);
204
+ fulfill();
205
+ } else {
206
+ logger.writingString(relativeFilePath);
207
+ fulfill();
208
+ }
209
+ });
327
210
  }
328
211
  },
329
- function (value) {
330
- // not called
212
+ function (error) {
213
+ logger.writingError(relativeFilePath, error.message);
214
+ fulfill();
331
215
  }
332
216
  );
333
217
  } else {
334
218
  console.log(
335
- `I don't recognize what this is but I will try to write it to a file: ` +
336
- relativeFilePath,
337
- typeof contents,
338
- contents
219
+ `\u001b[33m\u001b[1m[Funkophile]\u001b[0m Unrecognized content type for ${relativeFilePath}, attempting to write:`,
220
+ typeof contents
339
221
  );
340
- fse.outputFile(relativeFilePath, contents, fulfill);
341
- logger.writingString(relativeFilePath);
222
+ fse.outputFile(relativeFilePath, contents, (err) => {
223
+ if (err) {
224
+ logger.writingError(relativeFilePath, err.message);
225
+ fulfill();
226
+ } else {
227
+ logger.writingString(relativeFilePath);
228
+ fulfill();
229
+ }
230
+ });
342
231
  }
343
232
  } else {
233
+ // console.log(`\u001b[90m\u001b[1m[Funkophile]\u001b[0m Skipping unchanged file: ${key}`);
344
234
  fulfill();
345
235
  }
346
236
  }
347
237
  });
348
238
  })
349
239
  ).then(() => {
240
+ // console.log('\u001b[36m\u001b[1m[Funkophile]\u001b[0m Cleaning empty folders...');
350
241
  cleanEmptyFoldersRecursively(funkophileConfig.options.outFolder);
351
242
 
352
- if (funkophileConfig.mode === "build") {
353
- logger.done();
354
- } else if (funkophileConfig.mode === "watch") {
355
- logger.waiting();
356
- } else {
357
- console.error(
358
- `The mode should be 'watch' or 'build', not "${funkophileConfig.mode}"`
359
- );
360
- process.exit(-1);
361
- }
243
+ logDone(funkophileConfig, currentState)
362
244
  });
245
+ // .catch((error) => {
246
+ // // console.error('\u001b[31m\u001b[1m[Funkophile]\u001b[0m Error during file operations:', error);
247
+ // });
363
248
  });
364
249
 
365
- // lastly, turn the store `on`.
366
- // This is to prevent unecessary recomputations when initialy adding files to redux
367
- store.dispatch({
368
- type: INITIALIZE,
369
- payload: true,
370
- });
250
+ console.log(
251
+ "\u001b[32m\u001b[1m[Funkophile]\u001b[0m Dispatching INITIALIZE action to enable processing..."
252
+ );
253
+ // Debug: log the current state after all files are processed
254
+ const currentState = store.getState();
255
+ console.log(
256
+ "\u001b[36m\u001b[1m[Funkophile]\u001b[0m Current state keys:",
257
+ Object.keys(currentState)
258
+ );
259
+
260
+ logInputKeys(funkophileConfig, currentState);
261
+
262
+ // Add a small delay to ensure all file operations are complete before initializing
263
+ setTimeout(() => {
264
+ // lastly, turn the store `on`.
265
+ // This is to prevent unecessary recomputations when initialy adding files to redux
266
+ store.dispatch({
267
+ type: INITIALIZE,
268
+ payload: true,
269
+ });
270
+ console.log(
271
+ "\u001b[32m\u001b[1m[Funkophile]\u001b[0m Store initialized. Ready to process changes!"
272
+ );
273
+ }, 100);
371
274
  });
372
275
  };
package/mocha.log ADDED
@@ -0,0 +1,59 @@
1
+ warning ../../package.json: No license field
2
+ $ mocha --loader=ts '**/*.test.ts'
3
+
4
+
5
+ Funkophile Core
6
+ makeStore
7
+ ✔ should create a store with empty state until it is initialized
8
+ omit
9
+ ✔ should remove the specified key from object
10
+ selectors
11
+ for the pages
12
+ ✔ contentsOfFiles should concatenate all file contents
13
+ ✔ contentOfFile should return first file content
14
+ ✔ srcAndContentOfFile should return src and content
15
+ ✔ srcAndContentOfFiles should return array of src/content pairs
16
+ for the posts
17
+ ✔ contentsOfFiles should concatenate all file contents
18
+ ✔ contentOfFile should return first file content
19
+ ✔ srcAndContentOfFile should return src and content
20
+ ✔ srcAndContentOfFiles should return array of src/content pairs
21
+ createInputSelectors
22
+ ✔ should create a selector for each input key
23
+ ✔ selectors should return the corresponding state slice
24
+ store actions
25
+ ✔ should handle INITIALIZE action
26
+ ✔ should handle UPSERT action
27
+ ✔ should handle REMOVE action
28
+ edge cases
29
+ An input selector returned a different result when passed same arguments.
30
+ This means your output selector will likely run more frequently than intended.
31
+ Avoid returning a new reference inside your input selector, e.g.
32
+ `createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)` {
33
+ arguments: [Arguments] {
34
+ '0': { timestamp: 1752731765346, posts: [Object], pages: [Object] }
35
+ },
36
+ firstInputs: [ {} ],
37
+ secondInputs: [ {} ],
38
+ stack: 'Error\n' +
39
+ ' at Object.runInputStabilityCheck (/Users/adam/Code/funkophile/node_modules/reselect/src/devModeChecks/inputStabilityCheck.ts:41:13)\n' +
40
+ ' at dependenciesChecker (/Users/adam/Code/funkophile/node_modules/reselect/src/createSelectorCreator.ts:432:31)\n' +
41
+ ' at memoized (/Users/adam/Code/funkophile/node_modules/reselect/src/weakMapMemoize.ts:228:21)\n' +
42
+ ' at Context.<anonymous> (/Users/adam/Code/funkophile/index.test.ts:193:14)\n' +
43
+ ' at callFn (/Users/adam/Code/funkophile/node_modules/mocha/lib/runnable.js:366:21)\n' +
44
+ ' at Runnable.run (/Users/adam/Code/funkophile/node_modules/mocha/lib/runnable.js:354:5)\n' +
45
+ ' at Runner.runTest (/Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:715:10)\n' +
46
+ ' at /Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:838:12\n' +
47
+ ' at next (/Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:630:14)\n' +
48
+ ' at /Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:640:7\n' +
49
+ ' at next (/Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:523:14)\n' +
50
+ ' at Immediate._onImmediate (/Users/adam/Code/funkophile/node_modules/mocha/lib/runner.js:608:5)\n' +
51
+ ' at process.processImmediate (node:internal/timers:478:21)'
52
+ }
53
+ ✔ should handle empty file contents
54
+ ✔ should handle Buffer content
55
+ ✔ should throw on invalid selector
56
+
57
+
58
+ 18 passing (10ms)
59
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "funkophile",
3
- "version": "0.2.4",
3
+ "version": "1.0.0",
4
4
  "repository": "git@github.com:adamwong246/funkophile.git",
5
5
  "author": "adam wong <adamwong246@gmail.com>",
6
6
  "license": "MIT",
@@ -9,33 +9,56 @@
9
9
  "static site generator"
10
10
  ],
11
11
  "type": "module",
12
- "main": "./dist/esm.index.js",
12
+ "test": "mocha",
13
+ "module": "./dist/esm/index.js",
13
14
  "types": "./dist/esm/index.d.ts",
15
+ "mocha": {
16
+ "node-option": [
17
+ "import=tsx"
18
+ ]
19
+ },
14
20
  "scripts": {
15
- "transpile": "tsc --project tsconfig.json "
21
+ "build": "tsx build.ts",
22
+ "dev": "tsx --watch dev.ts",
23
+ "test": "mocha index.test.ts",
24
+ "typecheck": "tsc --noEmit"
16
25
  },
17
26
  "dependencies": {
18
27
  "@tsconfig/node-lts-strictest-esm": "^18.12.1",
19
28
  "@types/bluebird": "^3.5.42",
29
+ "@types/chai": "^5.2.2",
20
30
  "@types/chokidar": "^2.1.7",
21
31
  "@types/fs-extra": "^11.0.4",
32
+ "@types/mocha": "^10.0.10",
22
33
  "@types/redux": "^3.6.0",
23
34
  "@types/reselect": "^2.2.0",
24
35
  "bluebird": "3.7.2",
36
+ "chai": "^5.2.1",
25
37
  "chokidar": "^4.0.3",
38
+ "esbuild": "^0.25.0",
26
39
  "fs-extra": "^11.3.0",
27
40
  "glob": "11.0.1",
41
+ "mocha": "^11.7.1",
42
+ "mocha-junit-reporter": "^2.2.0",
43
+ "ts-node": "^10.9.1",
28
44
  "tsc": "^2.0.4",
45
+ "tsx": "^4.20.6",
29
46
  "typescript": "^5.8.2"
30
47
  },
48
+ "devDependencies": {
49
+ "chokidar-cli": "^3.0.0"
50
+ },
31
51
  "exports": {
32
52
  ".": {
33
- "types": "./dist/esm/index.d.ts",
34
- "import": "./dist/esm/index.js",
53
+ "import": {
54
+ "default": "./dist/esm/index.js"
55
+ },
35
56
  "default": "./dist/esm/index.js"
36
57
  },
37
58
  "./funkophileHelpers": {
38
- "import": "./dist/esm/funkophileHelpers.js"
59
+ "types": "./dist/esm/funkophileHelpers.d.ts",
60
+ "import": "./dist/esm/funkophileHelpers.js",
61
+ "default": "./dist/esm/funkophileHelpers.js"
39
62
  }
40
63
  }
41
64
  }