🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@yafh/eslint-plugin

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@yafh/eslint-plugin - npm Package Compare versions

Comparing version
0.5.0
to
0.6.0
+507
-1
dist/index.js

@@ -1,1 +0,507 @@

"use strict";Object.defineProperty(exports, "__esModule", {value: true});var _types = require('@typescript-eslint/types');var _utils = require('@typescript-eslint/utils');var i=_utils.ESLintUtils.RuleCreator(e=>e);function c(e){return e.toLowerCase().trim()}function f(e,t){let o=c(e.source.value);return typeof t=="string"?o===t:t.some(r=>o.startsWith(c(r)))}function d(e,t){let o=c(e.source.value);return typeof t=="string"?o.startsWith(c(t)):t.some(r=>o.startsWith(c(r)))}function g(e,t){let o=e.source.value;return t.test(o)}function x(e){return e.type===_types.AST_NODE_TYPES.ImportSpecifier&&(e.imported.range[0]!==e.local.range[0]||e.imported.range[1]!==e.local.range[1])}var v="icon-component-prefix",I=i({name:v,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[{type:["string","array"],description:"Icon Component source matcher"},{type:["string"],description:"prefix"}],messages:{missingIconComponentPrefix:"Expect icon component prefix '{{prefix}}'"}},defaultOptions:[["@ricons","@vicons","@v2icons","@sicons"],"Icon"],create:(e,t)=>({ImportDeclaration(o){let[r,s]=t;if(d(o,r))for(let n of o.specifiers)n.local.name.startsWith(s)||e.report({loc:n.loc,messageId:"missingIconComponentPrefix",data:{prefix:s},fix(l){let m=RegExp(`^${s}`,"i").test(n.local.name),a=s+(m?n.local.name.substring(s.length):n.local.name);return n.type===_types.AST_NODE_TYPES.ImportSpecifier&&!x(n)&&(a=`${n.local.name} as ${a}`),l.replaceText(n.local,a)}})}})});var _path = require('path');var R="no-index-vue",y=i({name:R,meta:{type:"problem",docs:{description:"",recommended:"recommended"},schema:[],messages:{noIndexVue:"Do not use index.vue"}},defaultOptions:[],create:e=>({Program(){_path.basename.call(void 0, e.getFilename()).toLocaleLowerCase()==="index.vue"&&e.report({loc:{line:1,column:0},messageId:"noIndexVue"})}})});var N="no-multiple-slash-comment";function j(e){return e.type!==_utils.AST_TOKEN_TYPES.Line?!1:/^\/\s*<(amd-module|amd-dependency|reference){1}.*\/>\s*$/.test(e.value)}var S=i({name:N,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[],messages:{noMultipleSlashComment:"Do not use multiple slashes for single line comments."}},defaultOptions:[],create:e=>{let t=e.getSourceCode();return{Program(){t.getAllComments().filter(o=>o.type==="Line").filter(o=>!j(o)).filter(o=>/^\/+/.test(o.value)).forEach(o=>{e.report({node:o,messageId:"noMultipleSlashComment",fix:r=>r.replaceText(o,`//${o.value.replace(/^\/+/,"")}`)})})}}}});var _pascalcase = require('pascal-case');var W="pascal-case-component-name",C=i({name:W,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},schema:[{type:["string","array"],description:"Component file extensions"}],messages:{missingPascalCaseComponentName:"Component name must be PascalCase. e.g. {{pascalCase}}"}},defaultOptions:["vue"],create:(e,t)=>({Program(){let o=_path.basename.call(void 0, e.getFilename());if(!RegExp(`\\.(${Array.isArray(t[0])?t[0].join("|"):t[0]})$`).test(o))return;let r=o.split(".")[0],s=_pascalcase.pascalCase.call(void 0, r,{transform:_pascalcase.pascalCaseTransformMerge});r!==s&&e.report({loc:{line:1,column:0},messageId:"missingPascalCaseComponentName",data:{pascalCase:s+o.slice(r.length)}})}})});var k="no-cjs-icon-component",_=/^@(r|v|v2)icons/i;function w(e){var m;let[t,o,r,...s]=e.split("/"),n=o!=="utils"&&!["es","",void 0].includes((m=r==null?void 0:r.trim())==null?void 0:m.toLocaleLowerCase());return{org:t,iconSet:o,isUtil:o==="utils",shouldFix:n,fixSource:()=>{var u;if(!n)return e;let a=[t,o,"es"];return((u=r==null?void 0:r.trim())==null?void 0:u.toLocaleLowerCase())!=="lib"&&a.push(r),a.push(...s),a.join("/")}}}var h=i({name:k,meta:{type:"problem",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[],messages:{noCjsIconCompnoent:"Do not import icon components maybe cjs."}},defaultOptions:[],create:e=>({ImportDeclaration(t){if(!g(t,_))return;let{shouldFix:o,fixSource:r}=w(t.source.value);o&&e.report({messageId:"noCjsIconCompnoent",node:t,fix(s){return s.replaceText(t.source,`'${r()}'`)}})}})});var F="no-default-import",O=i({name:F,meta:{type:"problem",docs:{description:"",recommended:"recommended"},schema:[{type:["array","string"],description:"No default import source matcher"}],messages:{noDefaultImport:"Do not use default imports in '{{source}}'",noWrokspaceImport:"Do not use workspace imports in '{{source}}'"}},defaultOptions:[[]],create:(e,t)=>({ImportDeclaration(o){let[r]=t;if(!f(o,r)||o.importKind==="type")return;let s;for(let n of o.specifiers)if(n.type==="ImportDefaultSpecifier"){s="noDefaultImport";break}else if(n.type==="ImportNamespaceSpecifier"){s="noWrokspaceImport";break}s&&e.report({node:o,messageId:s,data:{source:o.source.value}})}})});var V={"@yafh/icon-component-prefix":"error","@yafh/no-cjs-icon-component":"error","@yafh/no-multiple-slash-comment":"error"};function p(e){return{plugins:["@yafh"],rules:{...V,...e}}}var T={recommended:p({}),"recommended-vue":p({"@yafh/no-index-vue":"error","@yafh/pascal-case-component-name":"error"}),"recommended-solid":p({"@yafh/pascal-case-component-name":["error","tsx"]})};var xe={rules:{"icon-component-prefix":I,"no-index-vue":y,"no-multiple-slash-comment":S,"pascal-case-component-name":C,"no-cjs-icon-component":h,"no-default-import":O},configs:T};exports.default = xe;
"use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/rules/icon-component-prefix.ts
var _types = require('@typescript-eslint/types');
// src/utils/common.ts
var _utils = require('@typescript-eslint/utils');
var createRule = _utils.ESLintUtils.RuleCreator((name8) => name8);
function normalizeSource(source) {
return source.toLowerCase().trim();
}
function isStrictSourceOf(node, matcher) {
const source = normalizeSource(node.source.value);
if (typeof matcher === "string")
return source === matcher;
else
return matcher.some((m) => source.startsWith(normalizeSource(m)));
}
function isSourceOf(node, matcher) {
const source = normalizeSource(node.source.value);
if (typeof matcher === "string")
return source.startsWith(normalizeSource(matcher));
else
return matcher.some((m) => source.startsWith(normalizeSource(m)));
}
function isSourceOfRegExp(node, matcher) {
const source = node.source.value;
return matcher.test(source);
}
function isAliasImportSpecifier(node) {
return node.type === _types.AST_NODE_TYPES.ImportSpecifier && (node.imported.range[0] !== node.local.range[0] || node.imported.range[1] !== node.local.range[1]);
}
// src/rules/icon-component-prefix.ts
var name = "icon-component-prefix";
var icon_component_prefix_default = createRule({
name,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [
{
type: ["string", "array"],
description: "Icon Component source matcher"
},
{
type: ["string"],
description: "prefix"
}
],
messages: {
missingIconComponentPrefix: "Expect icon component prefix '{{prefix}}'"
}
},
defaultOptions: [["@ricons", "@vicons", "@v2icons", "@sicons"], "Icon"],
create: (context, options) => {
return {
ImportDeclaration(node) {
const [matcher, prefix] = options;
if (!isSourceOf(node, matcher))
return;
for (const specifier of node.specifiers) {
if (!specifier.local.name.startsWith(prefix)) {
context.report({
loc: specifier.loc,
messageId: "missingIconComponentPrefix",
data: {
prefix
},
fix(fixer) {
const caseMiss = RegExp(`^${prefix}`, "i").test(specifier.local.name);
let code = prefix + (caseMiss ? specifier.local.name.substring(prefix.length) : specifier.local.name);
if (specifier.type === _types.AST_NODE_TYPES.ImportSpecifier && !isAliasImportSpecifier(specifier))
code = `${specifier.local.name} as ${code}`;
return fixer.replaceText(specifier.local, code);
}
});
}
}
}
};
}
});
// src/rules/no-index-vue.ts
var _path = require('path');
var name2 = "no-index-vue";
var no_index_vue_default = createRule(
{
name: name2,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
schema: [],
messages: {
noIndexVue: "Do not use index.vue"
}
},
defaultOptions: [],
create: (context) => {
return {
Program() {
if (_path.basename.call(void 0, context.getFilename()).toLocaleLowerCase() === "index.vue") {
context.report({
loc: {
line: 1,
column: 0
},
messageId: "noIndexVue"
});
}
}
};
}
}
);
// src/rules/no-multiple-slash-comment.ts
var name3 = "no-multiple-slash-comment";
function isTripleSlashDirectives(comment) {
if (comment.type !== _utils.AST_TOKEN_TYPES.Line)
return false;
return /^\/\s*<(amd-module|amd-dependency|reference){1}.*\/>\s*$/.test(comment.value);
}
var no_multiple_slash_comment_default = createRule({
name: name3,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [],
messages: {
noMultipleSlashComment: "Do not use multiple slashes for single line comments."
}
},
defaultOptions: [],
create: (context) => {
const sourceCode = context.getSourceCode();
return {
Program() {
sourceCode.getAllComments().filter((comment) => comment.type === "Line").filter((comment) => !isTripleSlashDirectives(comment)).filter((comment) => /^\/+/.test(comment.value)).forEach((comment) => {
context.report({
node: comment,
messageId: "noMultipleSlashComment",
fix: (fixer) => fixer.replaceText(comment, `//${comment.value.replace(/^\/+/, "")}`)
});
});
}
};
}
});
// src/rules/pascal-case-component-name.ts
var _pascalcase = require('pascal-case');
var name4 = "pascal-case-component-name";
var pascal_case_component_name_default = createRule(
{
name: name4,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
schema: [
{
type: ["string", "array"],
description: "Component file extensions"
}
],
messages: {
missingPascalCaseComponentName: "Component name must be PascalCase. e.g. {{pascalCase}}"
}
},
defaultOptions: ["vue"],
create: (context, options) => {
return {
Program() {
const baseName = _path.basename.call(void 0, context.getFilename());
if (!RegExp(`\\.(${Array.isArray(options[0]) ? options[0].join("|") : options[0]})$`).test(baseName))
return;
const fileName = baseName.split(".")[0];
const pascalCaseName = _pascalcase.pascalCase.call(void 0, fileName, { transform: _pascalcase.pascalCaseTransformMerge });
if (fileName !== pascalCaseName) {
context.report({
loc: {
line: 1,
column: 0
},
messageId: "missingPascalCaseComponentName",
data: {
pascalCase: pascalCaseName + baseName.slice(fileName.length)
}
});
}
}
};
}
}
);
// src/rules/no-cjs-icon-component.ts
var name5 = "no-cjs-icon-component";
var singleIconComponentRE = /^@(r|v|v2)icons/i;
function parse(source) {
var _a;
const [org, iconSet, es, ...seg] = source.split("/");
const shouldFix = iconSet !== "utils" && !["es", "", void 0].includes((_a = es == null ? void 0 : es.trim()) == null ? void 0 : _a.toLocaleLowerCase());
const fixSource = () => {
var _a2;
if (!shouldFix)
return source;
const fixed = [org, iconSet, "es"];
if (((_a2 = es == null ? void 0 : es.trim()) == null ? void 0 : _a2.toLocaleLowerCase()) !== "lib")
fixed.push(es);
fixed.push(...seg);
return fixed.join("/");
};
return {
org,
iconSet,
isUtil: iconSet === "utils",
shouldFix,
fixSource
};
}
var no_cjs_icon_component_default = createRule({
name: name5,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [],
messages: {
noCjsIconCompnoent: "Do not import icon components maybe cjs."
}
},
defaultOptions: [],
create: (context) => {
return {
ImportDeclaration(node) {
if (!isSourceOfRegExp(node, singleIconComponentRE))
return;
const { shouldFix, fixSource } = parse(node.source.value);
if (shouldFix) {
context.report({
messageId: "noCjsIconCompnoent",
node,
fix(fixer) {
return fixer.replaceText(node.source, `'${fixSource()}'`);
}
});
}
}
};
}
});
// src/rules/no-default-import.ts
var name6 = "no-default-import";
var no_default_import_default = createRule({
name: name6,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
schema: [
{
type: ["array", "string"],
description: "No default import source matcher"
}
],
messages: {
noDefaultImport: "Do not use default imports in '{{source}}'",
noWrokspaceImport: "Do not use workspace imports in '{{source}}'"
}
},
defaultOptions: [[]],
create: (context, options) => {
return {
ImportDeclaration(node) {
const [matcher] = options;
if (!isStrictSourceOf(node, matcher))
return;
if (node.importKind === "type")
return;
let messageId;
for (const specifier of node.specifiers) {
if (specifier.type === "ImportDefaultSpecifier") {
messageId = "noDefaultImport";
break;
} else if (specifier.type === "ImportNamespaceSpecifier") {
messageId = "noWrokspaceImport";
break;
}
}
if (messageId) {
context.report({
node,
messageId,
data: {
source: node.source.value
}
});
}
}
};
}
});
// src/utils/jsx.ts
function isWhiteSpaces(value) {
return typeof value === "string" ? /^\s*$/.test(value) : false;
}
function findJsxProp(context, node, propName) {
const attributes = node.openingElement.attributes;
return attributes.find((attribute) => {
if (attribute.type === "JSXSpreadAttribute") {
const variable = findSpreadVariable(context, attribute.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init)
return findObjectProp(context, variable.defs[0].node.init, propName, []);
}
return attribute.name && propName.includes(attribute.name.name);
});
}
function isLineBreak(node) {
const isLiteral = node.type === "Literal" || node.type === "JSXText";
const isMultiline = node.loc.start.line !== node.loc.end.line;
const _isWhiteSpaces = isWhiteSpaces(node.value);
return isLiteral && isMultiline && _isWhiteSpaces;
}
function isJsxEmptyExpression(node) {
if (node.type === "JSXEmptyExpression")
return true;
else if (node.type === "JSXExpressionContainer" && node.expression.type === "JSXEmptyExpression")
return true;
return false;
}
function findObjectProp(context, node, propName, seenProps) {
if (!(node == null ? void 0 : node.properties))
return;
const _propName = Array.isArray(propName) ? propName : [propName];
return node.properties.find((prop) => {
if (prop.type === "Property")
return _propName.includes(prop.key.name);
if (prop.type === "ExperimentalSpreadProperty" || prop.type === "SpreadElement") {
const variable = findSpreadVariable(context, prop.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init) {
if (seenProps.includes(prop.argument.name))
return false;
const newSeenProps = seenProps.concat(prop.argument.name || []);
return findObjectProp(context, variable.defs[0].node.init, propName, newSeenProps);
}
}
return false;
});
}
function variablesInScope(context) {
let scope = context.getScope();
let variables = scope.variables;
while (scope.type !== "global") {
scope = scope.upper;
variables = scope.variables.concat(variables);
}
if (scope.childScopes.length) {
variables = scope.childScopes[0].variables.concat(variables);
if (scope.childScopes[0].childScopes.length)
variables = scope.childScopes[0].childScopes[0].variables.concat(variables);
}
variables.reverse();
return variables;
}
function findSpreadVariable(context, name8) {
return variablesInScope(context).find((item) => item.name === name8);
}
// src/rules/jsx-no-danger-with-children.ts
var name7 = "jsx-no-danger-with-children";
var jsx_no_danger_with_children_default = createRule({
name: name7,
meta: {
type: "problem",
docs: {
description: "Disallow when a DOM element is using both children and innerHtml",
recommended: "recommended"
},
schema: [
{
type: ["array", "string"],
description: "`innerHTML` prop name"
}
],
messages: {
jsxNoDangerWithChildren: "Only set one of `children` or {{props}}"
}
},
defaultOptions: [{ propsName: ["innerHTML", "dangerouslySetInnerHTML"], rendererName: ["createElement", "createComponent"] }],
create: (context, options) => {
const propName = Array.isArray(options[0].propsName) ? options[0].propsName : [options[0].propsName];
const rendererName = Array.isArray(options[0].rendererName) ? options[0].rendererName : [options[0].rendererName];
return {
JSXElement(node) {
let hasChildren = false;
if (node.children.length && !node.children.every((e) => isLineBreak(e) || isJsxEmptyExpression(e)))
hasChildren = true;
else if (findJsxProp(context, node, "children"))
hasChildren = true;
if (node.openingElement.attributes && hasChildren && findJsxProp(context, node, propName)) {
context.report({
node,
messageId: "jsxNoDangerWithChildren",
data: {
props: propName.map((e) => `props.${e}`).join(" or ")
}
});
}
},
CallExpression(node) {
if (node.callee && node.callee.type === "MemberExpression" && !node.callee.computed && rendererName.includes(node.callee.property.name) && node.arguments.length > 1) {
let hasChildren = false;
let props = node.arguments[1];
if (props.type === "Identifier") {
const variable = variablesInScope(context).find((item) => item.name === props.name);
if (variable && variable.defs.length && variable.defs[0].node.init)
props = variable.defs[0].node.init;
}
const dangerously = findObjectProp(context, props, propName, []);
if (node.arguments.length === 2) {
if (findObjectProp(context, props, "children", []))
hasChildren = true;
} else {
hasChildren = true;
}
if (dangerously && hasChildren) {
context.report({
node,
messageId: "jsxNoDangerWithChildren",
data: {
props: propName.map((e) => `props.${e}`).join(" or ")
}
});
}
}
}
};
}
});
// src/configs.ts
var commonRule = {
"@yafh/icon-component-prefix": "error",
"@yafh/no-cjs-icon-component": "error",
"@yafh/no-multiple-slash-comment": "error"
};
function rules(rules2) {
return {
plugins: ["@yafh"],
rules: {
...commonRule,
...rules2
}
};
}
var configs_default = {
"recommended": rules({}),
"vue-recommended": rules({
"@yafh/no-index-vue": "error",
"@yafh/pascal-case-component-name": "error"
}),
"solid-recommended": rules({
"@yafh/pascal-case-component-name": ["error", ["tsx", "jsx"]],
"@yafh/jsx-no-danger-with-children": "error"
})
};
// src/index.ts
var src_default = {
rules: {
"icon-component-prefix": icon_component_prefix_default,
"no-index-vue": no_index_vue_default,
"no-multiple-slash-comment": no_multiple_slash_comment_default,
"pascal-case-component-name": pascal_case_component_name_default,
"no-cjs-icon-component": no_cjs_icon_component_default,
"no-default-import": no_default_import_default,
"jsx-no-danger-with-children": jsx_no_danger_with_children_default
},
configs: configs_default
};
exports.default = src_default;

