@eslint/json 0.14.0 → 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.
@@ -0,0 +1,139 @@
1
+ /**
2
+ * @fileoverview Rule to detect unsafe values in JSON.
3
+ * @author Bradley Meck Farias
4
+ */
5
+ //-----------------------------------------------------------------------------
6
+ // Type Definitions
7
+ //-----------------------------------------------------------------------------
8
+ /**
9
+ * @import { JSONRuleDefinition } from "../types.js";
10
+ * @typedef {"unsafeNumber"|"unsafeInteger"|"unsafeZero"|"subnormal"|"loneSurrogate"} NoUnsafeValuesMessageIds
11
+ * @typedef {JSONRuleDefinition<{ MessageIds: NoUnsafeValuesMessageIds }>} NoUnsafeValuesRuleDefinition
12
+ */
13
+ //-----------------------------------------------------------------------------
14
+ // Helpers
15
+ //-----------------------------------------------------------------------------
16
+ /*
17
+ * This rule is based on the JSON grammar from RFC 8259, section 6.
18
+ * https://tools.ietf.org/html/rfc8259#section-6
19
+ *
20
+ * Also, this rule is based on the JSON5 grammar from json5.org, section 6.
21
+ * https://spec.json5.org/#numbers
22
+ *
23
+ * We separately capture the integer and fractional parts of a number, so that
24
+ * we can check for unsafe numbers that will evaluate to Infinity.
25
+ */
26
+ const NUMBER = /^[+-]?(?<int>0|([1-9]\d*))?(?:\.(?<frac>\d*))?(?:e[+-]?\d+)?$/iu;
27
+ const NON_ZERO = /[1-9]/u;
28
+ //-----------------------------------------------------------------------------
29
+ // Rule Definition
30
+ //-----------------------------------------------------------------------------
31
+ /** @type {NoUnsafeValuesRuleDefinition} */
32
+ const rule = {
33
+ meta: {
34
+ type: "problem",
35
+ docs: {
36
+ recommended: true,
37
+ description: "Disallow JSON values that are unsafe for interchange",
38
+ url: "https://github.com/eslint/json/tree/main/docs/rules/no-unsafe-values.md",
39
+ },
40
+ messages: {
41
+ unsafeNumber: "The number '{{ value }}' will evaluate to Infinity.",
42
+ unsafeInteger: "The integer '{{ value }}' is outside the safe integer range.",
43
+ unsafeZero: "The number '{{ value }}' will evaluate to zero.",
44
+ subnormal: "Unexpected subnormal number '{{ value }}' found, which may cause interoperability issues.",
45
+ loneSurrogate: "Lone surrogate '{{ surrogate }}' found.",
46
+ },
47
+ },
48
+ create(context) {
49
+ return {
50
+ Number(node) {
51
+ const value = context.sourceCode.getText(node);
52
+ if (Number.isFinite(node.value) !== true) {
53
+ context.report({
54
+ loc: node.loc,
55
+ messageId: "unsafeNumber",
56
+ data: { value },
57
+ });
58
+ }
59
+ else {
60
+ // Also matches -0, intentionally
61
+ if (node.value === 0) {
62
+ // If the value has been rounded down to 0, but there was some
63
+ // fraction or non-zero part before the e-, this is a very small
64
+ // number that doesn't fit inside an f64.
65
+ const match = value.match(NUMBER);
66
+ if (match === null) {
67
+ return;
68
+ }
69
+ // If any part of the number other than the exponent has a
70
+ // non-zero digit in it, this number was not intended to be
71
+ // evaluated down to a zero.
72
+ if (NON_ZERO.test(match.groups.int) ||
73
+ NON_ZERO.test(match.groups.frac)) {
74
+ context.report({
75
+ loc: node.loc,
76
+ messageId: "unsafeZero",
77
+ data: { value },
78
+ });
79
+ }
80
+ }
81
+ else if (!/[.e]/iu.test(value)) {
82
+ // Intended to be an integer
83
+ if (node.value > Number.MAX_SAFE_INTEGER ||
84
+ node.value < Number.MIN_SAFE_INTEGER) {
85
+ context.report({
86
+ loc: node.loc,
87
+ messageId: "unsafeInteger",
88
+ data: { value },
89
+ });
90
+ }
91
+ }
92
+ else {
93
+ // Floating point. Check for subnormal.
94
+ const buffer = new ArrayBuffer(8);
95
+ const view = new DataView(buffer);
96
+ view.setFloat64(0, node.value, false);
97
+ const asBigInt = view.getBigUint64(0, false);
98
+ // Subnormals have an 11-bit exponent of 0 and a non-zero mantissa.
99
+ if ((asBigInt & 0x7ff0000000000000n) === 0n) {
100
+ context.report({
101
+ loc: node.loc,
102
+ messageId: "subnormal",
103
+ // Value included so that it's seen in scientific notation
104
+ data: {
105
+ value,
106
+ },
107
+ });
108
+ }
109
+ }
110
+ }
111
+ },
112
+ String(node) {
113
+ if (node.value.isWellFormed) {
114
+ if (node.value.isWellFormed()) {
115
+ return;
116
+ }
117
+ }
118
+ // match any high surrogate and, if it exists, a paired low surrogate
119
+ // match any low surrogate not already matched
120
+ const surrogatePattern = /[\uD800-\uDBFF][\uDC00-\uDFFF]?|[\uDC00-\uDFFF]/gu;
121
+ /** @type {RegExpExecArray | null} */
122
+ let match;
123
+ while ((match = surrogatePattern.exec(node.value)) !== null) {
124
+ // only need to report non-paired surrogates
125
+ if (match[0].length < 2) {
126
+ context.report({
127
+ loc: node.loc,
128
+ messageId: "loneSurrogate",
129
+ data: {
130
+ surrogate: JSON.stringify(match[0]).slice(1, -1),
131
+ },
132
+ });
133
+ }
134
+ }
135
+ },
136
+ };
137
+ },
138
+ };
139
+ export default rule;
@@ -0,0 +1,34 @@
1
+ export default rule;
2
+ export type SortOptions = {
3
+ /**
4
+ * Whether key comparisons are case-sensitive.
5
+ */
6
+ caseSensitive: boolean;
7
+ /**
8
+ * Whether to use natural sort order instead of purely alphanumeric.
9
+ */
10
+ natural: boolean;
11
+ /**
12
+ * Minimum number of keys in an object before enforcing sorting.
13
+ */
14
+ minKeys: number;
15
+ /**
16
+ * Whether a blank line between properties starts a new group that is independently sorted.
17
+ */
18
+ allowLineSeparatedGroups: boolean;
19
+ };
20
+ export type SortKeysMessageIds = "sortKeys";
21
+ export type SortDirection = "asc" | "desc";
22
+ export type SortKeysRuleOptions = [SortDirection, SortOptions];
23
+ export type SortKeysRuleDefinition = JSONRuleDefinition<{
24
+ RuleOptions: SortKeysRuleOptions;
25
+ MessageIds: SortKeysMessageIds;
26
+ }>;
27
+ export type Comparator = (a: string, b: string) => boolean;
28
+ export type DirectionName = "ascending" | "descending";
29
+ export type SortName = "alphanumeric" | "natural";
30
+ export type Sensitivity = "sensitive" | "insensitive";
31
+ export type ComparatorMap = Record<DirectionName, Record<SortName, Record<Sensitivity, Comparator>>>;
32
+ /** @type {SortKeysRuleDefinition} */
33
+ declare const rule: SortKeysRuleDefinition;
34
+ import type { JSONRuleDefinition } from "../types.js";
@@ -0,0 +1,185 @@
1
+ /**
2
+ * @fileoverview Rule to require JSON object keys to be sorted.
3
+ * Copied largely from https://github.com/eslint/eslint/blob/main/lib/rules/sort-keys.js
4
+ * @author Robin Thomas
5
+ */
6
+ //-----------------------------------------------------------------------------
7
+ // Imports
8
+ //-----------------------------------------------------------------------------
9
+ import naturalCompare from "natural-compare";
10
+ import { getKey, getRawKey } from "../util.js";
11
+ //-----------------------------------------------------------------------------
12
+ // Type Definitions
13
+ //-----------------------------------------------------------------------------
14
+ /**
15
+ * @import { JSONRuleDefinition } from "../types.js";
16
+ * @import { MemberNode } from "@humanwhocodes/momoa";
17
+ * @typedef {Object} SortOptions
18
+ * @property {boolean} caseSensitive Whether key comparisons are case-sensitive.
19
+ * @property {boolean} natural Whether to use natural sort order instead of purely alphanumeric.
20
+ * @property {number} minKeys Minimum number of keys in an object before enforcing sorting.
21
+ * @property {boolean} allowLineSeparatedGroups Whether a blank line between properties starts a new group that is independently sorted.
22
+ * @typedef {"sortKeys"} SortKeysMessageIds
23
+ * @typedef {"asc"|"desc"} SortDirection
24
+ * @typedef {[SortDirection, SortOptions]} SortKeysRuleOptions
25
+ * @typedef {JSONRuleDefinition<{ RuleOptions: SortKeysRuleOptions, MessageIds: SortKeysMessageIds }>} SortKeysRuleDefinition
26
+ * @typedef {(a:string,b:string) => boolean} Comparator
27
+ * @typedef {"ascending"|"descending"} DirectionName
28
+ * @typedef {"alphanumeric"|"natural"} SortName
29
+ * @typedef {"sensitive"|"insensitive"} Sensitivity
30
+ * @typedef {Record<DirectionName, Record<SortName, Record<Sensitivity, Comparator>>>} ComparatorMap
31
+ */
32
+ //-----------------------------------------------------------------------------
33
+ // Helpers
34
+ //-----------------------------------------------------------------------------
35
+ const hasNonWhitespace = /\S/u;
36
+ /** @type {ComparatorMap} */
37
+ const comparators = {
38
+ ascending: {
39
+ alphanumeric: {
40
+ sensitive: (a, b) => a <= b,
41
+ insensitive: (a, b) => a.toLowerCase() <= b.toLowerCase(),
42
+ },
43
+ natural: {
44
+ sensitive: (a, b) => naturalCompare(a, b) <= 0,
45
+ insensitive: (a, b) => naturalCompare(a.toLowerCase(), b.toLowerCase()) <= 0,
46
+ },
47
+ },
48
+ descending: {
49
+ alphanumeric: {
50
+ sensitive: (a, b) => comparators.ascending.alphanumeric.sensitive(b, a),
51
+ insensitive: (a, b) => comparators.ascending.alphanumeric.insensitive(b, a),
52
+ },
53
+ natural: {
54
+ sensitive: (a, b) => comparators.ascending.natural.sensitive(b, a),
55
+ insensitive: (a, b) => comparators.ascending.natural.insensitive(b, a),
56
+ },
57
+ },
58
+ };
59
+ //-----------------------------------------------------------------------------
60
+ // Rule Definition
61
+ //-----------------------------------------------------------------------------
62
+ /** @type {SortKeysRuleDefinition} */
63
+ const rule = {
64
+ meta: {
65
+ type: "suggestion",
66
+ defaultOptions: [
67
+ "asc",
68
+ {
69
+ allowLineSeparatedGroups: false,
70
+ caseSensitive: true,
71
+ minKeys: 2,
72
+ natural: false,
73
+ },
74
+ ],
75
+ docs: {
76
+ recommended: false,
77
+ description: `Require JSON object keys to be sorted`,
78
+ url: "https://github.com/eslint/json/tree/main/docs/rules/sort-keys.md",
79
+ },
80
+ messages: {
81
+ sortKeys: "Expected object keys to be in {{sortName}} case-{{sensitivity}} {{direction}} order. '{{thisName}}' should be before '{{prevName}}'.",
82
+ },
83
+ schema: [
84
+ {
85
+ enum: ["asc", "desc"],
86
+ },
87
+ {
88
+ type: "object",
89
+ properties: {
90
+ caseSensitive: {
91
+ type: "boolean",
92
+ },
93
+ natural: {
94
+ type: "boolean",
95
+ },
96
+ minKeys: {
97
+ type: "integer",
98
+ minimum: 2,
99
+ },
100
+ allowLineSeparatedGroups: {
101
+ type: "boolean",
102
+ },
103
+ },
104
+ additionalProperties: false,
105
+ },
106
+ ],
107
+ },
108
+ create(context) {
109
+ const { sourceCode } = context;
110
+ const [directionShort, { allowLineSeparatedGroups, caseSensitive, natural, minKeys },] = context.options;
111
+ /** @type {DirectionName} */
112
+ const direction = directionShort === "asc" ? "ascending" : "descending";
113
+ /** @type {SortName} */
114
+ const sortName = natural ? "natural" : "alphanumeric";
115
+ /** @type {Sensitivity} */
116
+ const sensitivity = caseSensitive ? "sensitive" : "insensitive";
117
+ /** @type {Comparator} */
118
+ const isValidOrder = comparators[direction][sortName][sensitivity];
119
+ // Note that @humanwhocodes/momoa doesn't include comments in the object.members tree, so we can't just see if a member is preceded by a comment
120
+ const commentLineNums = new Set();
121
+ for (const comment of sourceCode.comments) {
122
+ for (let lineNum = comment.loc.start.line; lineNum <= comment.loc.end.line; lineNum += 1) {
123
+ commentLineNums.add(lineNum);
124
+ }
125
+ }
126
+ /**
127
+ * Checks if two members are line-separated.
128
+ * @param {MemberNode} prevMember The previous member.
129
+ * @param {MemberNode} member The current member.
130
+ * @returns {boolean} True if the members are separated by at least one blank line (ignoring comment-only lines).
131
+ */
132
+ function isLineSeparated(prevMember, member) {
133
+ // Note that there can be comments *inside* members, e.g. `{"foo: /* comment *\/ "bar"}`, but these are ignored when calculating line-separated groups
134
+ const prevMemberEndLine = prevMember.loc.end.line;
135
+ const thisStartLine = member.loc.start.line;
136
+ if (thisStartLine - prevMemberEndLine < 2) {
137
+ return false;
138
+ }
139
+ for (let lineNum = prevMemberEndLine + 1; lineNum < thisStartLine; lineNum += 1) {
140
+ if (!commentLineNums.has(lineNum) &&
141
+ !hasNonWhitespace.test(sourceCode.lines[lineNum - 1])) {
142
+ return true;
143
+ }
144
+ }
145
+ return false;
146
+ }
147
+ return {
148
+ Object(node) {
149
+ /** @type {MemberNode} */
150
+ let prevMember;
151
+ /** @type {string} */
152
+ let prevName;
153
+ /** @type {string} */
154
+ let prevRawName;
155
+ if (node.members.length < minKeys) {
156
+ return;
157
+ }
158
+ for (const member of node.members) {
159
+ const thisName = getKey(member);
160
+ const thisRawName = getRawKey(member, sourceCode);
161
+ if (prevMember &&
162
+ !isValidOrder(prevName, thisName) &&
163
+ (!allowLineSeparatedGroups ||
164
+ !isLineSeparated(prevMember, member))) {
165
+ context.report({
166
+ loc: member.name.loc,
167
+ messageId: "sortKeys",
168
+ data: {
169
+ thisName: thisRawName,
170
+ prevName: prevRawName,
171
+ direction,
172
+ sensitivity,
173
+ sortName,
174
+ },
175
+ });
176
+ }
177
+ prevMember = member;
178
+ prevName = thisName;
179
+ prevRawName = thisRawName;
180
+ }
181
+ },
182
+ };
183
+ },
184
+ };
185
+ export default rule;
@@ -0,0 +1,17 @@
1
+ export default rule;
2
+ export type TopLevelInteropMessageIds = "topLevel";
3
+ export type TopLevelInteropRuleDefinition = JSONRuleDefinition<{
4
+ MessageIds: TopLevelInteropMessageIds;
5
+ }>;
6
+ /**
7
+ * @fileoverview Rule to ensure top-level items are either an array or object.
8
+ * @author Joe Hildebrand
9
+ */
10
+ /**
11
+ * @import { JSONRuleDefinition } from "../types.js";
12
+ * @typedef {"topLevel"} TopLevelInteropMessageIds
13
+ * @typedef {JSONRuleDefinition<{ MessageIds: TopLevelInteropMessageIds }>} TopLevelInteropRuleDefinition
14
+ */
15
+ /** @type {TopLevelInteropRuleDefinition} */
16
+ declare const rule: TopLevelInteropRuleDefinition;
17
+ import type { JSONRuleDefinition } from "../types.js";
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @fileoverview Rule to ensure top-level items are either an array or object.
3
+ * @author Joe Hildebrand
4
+ */
5
+ //-----------------------------------------------------------------------------
6
+ // Type Definitions
7
+ //-----------------------------------------------------------------------------
8
+ /**
9
+ * @import { JSONRuleDefinition } from "../types.js";
10
+ * @typedef {"topLevel"} TopLevelInteropMessageIds
11
+ * @typedef {JSONRuleDefinition<{ MessageIds: TopLevelInteropMessageIds }>} TopLevelInteropRuleDefinition
12
+ */
13
+ //-----------------------------------------------------------------------------
14
+ // Rule Definition
15
+ //-----------------------------------------------------------------------------
16
+ /** @type {TopLevelInteropRuleDefinition} */
17
+ const rule = {
18
+ meta: {
19
+ type: "problem",
20
+ docs: {
21
+ recommended: false,
22
+ description: "Require the JSON top-level value to be an array or object",
23
+ url: "https://github.com/eslint/json/tree/main/docs/rules/top-level-interop.md",
24
+ },
25
+ messages: {
26
+ topLevel: "Top level item should be array or object, got '{{type}}'.",
27
+ },
28
+ },
29
+ create(context) {
30
+ return {
31
+ Document(node) {
32
+ const { type } = node.body;
33
+ if (type !== "Object" && type !== "Array") {
34
+ context.report({
35
+ loc: node.loc,
36
+ messageId: "topLevel",
37
+ data: { type },
38
+ });
39
+ }
40
+ },
41
+ };
42
+ },
43
+ };
44
+ export default rule;
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Additional types for this package.
3
+ * @author Nicholas C. Zakas
4
+ */
5
+ export {};
package/dist/util.d.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @fileoverview Utility Library
3
+ * @author 루밀LuMir(lumirlumir)
4
+ */
5
+ /**
6
+ * @import { MemberNode } from "@humanwhocodes/momoa";
7
+ * @import { JSONSourceCode } from "./languages/json-source-code.js";
8
+ */
9
+ /**
10
+ * Gets the `MemberNode`'s key value.
11
+ * @param {MemberNode} node The node to get the key from.
12
+ * @returns {string} The key value.
13
+ */
14
+ export function getKey(node: MemberNode): string;
15
+ /**
16
+ * Gets the `MemberNode`'s raw key value.
17
+ * @param {MemberNode} node The node to get the raw key from.
18
+ * @param {JSONSourceCode} sourceCode The JSON source code object.
19
+ * @returns {string} The raw key value.
20
+ */
21
+ export function getRawKey(node: MemberNode, sourceCode: JSONSourceCode): string;
22
+ import type { MemberNode } from "@humanwhocodes/momoa";
23
+ import type { JSONSourceCode } from "./languages/json-source-code.js";
package/dist/util.js ADDED
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @fileoverview Utility Library
3
+ * @author 루밀LuMir(lumirlumir)
4
+ */
5
+ //-----------------------------------------------------------------------------
6
+ // Type Definitions
7
+ //-----------------------------------------------------------------------------
8
+ /**
9
+ * @import { MemberNode } from "@humanwhocodes/momoa";
10
+ * @import { JSONSourceCode } from "./languages/json-source-code.js";
11
+ */
12
+ //-----------------------------------------------------------------------------
13
+ // Helpers
14
+ //-----------------------------------------------------------------------------
15
+ /**
16
+ * Gets the `MemberNode`'s key value.
17
+ * @param {MemberNode} node The node to get the key from.
18
+ * @returns {string} The key value.
19
+ */
20
+ export function getKey(node) {
21
+ return node.name.type === "String" ? node.name.value : node.name.name;
22
+ }
23
+ /**
24
+ * Gets the `MemberNode`'s raw key value.
25
+ * @param {MemberNode} node The node to get the raw key from.
26
+ * @param {JSONSourceCode} sourceCode The JSON source code object.
27
+ * @returns {string} The raw key value.
28
+ */
29
+ export function getRawKey(node, sourceCode) {
30
+ return node.name.type === "String"
31
+ ? sourceCode.getText(node.name, -1, -1)
32
+ : sourceCode.getText(node.name);
33
+ }
package/package.json CHANGED
@@ -1,29 +1,15 @@
1
1
  {
2
2
  "name": "@eslint/json",
3
- "version": "0.14.0",
3
+ "version": "1.0.0",
4
4
  "description": "JSON linting plugin for ESLint",
5
5
  "author": "Nicholas C. Zakas",
6
6
  "type": "module",
7
- "main": "dist/esm/index.js",
8
- "types": "dist/esm/index.d.ts",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "require": {
12
- "types": "./dist/cjs/index.d.cts",
13
- "default": "./dist/cjs/index.cjs"
14
- },
15
- "import": {
16
- "types": "./dist/esm/index.d.ts",
17
- "default": "./dist/esm/index.js"
18
- }
19
- },
20
- "./types": {
21
- "require": {
22
- "types": "./dist/cjs/types.cts"
23
- },
24
- "import": {
25
- "types": "./dist/esm/types.d.ts"
26
- }
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
27
13
  }
