@manuscripts/track-changes-plugin 0.0.4 → 0.1.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.
- package/dist/index.es.js +25 -13
- package/dist/index.js +25 -13
- package/dist/plugin.d.ts +2 -2
- package/dist/track/deleteNode.d.ts +1 -1
- package/dist/track/steps/deleteAndMergeSplitNodes.d.ts +1 -1
- package/dist/track/steps/setFragmentAsInserted.d.ts +1 -1
- package/dist/track/trackTransaction.d.ts +1 -1
- package/package.json +14 -18
package/dist/index.es.js
CHANGED
|
@@ -327,8 +327,9 @@ function deleteNode(node, pos, tr) {
|
|
|
327
327
|
var _a;
|
|
328
328
|
const startPos = tr.doc.resolve(pos + 1);
|
|
329
329
|
const range = startPos.blockRange(tr.doc.resolve(startPos.pos - 2 + node.nodeSize));
|
|
330
|
-
const targetDepth = range
|
|
331
|
-
|
|
330
|
+
const targetDepth = range && liftTarget(range);
|
|
331
|
+
// Check with typeof since with old prosemirror-transform targetDepth is undefined
|
|
332
|
+
if (range && typeof targetDepth === 'number') {
|
|
332
333
|
return tr.lift(range, targetDepth);
|
|
333
334
|
}
|
|
334
335
|
const resPos = tr.doc.resolve(pos);
|
|
@@ -505,7 +506,7 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new Mappi
|
|
|
505
506
|
// or were already deleted by an applied block delete
|
|
506
507
|
const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
|
|
507
508
|
if (!node) {
|
|
508
|
-
log.warn('no node found to update for change', change);
|
|
509
|
+
!deleted && log.warn('no node found to update for change', change);
|
|
509
510
|
return;
|
|
510
511
|
}
|
|
511
512
|
if (ChangeSet.isTextChange(change) && noChangeNeeded) {
|
|
@@ -929,6 +930,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
929
930
|
// But from what I remember what it safeguards against is, when you've already deleted a node
|
|
930
931
|
// say an inserted blockquote that had all its children deleted, nodesBetween still iterates over those
|
|
931
932
|
// nodes and therefore we have to make this check to ensure they still exist in the doc.
|
|
933
|
+
//
|
|
932
934
|
if (nodeEnd > offsetFrom && !nodeWasDeleted && !wasWithinGap) {
|
|
933
935
|
// |<p>asdf</p>| -> node deleted completely
|
|
934
936
|
const nodeCompletelyDeleted = offsetPos >= offsetFrom && nodeEnd <= offsetTo;
|
|
@@ -1209,11 +1211,9 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1209
1211
|
* This skips the direct dependency to prosemirror-state where multiple versions might cause conflicts
|
|
1210
1212
|
* as the created instances might belong to different prosemirror-state import than one used in the editor.
|
|
1211
1213
|
* @param sel
|
|
1212
|
-
* @param doc
|
|
1213
|
-
* @param from
|
|
1214
1214
|
* @returns
|
|
1215
1215
|
*/
|
|
1216
|
-
const
|
|
1216
|
+
const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
|
|
1217
1217
|
/**
|
|
1218
1218
|
* Inverts transactions to wrap their contents/operations with track data instead
|
|
1219
1219
|
*
|
|
@@ -1257,7 +1257,12 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1257
1257
|
else if (step instanceof ReplaceStep) {
|
|
1258
1258
|
const selectionPos = trackReplaceStep(step, oldState, newTr, emptyAttrs);
|
|
1259
1259
|
if (!wasNodeSelection) {
|
|
1260
|
-
|
|
1260
|
+
const sel = getSelectionStaticConstructor(tr.selection);
|
|
1261
|
+
// Use Selection.near to fix selections that point to a block node instead of inline content
|
|
1262
|
+
// eg when inserting a complete new paragraph. -1 finds the first valid position moving backwards
|
|
1263
|
+
// inside the content
|
|
1264
|
+
const near = sel.near(newTr.doc.resolve(selectionPos), -1);
|
|
1265
|
+
newTr.setSelection(near);
|
|
1261
1266
|
}
|
|
1262
1267
|
}
|
|
1263
1268
|
else if (step instanceof ReplaceAroundStep) {
|
|
@@ -1265,10 +1270,15 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1265
1270
|
// } else if (step instanceof AddMarkStep) {
|
|
1266
1271
|
// } else if (step instanceof RemoveMarkStep) {
|
|
1267
1272
|
}
|
|
1273
|
+
// TODO: here we could check whether adjacent inserts & deletes cancel each other out.
|
|
1274
|
+
// However, this should not be done by diffing and only matching node or char by char instead since
|
|
1275
|
+
// it's A easier and B more intuitive to user.
|
|
1268
1276
|
// The old meta keys are not copied to the new transaction since this will cause race-conditions
|
|
1269
|
-
// when a single meta-field is
|
|
1270
|
-
// inputType
|
|
1271
|
-
//
|
|
1277
|
+
// when a single meta-field is expected to having been processed / removed. Generic input meta keys,
|
|
1278
|
+
// inputType and uiEvent, are re-added since some plugins might depend on them and process the transaction
|
|
1279
|
+
// after track-changes plugin.
|
|
1280
|
+
tr.getMeta('inputType') && newTr.setMeta('inputType', tr.getMeta('inputType'));
|
|
1281
|
+
tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
|
|
1272
1282
|
});
|
|
1273
1283
|
// This is kinda hacky solution at the moment to maintain NodeSelections over transactions
|
|
1274
1284
|
// These are required by at least cross-references that need it to activate the selector pop-up
|
|
@@ -1276,7 +1286,8 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1276
1286
|
const mappedPos = newTr.mapping.map(tr.selection.from);
|
|
1277
1287
|
const resPos = newTr.doc.resolve(mappedPos);
|
|
1278
1288
|
const nodePos = mappedPos - (((_a = resPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.nodeSize) || 0);
|
|
1279
|
-
|
|
1289
|
+
const sel = getSelectionStaticConstructor(tr.selection);
|
|
1290
|
+
newTr.setSelection(sel.create(newTr.doc, nodePos));
|
|
1280
1291
|
}
|
|
1281
1292
|
log.info('NEW transaction', newTr);
|
|
1282
1293
|
return newTr;
|
|
@@ -1326,7 +1337,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1326
1337
|
key: trackChangesPluginKey,
|
|
1327
1338
|
props: {
|
|
1328
1339
|
editable(state) {
|
|
1329
|
-
|
|
1340
|
+
var _a;
|
|
1341
|
+
return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !== TrackChangesStatus.viewSnapshots;
|
|
1330
1342
|
},
|
|
1331
1343
|
},
|
|
1332
1344
|
state: {
|
|
@@ -1396,7 +1408,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1396
1408
|
(wasAppended && getAction(wasAppended, TrackChangesAction.skipTrack));
|
|
1397
1409
|
if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$')) {
|
|
1398
1410
|
createdTr = trackTransaction(tr, oldState, createdTr, userID);
|
|
1399
|
-
createdTr.setMeta('origin', trackChangesPluginKey);
|
|
1400
1411
|
infiniteLoopCounter.iters += 1;
|
|
1401
1412
|
}
|
|
1402
1413
|
docChanged = docChanged || tr.docChanged;
|
|
@@ -1423,6 +1434,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1423
1434
|
log.warn('had to fix inconsistent changes in', createdTr);
|
|
1424
1435
|
}
|
|
1425
1436
|
if (docChanged || createdTr.docChanged || changed) {
|
|
1437
|
+
createdTr.setMeta('origin', trackChangesPluginKey);
|
|
1426
1438
|
return setAction(createdTr, TrackChangesAction.refreshChanges, true);
|
|
1427
1439
|
}
|
|
1428
1440
|
return null;
|
package/dist/index.js
CHANGED
|
@@ -335,8 +335,9 @@ function deleteNode(node, pos, tr) {
|
|
|
335
335
|
var _a;
|
|
336
336
|
const startPos = tr.doc.resolve(pos + 1);
|
|
337
337
|
const range = startPos.blockRange(tr.doc.resolve(startPos.pos - 2 + node.nodeSize));
|
|
338
|
-
const targetDepth = range
|
|
339
|
-
|
|
338
|
+
const targetDepth = range && prosemirrorTransform.liftTarget(range);
|
|
339
|
+
// Check with typeof since with old prosemirror-transform targetDepth is undefined
|
|
340
|
+
if (range && typeof targetDepth === 'number') {
|
|
340
341
|
return tr.lift(range, targetDepth);
|
|
341
342
|
}
|
|
342
343
|
const resPos = tr.doc.resolve(pos);
|
|
@@ -513,7 +514,7 @@ function applyAcceptedRejectedChanges(tr, schema, changes, deleteMap = new prose
|
|
|
513
514
|
// or were already deleted by an applied block delete
|
|
514
515
|
const { pos: from, deleted } = deleteMap.mapResult(change.from), node = tr.doc.nodeAt(from), noChangeNeeded = deleted || ChangeSet.shouldNotDelete(change);
|
|
515
516
|
if (!node) {
|
|
516
|
-
log.warn('no node found to update for change', change);
|
|
517
|
+
!deleted && log.warn('no node found to update for change', change);
|
|
517
518
|
return;
|
|
518
519
|
}
|
|
519
520
|
if (ChangeSet.isTextChange(change) && noChangeNeeded) {
|
|
@@ -937,6 +938,7 @@ function deleteAndMergeSplitNodes(from, to, gap, startDoc, newTr, schema, trackA
|
|
|
937
938
|
// But from what I remember what it safeguards against is, when you've already deleted a node
|
|
938
939
|
// say an inserted blockquote that had all its children deleted, nodesBetween still iterates over those
|
|
939
940
|
// nodes and therefore we have to make this check to ensure they still exist in the doc.
|
|
941
|
+
//
|
|
940
942
|
if (nodeEnd > offsetFrom && !nodeWasDeleted && !wasWithinGap) {
|
|
941
943
|
// |<p>asdf</p>| -> node deleted completely
|
|
942
944
|
const nodeCompletelyDeleted = offsetPos >= offsetFrom && nodeEnd <= offsetTo;
|
|
@@ -1217,11 +1219,9 @@ function trackReplaceStep(step, oldState, newTr, attrs) {
|
|
|
1217
1219
|
* This skips the direct dependency to prosemirror-state where multiple versions might cause conflicts
|
|
1218
1220
|
* as the created instances might belong to different prosemirror-state import than one used in the editor.
|
|
1219
1221
|
* @param sel
|
|
1220
|
-
* @param doc
|
|
1221
|
-
* @param from
|
|
1222
1222
|
* @returns
|
|
1223
1223
|
*/
|
|
1224
|
-
const
|
|
1224
|
+
const getSelectionStaticConstructor = (sel) => Object.getPrototypeOf(sel).constructor;
|
|
1225
1225
|
/**
|
|
1226
1226
|
* Inverts transactions to wrap their contents/operations with track data instead
|
|
1227
1227
|
*
|
|
@@ -1265,7 +1265,12 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1265
1265
|
else if (step instanceof prosemirrorTransform.ReplaceStep) {
|
|
1266
1266
|
const selectionPos = trackReplaceStep(step, oldState, newTr, emptyAttrs);
|
|
1267
1267
|
if (!wasNodeSelection) {
|
|
1268
|
-
|
|
1268
|
+
const sel = getSelectionStaticConstructor(tr.selection);
|
|
1269
|
+
// Use Selection.near to fix selections that point to a block node instead of inline content
|
|
1270
|
+
// eg when inserting a complete new paragraph. -1 finds the first valid position moving backwards
|
|
1271
|
+
// inside the content
|
|
1272
|
+
const near = sel.near(newTr.doc.resolve(selectionPos), -1);
|
|
1273
|
+
newTr.setSelection(near);
|
|
1269
1274
|
}
|
|
1270
1275
|
}
|
|
1271
1276
|
else if (step instanceof prosemirrorTransform.ReplaceAroundStep) {
|
|
@@ -1273,10 +1278,15 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1273
1278
|
// } else if (step instanceof AddMarkStep) {
|
|
1274
1279
|
// } else if (step instanceof RemoveMarkStep) {
|
|
1275
1280
|
}
|
|
1281
|
+
// TODO: here we could check whether adjacent inserts & deletes cancel each other out.
|
|
1282
|
+
// However, this should not be done by diffing and only matching node or char by char instead since
|
|
1283
|
+
// it's A easier and B more intuitive to user.
|
|
1276
1284
|
// The old meta keys are not copied to the new transaction since this will cause race-conditions
|
|
1277
|
-
// when a single meta-field is
|
|
1278
|
-
// inputType
|
|
1279
|
-
//
|
|
1285
|
+
// when a single meta-field is expected to having been processed / removed. Generic input meta keys,
|
|
1286
|
+
// inputType and uiEvent, are re-added since some plugins might depend on them and process the transaction
|
|
1287
|
+
// after track-changes plugin.
|
|
1288
|
+
tr.getMeta('inputType') && newTr.setMeta('inputType', tr.getMeta('inputType'));
|
|
1289
|
+
tr.getMeta('uiEvent') && newTr.setMeta('uiEvent', tr.getMeta('uiEvent'));
|
|
1280
1290
|
});
|
|
1281
1291
|
// This is kinda hacky solution at the moment to maintain NodeSelections over transactions
|
|
1282
1292
|
// These are required by at least cross-references that need it to activate the selector pop-up
|
|
@@ -1284,7 +1294,8 @@ function trackTransaction(tr, oldState, newTr, userID) {
|
|
|
1284
1294
|
const mappedPos = newTr.mapping.map(tr.selection.from);
|
|
1285
1295
|
const resPos = newTr.doc.resolve(mappedPos);
|
|
1286
1296
|
const nodePos = mappedPos - (((_a = resPos.nodeBefore) === null || _a === void 0 ? void 0 : _a.nodeSize) || 0);
|
|
1287
|
-
|
|
1297
|
+
const sel = getSelectionStaticConstructor(tr.selection);
|
|
1298
|
+
newTr.setSelection(sel.create(newTr.doc, nodePos));
|
|
1288
1299
|
}
|
|
1289
1300
|
log.info('NEW transaction', newTr);
|
|
1290
1301
|
return newTr;
|
|
@@ -1334,7 +1345,8 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1334
1345
|
key: trackChangesPluginKey,
|
|
1335
1346
|
props: {
|
|
1336
1347
|
editable(state) {
|
|
1337
|
-
|
|
1348
|
+
var _a;
|
|
1349
|
+
return ((_a = trackChangesPluginKey.getState(state)) === null || _a === void 0 ? void 0 : _a.status) !== exports.TrackChangesStatus.viewSnapshots;
|
|
1338
1350
|
},
|
|
1339
1351
|
},
|
|
1340
1352
|
state: {
|
|
@@ -1404,7 +1416,6 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1404
1416
|
(wasAppended && getAction(wasAppended, exports.TrackChangesAction.skipTrack));
|
|
1405
1417
|
if (tr.docChanged && !skipMetaUsed && !skipTrackUsed && !tr.getMeta('history$')) {
|
|
1406
1418
|
createdTr = trackTransaction(tr, oldState, createdTr, userID);
|
|
1407
|
-
createdTr.setMeta('origin', trackChangesPluginKey);
|
|
1408
1419
|
infiniteLoopCounter.iters += 1;
|
|
1409
1420
|
}
|
|
1410
1421
|
docChanged = docChanged || tr.docChanged;
|
|
@@ -1431,6 +1442,7 @@ const trackChangesPlugin = (opts = { userID: 'anonymous:Anonymous' }) => {
|
|
|
1431
1442
|
log.warn('had to fix inconsistent changes in', createdTr);
|
|
1432
1443
|
}
|
|
1433
1444
|
if (docChanged || createdTr.docChanged || changed) {
|
|
1445
|
+
createdTr.setMeta('origin', trackChangesPluginKey);
|
|
1434
1446
|
return setAction(createdTr, exports.TrackChangesAction.refreshChanges, true);
|
|
1435
1447
|
}
|
|
1436
1448
|
return null;
|
package/dist/plugin.d.ts
CHANGED
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { Plugin, PluginKey } from 'prosemirror-state';
|
|
17
17
|
import { TrackChangesOptions, TrackChangesState } from './types/track';
|
|
18
|
-
export declare const trackChangesPluginKey: PluginKey<TrackChangesState
|
|
18
|
+
export declare const trackChangesPluginKey: PluginKey<TrackChangesState>;
|
|
19
19
|
/**
|
|
20
20
|
* The ProseMirror plugin needed to enable track-changes.
|
|
21
21
|
*
|
|
22
22
|
* Accepts an empty options object as an argument but note that this uses 'anonymous:Anonymous' as the default userID.
|
|
23
23
|
* @param opts
|
|
24
24
|
*/
|
|
25
|
-
export declare const trackChangesPlugin: (opts?: TrackChangesOptions) => Plugin<TrackChangesState
|
|
25
|
+
export declare const trackChangesPlugin: (opts?: TrackChangesOptions) => Plugin<TrackChangesState>;
|
|
@@ -24,4 +24,4 @@ import { Transaction } from 'prosemirror-state';
|
|
|
24
24
|
* @param tr
|
|
25
25
|
* @returns
|
|
26
26
|
*/
|
|
27
|
-
export declare function deleteNode(node: PMNode, pos: number, tr: Transaction): Transaction
|
|
27
|
+
export declare function deleteNode(node: PMNode, pos: number, tr: Transaction): Transaction;
|
|
@@ -49,5 +49,5 @@ export declare function deleteAndMergeSplitNodes(from: number, to: number, gap:
|
|
|
49
49
|
} | undefined, startDoc: PMNode, newTr: Transaction, schema: Schema, trackAttrs: NewEmptyAttrs, insertSlice: ExposedSlice): {
|
|
50
50
|
deleteMap: Mapping;
|
|
51
51
|
mergedInsertPos: undefined;
|
|
52
|
-
newSliceContent: Fragment
|
|
52
|
+
newSliceContent: Fragment;
|
|
53
53
|
};
|
|
@@ -15,4 +15,4 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { Fragment, Schema } from 'prosemirror-model';
|
|
17
17
|
import { NewInsertAttrs } from '../../types/track';
|
|
18
|
-
export declare function setFragmentAsInserted(inserted: Fragment, insertAttrs: NewInsertAttrs, schema: Schema): Fragment
|
|
18
|
+
export declare function setFragmentAsInserted(inserted: Fragment, insertAttrs: NewInsertAttrs, schema: Schema): Fragment;
|
|
@@ -14,4 +14,4 @@ import type { EditorState, Transaction } from 'prosemirror-state';
|
|
|
14
14
|
* @param userID User id
|
|
15
15
|
* @returns newTr that inverts the initial tr and applies track attributes/marks
|
|
16
16
|
*/
|
|
17
|
-
export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, userID: string): Transaction
|
|
17
|
+
export declare function trackTransaction(tr: Transaction, oldState: EditorState, newTr: Transaction, userID: string): Transaction;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manuscripts/track-changes-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"author": "Atypon Systems LLC",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/Atypon-OpenSource/manuscripts-quarterback/tree/main/quarterback-packages/track-changes-plugin",
|
|
@@ -21,30 +21,25 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
+
"@manuscripts/manuscript-transform": "^0.49.1",
|
|
24
25
|
"@rollup/plugin-commonjs": "^22.0.0",
|
|
25
26
|
"@types/debug": "^4.1.7",
|
|
26
27
|
"@types/jest": "27.5.1",
|
|
27
28
|
"@types/node": "^17.0.35",
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"@types/prosemirror-schema-list": "^1.0.3",
|
|
31
|
-
"@types/prosemirror-state": "^1.3.0",
|
|
32
|
-
"@types/prosemirror-transform": "^1.4.1",
|
|
33
|
-
"@types/prosemirror-view": "^1.23.3",
|
|
34
|
-
"jest": "28.1.0",
|
|
35
|
-
"jest-environment-jsdom": "28.1.0",
|
|
29
|
+
"jest": "27.5.1",
|
|
30
|
+
"jest-environment-jsdom": "27.5.1",
|
|
36
31
|
"jsdom": "^19.0.0",
|
|
37
|
-
"prosemirror-commands": "^1.
|
|
38
|
-
"prosemirror-example-setup": "^1.1
|
|
39
|
-
"prosemirror-keymap": "^1.
|
|
40
|
-
"prosemirror-model": "^1.
|
|
41
|
-
"prosemirror-schema-list": "^1.
|
|
42
|
-
"prosemirror-state": "^1.
|
|
43
|
-
"prosemirror-transform": "^1.
|
|
44
|
-
"prosemirror-view": "^1.
|
|
32
|
+
"prosemirror-commands": "^1.3.0",
|
|
33
|
+
"prosemirror-example-setup": "^1.2.1",
|
|
34
|
+
"prosemirror-keymap": "^1.2.0",
|
|
35
|
+
"prosemirror-model": "^1.18.1",
|
|
36
|
+
"prosemirror-schema-list": "^1.2.0",
|
|
37
|
+
"prosemirror-state": "^1.4.1",
|
|
38
|
+
"prosemirror-transform": "^1.6.0",
|
|
39
|
+
"prosemirror-view": "^1.26.2",
|
|
45
40
|
"rollup": "^2.74.0",
|
|
46
41
|
"rollup-plugin-typescript2": "^0.31.2",
|
|
47
|
-
"ts-jest": "
|
|
42
|
+
"ts-jest": "27.1.4",
|
|
48
43
|
"tslib": "^2.4.0",
|
|
49
44
|
"typescript": "^4.6.4"
|
|
50
45
|
},
|
|
@@ -62,6 +57,7 @@
|
|
|
62
57
|
"watch": "rollup -cw",
|
|
63
58
|
"test": "jest --runInBand",
|
|
64
59
|
"format": "prettier --write \"*.+(js|json|yml|yaml|ts|md|graphql|mdx)\" src/ test/",
|
|
60
|
+
"typecheck": "tsc --project tsconfig.test.json --noEmit",
|
|
65
61
|
"lint": "eslint --cache --ext .js,.ts, ./src ./test",
|
|
66
62
|
"lint:fix": "eslint --fix --ext .js,.ts, ./src ./test"
|
|
67
63
|
}
|