@@ -1,1 +0,507 @@

import{AST_NODE_TYPES as b}from"@typescript-eslint/types";import{ESLintUtils as M}from"@typescript-eslint/utils";import{AST_NODE_TYPES as E}from"@typescript-eslint/types";var i=M.RuleCreator(e=>e);function c(e){return e.toLowerCase().trim()}function f(e,t){let o=c(e.source.value);return typeof t=="string"?o===t:t.some(r=>o.startsWith(c(r)))}function d(e,t){let o=c(e.source.value);return typeof t=="string"?o.startsWith(c(t)):t.some(r=>o.startsWith(c(r)))}function g(e,t){let o=e.source.value;return t.test(o)}function x(e){return e.type===E.ImportSpecifier&&(e.imported.range[0]!==e.local.range[0]||e.imported.range[1]!==e.local.range[1])}var v="icon-component-prefix",I=i({name:v,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[{type:["string","array"],description:"Icon Component source matcher"},{type:["string"],description:"prefix"}],messages:{missingIconComponentPrefix:"Expect icon component prefix '{{prefix}}'"}},defaultOptions:[["@ricons","@vicons","@v2icons","@sicons"],"Icon"],create:(e,t)=>({ImportDeclaration(o){let[r,s]=t;if(d(o,r))for(let n of o.specifiers)n.local.name.startsWith(s)||e.report({loc:n.loc,messageId:"missingIconComponentPrefix",data:{prefix:s},fix(l){let m=RegExp(`^${s}`,"i").test(n.local.name),a=s+(m?n.local.name.substring(s.length):n.local.name);return n.type===b.ImportSpecifier&&!x(n)&&(a=`${n.local.name} as ${a}`),l.replaceText(n.local,a)}})}})});import{basename as D}from"node:path";var R="no-index-vue",y=i({name:R,meta:{type:"problem",docs:{description:"",recommended:"recommended"},schema:[],messages:{noIndexVue:"Do not use index.vue"}},defaultOptions:[],create:e=>({Program(){D(e.getFilename()).toLocaleLowerCase()==="index.vue"&&e.report({loc:{line:1,column:0},messageId:"noIndexVue"})}})});import{AST_TOKEN_TYPES as P}from"@typescript-eslint/utils";var N="no-multiple-slash-comment";function j(e){return e.type!==P.Line?!1:/^\/\s*<(amd-module|amd-dependency|reference){1}.*\/>\s*$/.test(e.value)}var S=i({name:N,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[],messages:{noMultipleSlashComment:"Do not use multiple slashes for single line comments."}},defaultOptions:[],create:e=>{let t=e.getSourceCode();return{Program(){t.getAllComments().filter(o=>o.type==="Line").filter(o=>!j(o)).filter(o=>/^\/+/.test(o.value)).forEach(o=>{e.report({node:o,messageId:"noMultipleSlashComment",fix:r=>r.replaceText(o,`//${o.value.replace(/^\/+/,"")}`)})})}}}});import{basename as L}from"node:path";import{pascalCase as A,pascalCaseTransformMerge as $}from"pascal-case";var W="pascal-case-component-name",C=i({name:W,meta:{type:"suggestion",docs:{description:"",recommended:"recommended"},schema:[{type:["string","array"],description:"Component file extensions"}],messages:{missingPascalCaseComponentName:"Component name must be PascalCase. e.g. {{pascalCase}}"}},defaultOptions:["vue"],create:(e,t)=>({Program(){let o=L(e.getFilename());if(!RegExp(`\\.(${Array.isArray(t[0])?t[0].join("|"):t[0]})$`).test(o))return;let r=o.split(".")[0],s=A(r,{transform:$});r!==s&&e.report({loc:{line:1,column:0},messageId:"missingPascalCaseComponentName",data:{pascalCase:s+o.slice(r.length)}})}})});var k="no-cjs-icon-component",_=/^@(r|v|v2)icons/i;function w(e){var m;let[t,o,r,...s]=e.split("/"),n=o!=="utils"&&!["es","",void 0].includes((m=r==null?void 0:r.trim())==null?void 0:m.toLocaleLowerCase());return{org:t,iconSet:o,isUtil:o==="utils",shouldFix:n,fixSource:()=>{var u;if(!n)return e;let a=[t,o,"es"];return((u=r==null?void 0:r.trim())==null?void 0:u.toLocaleLowerCase())!=="lib"&&a.push(r),a.push(...s),a.join("/")}}}var h=i({name:k,meta:{type:"problem",docs:{description:"",recommended:"recommended"},fixable:"code",schema:[],messages:{noCjsIconCompnoent:"Do not import icon components maybe cjs."}},defaultOptions:[],create:e=>({ImportDeclaration(t){if(!g(t,_))return;let{shouldFix:o,fixSource:r}=w(t.source.value);o&&e.report({messageId:"noCjsIconCompnoent",node:t,fix(s){return s.replaceText(t.source,`'${r()}'`)}})}})});var F="no-default-import",O=i({name:F,meta:{type:"problem",docs:{description:"",recommended:"recommended"},schema:[{type:["array","string"],description:"No default import source matcher"}],messages:{noDefaultImport:"Do not use default imports in '{{source}}'",noWrokspaceImport:"Do not use workspace imports in '{{source}}'"}},defaultOptions:[[]],create:(e,t)=>({ImportDeclaration(o){let[r]=t;if(!f(o,r)||o.importKind==="type")return;let s;for(let n of o.specifiers)if(n.type==="ImportDefaultSpecifier"){s="noDefaultImport";break}else if(n.type==="ImportNamespaceSpecifier"){s="noWrokspaceImport";break}s&&e.report({node:o,messageId:s,data:{source:o.source.value}})}})});var V={"@yafh/icon-component-prefix":"error","@yafh/no-cjs-icon-component":"error","@yafh/no-multiple-slash-comment":"error"};function p(e){return{plugins:["@yafh"],rules:{...V,...e}}}var T={recommended:p({}),"recommended-vue":p({"@yafh/no-index-vue":"error","@yafh/pascal-case-component-name":"error"}),"recommended-solid":p({"@yafh/pascal-case-component-name":["error","tsx"]})};var xe={rules:{"icon-component-prefix":I,"no-index-vue":y,"no-multiple-slash-comment":S,"pascal-case-component-name":C,"no-cjs-icon-component":h,"no-default-import":O},configs:T};export{xe as default};
// src/rules/icon-component-prefix.ts
import { AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/types";
// src/utils/common.ts
import { ESLintUtils } from "@typescript-eslint/utils";
import { AST_NODE_TYPES } from "@typescript-eslint/types";
var createRule = ESLintUtils.RuleCreator((name8) => name8);
function normalizeSource(source) {
return source.toLowerCase().trim();
}
function isStrictSourceOf(node, matcher) {
const source = normalizeSource(node.source.value);
if (typeof matcher === "string")
return source === matcher;
else
return matcher.some((m) => source.startsWith(normalizeSource(m)));
}
function isSourceOf(node, matcher) {
const source = normalizeSource(node.source.value);
if (typeof matcher === "string")
return source.startsWith(normalizeSource(matcher));
else
return matcher.some((m) => source.startsWith(normalizeSource(m)));
}
function isSourceOfRegExp(node, matcher) {
const source = node.source.value;
return matcher.test(source);
}
function isAliasImportSpecifier(node) {
return node.type === AST_NODE_TYPES.ImportSpecifier && (node.imported.range[0] !== node.local.range[0] || node.imported.range[1] !== node.local.range[1]);
}
// src/rules/icon-component-prefix.ts
var name = "icon-component-prefix";
var icon_component_prefix_default = createRule({
name,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [
{
type: ["string", "array"],
description: "Icon Component source matcher"
},
{
type: ["string"],
description: "prefix"
}
],
messages: {
missingIconComponentPrefix: "Expect icon component prefix '{{prefix}}'"
}
},
defaultOptions: [["@ricons", "@vicons", "@v2icons", "@sicons"], "Icon"],
create: (context, options) => {
return {
ImportDeclaration(node) {
const [matcher, prefix] = options;
if (!isSourceOf(node, matcher))
return;
for (const specifier of node.specifiers) {
if (!specifier.local.name.startsWith(prefix)) {
context.report({
loc: specifier.loc,
messageId: "missingIconComponentPrefix",
data: {
prefix
},
fix(fixer) {
const caseMiss = RegExp(`^${prefix}`, "i").test(specifier.local.name);
let code = prefix + (caseMiss ? specifier.local.name.substring(prefix.length) : specifier.local.name);
if (specifier.type === AST_NODE_TYPES2.ImportSpecifier && !isAliasImportSpecifier(specifier))
code = `${specifier.local.name} as ${code}`;
return fixer.replaceText(specifier.local, code);
}
});
}
}
}
};
}
});
// src/rules/no-index-vue.ts
import { basename } from "node:path";
var name2 = "no-index-vue";
var no_index_vue_default = createRule(
{
name: name2,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
schema: [],
messages: {
noIndexVue: "Do not use index.vue"
}
},
defaultOptions: [],
create: (context) => {
return {
Program() {
if (basename(context.getFilename()).toLocaleLowerCase() === "index.vue") {
context.report({
loc: {
line: 1,
column: 0
},
messageId: "noIndexVue"
});
}
}
};
}
}
);
// src/rules/no-multiple-slash-comment.ts
import { AST_TOKEN_TYPES } from "@typescript-eslint/utils";
var name3 = "no-multiple-slash-comment";
function isTripleSlashDirectives(comment) {
if (comment.type !== AST_TOKEN_TYPES.Line)
return false;
return /^\/\s*<(amd-module|amd-dependency|reference){1}.*\/>\s*$/.test(comment.value);
}
var no_multiple_slash_comment_default = createRule({
name: name3,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [],
messages: {
noMultipleSlashComment: "Do not use multiple slashes for single line comments."
}
},
defaultOptions: [],
create: (context) => {
const sourceCode = context.getSourceCode();
return {
Program() {
sourceCode.getAllComments().filter((comment) => comment.type === "Line").filter((comment) => !isTripleSlashDirectives(comment)).filter((comment) => /^\/+/.test(comment.value)).forEach((comment) => {
context.report({
node: comment,
messageId: "noMultipleSlashComment",
fix: (fixer) => fixer.replaceText(comment, `//${comment.value.replace(/^\/+/, "")}`)
});
});
}
};
}
});
// src/rules/pascal-case-component-name.ts
import { basename as basename2 } from "node:path";
import { pascalCase, pascalCaseTransformMerge } from "pascal-case";
var name4 = "pascal-case-component-name";
var pascal_case_component_name_default = createRule(
{
name: name4,
meta: {
type: "suggestion",
docs: {
description: "",
recommended: "recommended"
},
schema: [
{
type: ["string", "array"],
description: "Component file extensions"
}
],
messages: {
missingPascalCaseComponentName: "Component name must be PascalCase. e.g. {{pascalCase}}"
}
},
defaultOptions: ["vue"],
create: (context, options) => {
return {
Program() {
const baseName = basename2(context.getFilename());
if (!RegExp(`\\.(${Array.isArray(options[0]) ? options[0].join("|") : options[0]})$`).test(baseName))
return;
const fileName = baseName.split(".")[0];
const pascalCaseName = pascalCase(fileName, { transform: pascalCaseTransformMerge });
if (fileName !== pascalCaseName) {
context.report({
loc: {
line: 1,
column: 0
},
messageId: "missingPascalCaseComponentName",
data: {
pascalCase: pascalCaseName + baseName.slice(fileName.length)
}
});
}
}
};
}
}
);
// src/rules/no-cjs-icon-component.ts
var name5 = "no-cjs-icon-component";
var singleIconComponentRE = /^@(r|v|v2)icons/i;
function parse(source) {
var _a;
const [org, iconSet, es, ...seg] = source.split("/");
const shouldFix = iconSet !== "utils" && !["es", "", void 0].includes((_a = es == null ? void 0 : es.trim()) == null ? void 0 : _a.toLocaleLowerCase());
const fixSource = () => {
var _a2;
if (!shouldFix)
return source;
const fixed = [org, iconSet, "es"];
if (((_a2 = es == null ? void 0 : es.trim()) == null ? void 0 : _a2.toLocaleLowerCase()) !== "lib")
fixed.push(es);
fixed.push(...seg);
return fixed.join("/");
};
return {
org,
iconSet,
isUtil: iconSet === "utils",
shouldFix,
fixSource
};
}
var no_cjs_icon_component_default = createRule({
name: name5,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
fixable: "code",
schema: [],
messages: {
noCjsIconCompnoent: "Do not import icon components maybe cjs."
}
},
defaultOptions: [],
create: (context) => {
return {
ImportDeclaration(node) {
if (!isSourceOfRegExp(node, singleIconComponentRE))
return;
const { shouldFix, fixSource } = parse(node.source.value);
if (shouldFix) {
context.report({
messageId: "noCjsIconCompnoent",
node,
fix(fixer) {
return fixer.replaceText(node.source, `'${fixSource()}'`);
}
});
}
}
};
}
});
// src/rules/no-default-import.ts
var name6 = "no-default-import";
var no_default_import_default = createRule({
name: name6,
meta: {
type: "problem",
docs: {
description: "",
recommended: "recommended"
},
schema: [
{
type: ["array", "string"],
description: "No default import source matcher"
}
],
messages: {
noDefaultImport: "Do not use default imports in '{{source}}'",
noWrokspaceImport: "Do not use workspace imports in '{{source}}'"
}
},
defaultOptions: [[]],
create: (context, options) => {
return {
ImportDeclaration(node) {
const [matcher] = options;
if (!isStrictSourceOf(node, matcher))
return;
if (node.importKind === "type")
return;
let messageId;
for (const specifier of node.specifiers) {
if (specifier.type === "ImportDefaultSpecifier") {
messageId = "noDefaultImport";
break;
} else if (specifier.type === "ImportNamespaceSpecifier") {
messageId = "noWrokspaceImport";
break;
}
}
if (messageId) {
context.report({
node,
messageId,
data: {
source: node.source.value
}
});
}
}
};
}
});
// src/utils/jsx.ts
function isWhiteSpaces(value) {
return typeof value === "string" ? /^\s*$/.test(value) : false;
}
function findJsxProp(context, node, propName) {
const attributes = node.openingElement.attributes;
return attributes.find((attribute) => {
if (attribute.type === "JSXSpreadAttribute") {
const variable = findSpreadVariable(context, attribute.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init)
return findObjectProp(context, variable.defs[0].node.init, propName, []);
}
return attribute.name && propName.includes(attribute.name.name);
});
}
function isLineBreak(node) {
const isLiteral = node.type === "Literal" || node.type === "JSXText";
const isMultiline = node.loc.start.line !== node.loc.end.line;
const _isWhiteSpaces = isWhiteSpaces(node.value);
return isLiteral && isMultiline && _isWhiteSpaces;
}
function isJsxEmptyExpression(node) {
if (node.type === "JSXEmptyExpression")
return true;
else if (node.type === "JSXExpressionContainer" && node.expression.type === "JSXEmptyExpression")
return true;
return false;
}
function findObjectProp(context, node, propName, seenProps) {
if (!(node == null ? void 0 : node.properties))
return;
const _propName = Array.isArray(propName) ? propName : [propName];
return node.properties.find((prop) => {
if (prop.type === "Property")
return _propName.includes(prop.key.name);
if (prop.type === "ExperimentalSpreadProperty" || prop.type === "SpreadElement") {
const variable = findSpreadVariable(context, prop.argument.name);
if (variable && variable.defs.length && variable.defs[0].node.init) {
if (seenProps.includes(prop.argument.name))
return false;
const newSeenProps = seenProps.concat(prop.argument.name || []);
return findObjectProp(context, variable.defs[0].node.init, propName, newSeenProps);
}
}
return false;
});
}
function variablesInScope(context) {
let scope = context.getScope();
let variables = scope.variables;
while (scope.type !== "global") {
scope = scope.upper;
variables = scope.variables.concat(variables);
}
if (scope.childScopes.length) {
variables = scope.childScopes[0].variables.concat(variables);
if (scope.childScopes[0].childScopes.length)
variables = scope.childScopes[0].childScopes[0].variables.concat(variables);
}
variables.reverse();
return variables;
}
function findSpreadVariable(context, name8) {
return variablesInScope(context).find((item) => item.name === name8);
}
// src/rules/jsx-no-danger-with-children.ts
var name7 = "jsx-no-danger-with-children";
var jsx_no_danger_with_children_default = createRule({
name: name7,
meta: {
type: "problem",
docs: {
description: "Disallow when a DOM element is using both children and innerHtml",
recommended: "recommended"
},
schema: [
{
type: ["array", "string"],
description: "`innerHTML` prop name"
}
],
messages: {
jsxNoDangerWithChildren: "Only set one of `children` or {{props}}"
}
},
defaultOptions: [{ propsName: ["innerHTML", "dangerouslySetInnerHTML"], rendererName: ["createElement", "createComponent"] }],
create: (context, options) => {
const propName = Array.isArray(options[0].propsName) ? options[0].propsName : [options[0].propsName];
const rendererName = Array.isArray(options[0].rendererName) ? options[0].rendererName : [options[0].rendererName];
return {
JSXElement(node) {
let hasChildren = false;
if (node.children.length && !node.children.every((e) => isLineBreak(e) || isJsxEmptyExpression(e)))
hasChildren = true;
else if (findJsxProp(context, node, "children"))
hasChildren = true;
if (node.openingElement.attributes && hasChildren && findJsxProp(context, node, propName)) {
context.report({
node,
messageId: "jsxNoDangerWithChildren",
data: {
props: propName.map((e) => `props.${e}`).join(" or ")
}
});
}
},
CallExpression(node) {
if (node.callee && node.callee.type === "MemberExpression" && !node.callee.computed && rendererName.includes(node.callee.property.name) && node.arguments.length > 1) {
let hasChildren = false;
let props = node.arguments[1];
if (props.type === "Identifier") {
const variable = variablesInScope(context).find((item) => item.name === props.name);
if (variable && variable.defs.length && variable.defs[0].node.init)
props = variable.defs[0].node.init;
}
const dangerously = findObjectProp(context, props, propName, []);
if (node.arguments.length === 2) {
if (findObjectProp(context, props, "children", []))
hasChildren = true;
} else {
hasChildren = true;
}
if (dangerously && hasChildren) {
context.report({
node,
messageId: "jsxNoDangerWithChildren",
data: {
props: propName.map((e) => `props.${e}`).join(" or ")
}
});
}
}
}
};
}
});
// src/configs.ts
var commonRule = {
"@yafh/icon-component-prefix": "error",
"@yafh/no-cjs-icon-component": "error",
"@yafh/no-multiple-slash-comment": "error"
};
function rules(rules2) {
return {
plugins: ["@yafh"],
rules: {
...commonRule,
...rules2
}
};
}
var configs_default = {
"recommended": rules({}),
"vue-recommended": rules({
"@yafh/no-index-vue": "error",
"@yafh/pascal-case-component-name": "error"
}),
"solid-recommended": rules({
"@yafh/pascal-case-component-name": ["error", ["tsx", "jsx"]],
"@yafh/jsx-no-danger-with-children": "error"
})
};
// src/index.ts
var src_default = {
rules: {
"icon-component-prefix": icon_component_prefix_default,
"no-index-vue": no_index_vue_default,
"no-multiple-slash-comment": no_multiple_slash_comment_default,
"pascal-case-component-name": pascal_case_component_name_default,
"no-cjs-icon-component": no_cjs_icon_component_default,
"no-default-import": no_default_import_default,
"jsx-no-danger-with-children": jsx_no_danger_with_children_default
},
configs: configs_default
};
export {
src_default as default
};
+1
-1
{
"name": "@yafh/eslint-plugin",
"version": "0.5.0",
"version": "0.6.0",
"license": "MIT",

@@ -5,0 +5,0 @@ "description": "Eslint plugin for YanAndFish",