28
14
  },
29
15
  "files": [
@@ -41,10 +27,7 @@
41
27
  "prettier --write"
42
28
  ],
43
29
  "!(*.js)": "prettier --write --ignore-unknown",
44
- "README.md": [
45
- "npm run build:update-rules-docs"
46
- ],
47
- "{src/rules/*.js,tools/update-rules-docs.js}": [
30
+ "{src/rules/*.js,tools/update-rules-docs.js,README.md}": [
48
31
  "npm run build:update-rules-docs",
49
32
  "git add README.md"
50
33
  ]
@@ -58,20 +41,20 @@
58
41
  },
59
42
  "homepage": "https://github.com/eslint/json#readme",
60
43
  "scripts": {
61
- "build:dedupe-types": "node tools/dedupe-types.js dist/cjs/index.cjs dist/esm/index.js",
62
- "build:cts": "node tools/build-cts.js",
44
+ "build": "npm run build:rules && npm run build:types && npm run build:update-rules-docs",
63
45
  "build:rules": "node tools/build-rules.js",
64
- "build": "npm run build:rules && rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts",
46
+ "build:types": "tsc",
65
47
  "build:update-rules-docs": "node tools/update-rules-docs.js",
66
48
  "prepare": "npm run build",
67
49
  "pretest": "npm run build",
68
50
  "lint": "eslint",
69
51
  "lint:fix": "eslint --fix",
52
+ "lint:types": "attw --pack --profile esm-only",
70
53
  "fmt": "prettier --write .",
71
54
  "fmt:check": "prettier --check .",
72
55
  "test": "mocha \"tests/**/*.test.js\"",
73
56
  "test:coverage": "c8 npm test",
74
- "test:jsr": "npx jsr@latest publish --dry-run",
57
+ "test:jsr": "npx -y jsr@latest publish --dry-run",
75
58
  "test:types": "tsc -p tests/types/tsconfig.json"
76
59
  },
