diff --git a/CLAUDE.md b/CLAUDE.md index d7c82d2b..eee3c8b9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -49,7 +49,6 @@ The library provides three main editor components in `/src/`: ### Dependencies - **ace-builds** - Modern Ace editor (replaces legacy brace) - **diff-match-patch** - Powers diff editor functionality -- **lodash.get**, **lodash.isequal** - Minimal lodash utilities - **prop-types** - Runtime type checking for older React versions ## Development Notes diff --git a/package-lock.json b/package-lock.json index b75096c3..4b034ff6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,7 @@ "dependencies": { "ace-builds": "^1.36.3", "diff-match-patch": "^1.0.5", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", + "fast-equals": "^5.3.3", "prop-types": "^15.8.1" }, "devDependencies": { @@ -26,9 +25,6 @@ "@testing-library/react": "^16.2.0", "@types/chai": "^4.3.14", "@types/diff-match-patch": "^1.0.36", - "@types/lodash": "^4.17.0", - "@types/lodash.get": "^4.4.9", - "@types/lodash.isequal": "^4.5.8", "@types/node": "^22.5.5", "@types/prop-types": "^15.7.12", "@types/react": "^19.0.8", @@ -3343,32 +3339,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", - "dev": true - }, - "node_modules/@types/lodash.get": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@types/lodash.get/-/lodash.get-4.4.9.tgz", - "integrity": "sha512-J5dvW98sxmGnamqf+/aLP87PYXyrha9xIgc2ZlHl6OHMFR2Ejdxep50QfU0abO1+CH6+ugx+8wEUN1toImAinA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, - "node_modules/@types/lodash.isequal": { - "version": "4.5.8", - "resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz", - "integrity": "sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, "node_modules/@types/node": { "version": "22.5.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", @@ -4261,6 +4231,15 @@ "node": ">=12.0.0" } }, + "node_modules/fast-equals": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.3.3.tgz", + "integrity": "sha512-/boTcHZeIAQ2r/tL11voclBHDeP9WPxLt+tyAbVSyyXuUFyh0Tne7gJZTqGbxnvj79TjLdCXLOY7UIPhyG5MTw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -4930,16 +4909,6 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", diff --git a/package.json b/package.json index c3ebf95a..ec7de2c0 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,6 @@ "@testing-library/react": "^16.2.0", "@types/chai": "^4.3.14", "@types/diff-match-patch": "^1.0.36", - "@types/lodash": "^4.17.0", - "@types/lodash.get": "^4.4.9", - "@types/lodash.isequal": "^4.5.8", "@types/node": "^22.5.5", "@types/prop-types": "^15.7.12", "@types/react": "^19.0.8", @@ -73,8 +70,7 @@ "dependencies": { "ace-builds": "^1.36.3", "diff-match-patch": "^1.0.5", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", + "fast-equals": "^5.3.3", "prop-types": "^15.8.1" }, "husky": { diff --git a/src/ace.tsx b/src/ace.tsx index 67156ce0..7c941358 100644 --- a/src/ace.tsx +++ b/src/ace.tsx @@ -3,7 +3,7 @@ import * as AceBuilds from "ace-builds"; import * as PropTypes from "prop-types"; import * as React from "react"; -import isEqual from "lodash.isequal"; +import { deepEqual } from "fast-equals"; import { debounce, @@ -415,22 +415,25 @@ export default class ReactAce extends React.Component { if (nextProps.showGutter !== oldProps.showGutter) { this.editor.renderer.setShowGutter(nextProps.showGutter); } - if (!isEqual(nextProps.setOptions, oldProps.setOptions)) { + if (!deepEqual(nextProps.setOptions, oldProps.setOptions)) { this.handleOptions(nextProps); } // if the value or annotations changed, set the annotations // changing the value may create create a new session which will require annotations to be re-set - if (valueChanged || !isEqual(nextProps.annotations, oldProps.annotations)) { + if ( + valueChanged || + !deepEqual(nextProps.annotations, oldProps.annotations) + ) { this.editor.getSession().setAnnotations(nextProps.annotations || []); } const oldMarkers = oldProps.markers || []; const nextMarkers = nextProps.markers || []; - if (!isEqual(oldMarkers, nextMarkers)) { + if (!deepEqual(oldMarkers, nextMarkers)) { this.handleMarkers(nextMarkers); } // this doesn't look like it works at all.... - if (!isEqual(nextProps.scrollMargin, oldProps.scrollMargin)) { + if (!deepEqual(nextProps.scrollMargin, oldProps.scrollMargin)) { this.handleScrollMargins(nextProps.scrollMargin); } diff --git a/src/split.tsx b/src/split.tsx index 173a5da9..0321b892 100644 --- a/src/split.tsx +++ b/src/split.tsx @@ -9,8 +9,7 @@ import { Ace, Range } from "ace-builds"; // oxlint-disable-line import { Split } from "ace-builds/src-noconflict/ext-split"; import * as PropTypes from "prop-types"; import * as React from "react"; -import isEqual from "lodash.isequal"; -import get from "lodash.get"; +import { deepEqual } from "fast-equals"; import { IAceEditor, IAceOptions, @@ -242,8 +241,8 @@ export default class SplitComponent extends React.Component { for (let i = 0; i < editorProps.length; i++) { editor[editorProps[i]] = this.props.editorProps[editorProps[i]]; } - const defaultValueForEditor = get(defaultValue, index); - const valueForEditor = get(value, index, ""); + const defaultValueForEditor = defaultValue?.[index]; + const valueForEditor = value?.[index] ?? ""; editor.session.setUndoManager(new ace.UndoManager()); editor.setTheme(`ace/theme/${theme}`); editor.renderer.setScrollMargin( @@ -274,8 +273,8 @@ export default class SplitComponent extends React.Component { : defaultValueForEditor, cursorStart ); - const newAnnotations = get(annotations, index, []); - const newMarkers = get(markers, index, []); + const newAnnotations = annotations?.[index] ?? []; + const newMarkers = markers?.[index] ?? []; editor.getSession().setAnnotations(newAnnotations); if (newMarkers && newMarkers.length > 0) { this.handleMarkers(newMarkers, editor); @@ -287,7 +286,7 @@ export default class SplitComponent extends React.Component { editor.setOption(option as any, this.props[option]); } else if (this.props[option]) { console.warn( - `ReaceAce: editor option ${option} was activated but not found. Did you need to import a related tool or did you possibly mispell the option?` + `ReactAce: editor option ${option} was activated but not found. Did you need to import a related tool or did you possibly misspell the option?` ); } } @@ -374,10 +373,10 @@ export default class SplitComponent extends React.Component { editor.setOption(option as any, nextProps[option]); } } - if (!isEqual(nextProps.setOptions, oldProps.setOptions)) { + if (!deepEqual(nextProps.setOptions, oldProps.setOptions)) { this.handleOptions(nextProps, editor); } - const nextValue = get(nextProps.value, index, ""); + const nextValue = nextProps.value?.[index] ?? ""; if (editor.getValue() !== nextValue) { // editor.setValue is a synchronous function call, change event is emitted before setValue return. this.silent = true; @@ -386,15 +385,15 @@ export default class SplitComponent extends React.Component { (editor.session.selection as any).fromJSON(pos); this.silent = false; } - const newAnnotations = get(nextProps.annotations, index, []); - const oldAnnotations = get(oldProps.annotations, index, []); - if (!isEqual(newAnnotations, oldAnnotations)) { + const newAnnotations = nextProps.annotations?.[index] ?? []; + const oldAnnotations = oldProps.annotations?.[index] ?? []; + if (!deepEqual(newAnnotations, oldAnnotations)) { editor.getSession().setAnnotations(newAnnotations); } - const newMarkers = get(nextProps.markers, index, []); - const oldMarkers = get(oldProps.markers, index, []); - if (!isEqual(newMarkers, oldMarkers) && Array.isArray(newMarkers)) { + const newMarkers = nextProps.markers?.[index] ?? []; + const oldMarkers = oldProps.markers?.[index] ?? []; + if (!deepEqual(newMarkers, oldMarkers) && Array.isArray(newMarkers)) { this.handleMarkers(newMarkers, editor); } });