Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

View file

@ -0,0 +1,14 @@
import type { Linter } from 'eslint'
export declare const configs: {
/**
* The default recommended config in Flat Config Format
*/
recommended: Linter.Config
/**
* Enable all rules, in Flat Config Format
*/
all: Linter.Config
}
export type Configs = typeof configs

View file

@ -0,0 +1,14 @@
import type { ESLint } from 'eslint'
import type { Configs } from './configs'
import type { Rules } from './rules'
export type { Configs } from './configs'
export type { RuleOptions } from './rule-options'
export type { Rules } from './rules'
declare const plugin: {
rules: Rules
configs: ESLint.Plugin['configs'] & Configs
}
export default plugin

View file

@ -0,0 +1,62 @@
/* eslint-disable */
/* prettier-ignore */
import type { Linter } from 'eslint'
export interface RuleOptions {
/**
* Enforce or ban the use of inline type-only markers for named imports.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/consistent-type-specifier-style/README.md
*/
'import-lite/consistent-type-specifier-style'?: Linter.RuleEntry<ImportLiteConsistentTypeSpecifierStyle>
/**
* Ensure all exports appear after other statements.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/exports-last/README.md
*/
'import-lite/exports-last'?: Linter.RuleEntry<[]>
/**
* Ensure all imports appear before other statements.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/first/README.md
*/
'import-lite/first'?: Linter.RuleEntry<ImportLiteFirst>
/**
* Enforce a newline after import statements.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/newline-after-import/README.md
*/
'import-lite/newline-after-import'?: Linter.RuleEntry<ImportLiteNewlineAfterImport>
/**
* Forbid default exports.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/no-default-export/README.md
*/
'import-lite/no-default-export'?: Linter.RuleEntry<[]>
/**
* Forbid repeated import of the same module in multiple places.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/no-duplicates/README.md
*/
'import-lite/no-duplicates'?: Linter.RuleEntry<ImportLiteNoDuplicates>
/**
* Forbid the use of mutable exports with `var` or `let`.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/no-mutable-exports/README.md
*/
'import-lite/no-mutable-exports'?: Linter.RuleEntry<[]>
/**
* Forbid named default exports.
* @see https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/no-named-default/README.md
*/
'import-lite/no-named-default'?: Linter.RuleEntry<[]>
}
/* ======= Declarations ======= */
// ----- import-lite/consistent-type-specifier-style -----
type ImportLiteConsistentTypeSpecifierStyle = []|[("top-level" | "inline" | "prefer-top-level")]
// ----- import-lite/first -----
type ImportLiteFirst = []|[("absolute-first" | "disable-absolute-first")]
// ----- import-lite/newline-after-import -----
type ImportLiteNewlineAfterImport = []|[{
count?: number
exactCount?: boolean
considerComments?: boolean
}]
// ----- import-lite/no-duplicates -----
type ImportLiteNoDuplicates = []|[{
"prefer-inline"?: boolean
}]

View file

@ -0,0 +1,11 @@
import type { Rule } from 'eslint'
import type { RuleOptions } from './rule-options'
type RuleName<K extends string>
= K extends `${string}/${infer Name}`
? RuleName<Name>
: K
export type Rules = Required<{
[K in keyof RuleOptions as RuleName<K>]: Rule.RuleModule
}>

View file

@ -0,0 +1,46 @@
import "./vender.mjs";
import { t as consistent_type_specifier_style_default } from "./rules/consistent-type-specifier-style.mjs";
import { t as exports_last_default } from "./rules/exports-last.mjs";
import { t as first_default } from "./rules/first.mjs";
import { t as newline_after_import_default } from "./rules/newline-after-import.mjs";
import { t as no_default_export_default } from "./rules/no-default-export.mjs";
import { t as no_duplicates_default } from "./rules/no-duplicates.mjs";
import { t as no_mutable_exports_default } from "./rules/no-mutable-exports.mjs";
import { t as no_named_default_default } from "./rules/no-named-default.mjs";
//#region src/rules/index.ts
const rules = {
"consistent-type-specifier-style": consistent_type_specifier_style_default,
"exports-last": exports_last_default,
"first": first_default,
"newline-after-import": newline_after_import_default,
"no-default-export": no_default_export_default,
"no-duplicates": no_duplicates_default,
"no-mutable-exports": no_mutable_exports_default,
"no-named-default": no_named_default_default
};
//#endregion
//#region src/index.ts
const pluginName = "import-lite";
function generateConfig(name, filter = () => true) {
const ruleMeta = Object.entries(rules).filter(([ruleName, rule]) => !rule.meta?.deprecated && filter(ruleName, rule));
return {
name: `${pluginName}/${name}`,
plugins: { [pluginName]: {
name: pluginName,
rules
} },
rules: Object.fromEntries(ruleMeta.map(([ruleName]) => [`${pluginName}/${ruleName}`, "error"]))
};
}
var src_default = {
rules,
configs: {
recommended: generateConfig("recommended", (_, rule) => !!rule.meta?.docs?.recommended),
all: generateConfig("all")
}
};
//#endregion
export { src_default as default, pluginName };

View file

@ -0,0 +1,5 @@
//#region rolldown:runtime
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
//#endregion
export { __commonJSMin as t };

View file

