ts-patch-mongoose 3.1.0 → 4.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.
Files changed (46) hide show
  1. package/README.md +39 -27
  2. package/dist/index.cjs +287 -32
  3. package/dist/index.d.cts +23 -1
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +23 -1
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +287 -32
  8. package/package.json +19 -24
  9. package/biome.json +0 -47
  10. package/src/em.ts +0 -6
  11. package/src/helpers.ts +0 -174
  12. package/src/hooks/delete-hooks.ts +0 -49
  13. package/src/hooks/save-hooks.ts +0 -30
  14. package/src/hooks/update-hooks.ts +0 -125
  15. package/src/index.ts +0 -65
  16. package/src/model.ts +0 -50
  17. package/src/modules/power-assign.d.ts +0 -3
  18. package/src/ms.ts +0 -66
  19. package/src/omit-deep.ts +0 -56
  20. package/src/patch.ts +0 -154
  21. package/src/types.ts +0 -53
  22. package/src/version.ts +0 -13
  23. package/tests/constants/events.ts +0 -7
  24. package/tests/em.test.ts +0 -70
  25. package/tests/helpers.test.ts +0 -373
  26. package/tests/mongo/.gitignore +0 -3
  27. package/tests/mongo/server.ts +0 -31
  28. package/tests/ms.test.ts +0 -113
  29. package/tests/omit-deep.test.ts +0 -235
  30. package/tests/patch.test.ts +0 -200
  31. package/tests/plugin-all-features.test.ts +0 -844
  32. package/tests/plugin-complex-data.test.ts +0 -2647
  33. package/tests/plugin-event-created.test.ts +0 -371
  34. package/tests/plugin-event-deleted.test.ts +0 -400
  35. package/tests/plugin-event-updated.test.ts +0 -503
  36. package/tests/plugin-global.test.ts +0 -545
  37. package/tests/plugin-omit-all.test.ts +0 -349
  38. package/tests/plugin-patch-history-disabled.test.ts +0 -162
  39. package/tests/plugin-pre-delete.test.ts +0 -160
  40. package/tests/plugin-pre-save.test.ts +0 -54
  41. package/tests/plugin.test.ts +0 -576
  42. package/tests/schemas/Description.ts +0 -15
  43. package/tests/schemas/Product.ts +0 -38
  44. package/tests/schemas/User.ts +0 -22
  45. package/tsconfig.json +0 -32
  46. package/vite.config.mts +0 -24
package/dist/index.mjs CHANGED
@@ -1,7 +1,5 @@
1
1
  import mongoose, { Schema, model } from 'mongoose';
2
- import jsonpatch from 'fast-json-patch';
3
2
  import EventEmitter from 'node:events';
4
- import { assign } from 'power-assign';
5
3
 