77
60
  "keywords": [
@@ -83,28 +66,27 @@
83
66
  ],
84
67
  "license": "Apache-2.0",
85
68
  "dependencies": {
86
- "@eslint/core": "^0.17.0",
87
- "@eslint/plugin-kit": "^0.4.1",
69
+ "@eslint/core": "^1.0.1",
70
+ "@eslint/plugin-kit": "^0.5.1",
88
71
  "@humanwhocodes/momoa": "^3.3.10",
89
72
  "natural-compare": "^1.4.0"
90
73
  },
91
74
  "devDependencies": {
75
+ "@arethetypeswrong/cli": "^0.18.2",
92
76
  "c8": "^10.1.3",
93
77
  "dedent": "^1.5.3",
94
- "eslint": "^9.36.0",
78
+ "eslint": "^9.39.2",
95
79
  "eslint-config-eslint": "^13.0.0",
96
80
  "eslint-plugin-eslint-plugin": "^6.3.2",
97
- "lint-staged": "^15.2.7",
81
+ "globals": "^17.0.0",
82
+ "lint-staged": "^16.0.0",
98
83
  "mdast-util-from-markdown": "^2.0.2",
99
84
  "mocha": "^11.3.0",
100
- "prettier": "^3.4.1",
101
- "rollup": "^4.52.3",
102
- "rollup-plugin-copy": "^3.5.0",
103
- "rollup-plugin-delete": "^3.0.1",
85
+ "prettier": "3.8.1",
104
86
  "typescript": "^5.9.2",
105
87
  "yorkie": "^2.0.0"
106
88
  },
107
89
  "engines": {
108
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
90
+ "node": "^20.19.0 || ^22.13.0 || >=24"
109
91
  }
110
92
  }