@ -0,0 +1,99 @@
import { a as createRule, i as isCommaToken, r as getValue } from "../utils.mjs";
//#region src/rules/consistent-type-specifier-style/consistent-type-specifier-style.ts
function getImportText(node, sourceCode, specifiers) {
const sourceString = sourceCode.getText(node.source);
if (specifiers.length === 0) return "";
return `import type {${specifiers.map((s) => {
const importedName = getValue(s.imported);
if (importedName === s.local.name) return importedName;
return `${importedName} as ${s.local.name}`;
}).join(", ")}} from ${sourceString};`;
}
var consistent_type_specifier_style_default = createRule({
name: "consistent-type-specifier-style",
meta: {
type: "suggestion",
docs: { description: "Enforce or ban the use of inline type-only markers for named imports." },
fixable: "code",
schema: [{
type: "string",
enum: [
"top-level",
"inline",
"prefer-top-level"
],
default: "top-level"
}],
messages: {
inline: "Prefer using inline {{kind}} specifiers instead of a top-level {{kind}}-only import.",
topLevel: "Prefer using a top-level {{kind}}-only import instead of inline {{kind}} specifiers."
}
},
defaultOptions: ["top-level"],
create(context, [options]) {
const { sourceCode } = context;
if (options === "inline") return { ImportDeclaration(node) {
if (node.importKind === "value" || node.importKind == null) return;
if (node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
context.report({
node,
messageId: "inline",
data: { kind: node.importKind },
fix(fixer) {
const kindToken = sourceCode.getFirstToken(node, { skip: 1 });
return [kindToken ? fixer.remove(kindToken) : [], node.specifiers.map((specifier) => fixer.insertTextBefore(specifier, `${node.importKind} `))].flat();
}
});
} };
return { ImportDeclaration(node) {
if (node.importKind === "type" || node.specifiers.length === 0 || node.specifiers.length === 1 && (node.specifiers[0].type === "ImportDefaultSpecifier" || node.specifiers[0].type === "ImportNamespaceSpecifier")) return;
const typeSpecifiers = [];
const valueSpecifiers = [];
let defaultSpecifier = null;
for (const specifier of node.specifiers) {
if (specifier.type === "ImportDefaultSpecifier") {
defaultSpecifier = specifier;
continue;
}
if (!("importKind" in specifier)) continue;
if (specifier.importKind === "type") typeSpecifiers.push(specifier);
else if (specifier.importKind === "value" || specifier.importKind == null) valueSpecifiers.push(specifier);
}
const typeImport = getImportText(node, sourceCode, typeSpecifiers);
if (typeSpecifiers.length === node.specifiers.length) context.report({
node,
messageId: "topLevel",
data: { kind: "type" },
fix(fixer) {
return fixer.replaceText(node, typeImport);
}
});
else if (options === "top-level") for (const specifier of typeSpecifiers) context.report({
node: specifier,
messageId: "topLevel",
data: { kind: specifier.importKind },
fix(fixer) {
const fixes = [];
if (valueSpecifiers.length > 0) {
for (const specifier$1 of typeSpecifiers) {
const token = sourceCode.getTokenAfter(specifier$1);
if (token && isCommaToken(token)) fixes.push(fixer.remove(token));
fixes.push(fixer.remove(specifier$1));
}
const maybeComma = sourceCode.getTokenAfter(valueSpecifiers[valueSpecifiers.length - 1]);
if (isCommaToken(maybeComma)) fixes.push(fixer.remove(maybeComma));
} else if (defaultSpecifier) {
const comma = sourceCode.getTokenAfter(defaultSpecifier, isCommaToken);
const closingBrace = sourceCode.getTokenAfter(node.specifiers[node.specifiers.length - 1], (token) => token.type === "Punctuator" && token.value === "}");
fixes.push(fixer.removeRange([comma.range[0], closingBrace.range[1]]));
}
return [...fixes, fixer.insertTextAfter(node, `\n${typeImport}`)];
}
});
} };
}
});
//#endregion
export { consistent_type_specifier_style_default as t };

View file

@ -0,0 +1,30 @@
import { a as createRule } from "../utils.mjs";
//#region src/rules/exports-last/exports-last.ts
function isNonExportStatement({ type }) {
return type !== "ExportDefaultDeclaration" && type !== "ExportNamedDeclaration" && type !== "ExportAllDeclaration";
}
var exports_last_default = createRule({
name: "exports-last",
meta: {
type: "suggestion",
docs: { description: "Ensure all exports appear after other statements." },
schema: [],
messages: { end: "Export statements should appear at the end of the file" }
},
defaultOptions: [],
create(context) {
return { Program({ body }) {
const lastNonExportStatementIndex = body.findLastIndex(isNonExportStatement);
if (lastNonExportStatementIndex !== -1) {
for (const node of body.slice(0, lastNonExportStatementIndex)) if (!isNonExportStatement(node)) context.report({
node,
messageId: "end"
});
}
} };
}
});
//#endregion
export { exports_last_default as t };

View file

@ -0,0 +1,101 @@
import { a as createRule } from "../utils.mjs";
//#region src/rules/first/first.ts
function getImportValue(node) {
return node.type === "ImportDeclaration" ? node.source.value : "moduleReference" in node && "expression" in node.moduleReference && "value" in node.moduleReference.expression && node.moduleReference.expression.value;
}
function isPossibleDirective(node) {
return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string";
}
var first_default = createRule({
name: "first",
meta: {
type: "suggestion",
docs: { description: "Ensure all imports appear before other statements." },
fixable: "code",
schema: [{
type: "string",
enum: ["absolute-first", "disable-absolute-first"]
}],
messages: {
absolute: "Absolute imports should come before relative imports.",
order: "Import in body of module; reorder to top."
}
},
defaultOptions: [],
create(context, options) {
return { Program(n) {
const body = n.body;
if (!body?.length) return;
const absoluteFirst = options[0] === "absolute-first";
const { sourceCode } = context;
const originSourceCode = sourceCode.getText();
let nonImportCount = 0;
let anyExpressions = false;
let anyRelative = false;
let lastLegalImp = null;
const errorInfos = [];
let shouldSort = true;
let lastSortNodesIndex = 0;
for (const [index, node] of body.entries()) {
if (!anyExpressions && isPossibleDirective(node)) continue;
anyExpressions = true;
if (node.type === "ImportDeclaration" || node.type === "TSImportEqualsDeclaration") {
if (absoluteFirst) {
const importValue = getImportValue(node);
if (typeof importValue === "string" && /^\./.test(importValue)) anyRelative = true;
else if (anyRelative) context.report({
node: node.type === "ImportDeclaration" ? node.source : node.moduleReference,
messageId: "absolute"
});
}
if (nonImportCount > 0) {
/** @see https://eslint.org/docs/next/use/migrate-to-9.0.0#-removed-multiple-context-methods */
for (const variable of sourceCode.getDeclaredVariables(node)) {
if (!shouldSort) break;
for (const reference of variable.references) if (reference.identifier.range[0] < node.range[1]) {
shouldSort = false;
break;
}
}
if (shouldSort) lastSortNodesIndex = errorInfos.length;
errorInfos.push({
node,
range: [body[index - 1].range[1], node.range[1]]
});
} else lastLegalImp = node;
} else nonImportCount++;
}
if (errorInfos.length === 0) return;
for (const [index, { node }] of errorInfos.entries()) {
let fix;
if (index < lastSortNodesIndex) fix = (fixer) => fixer.insertTextAfter(node, "");
else if (index === lastSortNodesIndex) {
const sortNodes = errorInfos.slice(0, lastSortNodesIndex + 1);
fix = (fixer) => {
const removeFixers = sortNodes.map(({ range: range$1 }) => fixer.removeRange(range$1));
const range = [0, removeFixers[removeFixers.length - 1].range[1]];
let insertSourceCode = sortNodes.map(({ range: range$1 }) => {
const nodeSourceCode = originSourceCode.slice(...range$1);
if (/\S/.test(nodeSourceCode[0])) return `\n${nodeSourceCode}`;
return nodeSourceCode;
}).join("");
let replaceSourceCode = "";
if (!lastLegalImp) insertSourceCode = insertSourceCode.trim() + insertSourceCode.match(/^(\s+)/)[0];
const fixers = [lastLegalImp ? fixer.insertTextAfter(lastLegalImp, insertSourceCode) : fixer.insertTextBefore(body[0], insertSourceCode), ...removeFixers];
for (const [i, computedFixer] of fixers.entries()) replaceSourceCode += originSourceCode.slice(fixers[i - 1] ? fixers[i - 1].range[1] : 0, computedFixer.range[0]) + computedFixer.text;
return fixer.replaceTextRange(range, replaceSourceCode);
};
}
context.report({
node,
messageId: "order",
fix
});
}
} };
}
});
//#endregion
export { first_default as t };

View file

@ -0,0 +1,170 @@
import { a as createRule } from "../utils.mjs";
//#region src/rules/newline-after-import/newline-after-import.ts
function isStaticRequire(node) {
return node && node.callee && node.callee.type === "Identifier" && node.callee.name === "require" && node.arguments.length === 1 && node.arguments[0].type === "Literal" && typeof node.arguments[0].value === "string";
}
function containsNodeOrEqual(outerNode, innerNode) {
return outerNode.range[0] <= innerNode.range[0] && outerNode.range[1] >= innerNode.range[1];
}
function getScopeBody(scope) {
if (scope.block.type === "SwitchStatement") {
console.log("SwitchStatement scopes not supported");
return [];
}
const body = "body" in scope.block ? scope.block.body : null;
if (body && "type" in body && body.type === "BlockStatement") return body.body;
return Array.isArray(body) ? body : [];
}
function findNodeIndexInScopeBody(body, nodeToFind) {
return body.findIndex((node) => containsNodeOrEqual(node, nodeToFind));
}
function getLineDifference(node, nextNode) {
return nextNode.loc.start.line - node.loc.end.line;
}
function isClassWithDecorator(node) {
return node.type === "ClassDeclaration" && !!node.decorators?.length;
}
function isExportDefaultClass(node) {
return node.type === "ExportDefaultDeclaration" && node.declaration.type === "ClassDeclaration";
}
function isExportNameClass(node) {
return node.type === "ExportNamedDeclaration" && node.declaration?.type === "ClassDeclaration";
}
var newline_after_import_default = createRule({
name: "newline-after-import",
meta: {
type: "layout",
docs: { description: "Enforce a newline after import statements." },
fixable: "whitespace",
schema: [{
type: "object",
properties: {
count: {
type: "integer",
minimum: 1
},
exactCount: { type: "boolean" },
considerComments: { type: "boolean" }
},
additionalProperties: false
}],
messages: { newline: "Expected {{count}} empty line{{lineSuffix}} after {{type}} statement not followed by another {{type}}." }
},
defaultOptions: [{
count: 1,
exactCount: false,
considerComments: false
}],
create(context, [options]) {
const { count = 1, exactCount = false, considerComments = false } = options || {};
let level = 0;
const requireCalls = [];
function checkForNewLine(node, nextNode, type) {
if (isExportDefaultClass(nextNode) || isExportNameClass(nextNode)) {
const classNode = nextNode.declaration;
if (isClassWithDecorator(classNode)) nextNode = classNode.decorators[0];
} else if (isClassWithDecorator(nextNode)) nextNode = nextNode.decorators[0];
const lineDifference = getLineDifference(node, nextNode);
const EXPECTED_LINE_DIFFERENCE = count + 1;
if (lineDifference < EXPECTED_LINE_DIFFERENCE || exactCount && lineDifference !== EXPECTED_LINE_DIFFERENCE) {
let column = node.loc.start.column;
if (node.loc.start.line !== node.loc.end.line) column = 0;
context.report({
loc: {
line: node.loc.end.line,
column
},
messageId: "newline",
data: {
count,
lineSuffix: count > 1 ? "s" : "",
type
},
fix: exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
});
}
}
function commentAfterImport(node, nextComment, type) {
const lineDifference = getLineDifference(node, nextComment);
const EXPECTED_LINE_DIFFERENCE = count + 1;
if (lineDifference < EXPECTED_LINE_DIFFERENCE) {
let column = node.loc.start.column;
if (node.loc.start.line !== node.loc.end.line) column = 0;
context.report({
loc: {
line: node.loc.end.line,
column
},
messageId: "newline",
data: {
count,
lineSuffix: count > 1 ? "s" : "",
type
},
fix: exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(node, "\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference))
});
}
}
function incrementLevel() {
level++;
}
function decrementLevel() {
level--;
}
function checkImport(node) {
const { parent } = node;
if (!parent || !("body" in parent) || !parent.body) return;
const root = parent;
const nodePosition = root.body.indexOf(node);
const nextNode = root.body[nodePosition + 1];
const endLine = node.loc.end.line;
let nextComment;
if (root.comments !== void 0 && considerComments) nextComment = root.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + count + 1);
if (node.type === "TSImportEqualsDeclaration" && node.isExport) return;
if (nextComment) commentAfterImport(node, nextComment, "import");
else if (nextNode && nextNode.type !== "ImportDeclaration" && (nextNode.type !== "TSImportEqualsDeclaration" || nextNode.isExport)) checkForNewLine(node, nextNode, "import");
}
return {
"ImportDeclaration": checkImport,
"TSImportEqualsDeclaration": checkImport,
CallExpression(node) {
if (isStaticRequire(node) && level === 0) requireCalls.push(node);
},
"Program:exit": function(node) {
const scopeBody = getScopeBody(context.sourceCode.getScope(node));
for (const [index, node$1] of requireCalls.entries()) {
const nodePosition = findNodeIndexInScopeBody(scopeBody, node$1);
const statementWithRequireCall = scopeBody[nodePosition];
const nextStatement = scopeBody[nodePosition + 1];
const nextRequireCall = requireCalls[index + 1];
if (nextRequireCall && containsNodeOrEqual(statementWithRequireCall, nextRequireCall)) continue;
if (nextStatement && (!nextRequireCall || !containsNodeOrEqual(nextStatement, nextRequireCall))) {
let nextComment;
if ("comments" in statementWithRequireCall.parent && statementWithRequireCall.parent.comments !== void 0 && considerComments) {
const endLine = node$1.loc.end.line;
nextComment = statementWithRequireCall.parent.comments.find((o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + count + 1);
}
if (nextComment && nextComment !== void 0) commentAfterImport(statementWithRequireCall, nextComment, "require");
else checkForNewLine(statementWithRequireCall, nextStatement, "require");
}
}
},
"FunctionDeclaration": incrementLevel,
"FunctionExpression": incrementLevel,
"ArrowFunctionExpression": incrementLevel,
"BlockStatement": incrementLevel,
"ObjectExpression": incrementLevel,
"Decorator": incrementLevel,
"FunctionDeclaration:exit": decrementLevel,
"FunctionExpression:exit": decrementLevel,
"ArrowFunctionExpression:exit": decrementLevel,
"BlockStatement:exit": decrementLevel,
"ObjectExpression:exit": decrementLevel,
"Decorator:exit": decrementLevel
};
}
});
//#endregion
export { newline_after_import_default as t };

View file

@ -0,0 +1,49 @@
import { a as createRule, n as sourceType, r as getValue } from "../utils.mjs";
//#region src/rules/no-default-export/no-default-export.ts
var no_default_export_default = createRule({
name: "no-default-export",
meta: {
type: "suggestion",
docs: { description: "Forbid default exports." },
schema: [],
messages: {
preferNamed: "Prefer named exports.",
noAliasDefault: "Do not alias `{{local}}` as `default`. Just export `{{local}}` itself instead."
}
},
defaultOptions: [],
create(context) {
if (sourceType(context) !== "module") return {};
const { sourceCode } = context;
return {
ExportDefaultDeclaration(node) {
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
context.report({
node,
messageId: "preferNamed",
loc
});
},
ExportNamedDeclaration(node) {
for (const specifier of node.specifiers.filter((specifier$1) => getValue(specifier$1.exported) === "default")) {
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
if (specifier.type === "ExportDefaultSpecifier") context.report({
node,
messageId: "preferNamed",
loc
});
else if (specifier.type === "ExportSpecifier") context.report({
node,
messageId: "noAliasDefault",
data: { local: getValue(specifier.local) },
loc
});
}
}
};
}
});
//#endregion
export { no_default_export_default as t };

View file

@ -0,0 +1,190 @@
import { a as createRule, t as resolve } from "../utils.mjs";
//#region src/rules/no-duplicates/no-duplicates.ts
function checkImports(imported, context) {
imported.forEach((nodes, module) => {
if (nodes.length <= 1) return;
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
context.report({
node: node.source,
messageId: "duplicate",
data: { module },
fix: i === 0 ? getFix(nodes, context.sourceCode, context) : null
});
}
});
}
function getFix(nodes, sourceCode, context) {
const first = nodes[0];
if (hasProblematicComments(first, sourceCode) || hasNamespace(first)) return null;
const defaultImportNames = new Set(nodes.flatMap((x) => getDefaultImportName(x) || []));
if (defaultImportNames.size > 1) return null;
const restWithoutCommentsAndNamespaces = nodes.slice(1).filter((node) => !hasProblematicComments(node, sourceCode) && !hasNamespace(node));
const restWithoutCommentsAndNamespacesHasSpecifiers = restWithoutCommentsAndNamespaces.map(hasSpecifiers);
const specifiers = restWithoutCommentsAndNamespaces.reduce((acc, node, nodeIndex) => {
const tokens = sourceCode.getTokens(node);
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
if (openBrace == null || closeBrace == null) return acc;
acc.push({
importNode: node,
identifiers: sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(","),
isEmpty: !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex]
});
return acc;
}, []);
const unnecessaryImports = restWithoutCommentsAndNamespaces.filter((node, nodeIndex) => !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex] && !specifiers.some((specifier) => specifier.importNode === node));
const shouldAddSpecifiers = specifiers.length > 0;
const shouldRemoveUnnecessary = unnecessaryImports.length > 0;
const shouldAddDefault = getDefaultImportName(first) == null && defaultImportNames.size === 1;
if (!shouldAddSpecifiers && !shouldRemoveUnnecessary && !shouldAddDefault) return null;
const preferInline = context.options[0] && context.options[0]["prefer-inline"];
return (fixer) => {
const tokens = sourceCode.getTokens(first);
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
const firstToken = sourceCode.getFirstToken(first);
const [defaultImportName] = defaultImportNames;
const firstHasTrailingComma = closeBrace != null && isPunctuator(sourceCode.getTokenBefore(closeBrace), ",");
const firstIsEmpty = !hasSpecifiers(first);
const firstExistingIdentifiers = firstIsEmpty ? /* @__PURE__ */ new Set() : new Set(sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(",").map((x) => x.split(" as ")[0].trim()));
const [specifiersText] = specifiers.reduce(([result, needsComma, existingIdentifiers], specifier) => {
const isTypeSpecifier = "importNode" in specifier && specifier.importNode.importKind === "type";
const [specifierText, updatedExistingIdentifiers] = specifier.identifiers.reduce(([text, set], cur) => {
const trimmed = cur.trim();
if (trimmed.length === 0 || existingIdentifiers.has(trimmed)) return [text, set];
const curWithType = preferInline && isTypeSpecifier ? cur.replace(/^(\s*)/, "$1type ") : cur;
return [text.length > 0 ? `${text},${curWithType}` : curWithType, set.add(trimmed)];
}, ["", existingIdentifiers]);
return [
needsComma && !specifier.isEmpty && specifierText.length > 0 ? `${result},${specifierText}` : `${result}${specifierText}`,
specifier.isEmpty ? needsComma : true,
updatedExistingIdentifiers
];
}, [
"",
!firstHasTrailingComma && !firstIsEmpty,
firstExistingIdentifiers
]);
const fixes = [];
if (shouldAddSpecifiers && preferInline && first.importKind === "type") {
const typeIdentifierToken = tokens.find((token) => token.type === "Identifier" && token.value === "type");
if (typeIdentifierToken) fixes.push(fixer.removeRange([typeIdentifierToken.range[0], typeIdentifierToken.range[1] + 1]));
for (const identifier of tokens.filter((token) => firstExistingIdentifiers.has(token.value))) fixes.push(fixer.replaceTextRange([identifier.range[0], identifier.range[1]], `type ${identifier.value}`));
}
if (openBrace == null && shouldAddSpecifiers && shouldAddDefault) fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName}, {${specifiersText}} from`));
else if (openBrace == null && !shouldAddSpecifiers && shouldAddDefault) fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName} from`));
else if (openBrace != null && closeBrace != null && shouldAddDefault) {
fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName},`));
if (shouldAddSpecifiers) fixes.push(fixer.insertTextBefore(closeBrace, specifiersText));
} else if (openBrace == null && shouldAddSpecifiers && !shouldAddDefault) if (first.specifiers.length === 0) fixes.push(fixer.insertTextAfter(firstToken, ` {${specifiersText}} from`));
else fixes.push(fixer.insertTextAfter(first.specifiers[0], `, {${specifiersText}}`));
else if (openBrace != null && closeBrace != null && !shouldAddDefault) {
const tokenBefore = sourceCode.getTokenBefore(closeBrace);
fixes.push(fixer.insertTextAfter(tokenBefore, specifiersText));
}
for (const specifier of specifiers) {
const importNode = specifier.importNode;
fixes.push(fixer.remove(importNode));
const charAfterImportRange = [importNode.range[1], importNode.range[1] + 1];
if (sourceCode.text.slice(charAfterImportRange[0], charAfterImportRange[1]) === "\n") fixes.push(fixer.removeRange(charAfterImportRange));
}
for (const node of unnecessaryImports) {
fixes.push(fixer.remove(node));
const charAfterImportRange = [node.range[1], node.range[1] + 1];
if (sourceCode.text.slice(charAfterImportRange[0], charAfterImportRange[1]) === "\n") fixes.push(fixer.removeRange(charAfterImportRange));
}
return fixes;
};
}
function isPunctuator(node, value) {
return node.type === "Punctuator" && node.value === value;
}
function getDefaultImportName(node) {
return node.specifiers.find((specifier) => specifier.type === "ImportDefaultSpecifier")?.local.name;
}
function hasNamespace(node) {
return node.specifiers.some((specifier) => specifier.type === "ImportNamespaceSpecifier");
}
function hasSpecifiers(node) {
return node.specifiers.some((specifier) => specifier.type === "ImportSpecifier");
}
function hasProblematicComments(node, sourceCode) {
return hasCommentBefore(node, sourceCode) || hasCommentAfter(node, sourceCode) || hasCommentInsideNonSpecifiers(node, sourceCode);
}
function hasCommentBefore(node, sourceCode) {
return sourceCode.getCommentsBefore(node).some((comment) => comment.loc.end.line >= node.loc.start.line - 1);
}
function hasCommentAfter(node, sourceCode) {
return sourceCode.getCommentsAfter(node).some((comment) => comment.loc.start.line === node.loc.end.line);
}
function hasCommentInsideNonSpecifiers(node, sourceCode) {
const tokens = sourceCode.getTokens(node);
const openBraceIndex = tokens.findIndex((token) => isPunctuator(token, "{"));
const closeBraceIndex = tokens.findIndex((token) => isPunctuator(token, "}"));
return (openBraceIndex !== -1 && closeBraceIndex !== -1 ? [...tokens.slice(1, openBraceIndex + 1), ...tokens.slice(closeBraceIndex + 1)] : tokens.slice(1)).some((token) => sourceCode.getCommentsBefore(token).length > 0);
}
var no_duplicates_default = createRule({
name: "no-duplicates",
meta: {
type: "problem",
docs: {
recommended: true,
description: "Forbid repeated import of the same module in multiple places."
},
fixable: "code",
schema: [{
type: "object",
properties: { "prefer-inline": { type: "boolean" } },
additionalProperties: false
}],
messages: { duplicate: "'{{module}}' imported multiple times." }
},
defaultOptions: [],
create(context) {
const preferInline = context.options[0]?.["prefer-inline"];
const moduleMaps = /* @__PURE__ */ new Map();
function getImportMap(n) {
const parent = n.parent;
let map;
if (moduleMaps.has(parent)) map = moduleMaps.get(parent);
else {
map = {
imported: /* @__PURE__ */ new Map(),
nsImported: /* @__PURE__ */ new Map(),
defaultTypesImported: /* @__PURE__ */ new Map(),
namespaceTypesImported: /* @__PURE__ */ new Map(),
namedTypesImported: /* @__PURE__ */ new Map()
};
moduleMaps.set(parent, map);
}
if (n.importKind === "type") {
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportDefaultSpecifier") return map.defaultTypesImported;
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportNamespaceSpecifier") return map.namespaceTypesImported;
if (!preferInline) return map.namedTypesImported;
}
if (!preferInline && n.specifiers.some((spec) => "importKind" in spec && spec.importKind === "type")) return map.namedTypesImported;
return hasNamespace(n) ? map.nsImported : map.imported;
}
return {
ImportDeclaration(n) {
const resolvedPath = resolve(n.source.value);
const importMap = getImportMap(n);
if (importMap.has(resolvedPath)) importMap.get(resolvedPath).push(n);
else importMap.set(resolvedPath, [n]);
},
"Program:exit": function() {
for (const map of moduleMaps.values()) {
checkImports(map.imported, context);
checkImports(map.nsImported, context);
checkImports(map.defaultTypesImported, context);
checkImports(map.namedTypesImported, context);
}
}
};
}
});
//#endregion
export { no_duplicates_default as t };

View file

@ -0,0 +1,41 @@
import { a as createRule } from "../utils.mjs";
//#region src/rules/no-mutable-exports/no-mutable-exports.ts
var no_mutable_exports_default = createRule({
name: "no-mutable-exports",
meta: {
type: "suggestion",
docs: { description: "Forbid the use of mutable exports with `var` or `let`." },
schema: [],
messages: { noMutable: "Exporting mutable '{{kind}}' binding, use 'const' instead." }
},
defaultOptions: [],
create(context) {
function checkDeclaration(node) {
if ("kind" in node && (node.kind === "var" || node.kind === "let")) context.report({
node,
messageId: "noMutable",
data: { kind: node.kind }
});
}
function checkDeclarationsInScope({ variables }, name) {
for (const variable of variables) if (variable.name === name) {
for (const def of variable.defs) if (def.type === "Variable" && def.parent) checkDeclaration(def.parent);
}
}
return {
ExportDefaultDeclaration(node) {
const scope = context.sourceCode.getScope(node);
if ("name" in node.declaration) checkDeclarationsInScope(scope, node.declaration.name);
},
ExportNamedDeclaration(node) {
const scope = context.sourceCode.getScope(node);
if (node.declaration) checkDeclaration(node.declaration);
else if (!node.source) for (const specifier of node.specifiers) checkDeclarationsInScope(scope, specifier.local.name);
}
};
}
});
//#endregion
export { no_mutable_exports_default as t };

View file

@ -0,0 +1,28 @@
import { a as createRule, r as getValue } from "../utils.mjs";
//#region src/rules/no-named-default/no-named-default.ts
var no_named_default_default = createRule({
name: "no-named-default",
meta: {
type: "suggestion",
docs: { description: "Forbid named default exports." },
schema: [],
messages: { default: `Use default import syntax to import '{{importName}}'.` }
},
defaultOptions: [],
create(context) {
return { ImportDeclaration(node) {
for (const im of node.specifiers) {
if ("importKind" in im && im.importKind === "type") continue;
if (im.type === "ImportSpecifier" && getValue(im.imported) === "default") context.report({
node: im.local,
messageId: "default",
data: { importName: im.local.name }
});
}
} };
}
});
//#endregion
export { no_named_default_default as t };

View file

@ -0,0 +1,52 @@
import { t as require_eslint_utils } from "./vender.mjs";
//#region src/utils/index.ts
var import_eslint_utils = require_eslint_utils();
function createRule({ name, create, defaultOptions = [], meta }) {
return {
create: ((context) => {
const optionsCount = Math.max(context.options.length, defaultOptions.length);
return create(context, Array.from({ length: optionsCount }, (_, i) => {
if ((0, import_eslint_utils.isObjectNotArray)(context.options[i]) && (0, import_eslint_utils.isObjectNotArray)(defaultOptions[i])) return (0, import_eslint_utils.deepMerge)(defaultOptions[i], context.options[i]);
return context.options[i] ?? defaultOptions[i];
}));
}),
defaultOptions,
meta: {
...meta,
docs: {
...meta.docs,
url: `https://github.com/9romise/eslint-plugin-import-lite/blob/main/src/rules/${name}/README.md`
}
}
};
}
//#endregion
//#region src/utils/ast.ts
function isCommaToken(token) {
return token.type === "Punctuator" && token.value === ",";
}
function getValue(node) {
switch (node.type) {
case "Identifier": return node.name;
case "Literal": return node.value;
default: throw new Error(`Unsupported node type: ${node.type}`);
}
}
//#endregion
//#region src/utils/compat.ts
function sourceType(context) {
if ("sourceType" in context.parserOptions) return context.parserOptions.sourceType;
if ("languageOptions" in context && context.languageOptions) return context.languageOptions.sourceType;
}
//#endregion
//#region src/utils/resolve.ts
function resolve(path) {
return path;
}
//#endregion
export { createRule as a, isCommaToken as i, sourceType as n, getValue as r, resolve as t };