6
4
  const HistorySchema = new Schema(
7
5
  {
@@ -98,9 +96,10 @@ const ms = (val) => {
98
96
  if (str.length > 100) return Number.NaN;
99
97
  const match = RE.exec(str);
100
98
  if (!match) return Number.NaN;
101
- const n = Number.parseFloat(match[1] ?? "");
102
- const type = (match[2] ?? "ms").toLowerCase();
103
- return n * (UNITS[type] ?? 0);
99
+ const [, numStr, unitStr] = match;
100
+ const n = Number.parseFloat(String(numStr));
101
+ const type = (unitStr ?? "ms").toLowerCase();
102
+ return n * UNITS[type];
104
103
  };
105
104
 
106
105
  const isArray = Array.isArray;
@@ -247,6 +246,94 @@ class PatchEventEmitter extends EventEmitter {
247
246
  }
248
247
  const em = new PatchEventEmitter();
249
248
 
249
+ const escapeToken = (key) => {
250
+ if (!key.includes("/") && !key.includes("~")) return key;
251
+ return key.replaceAll("~", "~0").replaceAll("/", "~1");
252
+ };
253
+ const joinPath = (base, key) => `${base}/${escapeToken(key)}`;
254
+ const cloneValue = (value) => {
255
+ if (value === void 0) return null;
256
+ if (value === null || typeof value !== "object") return value;
257
+ return JSON.parse(JSON.stringify(value));
258
+ };
259
+ const isContainer = (value) => {
260
+ return typeof value === "object" && value !== null;
261
+ };
262
+ const keysOf = (value) => {
263
+ if (Array.isArray(value)) {
264
+ const indices = [];
265
+ for (let i = 0; i < value.length; i++) indices.push(String(i));
266
+ return indices;
267
+ }
268
+ return Object.keys(value);
269
+ };
270
+ const normalizeTarget = (target) => {
271
+ if (!isContainer(target) || Array.isArray(target)) return target;
272
+ const withToJSON = target;
273
+ return typeof withToJSON.toJSON === "function" ? withToJSON.toJSON() : target;
274
+ };
275
+ const emitTest = (path, value, invertible, out) => {
276
+ if (invertible) out.push({ op: "test", path, value: cloneValue(value) });
277
+ };
278
+ const emitReplace = (path, source, target, invertible, out) => {
279
+ emitTest(path, source, invertible, out);
280
+ out.push({ op: "replace", path, value: cloneValue(target) });
281
+ };
282
+ const emitRemove = (path, source, invertible, out) => {
283
+ emitTest(path, source, invertible, out);
284
+ out.push({ op: "remove", path });
285
+ };
286
+ const shouldTreatAsRemoval = (sourceChild, targetChild, sourceIsArray) => {
287
+ return targetChild === void 0 && sourceChild !== void 0 && !sourceIsArray;
288
+ };
289
+ const diffSourceKey = (scope, key) => {
290
+ const { source, target, targetKeySet, basePath, sourceIsArray, invertible, out } = scope;
291
+ const childPath = joinPath(basePath, key);
292
+ const sourceChild = source[key];
293
+ if (!targetKeySet.has(key)) {
294
+ emitRemove(childPath, sourceChild, invertible, out);
295
+ return;
296
+ }
297
+ const targetChild = target[key];
298
+ if (shouldTreatAsRemoval(sourceChild, targetChild, sourceIsArray)) {
299
+ emitRemove(childPath, sourceChild, invertible, out);
300
+ return;
301
+ }
302
+ diff(sourceChild, targetChild, childPath, invertible, out);
303
+ };
304
+ const diffAddedKeys = (target, sourceKeys, targetKeys, basePath, out) => {
305
+ const sourceKeySet = new Set(sourceKeys);
306
+ for (const key of targetKeys) {
307
+ if (sourceKeySet.has(key)) continue;
308
+ const targetChild = target[key];
309
+ if (targetChild === void 0) continue;
310
+ out.push({ op: "add", path: joinPath(basePath, key), value: cloneValue(targetChild) });
311
+ }
312
+ };
313
+ const diff = (source, target, basePath, invertible, out) => {
314
+ if (source === target) return;
315
+ const resolvedTarget = normalizeTarget(target);
316
+ const sourceIsArray = Array.isArray(source);
317
+ const targetIsArray = Array.isArray(resolvedTarget);
318
+ if (!isContainer(source) || !isContainer(resolvedTarget) || sourceIsArray !== targetIsArray) {
319
+ emitReplace(basePath, source, resolvedTarget, invertible, out);
320
+ return;
321
+ }
322
+ const sourceKeys = keysOf(source);
323
+ const targetKeys = keysOf(resolvedTarget);
324
+ const targetKeySet = new Set(targetKeys);
325
+ const scope = { source, target: resolvedTarget, targetKeySet, basePath, sourceIsArray, invertible, out };
326
+ for (const key of Array.from(sourceKeys).reverse()) {
327
+ diffSourceKey(scope, key);
328
+ }
329
+ diffAddedKeys(resolvedTarget, sourceKeys, targetKeys, basePath, out);
330
+ };
331
+ const compare = (source, target, invertible = false) => {
332
+ const out = [];
333
+ diff(source, target, "", invertible, out);
334
+ return out;
335
+ };
336
+
250
337
  const isPlainObject = (val) => {
251
338
  if (Object.prototype.toString.call(val) !== "[object Object]") return false;
252
339
  const prot = Object.getPrototypeOf(val);
@@ -377,13 +464,13 @@ const updatePatch = async (opts, context, current, original) => {
377
464
  const currentObject = getJsonOmit(opts, current);
378
465
  const originalObject = getJsonOmit(opts, original);
379
466
  if (isEmpty(originalObject) || isEmpty(currentObject)) return;
380
- const patch = jsonpatch.compare(originalObject, currentObject, true);
467
+ const patch = compare(originalObject, currentObject, true);
381
468
  if (isEmpty(patch)) return;
382
469
  emitEvent(context, opts.eventUpdated, { oldDoc: original, doc: current, patch });
383
470
  if (history) {
384
471
  let version = 0;
385
472
  const lastHistory = await HistoryModel.findOne({ collectionId: original._id }).sort("-version").exec();
386
- if (lastHistory && lastHistory.version >= 0) {
473
+ if (lastHistory) {
387
474
  version = lastHistory.version + 1;
388
475
  }
389
476
  const [user, reason, metadata] = await getData(opts, current);
@@ -466,38 +553,202 @@ const saveHooksInitialize = (schema, opts) => {
466
553
  });
467
554
  };
468
555
 
556
+ const hasOwn = Object.prototype.hasOwnProperty;
557
+ const parseSegment = (segment) => {
558
+ const asNumber2 = Number(segment);
559
+ return Number.isInteger(asNumber2) && String(asNumber2) === segment ? asNumber2 : segment;
560
+ };
561
+ const parsePath = (path) => {
562
+ const [first, ...rest] = path.split(".").map(parseSegment);
563
+ let leaf = first ?? path;
564
+ const crumbs = [];
565
+ for (const key of rest) {
566
+ crumbs.push({ key: leaf, nextNumeric: typeof key === "number" });
567
+ leaf = key;
568
+ }
569
+ return { leaf, crumbs };
570
+ };
571
+ const deepEqualJson = (a, b) => {
572
+ try {
573
+ return JSON.stringify(a) === JSON.stringify(b);
574
+ } catch {
575
+ return a === b;
576
+ }
577
+ };
578
+ const ensureContainer = (parent, key, hintNumeric) => {
579
+ const existing = parent[key];
580
+ if (existing !== null && typeof existing === "object") {
581
+ return existing;
582
+ }
583
+ const created = hintNumeric ? [] : {};
584
+ parent[key] = created;
585
+ return created;
586
+ };
587
+ const setAtPath = (doc, path, value) => {
588
+ const { leaf, crumbs } = parsePath(path);
589
+ let cursor = doc;
590
+ for (const crumb of crumbs) {
591
+ cursor = ensureContainer(cursor, crumb.key, crumb.nextNumeric);
592
+ }
593
+ cursor[leaf] = value;
594
+ };
595
+ const getAtPath = (doc, path) => {
596
+ const { leaf, crumbs } = parsePath(path);
597
+ let cursor = doc;
598
+ for (const crumb of crumbs) {
599
+ const next = cursor[crumb.key];
600
+ if (next === null || typeof next !== "object") return void 0;
601
+ cursor = next;
602
+ }
603
+ return { container: cursor, leaf, exists: hasOwn.call(cursor, leaf) };
604
+ };
605
+ const unsetAtPath = (doc, path) => {
606
+ const located = getAtPath(doc, path);
607
+ if (!located) return;
608
+ if (Array.isArray(located.container)) {
609
+ located.container[located.leaf] = void 0;
610
+ } else {
611
+ delete located.container[located.leaf];
612
+ }
613
+ };
614
+ const asNumber = (value) => typeof value === "number" ? value : 0;
615
+ const toArray = (value) => Array.isArray(value) ? value : void 0;
616
+ const shouldReplaceForMin = (current, candidate) => {
617
+ if (candidate === void 0) return false;
618
+ if (current === void 0) return true;
619
+ return candidate < current;
620
+ };
621
+ const shouldReplaceForMax = (current, candidate) => {
622
+ if (candidate === void 0) return false;
623
+ if (current === void 0) return true;
624
+ return candidate > current;
625
+ };
626
+ const operators = {
627
+ $set: (doc, path, value) => setAtPath(doc, path, value),
628
+ $unset: (doc, path) => unsetAtPath(doc, path),
629
+ $inc: (doc, path, delta) => {
630
+ const located = getAtPath(doc, path);
631
+ const current = located?.exists ? asNumber(located.container[located.leaf]) : 0;
632
+ setAtPath(doc, path, current + asNumber(delta));
633
+ },
634
+ $mul: (doc, path, factor) => {
635
+ const located = getAtPath(doc, path);
636
+ const current = located?.exists ? asNumber(located.container[located.leaf]) : 0;
637
+ setAtPath(doc, path, current * asNumber(factor));
638
+ },
639
+ $min: (doc, path, candidate) => {
640
+ const located = getAtPath(doc, path);
641
+ if (!located?.exists) {
642
+ setAtPath(doc, path, candidate);
643
+ return;
644
+ }
645
+ if (shouldReplaceForMin(located.container[located.leaf], candidate)) {
646
+ setAtPath(doc, path, candidate);
647
+ }
648
+ },
649
+ $max: (doc, path, candidate) => {
650
+ const located = getAtPath(doc, path);
651
+ if (!located?.exists) {
652
+ setAtPath(doc, path, candidate);
653
+ return;
654
+ }
655
+ if (shouldReplaceForMax(located.container[located.leaf], candidate)) {
656
+ setAtPath(doc, path, candidate);
657
+ }
658
+ },
659
+ $rename: (doc, path, newPath) => {
660
+ if (typeof newPath !== "string") return;
661
+ const located = getAtPath(doc, path);
662
+ if (!located?.exists) return;
663
+ const value = located.container[located.leaf];
664
+ unsetAtPath(doc, path);
665
+ setAtPath(doc, newPath, value);
666
+ },
667
+ $currentDate: (doc, path, spec) => {
668
+ const wantTimestamp = typeof spec === "object" && spec !== null && spec.$type === "timestamp";
669
+ setAtPath(doc, path, wantTimestamp ? Date.now() : /* @__PURE__ */ new Date());
670
+ },
671
+ $push: (doc, path, pushSpec) => {
672
+ const located = getAtPath(doc, path);
673
+ const existing = located?.exists ? toArray(located.container[located.leaf]) ?? [] : [];
674
+ const next = [...existing];
675
+ if (typeof pushSpec === "object" && pushSpec !== null && "$each" in pushSpec && Array.isArray(pushSpec.$each)) {
676
+ next.push(...pushSpec.$each);
677
+ } else {
678
+ next.push(pushSpec);
679
+ }
680
+ setAtPath(doc, path, next);
681
+ },
682
+ $addToSet: (doc, path, item) => {
683
+ const located = getAtPath(doc, path);
684
+ const existing = located?.exists ? toArray(located.container[located.leaf]) ?? [] : [];
685
+ const next = [...existing];
686
+ const rawItems = typeof item === "object" && item !== null && "$each" in item ? item.$each : item;
687
+ const toAdd = Array.isArray(rawItems) ? rawItems : [rawItems];
688
+ for (const candidate of toAdd) {
689
+ if (!next.some((existingEntry) => deepEqualJson(existingEntry, candidate))) {
690
+ next.push(candidate);
691
+ }
692
+ }
693
+ setAtPath(doc, path, next);
694
+ },
695
+ $pull: (doc, path, matcher) => {
696
+ const located = getAtPath(doc, path);
697
+ const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
698
+ if (!existing) return;
699
+ const filtered = existing.filter((entry) => !deepEqualJson(entry, matcher));
700
+ setAtPath(doc, path, filtered);
701
+ },
702
+ $pullAll: (doc, path, values) => {
703
+ const located = getAtPath(doc, path);
704
+ const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
705
+ if (!existing || !Array.isArray(values)) return;
706
+ const filtered = existing.filter((entry) => !values.some((target) => deepEqualJson(entry, target)));
707
+ setAtPath(doc, path, filtered);
708
+ },
709
+ $pop: (doc, path, direction) => {
710
+ const located = getAtPath(doc, path);
711
+ const existing = located?.exists ? toArray(located.container[located.leaf]) : void 0;
712
+ if (!existing || existing.length === 0) return;
713
+ const next = direction === -1 ? existing.slice(1) : existing.slice(0, -1);
714
+ setAtPath(doc, path, next);
715
+ }
716
+ };
717
+ const applyOperator = (doc, operator, fields) => {
718
+ const fn = operators[operator];
719
+ if (!fn || fields === null || typeof fields !== "object") return;
720
+ for (const [path, argument] of Object.entries(fields)) {
721
+ fn(doc, path, argument);
722
+ }
723
+ };
724
+ const applyUpdate = (doc, update) => {
725
+ const result = { ...doc };
726
+ for (const [key, value] of Object.entries(update)) {
727
+ if (key.startsWith("$")) {
728
+ applyOperator(result, key, value);
729
+ } else {
730
+ setAtPath(result, key, value);
731
+ }
732
+ }
733
+ return result;
734
+ };
735
+
469
736
  const updateMethods = ["update", "updateOne", "replaceOne", "updateMany", "findOneAndUpdate", "findOneAndReplace", "findByIdAndUpdate"];
470
737
  const trackChangedFields = (fields, updated, changed) => {
471
738
  if (!fields) return;
472
739
  for (const key of Object.keys(fields)) {
473
- const root = key.split(".")[0];
740
+ const [root = key] = key.split(".");
474
741
  changed.set(root, updated[root]);
475
742
  }
476
743
  };
477
- const applyPullAll = (updated, fields, changed) => {
478
- for (const [field, values] of Object.entries(fields)) {
479
- const arr = updated[field];
480
- if (Array.isArray(arr)) {
481
- const filtered = arr.filter((item) => !values.some((v) => JSON.stringify(v) === JSON.stringify(item)));
482
- updated[field] = filtered;
483
- changed.set(field, filtered);
484
- }
485
- }
486
- };
487
744
  const assignUpdate = (document, update, commands) => {
488
- let updated = assign(document.toObject(toObjectOptions), update);
745
+ let updated = applyUpdate(document.toObject(toObjectOptions), update);
489
746
  const changedByCommand = /* @__PURE__ */ new Map();
490
747
  for (const command of commands) {
491
- const op = Object.keys(command)[0];
748
+ const [op = ""] = Object.keys(command);
492
749
  const fields = command[op];
493
- try {
494
- updated = assign(updated, command);
495
- trackChangedFields(fields, updated, changedByCommand);
496
- } catch {
497
- if (op === "$pullAll" && fields) {
498
- applyPullAll(updated, fields, changedByCommand);
499
- }
500
- }
750
+ updated = applyUpdate(updated, command);
751
+ trackChangedFields(fields, updated, changedByCommand);
501
752
  }
502
753
  const doc = document.set(updated).toObject(toObjectOptions);
503
754
  for (const [field, value] of changedByCommand) {
@@ -552,11 +803,14 @@ const updateHooksInitialize = (schema, opts) => {
552
803
  const updateQuery = this.getUpdate();
553
804
  const { update, commands } = splitUpdateAndCommands(updateQuery);
554
805
  const filter = this.getFilter();
555
- const candidates = [update, assignUpdate(model.hydrate({}), update, commands), filter];
806
+ const simulated = assignUpdate(model.hydrate({}), update, commands);
807
+ const simulatedFilter = Object.fromEntries(Object.entries(simulated).filter(([, v]) => v !== void 0));
808
+ const candidates = [update, simulatedFilter, filter];
556
809
  let current = null;
557
810
  for (const query of candidates) {
558
811
  if (current || isEmpty(query)) continue;
559
- current = await model.findOne(query).sort({ _id: -1 }).lean().exec();
812
+ const found = await model.findOne(query).sort({ _id: -1 }).lean().exec();
813
+ current = found;
560
814
  }
561
815
  if (current) {
562
816
  this._context.createdDocs = [current];
@@ -588,13 +842,14 @@ const patchHistoryPlugin = (schema, opts) => {
588
842
  await createPatch(opts, context);
589
843
  });
590
844
  if (isMongooseLessThan8) {
591
- schema.pre(remove, { document: true, query: false }, async function() {
845
+ const legacySchema = schema;
846
+ legacySchema.pre(remove, { document: true, query: false }, async function() {
592
847
  const original = this.toObject(toObjectOptions);
593
848
  if (opts.preDelete && !isEmpty(original)) {
594
849
  await opts.preDelete([original]);
595
850
  }
596
851
  });
597
- schema.post(remove, { document: true, query: false }, async function() {
852
+ legacySchema.post(remove, { document: true, query: false }, async function() {
598
853
  const original = this.toObject(toObjectOptions);
599
854
  const model = this.constructor;
600
855
  const context = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-patch-mongoose",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "Patch history & events for mongoose models",
5
5
  "author": "ilovepixelart",
6
6
  "license": "MIT",
@@ -12,9 +12,6 @@
12
12
  "url": "https://github.com/ilovepixelart/ts-patch-mongoose/issues"
13
13
  },
14
14
  "homepage": "https://github.com/ilovepixelart/ts-patch-mongoose#readme",
15
- "directories": {
16
- "examples": "examples"
17
- },
18
15
  "keywords": [
19
16
  "backend",
20
17
  "mongoose",
@@ -36,15 +33,10 @@
36
33
  "log"
37
34
  ],
38
35
  "engines": {
39
- "node": ">=18"
36
+ "node": ">=20"
40
37
  },
41
38
  "files": [
42
- "dist",
43
- "src",
44
- "tests",
45
- "tsconfig.json",
46
- "vite.config.mts",
47
- "biome.json"
39
+ "dist"
48
40
  ],
49
41
  "type": "module",
50
42
  "exports": {
@@ -60,32 +52,33 @@
60
52
  "main": "./dist/index.cjs",
61
53
  "module": "./dist/index.mjs",
62
54
  "types": "./dist/index.d.cts",
55
+ "publishConfig": {
56
+ "access": "public",
57
+ "provenance": true
58
+ },
63
59
  "scripts": {
64
- "prepare": "simple-git-hooks",
65
60
  "biome": "npx @biomejs/biome check",
66
61
  "biome:fix": "npx @biomejs/biome check --write .",
67
62
  "test": "vitest run --coverage",
68
63
  "test:open": "vitest run --coverage && open-cli coverage/lcov-report/index.html",
69
64
  "type:check": "tsc --noEmit",
65
+ "type:check:tests": "tsc --noEmit -p tests/tsconfig.json",
70
66
  "build": "pkgroll --clean-dist",
71
- "release": "npm install && npm run biome && npm run type:check && npm run build && np --no-publish"
72
- },
73
- "dependencies": {
74
- "fast-json-patch": "3.1.1",
75
- "power-assign": "0.2.10"
67
+ "release": "npm install && npm run biome && npm run type:check && npm run type:check:tests && npm run build && np --no-publish"
76
68
  },
77
69
  "devDependencies": {
78
- "@biomejs/biome": "2.4.9",
79
- "@types/node": "25.5.0",
80
- "@vitest/coverage-v8": "4.1.2",
70
+ "@biomejs/biome": "2.4.11",
71
+ "@types/node": "25.6.0",
72
+ "@vitest/coverage-v8": "4.1.4",
73
+ "fast-check": "4.6.0",
81
74
  "mongodb-memory-server": "11.0.1",
82
- "mongoose": "9.3.3",
83
- "np": "11.0.2",
75
+ "mongoose": "9.4.1",
76
+ "np": "11.0.3",
84
77
  "open-cli": "9.0.0",
85
78
  "pkgroll": "2.27.0",
86
79
  "simple-git-hooks": "2.13.1",
87
80
  "typescript": "5.9.3",
88
- "vitest": "4.1.2"
81
+ "vitest": "4.1.4"
89
82
  },
90
83
  "peerDependencies": {
91
84
  "mongoose": ">=6.6.0 < 10"
@@ -99,6 +92,8 @@
99
92
  },
100
93
  "overrides": {
101
94
  "tmp": "0.2.5",
102
- "file-type": "21.3.2"
95
+ "file-type": "21.3.2",
96
+ "lodash": "4.18.1",
97
+ "vite": "8.0.8"
103
98
  }
104
99
  }
package/biome.json DELETED
@@ -1,47 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/2.4.9/schema.json",
3
- "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
4
- "files": {
5
- "ignoreUnknown": false,
6
- "includes": ["src/**/*.ts", "tests/**/*.ts"]
7
- },
8
- "formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 },
9
- "assist": {
10
- "actions": {
11
- "source": {
12
- "organizeImports": {
13
- "level": "on",
14
- "options": {
15
- "groups": [
16
- "vitest",
17
- ":BLANK_LINE:",
18
- ":NODE:",
19
- { "type": false },
20
- ":BLANK_LINE:"
21
- ]
22
- }
23
- }
24
- }
25
- }
26
- },
27
- "linter": {
28
- "enabled": true,
29
- "rules": {
30
- "recommended": true
31
- }
32
- },
33
- "javascript": {
34
- "formatter": {
35
- "trailingCommas": "all",
36
- "quoteStyle": "single",
37
- "semicolons": "asNeeded",
38
- "lineWidth": 320
39
- },
40
- "globals": ["Atomics", "SharedArrayBuffer"]
41
- },
42
- "json": {
43
- "formatter": {
44
- "trailingCommas": "none"
45
- }
46
- }
47
- }
package/src/em.ts DELETED
@@ -1,6 +0,0 @@
1
- import EventEmitter from 'node:events'
2
-
3
- class PatchEventEmitter extends EventEmitter {}
4
- const em = new PatchEventEmitter()
5
-
6
- export default em