@agilebot/eslint-plugin 0.3.6 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- export default plugin;
1
+ import * as eslint from 'eslint';
2
+
2
3
  declare namespace plugin {
3
- let rules: import('eslint').Linter.RulesRecord;
4
+ let rules: eslint.Linter.RulesRecord;
4
5
  namespace configs {
5
6
  namespace recommended {
6
7
  export let plugins: string[];
7
- let rules_1: import('eslint').Linter.RulesRecord;
8
+ let rules_1: eslint.Linter.RulesRecord;
8
9
  export { rules_1 as rules };
9
10
  export namespace settings {
10
11
  namespace react {
@@ -14,3 +15,5 @@ declare namespace plugin {
14
15
  }
15
16
  }
16
17
  }
18
+
19
+ export { plugin as default };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license @agilebot/eslint-plugin v0.3.6
2
+ * @license @agilebot/eslint-plugin v0.3.8
3
3
  *
4
4
  * Copyright (c) Agilebot, Inc. and its affiliates.
5
5
  *
@@ -8,9 +8,9 @@
8
8
  */
9
9
  'use strict';
10
10
 
11
+ var eslintUtils = require('@agilebot/eslint-utils');
11
12
  var fs = require('node:fs');
12
13
  var path = require('node:path');
13
- var eslintUtils = require('@agilebot/eslint-utils');
14
14
  var utils = require('@typescript-eslint/utils');
15
15
 
16
16
  function _interopNamespaceDefault(e) {
@@ -72,11 +72,136 @@ var enforceMuiIconAlias = {
72
72
  }
73
73
  };
74
74
 
75
+ var funcNaming = {
76
+ meta: {
77
+ docs: {
78
+ description: 'Enforce function naming convention'
79
+ },
80
+ schema: [{
81
+ type: 'object',
82
+ properties: {
83
+ format: {
84
+ "enum": ['camelCase', 'PascalCase']
85
+ }
86
+ }
87
+ }],
88
+ messages: {
89
+ invalidFuncNaming: 'Invalid function naming for non-React component, expected {{format}}',
90
+ invalidReactFCNaming: 'Invalid naming convention for React functional component, expected PascalCase'
91
+ }
92
+ },
93
+ create(context) {
94
+ if (!context.options[0]) {
95
+ throw new Error('Missing options');
96
+ }
97
+ const format = context.options[0].format;
98
+ function validate({
99
+ node,
100
+ fnName
101
+ }) {
102
+ let isPass;
103
+ switch (format) {
104
+ case 'camelCase':
105
+ if (!eslintUtils.isCamelCase(fnName)) {
106
+ isPass = false;
107
+ }
108
+ break;
109
+ case 'PascalCase':
110
+ if (!eslintUtils.isPascalCase(fnName)) {
111
+ isPass = false;
112
+ }
113
+ break;
114
+ }
115
+ if (isPass === false) {
116
+ context.report({
117
+ node: node,
118
+ messageId: 'invalidFuncNaming',
119
+ data: {
120
+ format
121
+ }
122
+ });
123
+ }
124
+ }
125
+ function checkJSXElement(node) {
126
+ if (!node) {
127
+ return false;
128
+ }
129
+ if (node.type === 'JSXElement' || node.type === 'JSXFragment') {
130
+ return true;
131
+ }
132
+ if (node.type === 'BlockStatement') {
133
+ for (const statement of node.body) {
134
+ if (statement.type === 'ReturnStatement') {
135
+ if (checkJSXElement(statement.argument)) {
136
+ return true;
137
+ }
138
+ } else if (checkJSXElement(statement)) {
139
+ return true;
140
+ }
141
+ }
142
+ }
143
+ if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression') {
144
+ return checkJSXElement(node.body);
145
+ }
146
+ return false;
147
+ }
148
+ return {
149
+ MethodDefinition(node) {
150
+ if (node.kind === 'method') ;
151
+ },
152
+ FunctionDeclaration(node) {
153
+ if (node.type === 'FunctionDeclaration' && node.id) {
154
+ const fnName = node.id.name;
155
+ const isReactComponent = checkJSXElement(node.body);
156
+ if (!isReactComponent) {
157
+ validate({
158
+ node,
159
+ fnName
160
+ });
161
+ }
162
+ }
163
+ },
164
+ VariableDeclarator(node) {
165
+ if (node.init && ['FunctionExpression', 'ArrowFunctionExpression'].includes(node.init.type)) {
166
+ const fnName = node.id.name;
167
+ let isReactComponent = checkJSXElement(node.init.body);
168
+ if (node.id.typeAnnotation && node.id.typeAnnotation.typeAnnotation) {
169
+ const typeAnnotation = node.id.typeAnnotation.typeAnnotation;
170
+ if (typeAnnotation.type === 'TSTypeReference' && typeAnnotation.typeName.type === 'Identifier') {
171
+ const typeName = typeAnnotation.typeName.name;
172
+ if (['FC', 'React.FC', 'FunctionComponent', 'React.FunctionComponent'].includes(typeName)) {
173
+ isReactComponent = true;
174
+ }
175
+ }
176
+ }
177
+ if (!isReactComponent) {
178
+ validate({
179
+ node,
180
+ fnName
181
+ });
182
+ }
183
+ }
184
+ },
185
+ Property(node) {
186
+ if (node.value.type === 'FunctionExpression') ;
187
+ }
188
+ };
189
+ }
190
+ };
191
+
75
192
  function getSetting(context, name) {
76
193
  return context.settings["agilebot/".concat(name)];
77
194
  }
78
195
 
79
- let warnedForMissingPrefix = false;
196
+ const warned = new Set();
197
+ function warnOnce(message) {
198
+ if (warned.has(message)) {
199
+ return;
200
+ }
201
+ warned.add(message);
202
+ console.warn("Warning: ".concat(message));
203
+ }
204
+
80
205
  var importMonorepo = {
81
206
  meta: {
82
207
  type: 'problem',
@@ -95,10 +220,7 @@ var importMonorepo = {
95
220
  ImportDeclaration(node) {
96
221
  let prefix = getSetting(context, 'monorepo-scope');
97
222
  if (!prefix) {
98
- if (!warnedForMissingPrefix) {
99
- console.error('Warning: agilebot/monorepo-scope is not set.');
100
- warnedForMissingPrefix = true;
101
- }
223
+ warnOnce('agilebot/monorepo-scope is not set.');
102
224
  return;
103
225
  }
104
226
  prefix = "".concat(prefix, "/");
@@ -269,6 +391,98 @@ var intlIdMissing = {
269
391
  }
270
392
  };
271
393
 
394
+ var intlIdNaming = {
395
+ meta: {
396
+ docs: {
397
+ description: 'Validates intl message ids naming convention',
398
+ category: 'Intl'
399
+ },
400
+ fixable: undefined,
401
+ schema: [{
402
+ type: 'object',
403
+ properties: {
404
+ format: {
405
+ "enum": ['camelCase', 'PascalCase']
406
+ }
407
+ }
408
+ }],
409
+ messages: {
410
+ invalidIdNaming: "Invalid id naming, expected {{format}}"
411
+ }
412
+ },
413
+ create: function (context) {
414
+ if (!context.options[0]) {
415
+ throw new Error('Missing options');
416
+ }
417
+ const format = context.options[0].format;
418
+ function report(node, value) {
419
+ const values = value.split('.');
420
+ let isPass;
421
+ for (const v of values) {
422
+ switch (format) {
423
+ case 'camelCase':
424
+ if (!eslintUtils.isCamelCase(v)) {
425
+ isPass = false;
426
+ }
427
+ break;
428
+ case 'PascalCase':
429
+ if (!eslintUtils.isPascalCase(v)) {
430
+ isPass = false;
431
+ }
432
+ break;
433
+ }
434
+ }
435
+ if (isPass === false) {
436
+ context.report({
437
+ node: node,
438
+ messageId: 'invalidIdNaming',
439
+ data: {
440
+ format
441
+ }
442
+ });
443
+ }
444
+ }
445
+ function processLiteral(node) {
446
+ report(node, node.value);
447
+ }
448
+ function processTemplateLiteral(node) {
449
+ const displayStr = templateLiteralDisplayStr(node);
450
+ report(node, displayStr);
451
+ }
452
+ function processAttrNode(node) {
453
+ if (node.value.type === 'Literal') {
454
+ return processLiteral(node.value);
455
+ }
456
+ if (node.value.type === 'JSXExpressionContainer' && node.value.expression.type === 'TemplateLiteral') {
457
+ return processTemplateLiteral(node.value.expression);
458
+ }
459
+ if (node.value.type === 'TemplateLiteral') {
460
+ return processTemplateLiteral(node.value);
461
+ }
462
+ }
463
+ return {
464
+ JSXIdentifier: function (node) {
465
+ const attrNode = findFormattedMessageAttrNode(node, 'id');
466
+ if (attrNode) {
467
+ return processAttrNode(attrNode);
468
+ }
469
+ },
470
+ CallExpression: function (node) {
471
+ const attrNode = findFormatMessageAttrNode(node, 'id');
472
+ if (attrNode) {
473
+ return processAttrNode(attrNode);
474
+ }
475
+ },
476
+ Property: function (node) {
477
+ const attrNode = findAttrNodeInDefineMessages(node, 'id') || findAttrNodeInDefineMessage(node, 'id');
478
+ if (attrNode) {
479
+ return processAttrNode(attrNode);
480
+ }
481
+ }
482
+ };
483
+ }
484
+ };
485
+
272
486
  var intlIdPrefix = {
273
487
  meta: {
274
488
  docs: {
@@ -2414,8 +2628,10 @@ var tssUnusedClasses = {
2414
2628
  var ruleFiles = /*#__PURE__*/Object.freeze({
2415
2629
  __proto__: null,
2416
2630
  rules_enforce_mui_icon_alias: enforceMuiIconAlias,
2631
+ rules_func_naming: funcNaming,
2417
2632
  rules_import_monorepo: importMonorepo,
2418
2633
  rules_intl_id_missing: intlIdMissing,
2634
+ rules_intl_id_naming: intlIdNaming,
2419
2635
  rules_intl_id_prefix: intlIdPrefix,
2420
2636
  rules_intl_id_unused: intlIdUnused,
2421
2637
  rules_intl_no_default: intlNoDefault,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agilebot/eslint-plugin",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "Agilebot's ESLint plugin",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@typescript-eslint/utils": "~7.9.0",
22
22
  "eslint-plugin-react": "^7.34.1",
23
- "@agilebot/eslint-utils": "0.3.6"
23
+ "@agilebot/eslint-utils": "0.3.8"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "eslint": "^7.0.0 || ^8.0.0"
@@ -35,8 +35,7 @@
35
35
  "eslint-vitest-rule-tester": "^0.3.2"
36
36
  },
37
37
  "scripts": {
38
- "build": "rollup -c rollup.config.mjs && nr dts",
39
- "dts": "tsc -p tsconfig.dts.json",
38
+ "build": "rollup -c rollup.config.mjs",
40
39
  "lint": "eslint src --fix"
41
40
  }
42
41
  }