elearning/Frontend-Learner/node_modules/@nuxt/eslint-plugin/dist/index.mjs
2026-01-13 10:48:02 +07:00

364 lines
8.9 KiB
JavaScript

import { AST_NODE_TYPES } from '@typescript-eslint/types';
import { ESLintUtils } from '@typescript-eslint/utils';
function createRule(rule) {
const _createRule = ESLintUtils.RuleCreator(
(name) => `https://eslint.nuxt.com/packages/plugin#nuxt${name}`
);
return _createRule(rule);
}
const processSuffixes = /* @__PURE__ */ new Set([
"client",
"browser",
"server",
"nitro",
"dev",
"test",
"prerender"
]);
const rule$2 = createRule({
name: "prefer-import-meta",
meta: {
type: "suggestion",
docs: {
description: "Prefer using `import.meta.*` over `process.*`"
},
schema: [],
messages: {
default: "Replace `process.{{ suffix }}` with `import.meta.{{ suffix }}`."
},
fixable: "code"
},
defaultOptions: [],
create: (context) => ({
MemberExpression: (node) => {
if (node.object.type === AST_NODE_TYPES.Identifier && node.object.name === "process" && node.property.type === AST_NODE_TYPES.Identifier && processSuffixes.has(node.property.name)) {
const suffix = node.property.name;
context.report({
node,
messageId: "default",
data: {
suffix
},
fix: (fixer) => fixer.replaceText(node, `import.meta.${suffix}`)
});
}
}
})
});
const OFFICIAL_MODULES = {
client: [
"site",
// SEO module
"colorMode",
"content",
"mdc",
"ui"
],
server: [
"hub"
]
};
const ORDER_KEYS = [
// Ids
"appId",
"buildId",
// Extends
"extends",
"theme",
// Extensions
"modules",
"plugins",
// Env ($production, $development, $test)
/^\$/,
// Nuxt Core Features
"ssr",
"pages",
"components",
"imports",
"devtools",
// Client-side Integrations
"app",
"css",
"vue",
"router",
"unhead",
...OFFICIAL_MODULES.client,
"spaLoadingTemplate",
// Runtime Configs
"appConfig",
"runtimeConfig",
// Dirs
"dir",
"rootDir",
"srcDir",
"appDir",
"workspaceDir",
"serverDir",
"buildDir",
"modulesDir",
"analyzeDir",
// Resultions
"alias",
"extensions",
"ignore",
"ignoreOptions",
"ignorePrefix",
// Build Pipeline Configs
"builder",
"build",
"generate",
"routeRules",
"sourcemap",
"optimization",
// Development
"dev",
"devServer",
"watch",
"watchers",
// Feature flags
"future",
"features",
"experimental",
"compatibilityDate",
// Nitro
"nitro",
...OFFICIAL_MODULES.server,
"serverHandlers",
"devServerHandlers",
// Tooling Integrations
"vite",
"webpack",
"typescript",
"postcss",
// Other Integrations
"test",
"telemetry",
// Logging
"debug",
"logLevel",
// Hooks
"hooks"
];
const rule$1 = createRule({
name: "nuxt-config-keys-order",
meta: {
type: "suggestion",
docs: {
description: "Prefer recommended order of Nuxt config properties"
},
schema: [],
messages: {
default: 'Expected config key "{{a}}" to come before "{{b}}"'
},
fixable: "code"
},
defaultOptions: [],
create(context) {
return {
ExportDefaultDeclaration(node) {
let object;
if (node.declaration.type === "ObjectExpression") {
object = node.declaration;
} else if (node.declaration.type === "CallExpression" && node.declaration.arguments[0].type === "ObjectExpression") {
object = node.declaration.arguments[0];
}
if (!object) {
return;
}
const hasFixes = sort(context, object);
if (!hasFixes) {
const envProps = object.properties.filter((i) => i.type === "Property" && i.key.type === "Identifier" && i.key.name.startsWith("$"));
for (const prop of envProps) {
if (prop.value.type === "ObjectExpression")
sort(context, prop.value);
}
}
}
};
}
});
function sort(context, node) {
return sortAst(
context,
node,
node.properties,
(prop) => {
if (prop.type === "Property")
return getString(prop.key);
return null;
},
sortKeys
);
}
function sortKeys(a, b) {
const indexA = ORDER_KEYS.findIndex((k) => typeof k === "string" ? k === a : k.test(a));
const indexB = ORDER_KEYS.findIndex((k) => typeof k === "string" ? k === b : k.test(b));
if (indexA === -1 && indexB !== -1)
return 1;
if (indexA !== -1 && indexB === -1)
return -1;
if (indexA < indexB)
return -1;
if (indexA > indexB)
return 1;
return a.localeCompare(b);
}
function sortAst(context, node, list, getName, sort2 = (a, b) => a.localeCompare(b), insertComma = true) {
const firstToken = context.sourceCode.getFirstToken(node);
const lastToken = context.sourceCode.getLastToken(node);
if (!firstToken || !lastToken)
return false;
if (list.length < 2)
return false;
const reordered = list.slice();
const ranges = /* @__PURE__ */ new Map();
const names = /* @__PURE__ */ new Map();
const rangeStart = Math.max(
firstToken.range[1],
context.sourceCode.getIndexFromLoc({
line: list[0].loc.start.line,
column: 0
})
);
let rangeEnd = rangeStart;
for (let i = 0; i < list.length; i++) {
const item = list[i];
let name = getName(item);
if (typeof name === "string")
name = [name];
names.set(item, name);
let lastRange = item.range[1];
const nextToken = context.sourceCode.getTokenAfter(item);
if (nextToken?.type === "Punctuator" && nextToken.value === ",")
lastRange = nextToken.range[1];
const nextChar = context.sourceCode.getText()[lastRange];
let text = getTextOf(context.sourceCode, [rangeEnd, lastRange]);
if (nextToken === lastToken && insertComma)
text += ",";
if (nextChar === "\n") {
lastRange++;
text += "\n";
}
ranges.set(item, [rangeEnd, lastRange, text]);
rangeEnd = lastRange;
}
const segments = [];
let segmentStart = -1;
for (let i = 0; i < list.length; i++) {
if (names.get(list[i]) == null) {
if (segmentStart > -1)
segments.push([segmentStart, i]);
segmentStart = -1;
} else {
if (segmentStart === -1)
segmentStart = i;
}
}
if (segmentStart > -1 && segmentStart !== list.length - 1)
segments.push([segmentStart, list.length]);
for (const [start, end] of segments) {
reordered.splice(
start,
end - start,
...reordered.slice(start, end).sort((a, b) => {
const nameA = names.get(a);
const nameB = names.get(b);
const length = Math.max(nameA.length, nameB.length);
for (let i = 0; i < length; i++) {
const a2 = nameA[i];
const b2 = nameB[i];
if (a2 == null || b2 == null || a2 === b2)
continue;
return sort2(a2, b2);
}
return 0;
})
);
}
const changed = reordered.some((prop, i) => prop !== list[i]);
if (!changed)
return false;
const newContent = reordered.map((i) => ranges.get(i)[2]).join("");
context.report({
node,
messageId: "default",
data: {
a: names.get(reordered[0])[0],
b: names.get(reordered[1])[0]
},
fix(fixer) {
return fixer.replaceTextRange([rangeStart, rangeEnd], newContent);
}
});
}
function getTextOf(sourceCode, node) {
if (!node)
return "";
if (Array.isArray(node))
return sourceCode.text.slice(node[0], node[1]);
return sourceCode.getText(node);
}
function getString(node) {
if (node.type === "Identifier")
return node.name;
if (node.type === "Literal")
return String(node.raw);
return null;
}
const rule = createRule({
name: "no-nuxt-config-test-key",
meta: {
type: "problem",
docs: {
description: "Disallow setting `test` key in Nuxt config"
},
schema: [],
messages: {
default: "Do not set `test` key in Nuxt config. The test environment is automatically detected."
}
},
defaultOptions: [],
create(context) {
return {
ExportDefaultDeclaration(node) {
let object;
if (node.declaration.type === "ObjectExpression") {
object = node.declaration;
} else if (node.declaration.type === "CallExpression" && node.declaration.arguments[0]?.type === "ObjectExpression") {
object = node.declaration.arguments[0];
}
if (!object) {
return;
}
for (const prop of object.properties) {
if (prop.type === "Property" && prop.key.type === "Identifier" && prop.key.name === "test" && (prop.value.type === "Literal" && typeof prop.value.value === "boolean" || prop.value.type === "Identifier" && (prop.value.name === "true" || prop.value.name === "false"))) {
context.report({
node: prop,
messageId: "default"
});
}
}
}
};
}
});
const rules = {
"prefer-import-meta": rule$2,
"nuxt-config-keys-order": rule$1,
"no-nuxt-config-test-key": rule
};
const index = {
meta: {
name: "@nuxt/eslint-plugin"
},
rules
};
export { index as default };