routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Yosuke Ota
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+42
View File
@@ -0,0 +1,42 @@
# eslint-json-compat-utils
A utility that converts rules made for checking the AST of `jsonc-eslint-parser` into rules compatible with `@eslint/json`.
## Installation
```bash
npm install eslint-json-compat-utils
```
## Usage
```js
import { toCompatRule } from "eslint-json-compat-utils";
export default toCompatRule({
meta: { /* ... */ },
create(context) {
return {
JSONArrayExpression: check,
};
},
})
```
### API
#### `toCompatRule(rule)`
Converts a rule object for `jsonc-eslint-parser` into a rule object for `@eslint/json` compatible.
#### `toCompatPlugin(plugin)`
Converts a plugin object for `jsonc-eslint-parser` into a plugin object for `@eslint/json` compatible.
[Example]
#### `toCompatCreate(create)`
Converts a `create` function for `jsonc-eslint-parser` into a `create` function for `@eslint/json` compatible.
[Example]: https://eslint-online-playground.netlify.app/#eNqVVMtu2zAQ/BWCpzaIqKhJ0cK9FGhPObQFeixTgJVWDhOJFEgqqGHo37NL0or8SIL4IMuc2dnX0Fs+qPpercGXrbVl/iHuvDV8xbfSyCC5UT1IvmKSf+03ReYQX/LzxHgA57U1iXQhKnExQ752egieoC2LR3jYaYNPIoOndyaQP6MBfEbv4ltSIq2gXEaMbYB5cJgZq5WcKFOW4A08fIcBTAOm1pByz6lto/xtEvl7JapPoqoWKVI9Gf4oPj91MseKBv7Z0dR5Jscava1v1SzxYU/CbOqMVJfLOSE0OAhBg9vhoroSl7kzaSZ+nosTtTWtXmPbuCLdD9YFRgtjrbM9LSnRSjqT/Is0mZMXd72gJmYxdONam91mCwosUxJfOqht39Msm2fEfsXo1yWX4dtgv9l+UCEFTwfRRC8wLxKKMeguLdjA/xjcQKvGLrA/NJq42FZ34Fd4wM/O9kws+U2ebyoISTsnBMJ3w6fx75W6YvsVvjtq+H0KnaJEfOJ3WbLo5+vfP3+wWNVbauyUWY94HK1PS0hwRt0YBeb6M8fYohmHTtcqQHEPm2h3nKRzFq00NyiEWLQgothhBze4IGnQaMf/Awwlw2bInu9tg/FRnYDT943h59CNFNxhoflaJ8ryzj0DnnLES/ST9lsGED/equkRF9i8OQ==
+822
View File
@@ -0,0 +1,822 @@
'use strict';
const eslint = require('eslint');
const jsoncEslintParser = require('jsonc-eslint-parser');
const esquery = require('esquery');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const esquery__default = /*#__PURE__*/_interopDefaultCompat(esquery);
function newProxyWithProperties(target, properties) {
return newProxyWithGet(target, (_target, prop) => {
if (prop in properties) {
return properties[prop];
}
return Reflect.get(target, prop);
});
}
function newProxyWithGet(target, get) {
return new Proxy(
Object.isFrozen(target) ? { __proto__: target } : target,
{
get(t, p, r) {
return proxyReflectValue(get(t, p, r), t, r);
}
}
);
}
function proxyReflectValue(value, target, receiver) {
if (typeof value === "function") {
return function(...args) {
const self = this;
return value.apply(self === receiver ? target : self, args);
};
}
return value;
}
const MOMOA_NODES = /* @__PURE__ */ new Set([
"Array",
"Boolean",
"Document",
"Element",
"Identifier",
"Infinity",
"Member",
"NaN",
"Null",
"Number",
"Object",
"String"
]);
function isJSONSourceCode(sourceCode) {
var _a, _b, _c;
return ((_a = sourceCode.ast) == null ? void 0 : _a.type) === "Document" && ((_c = (_b = sourceCode.ast.loc) == null ? void 0 : _b.start) == null ? void 0 : _c.column) === 1 && sourceCode.ast.body && isMomoaNode(sourceCode.ast.body) && typeof sourceCode.getParent === "function";
}
function isMomoaNode(node) {
return MOMOA_NODES.has(node.type);
}
function convertSourceLocationFromJsonToJsonc(loc) {
return {
start: convertPositionFromJsonToJsonc(loc.start),
end: convertPositionFromJsonToJsonc(loc.end)
};
}
function convertPositionFromJsonToJsonc(position) {
return {
line: position.line,
column: position.column - 1
};
}
function convertSourceLocationFromJsoncToJson(loc) {
return {
start: convertPositionFromJsoncToJson(loc.start),
end: convertPositionFromJsoncToJson(loc.end)
};
}
function convertPositionFromJsoncToJson(position) {
return {
line: position.line,
column: position.column + 1
};
}
const TOKEN_CONVERTERS = /* @__PURE__ */ new WeakMap();
function getTokenConverter(jsonSourceCode) {
const converter = TOKEN_CONVERTERS.get(jsonSourceCode.ast);
if (converter) {
return converter;
}
const convertedTokens = /* @__PURE__ */ new Map();
const tokenConverters = {
BlockComment(token) {
return {
type: "Block",
get value() {
return jsonSourceCode.text.slice(
token.range[0] + 2,
token.range[1] - 2
);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
},
LineComment(token) {
return {
type: "Line",
get value() {
return jsonSourceCode.text.slice(
token.range[0] + 2,
token.range[1]
);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
},
Boolean(token) {
return createStandardToken("Keyword", token);
},
Null(token) {
return createStandardToken("Keyword", token);
},
Identifier(token) {
return createStandardToken("Identifier", token);
},
Infinity(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Identifier", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Identifier", token);
},
NaN(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Identifier", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Identifier", token);
},
Number(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Numeric", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Numeric", token);
},
String(token) {
return createStandardToken("String", token);
},
Colon(token) {
return createPunctuator(":", token);
},
Comma(token) {
return createPunctuator(",", token);
},
LBracket(token) {
return createPunctuator("[", token);
},
LBrace(token) {
return createPunctuator("{", token);
},
RBracket(token) {
return createPunctuator("]", token);
},
RBrace(token) {
return createPunctuator("}", token);
}
};
TOKEN_CONVERTERS.set(jsonSourceCode.ast, convertToken);
return convertToken;
function createStandardToken(type, token) {
return {
type,
get value() {
return jsonSourceCode.text.slice(...token.range);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
}
function createPunctuator(value, token) {
return {
type: "Punctuator",
value,
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
}
function convertToken(token) {
if (convertedTokens.has(token)) {
return convertedTokens.get(token);
}
const newToken = tokenConverters[token.type](token);
convertedTokens.set(token, newToken);
return newToken;
}
}
const NODE_CONVERTERS = /* @__PURE__ */ new WeakMap();
function getNodeConverter(jsonSourceCode) {
const converter = NODE_CONVERTERS.get(jsonSourceCode.ast);
if (converter) {
return converter;
}
const tokenConverter = getTokenConverter(jsonSourceCode);
const convertedNodes = /* @__PURE__ */ new Map();
const nodeConverters = {
Array(node) {
let elements;
return {
get parent() {
return getParent(node);
},
type: "JSONArrayExpression",
get elements() {
return elements != null ? elements : elements = node.elements.map((e) => convertNode(e.value));
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Boolean(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Null(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: null,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Number(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const rawArgument = jsonSourceCode.text.slice(...argumentRange);
const literal = {
get parent() {
return unaryExpression;
},
type: "JSONLiteral",
value: Math.abs(node.value),
bigint: null,
regex: null,
raw: rawArgument,
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: literal,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, literal];
}
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
String(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Document(node) {
let expression, tokens, comments;
const program = {
get parent() {
return getParent(node);
},
type: "Program",
get body() {
return body;
},
get comments() {
return comments != null ? comments : comments = node.tokens.filter(
(token) => token.type === "LineComment" || token.type === "BlockComment"
).flatMap(tokenConverter);
},
get tokens() {
return tokens != null ? tokens : tokens = node.tokens.filter(
(token) => token.type !== "LineComment" && token.type !== "BlockComment"
).flatMap(tokenConverter);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
const expr = {
parent: program,
type: "JSONExpressionStatement",
get expression() {
return expression != null ? expression : expression = convertNode(node.body);
},
range: node.body.range,
loc: convertSourceLocationFromJsonToJsonc(node.body.loc)
};
const body = [expr];
return [program, expr];
},
Object(node) {
let members;
return {
get parent() {
return getParent(node);
},
type: "JSONObjectExpression",
get properties() {
return members != null ? members : members = node.members.map(convertNode);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Member(node) {
let keyNode, value;
return {
get parent() {
return getParent(node);
},
type: "JSONProperty",
get key() {
return keyNode != null ? keyNode : keyNode = convertNode(node.name);
},
get value() {
return value != null ? value : value = convertNode(node.value);
},
kind: "init",
method: false,
shorthand: false,
computed: false,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Identifier(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: node.name,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Infinity(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const identifier = {
get parent() {
return unaryExpression;
},
type: "JSONIdentifier",
name: "Infinity",
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: identifier,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, identifier];
}
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: "Infinity",
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
NaN(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const identifier = {
get parent() {
return unaryExpression;
},
type: "JSONIdentifier",
name: "NaN",
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: identifier,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, identifier];
}
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: "NaN",
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
}
};
NODE_CONVERTERS.set(jsonSourceCode.ast, convert);
return convert;
function convert(node) {
if (convertedNodes.has(node)) {
return convertedNodes.get(node);
}
const newNode = nodeConverters[node.type](node);
let result;
if (Array.isArray(newNode)) {
convertedNodes.set(
node,
result = {
node: newNode[0],
nodes: newNode
}
);
} else {
convertedNodes.set(node, result = { node: newNode });
}
return result;
}
function getParent(node) {
const parent = jsonSourceCode.getParent(node);
if (!parent) return null;
const parentNode = parent;
if (parentNode.type === "Element") {
return getParent(parentNode);
}
const convertedParent = convert(parentNode);
if (convertedParent.nodes) {
return convertedParent.nodes[convertedParent.nodes.length - 1];
}
return convertedParent.node;
}
function convertNode(node) {
return convert(node).node;
}
}
function convertJsoncSourceCode(jsonSourceCode) {
const convert = getNodeConverter(jsonSourceCode);
const jsSourceCode = new eslint.SourceCode({
text: jsonSourceCode.text,
ast: convert(jsonSourceCode.ast).nodes[0],
parserServices: { isJSON: true },
visitorKeys: jsoncEslintParser.VisitorKeys
});
const compatSourceCode = newProxyWithGet(
jsonSourceCode,
(target, prop, receiver) => {
const value = proxyReflectValue(
Reflect.get(jsSourceCode, prop),
jsSourceCode,
target
);
if (value !== void 0) return value;
return Reflect.get(jsonSourceCode, prop, receiver);
}
);
return compatSourceCode;
}
const NODE_TYPE_MAP = /* @__PURE__ */ new Map([
["Program", ["Document"]],
["JSONExpressionStatement", ["Document"]],
["JSONLiteral", ["Boolean", "String", "Null", "Number"]],
["JSONArrayExpression", ["Array"]],
["JSONObjectExpression", ["Object"]],
["JSONProperty", ["Member"]],
["JSONIdentifier", ["Identifier", "Infinity", "NaN"]],
["JSONUnaryExpression", ["Number", "Infinity", "NaN"]]
]);
const reIsSimpleNodeQuery = /^[a-z]+$/iu;
function convertQuery(eslintQuery) {
const exit = eslintQuery.endsWith(":exit");
const query = exit ? eslintQuery.slice(0, -5) : eslintQuery;
const converted = convertRawQuery(query);
return converted && (exit ? {
query: `${converted.query}:exit`,
match: converted.match
} : converted);
}
function convertRawQuery(query) {
const queries = query.split(",").map((q) => q.trim());
if (queries.every((q) => reIsSimpleNodeQuery.test(q))) {
const convertTargetNodes = new Set(queries);
const convertedQueries = [];
for (const node of queries) {
const converted = NODE_TYPE_MAP.get(node);
if (converted) {
convertedQueries.push(...converted);
} else {
convertTargetNodes.delete(node);
}
}
return convertedQueries.length ? {
query: convertedQueries.join(","),
match: (node) => convertTargetNodes.has(node.type)
} : null;
}
if (query === "*") {
return {
query: "*",
match: () => true
};
}
const selector = esquery__default.parse(query);
const match = (node) => {
let target = node;
const ancestors = [];
while (target.parent) {
ancestors.push(target.parent);
target = target.parent;
}
return esquery__default.matches(node, selector, ancestors, {
visitorKeys: jsoncEslintParser.VisitorKeys
});
};
return { query: "*", match };
}
function toCompatRuleListener(ruleListener, jsonSourceCode) {
const convert = getNodeConverter(jsonSourceCode);
const jsoncNodeVisitors = /* @__PURE__ */ new Map();
const queries = /* @__PURE__ */ new Set();
for (const [key, fn] of Object.entries(ruleListener)) {
if (!fn) continue;
queries.add(key);
const convertedQuery = convertQuery(key);
if (!convertedQuery) continue;
const { query, match } = convertedQuery;
queries.add(query);
let jsoncNodeVisitorList = jsoncNodeVisitors.get(query);
if (!jsoncNodeVisitorList) {
jsoncNodeVisitorList = [];
jsoncNodeVisitors.set(query, jsoncNodeVisitorList);
}
jsoncNodeVisitorList.push((node) => {
if (match(node)) {
fn(node);
}
});
}
const result = {};
for (const query of queries) {
result[query] = (node) => {
var _a;
if (isMomoaNode(node)) {
if (node.type !== "Element") {
const jsoncNodeVisitorList = jsoncNodeVisitors.get(query);
if (!jsoncNodeVisitorList) return;
const invoke = query.endsWith(":exit") ? invokeWithReverseConvertedNode : invokeWithConvertedNode;
invoke(node, (n) => {
jsoncNodeVisitorList.forEach((cb) => cb(n));
});
}
} else {
(_a = ruleListener[query]) == null ? void 0 : _a.call(ruleListener, node);
}
};
}
return result;
function invokeWithConvertedNode(node, cb) {
const jsonNodeData = convert(node);
if (jsonNodeData.nodes) {
for (const n of jsonNodeData.nodes) {
cb(n);
}
} else {
cb(jsonNodeData.node);
}
}
function invokeWithReverseConvertedNode(node, cb) {
const jsonNodeData = convert(node);
if (jsonNodeData.nodes) {
for (let index = jsonNodeData.nodes.length - 1; index >= 0; index--) {
const n = jsonNodeData.nodes[index];
cb(n);
}
} else {
cb(jsonNodeData.node);
}
}
}
const CONVERTED$2 = /* @__PURE__ */ new WeakMap();
function toCompatCreate(create) {
if (CONVERTED$2.has(create)) {
return CONVERTED$2.get(create);
}
const result = (context, ...args) => {
const originalSourceCode = context.sourceCode;
if (!originalSourceCode || !isJSONSourceCode(originalSourceCode)) {
return create(context, ...args);
}
let sourceCode;
const compatContext = newProxyWithProperties(context, {
get sourceCode() {
return sourceCode != null ? sourceCode : sourceCode = convertJsoncSourceCode(originalSourceCode);
},
report(descriptor) {
const momoaDescriptor = {
...descriptor
};
if ("loc" in momoaDescriptor && momoaDescriptor.loc) {
if ("line" in momoaDescriptor.loc) {
momoaDescriptor.loc = convertPositionFromJsoncToJson(
momoaDescriptor.loc
);
} else {
momoaDescriptor.loc = convertSourceLocationFromJsoncToJson(
momoaDescriptor.loc
);
}
}
if ("node" in momoaDescriptor && momoaDescriptor.node) {
momoaDescriptor.node = {
...momoaDescriptor.node,
loc: convertSourceLocationFromJsoncToJson(
momoaDescriptor.node.loc
)
};
}
context.report(momoaDescriptor);
}
});
return toCompatRuleListener(
create(compatContext, ...args),
originalSourceCode
);
};
CONVERTED$2.set(create, result);
return result;
}
const CONVERTED$1 = /* @__PURE__ */ new WeakMap();
function toCompatRule(rule) {
if (CONVERTED$1.has(rule)) {
return CONVERTED$1.get(rule);
}
const result = {
...rule,
create: toCompatCreate(rule.create)
};
CONVERTED$1.set(rule, result);
return result;
}
const CONVERTED = /* @__PURE__ */ new WeakMap();
function toCompatPlugin(plugin) {
if (!plugin.rules) {
return plugin;
}
if (CONVERTED.has(plugin)) {
return CONVERTED.get(plugin);
}
const rules = newProxyWithGet(plugin.rules, (target, prop) => {
const rule = Reflect.get(target, prop);
return rule && toCompatRule(rule);
});
const result = newProxyWithProperties(plugin, {
rules
});
CONVERTED.set(plugin, result);
return result;
}
exports.toCompatCreate = toCompatCreate;
exports.toCompatPlugin = toCompatPlugin;
exports.toCompatRule = toCompatRule;
+26
View File
@@ -0,0 +1,26 @@
import { Rule } from 'eslint';
type LazyCreate = (context: any, ...args: any[]) => any;
/**
* This is a helper function that converts the given create function into `@eslint/json` compatible create function.
*/
declare function toCompatCreate<F extends LazyCreate>(create: F): F;
type LazyRuleModule = {
create: LazyCreate;
meta?: Rule.RuleMetaData;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatRule<R extends LazyRuleModule>(rule: R): R;
type LazyPlugin = {
rules?: Record<string, LazyRuleModule> | undefined;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatPlugin<P extends LazyPlugin>(plugin: P): P;
export { toCompatCreate, toCompatPlugin, toCompatRule };
+26
View File
@@ -0,0 +1,26 @@
import { Rule } from 'eslint';
type LazyCreate = (context: any, ...args: any[]) => any;
/**
* This is a helper function that converts the given create function into `@eslint/json` compatible create function.
*/
declare function toCompatCreate<F extends LazyCreate>(create: F): F;
type LazyRuleModule = {
create: LazyCreate;
meta?: Rule.RuleMetaData;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatRule<R extends LazyRuleModule>(rule: R): R;
type LazyPlugin = {
rules?: Record<string, LazyRuleModule> | undefined;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatPlugin<P extends LazyPlugin>(plugin: P): P;
export { toCompatCreate, toCompatPlugin, toCompatRule };
+26
View File
@@ -0,0 +1,26 @@
import { Rule } from 'eslint';
type LazyCreate = (context: any, ...args: any[]) => any;
/**
* This is a helper function that converts the given create function into `@eslint/json` compatible create function.
*/
declare function toCompatCreate<F extends LazyCreate>(create: F): F;
type LazyRuleModule = {
create: LazyCreate;
meta?: Rule.RuleMetaData;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatRule<R extends LazyRuleModule>(rule: R): R;
type LazyPlugin = {
rules?: Record<string, LazyRuleModule> | undefined;
};
/**
* This is a helper function that converts the given rule object into `@eslint/json` compatible rule.
*/
declare function toCompatPlugin<P extends LazyPlugin>(plugin: P): P;
export { toCompatCreate, toCompatPlugin, toCompatRule };
+814
View File
@@ -0,0 +1,814 @@
import { SourceCode } from 'eslint';
import { VisitorKeys } from 'jsonc-eslint-parser';
import esquery from 'esquery';
function newProxyWithProperties(target, properties) {
return newProxyWithGet(target, (_target, prop) => {
if (prop in properties) {
return properties[prop];
}
return Reflect.get(target, prop);
});
}
function newProxyWithGet(target, get) {
return new Proxy(
Object.isFrozen(target) ? { __proto__: target } : target,
{
get(t, p, r) {
return proxyReflectValue(get(t, p, r), t, r);
}
}
);
}
function proxyReflectValue(value, target, receiver) {
if (typeof value === "function") {
return function(...args) {
const self = this;
return value.apply(self === receiver ? target : self, args);
};
}
return value;
}
const MOMOA_NODES = /* @__PURE__ */ new Set([
"Array",
"Boolean",
"Document",
"Element",
"Identifier",
"Infinity",
"Member",
"NaN",
"Null",
"Number",
"Object",
"String"
]);
function isJSONSourceCode(sourceCode) {
var _a, _b, _c;
return ((_a = sourceCode.ast) == null ? void 0 : _a.type) === "Document" && ((_c = (_b = sourceCode.ast.loc) == null ? void 0 : _b.start) == null ? void 0 : _c.column) === 1 && sourceCode.ast.body && isMomoaNode(sourceCode.ast.body) && typeof sourceCode.getParent === "function";
}
function isMomoaNode(node) {
return MOMOA_NODES.has(node.type);
}
function convertSourceLocationFromJsonToJsonc(loc) {
return {
start: convertPositionFromJsonToJsonc(loc.start),
end: convertPositionFromJsonToJsonc(loc.end)
};
}
function convertPositionFromJsonToJsonc(position) {
return {
line: position.line,
column: position.column - 1
};
}
function convertSourceLocationFromJsoncToJson(loc) {
return {
start: convertPositionFromJsoncToJson(loc.start),
end: convertPositionFromJsoncToJson(loc.end)
};
}
function convertPositionFromJsoncToJson(position) {
return {
line: position.line,
column: position.column + 1
};
}
const TOKEN_CONVERTERS = /* @__PURE__ */ new WeakMap();
function getTokenConverter(jsonSourceCode) {
const converter = TOKEN_CONVERTERS.get(jsonSourceCode.ast);
if (converter) {
return converter;
}
const convertedTokens = /* @__PURE__ */ new Map();
const tokenConverters = {
BlockComment(token) {
return {
type: "Block",
get value() {
return jsonSourceCode.text.slice(
token.range[0] + 2,
token.range[1] - 2
);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
},
LineComment(token) {
return {
type: "Line",
get value() {
return jsonSourceCode.text.slice(
token.range[0] + 2,
token.range[1]
);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
},
Boolean(token) {
return createStandardToken("Keyword", token);
},
Null(token) {
return createStandardToken("Keyword", token);
},
Identifier(token) {
return createStandardToken("Identifier", token);
},
Infinity(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Identifier", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Identifier", token);
},
NaN(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Identifier", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Identifier", token);
},
Number(token) {
const raw = jsonSourceCode.text.slice(...token.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
return [
createPunctuator(raw[0], {
range: [token.range[0], token.range[0] + 1],
loc: {
start: token.loc.start,
end: {
line: token.loc.start.line,
column: token.loc.start.column + 1
}
}
}),
createStandardToken("Numeric", {
range: [token.range[0] + 1, token.range[1]],
loc: {
start: {
line: token.loc.start.line,
column: token.loc.start.column + 1
},
end: token.loc.end
}
})
];
}
return createStandardToken("Numeric", token);
},
String(token) {
return createStandardToken("String", token);
},
Colon(token) {
return createPunctuator(":", token);
},
Comma(token) {
return createPunctuator(",", token);
},
LBracket(token) {
return createPunctuator("[", token);
},
LBrace(token) {
return createPunctuator("{", token);
},
RBracket(token) {
return createPunctuator("]", token);
},
RBrace(token) {
return createPunctuator("}", token);
}
};
TOKEN_CONVERTERS.set(jsonSourceCode.ast, convertToken);
return convertToken;
function createStandardToken(type, token) {
return {
type,
get value() {
return jsonSourceCode.text.slice(...token.range);
},
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
}
function createPunctuator(value, token) {
return {
type: "Punctuator",
value,
range: token.range,
loc: convertSourceLocationFromJsonToJsonc(token.loc)
};
}
function convertToken(token) {
if (convertedTokens.has(token)) {
return convertedTokens.get(token);
}
const newToken = tokenConverters[token.type](token);
convertedTokens.set(token, newToken);
return newToken;
}
}
const NODE_CONVERTERS = /* @__PURE__ */ new WeakMap();
function getNodeConverter(jsonSourceCode) {
const converter = NODE_CONVERTERS.get(jsonSourceCode.ast);
if (converter) {
return converter;
}
const tokenConverter = getTokenConverter(jsonSourceCode);
const convertedNodes = /* @__PURE__ */ new Map();
const nodeConverters = {
Array(node) {
let elements;
return {
get parent() {
return getParent(node);
},
type: "JSONArrayExpression",
get elements() {
return elements != null ? elements : elements = node.elements.map((e) => convertNode(e.value));
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Boolean(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Null(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: null,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Number(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const rawArgument = jsonSourceCode.text.slice(...argumentRange);
const literal = {
get parent() {
return unaryExpression;
},
type: "JSONLiteral",
value: Math.abs(node.value),
bigint: null,
regex: null,
raw: rawArgument,
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: literal,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, literal];
}
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
String(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONLiteral",
value: node.value,
bigint: null,
regex: null,
get raw() {
return jsonSourceCode.text.slice(...node.range);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Document(node) {
let expression, tokens, comments;
const program = {
get parent() {
return getParent(node);
},
type: "Program",
get body() {
return body;
},
get comments() {
return comments != null ? comments : comments = node.tokens.filter(
(token) => token.type === "LineComment" || token.type === "BlockComment"
).flatMap(tokenConverter);
},
get tokens() {
return tokens != null ? tokens : tokens = node.tokens.filter(
(token) => token.type !== "LineComment" && token.type !== "BlockComment"
).flatMap(tokenConverter);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
const expr = {
parent: program,
type: "JSONExpressionStatement",
get expression() {
return expression != null ? expression : expression = convertNode(node.body);
},
range: node.body.range,
loc: convertSourceLocationFromJsonToJsonc(node.body.loc)
};
const body = [expr];
return [program, expr];
},
Object(node) {
let members;
return {
get parent() {
return getParent(node);
},
type: "JSONObjectExpression",
get properties() {
return members != null ? members : members = node.members.map(convertNode);
},
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Member(node) {
let keyNode, value;
return {
get parent() {
return getParent(node);
},
type: "JSONProperty",
get key() {
return keyNode != null ? keyNode : keyNode = convertNode(node.name);
},
get value() {
return value != null ? value : value = convertNode(node.value);
},
kind: "init",
method: false,
shorthand: false,
computed: false,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Identifier(node) {
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: node.name,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
Infinity(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const identifier = {
get parent() {
return unaryExpression;
},
type: "JSONIdentifier",
name: "Infinity",
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: identifier,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, identifier];
}
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: "Infinity",
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
},
NaN(node) {
const raw = jsonSourceCode.text.slice(...node.range);
if (raw.startsWith("-") || raw.startsWith("+")) {
const argumentRange = [node.range[0] + 1, node.range[1]];
const identifier = {
get parent() {
return unaryExpression;
},
type: "JSONIdentifier",
name: "NaN",
range: argumentRange,
loc: convertSourceLocationFromJsonToJsonc({
start: {
line: node.loc.start.line,
column: node.loc.start.column + 1
},
end: node.loc.end
})
};
const unaryExpression = {
get parent() {
return getParent(node);
},
type: "JSONUnaryExpression",
operator: raw[0],
prefix: true,
argument: identifier,
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
return [unaryExpression, identifier];
}
return {
get parent() {
return getParent(node);
},
type: "JSONIdentifier",
name: "NaN",
range: node.range,
loc: convertSourceLocationFromJsonToJsonc(node.loc)
};
}
};
NODE_CONVERTERS.set(jsonSourceCode.ast, convert);
return convert;
function convert(node) {
if (convertedNodes.has(node)) {
return convertedNodes.get(node);
}
const newNode = nodeConverters[node.type](node);
let result;
if (Array.isArray(newNode)) {
convertedNodes.set(
node,
result = {
node: newNode[0],
nodes: newNode
}
);
} else {
convertedNodes.set(node, result = { node: newNode });
}
return result;
}
function getParent(node) {
const parent = jsonSourceCode.getParent(node);
if (!parent) return null;
const parentNode = parent;
if (parentNode.type === "Element") {
return getParent(parentNode);
}
const convertedParent = convert(parentNode);
if (convertedParent.nodes) {
return convertedParent.nodes[convertedParent.nodes.length - 1];
}
return convertedParent.node;
}
function convertNode(node) {
return convert(node).node;
}
}
function convertJsoncSourceCode(jsonSourceCode) {
const convert = getNodeConverter(jsonSourceCode);
const jsSourceCode = new SourceCode({
text: jsonSourceCode.text,
ast: convert(jsonSourceCode.ast).nodes[0],
parserServices: { isJSON: true },
visitorKeys: VisitorKeys
});
const compatSourceCode = newProxyWithGet(
jsonSourceCode,
(target, prop, receiver) => {
const value = proxyReflectValue(
Reflect.get(jsSourceCode, prop),
jsSourceCode,
target
);
if (value !== void 0) return value;
return Reflect.get(jsonSourceCode, prop, receiver);
}
);
return compatSourceCode;
}
const NODE_TYPE_MAP = /* @__PURE__ */ new Map([
["Program", ["Document"]],
["JSONExpressionStatement", ["Document"]],
["JSONLiteral", ["Boolean", "String", "Null", "Number"]],
["JSONArrayExpression", ["Array"]],
["JSONObjectExpression", ["Object"]],
["JSONProperty", ["Member"]],
["JSONIdentifier", ["Identifier", "Infinity", "NaN"]],
["JSONUnaryExpression", ["Number", "Infinity", "NaN"]]
]);
const reIsSimpleNodeQuery = /^[a-z]+$/iu;
function convertQuery(eslintQuery) {
const exit = eslintQuery.endsWith(":exit");
const query = exit ? eslintQuery.slice(0, -5) : eslintQuery;
const converted = convertRawQuery(query);
return converted && (exit ? {
query: `${converted.query}:exit`,
match: converted.match
} : converted);
}
function convertRawQuery(query) {
const queries = query.split(",").map((q) => q.trim());
if (queries.every((q) => reIsSimpleNodeQuery.test(q))) {
const convertTargetNodes = new Set(queries);
const convertedQueries = [];
for (const node of queries) {
const converted = NODE_TYPE_MAP.get(node);
if (converted) {
convertedQueries.push(...converted);
} else {
convertTargetNodes.delete(node);
}
}
return convertedQueries.length ? {
query: convertedQueries.join(","),
match: (node) => convertTargetNodes.has(node.type)
} : null;
}
if (query === "*") {
return {
query: "*",
match: () => true
};
}
const selector = esquery.parse(query);
const match = (node) => {
let target = node;
const ancestors = [];
while (target.parent) {
ancestors.push(target.parent);
target = target.parent;
}
return esquery.matches(node, selector, ancestors, {
visitorKeys: VisitorKeys
});
};
return { query: "*", match };
}
function toCompatRuleListener(ruleListener, jsonSourceCode) {
const convert = getNodeConverter(jsonSourceCode);
const jsoncNodeVisitors = /* @__PURE__ */ new Map();
const queries = /* @__PURE__ */ new Set();
for (const [key, fn] of Object.entries(ruleListener)) {
if (!fn) continue;
queries.add(key);
const convertedQuery = convertQuery(key);
if (!convertedQuery) continue;
const { query, match } = convertedQuery;
queries.add(query);
let jsoncNodeVisitorList = jsoncNodeVisitors.get(query);
if (!jsoncNodeVisitorList) {
jsoncNodeVisitorList = [];
jsoncNodeVisitors.set(query, jsoncNodeVisitorList);
}
jsoncNodeVisitorList.push((node) => {
if (match(node)) {
fn(node);
}
});
}
const result = {};
for (const query of queries) {
result[query] = (node) => {
var _a;
if (isMomoaNode(node)) {
if (node.type !== "Element") {
const jsoncNodeVisitorList = jsoncNodeVisitors.get(query);
if (!jsoncNodeVisitorList) return;
const invoke = query.endsWith(":exit") ? invokeWithReverseConvertedNode : invokeWithConvertedNode;
invoke(node, (n) => {
jsoncNodeVisitorList.forEach((cb) => cb(n));
});
}
} else {
(_a = ruleListener[query]) == null ? void 0 : _a.call(ruleListener, node);
}
};
}
return result;
function invokeWithConvertedNode(node, cb) {
const jsonNodeData = convert(node);
if (jsonNodeData.nodes) {
for (const n of jsonNodeData.nodes) {
cb(n);
}
} else {
cb(jsonNodeData.node);
}
}
function invokeWithReverseConvertedNode(node, cb) {
const jsonNodeData = convert(node);
if (jsonNodeData.nodes) {
for (let index = jsonNodeData.nodes.length - 1; index >= 0; index--) {
const n = jsonNodeData.nodes[index];
cb(n);
}
} else {
cb(jsonNodeData.node);
}
}
}
const CONVERTED$2 = /* @__PURE__ */ new WeakMap();
function toCompatCreate(create) {
if (CONVERTED$2.has(create)) {
return CONVERTED$2.get(create);
}
const result = (context, ...args) => {
const originalSourceCode = context.sourceCode;
if (!originalSourceCode || !isJSONSourceCode(originalSourceCode)) {
return create(context, ...args);
}
let sourceCode;
const compatContext = newProxyWithProperties(context, {
get sourceCode() {
return sourceCode != null ? sourceCode : sourceCode = convertJsoncSourceCode(originalSourceCode);
},
report(descriptor) {
const momoaDescriptor = {
...descriptor
};
if ("loc" in momoaDescriptor && momoaDescriptor.loc) {
if ("line" in momoaDescriptor.loc) {
momoaDescriptor.loc = convertPositionFromJsoncToJson(
momoaDescriptor.loc
);
} else {
momoaDescriptor.loc = convertSourceLocationFromJsoncToJson(
momoaDescriptor.loc
);
}
}
if ("node" in momoaDescriptor && momoaDescriptor.node) {
momoaDescriptor.node = {
...momoaDescriptor.node,
loc: convertSourceLocationFromJsoncToJson(
momoaDescriptor.node.loc
)
};
}
context.report(momoaDescriptor);
}
});
return toCompatRuleListener(
create(compatContext, ...args),
originalSourceCode
);
};
CONVERTED$2.set(create, result);
return result;
}
const CONVERTED$1 = /* @__PURE__ */ new WeakMap();
function toCompatRule(rule) {
if (CONVERTED$1.has(rule)) {
return CONVERTED$1.get(rule);
}
const result = {
...rule,
create: toCompatCreate(rule.create)
};
CONVERTED$1.set(rule, result);
return result;
}
const CONVERTED = /* @__PURE__ */ new WeakMap();
function toCompatPlugin(plugin) {
if (!plugin.rules) {
return plugin;
}
if (CONVERTED.has(plugin)) {
return CONVERTED.get(plugin);
}
const rules = newProxyWithGet(plugin.rules, (target, prop) => {
const rule = Reflect.get(target, prop);
return rule && toCompatRule(rule);
});
const result = newProxyWithProperties(plugin, {
rules
});
CONVERTED.set(plugin, result);
return result;
}
export { toCompatCreate, toCompatPlugin, toCompatRule };
+96
View File
@@ -0,0 +1,96 @@
{
"name": "eslint-json-compat-utils",
"version": "0.2.3",
"description": "A utility that converts rules made for checking the AST of `jsonc-eslint-parser` into rules compatible with `@eslint/json`.",
"engines": {
"node": ">=12"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./package.json": "./package.json"
},
"main": "./dist/index.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"prebuild": "npm run -s clean",
"build": "unbuild",
"clean": "rimraf .nyc_output dist coverage",
"lint": "npm-run-all \"lint:*\"",
"lint:js": "eslint .",
"eslint-fix": "eslint . --fix",
"lint:ts": "tsc --noEmit",
"test:cover": "nyc --reporter=lcov npm run test",
"test": "npm run mocha -- \"tests/src/**/*.ts\" --reporter dot --timeout 60000",
"ts": "node -r esbuild-register",
"mocha": "npm run ts -- ./node_modules/mocha/bin/mocha.js",
"prerelease": "npm run clean && npm run build",
"release": "changeset publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ota-meshi/eslint-json-compat-utils.git"
},
"keywords": [
"eslint"
],
"author": "Yosuke Ota (https://github.com/ota-meshi)",
"license": "MIT",
"bugs": {
"url": "https://github.com/ota-meshi/eslint-json-compat-utils/issues"
},
"homepage": "https://github.com/ota-meshi/eslint-json-compat-utils#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"esquery": "^1.6.0"
},
"peerDependenciesMeta": {
"@eslint/json": {
"optional": true
}
},
"peerDependencies": {
"eslint": "*",
"jsonc-eslint-parser": "^2.4.0 || ^3.0.0"
},
"devDependencies": {
"@changesets/cli": "^2.26.2",
"@eslint/js": "^10.0.0",
"@eslint/json": "^1.0.0",
"@ota-meshi/eslint-plugin": "^0.20.0",
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
"@types/eslint": "^9.0.0",
"@types/esquery": "^1.5.4",
"@types/mocha": "^10.0.0",
"@types/node": "^24.0.0",
"@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^8.13.0",
"@typescript-eslint/parser": "^8.13.0",
"esbuild-register": "^3.5.0",
"eslint": "^10.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-jsdoc": "^62.0.0",
"eslint-plugin-json-schema-validator": "^6.0.0",
"eslint-plugin-jsonc": "^3.0.0",
"eslint-plugin-n": "^17.0.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-yml": "^3.0.0",
"jsonc-eslint-parser": "^3.0.0",
"mocha": "^11.0.0",
"npm-run-all2": "^8.0.0",
"nyc": "^18.0.0",
"prettier": "^3.0.3",
"typescript": "^5.6.3",
"typescript-eslint": "^8.13.0",
"unbuild": "^3.0.0"
}
}