View file

@ -0,0 +1,205 @@
import { t as __commonJSMin } from "./rolldown-runtime.mjs";
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/deepMerge.js
var require_deepMerge = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObjectNotArray = isObjectNotArray;
exports.deepMerge = deepMerge;
/**
* Check if the variable contains an object strictly rejecting arrays
* @returns `true` if obj is an object
*/
function isObjectNotArray(obj) {
return typeof obj === "object" && obj != null && !Array.isArray(obj);
}
/**
* Pure function - doesn't mutate either parameter!
* Merges two objects together deeply, overwriting the properties in first with the properties in second
* @param first The first object
* @param second The second object
* @returns a new object
*/
function deepMerge(first = {}, second = {}) {
const keys = new Set([...Object.keys(first), ...Object.keys(second)]);
return Object.fromEntries([...keys].map((key) => {
const firstHasKey = key in first;
const secondHasKey = key in second;
const firstValue = first[key];
const secondValue = second[key];
let value;
if (firstHasKey && secondHasKey) if (isObjectNotArray(firstValue) && isObjectNotArray(secondValue)) value = deepMerge(firstValue, secondValue);
else value = secondValue;
else if (firstHasKey) value = firstValue;
else value = secondValue;
return [key, value];
}));
}
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/applyDefault.js
var require_applyDefault = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyDefault = applyDefault;
const deepMerge_1 = require_deepMerge();
/**
* Pure function - doesn't mutate either parameter!
* Uses the default options and overrides with the options provided by the user
* @param defaultOptions the defaults
* @param userOptions the user opts
* @returns the options with defaults
*/
function applyDefault(defaultOptions, userOptions) {
const options = structuredClone(defaultOptions);
if (userOptions == null) return options;
options.forEach((opt, i) => {
if (userOptions[i] !== void 0) {
const userOpt = userOptions[i];
if ((0, deepMerge_1.isObjectNotArray)(userOpt) && (0, deepMerge_1.isObjectNotArray)(opt)) options[i] = (0, deepMerge_1.deepMerge)(opt, userOpt);
else options[i] = userOpt;
}
});
return options;
}
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/parserSeemsToBeTSESLint.js
var require_parserSeemsToBeTSESLint = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.parserSeemsToBeTSESLint = parserSeemsToBeTSESLint;
function parserSeemsToBeTSESLint(parser) {
return !!parser && /(?:typescript-eslint|\.\.)[\w/\\]*parser/.test(parser);
}
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/getParserServices.js
var require_getParserServices = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.getParserServices = getParserServices;
const parserSeemsToBeTSESLint_1 = require_parserSeemsToBeTSESLint();
const ERROR_MESSAGE_REQUIRES_PARSER_SERVICES = "You have used a rule which requires type information, but don't have parserOptions set to generate type information for this file. See https://typescript-eslint.io/getting-started/typed-linting for enabling linting with type information.";
const ERROR_MESSAGE_UNKNOWN_PARSER = "Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward \"parserOptions.project\" to @typescript-eslint/parser.";
function getParserServices(context, allowWithoutFullTypeInformation = false) {
const parser = context.parserPath || context.languageOptions.parser?.meta?.name;
if (context.sourceCode.parserServices?.esTreeNodeToTSNodeMap == null || context.sourceCode.parserServices.tsNodeToESTreeNodeMap == null) throwError(parser);
if (context.sourceCode.parserServices.program == null && !allowWithoutFullTypeInformation) throwError(parser);
return context.sourceCode.parserServices;
}
function throwError(parser) {
const messages = [
ERROR_MESSAGE_REQUIRES_PARSER_SERVICES,
`Parser: ${parser || "(unknown)"}`,
!(0, parserSeemsToBeTSESLint_1.parserSeemsToBeTSESLint)(parser) && ERROR_MESSAGE_UNKNOWN_PARSER
].filter(Boolean);
throw new Error(messages.join("\n"));
}
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/InferTypesFromRule.js
var require_InferTypesFromRule = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/nullThrows.js
var require_nullThrows = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.NullThrowsReasons = void 0;
exports.nullThrows = nullThrows;
/**
* A set of common reasons for calling nullThrows
*/
exports.NullThrowsReasons = {
MissingParent: "Expected node to have a parent.",
MissingToken: (token, thing) => `Expected to find a ${token} for the ${thing}.`
};
/**
* Assert that a value must not be null or undefined.
* This is a nice explicit alternative to the non-null assertion operator.
*/
function nullThrows(value, message) {
if (value == null) throw new Error(`Non-null Assertion Failed: ${message}`);
return value;
}
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/RuleCreator.js
var require_RuleCreator = /* @__PURE__ */ __commonJSMin(((exports) => {
Object.defineProperty(exports, "__esModule", { value: true });
exports.RuleCreator = RuleCreator;
const applyDefault_1 = require_applyDefault();
/**
* Creates reusable function to create rules with default options and docs URLs.
*
* @param urlCreator Creates a documentation URL for a given rule name.
* @returns Function to create a rule with the docs URL format.
*/
function RuleCreator(urlCreator) {
return function createNamedRule({ meta, name, ...rule }) {
return createRule({
meta: {
...meta,
docs: {
...meta.docs,
url: urlCreator(name)
}
},
...rule
});
};
}
function createRule({ create, defaultOptions, meta }) {
return {
create(context) {
return create(context, (0, applyDefault_1.applyDefault)(defaultOptions, context.options));
},
defaultOptions,
meta
};
}
/**
* Creates a well-typed TSESLint custom ESLint rule without a docs URL.
*
* @returns Well-typed TSESLint custom ESLint rule.
* @remarks It is generally better to provide a docs URL function to RuleCreator.
*/
RuleCreator.withoutDocs = function withoutDocs(args) {
return createRule(args);
};
}));
//#endregion
//#region node_modules/.pnpm/@typescript-eslint+utils@8.50.0_eslint@9.39.2_jiti@2.5.1__typescript@5.9.3/node_modules/@typescript-eslint/utils/dist/eslint-utils/index.js
var require_eslint_utils = /* @__PURE__ */ __commonJSMin(((exports) => {
var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
if (k2 === void 0) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) desc = {
enumerable: true,
get: function() {
return m[k];
}
};
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === void 0) k2 = k;
o[k2] = m[k];
}));
var __exportStar = exports && exports.__exportStar || function(m, exports$1) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require_applyDefault(), exports);
__exportStar(require_deepMerge(), exports);
__exportStar(require_getParserServices(), exports);
__exportStar(require_InferTypesFromRule(), exports);
__exportStar(require_nullThrows(), exports);
__exportStar(require_RuleCreator(), exports);
}));
//#endregion
export { require_eslint_utils as t };