@agilebot/eslint-plugin 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,67 @@
1
+ /* eslint-disable no-sync */
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { tsImport } = require('./import');
5
+ const { getSetting } = require('./settings');
6
+
7
+ /**
8
+ * Map of locale file paths to keys and modified time
9
+ *
10
+ * @type {{string: {keys: Array, mtime: number}}}
11
+ */
12
+ const localeFilesKeys = {};
13
+
14
+ /**
15
+ * Get a list of ids keys from reading locale files
16
+ * Keeps track of modified times and reloads if changed,; useful for realtime eslint in-editor
17
+ *
18
+ * @param {object} context - Context
19
+ * @returns {string[]} results - Array of ids
20
+ */
21
+ function getIntlIds(context) {
22
+ const projectRoot = getSetting(context, 'project-root');
23
+ const localeFiles = getSetting(context, 'locale-files');
24
+
25
+ if (!localeFiles) {
26
+ throw new Error('localeFiles not in settings');
27
+ }
28
+
29
+ const results = [];
30
+ localeFiles.forEach(f => {
31
+ const fullPath = projectRoot ? path.join(projectRoot, f) : f;
32
+ const mtime = fs.lstatSync(fullPath).mtime.getTime();
33
+ if (
34
+ !localeFilesKeys[fullPath] ||
35
+ mtime !== localeFilesKeys[fullPath].mtime
36
+ ) {
37
+ let json;
38
+ if (fullPath.endsWith('.json')) {
39
+ json = JSON.parse(fs.readFileSync(fullPath));
40
+ } else if (fullPath.endsWith('.ts')) {
41
+ json = tsImport(fullPath);
42
+ if (typeof json === 'object' && json.default) {
43
+ json = json.default;
44
+ }
45
+ } else if (fullPath.endsWith('.js')) {
46
+ json = require(fullPath);
47
+ if (typeof json === 'object' && json.default) {
48
+ json = json.default;
49
+ }
50
+ } else {
51
+ throw new Error('unsupported file extension');
52
+ }
53
+
54
+ localeFilesKeys[fullPath] = {
55
+ keys: Object.keys(json),
56
+ mtime: mtime
57
+ };
58
+ }
59
+ results.push(...localeFilesKeys[fullPath].keys);
60
+ });
61
+
62
+ return results;
63
+ }
64
+
65
+ module.exports = {
66
+ getIntlIds
67
+ };
@@ -0,0 +1,104 @@
1
+ // Helper function to get the basic identifier from various node types
2
+ function getBasicIdentifier(node) {
3
+ if (node.type === 'Identifier') {
4
+ // Return the identifier name for simple cases like classes.foo
5
+ return node.name;
6
+ }
7
+
8
+ if (node.type === 'Literal') {
9
+ // Return the literal value for cases like classes['foo']
10
+ return node.value;
11
+ }
12
+
13
+ if (node.type === 'TemplateLiteral') {
14
+ // Handle template literals, e.g., classes[`foo`]
15
+ if (node.expressions.length) {
16
+ // Template literals with expressions, e.g., classes[`foo${bar}`]
17
+ return null;
18
+ }
19
+ return node.quasis[0].value.raw;
20
+ }
21
+
22
+ // Handle other cases, e.g., classes['foo' + bar]
23
+ return null;
24
+ }
25
+
26
+ // Helper function to recursively get the base identifier from a MemberExpression node
27
+ function getBaseIdentifier(node) {
28
+ if (node.type === 'Identifier') {
29
+ return node;
30
+ } else if (node.type === 'CallExpression') {
31
+ return getBaseIdentifier(node.callee);
32
+ } else if (node.type === 'MemberExpression') {
33
+ return getBaseIdentifier(node.object);
34
+ }
35
+ return null;
36
+ }
37
+
38
+ function getStyesObj(node) {
39
+ const isMakeStyles = node.callee.name === 'makeStyles';
40
+
41
+ const isModernApi =
42
+ node.callee.type === 'MemberExpression' &&
43
+ node.callee.property.name === 'create' &&
44
+ getBaseIdentifier(node.callee.object) &&
45
+ getBaseIdentifier(node.callee.object).name === 'tss';
46
+
47
+ if (!isMakeStyles && !isModernApi) {
48
+ return;
49
+ }
50
+
51
+ const styles = (() => {
52
+ if (isMakeStyles) {
53
+ return node.parent.arguments[0];
54
+ }
55
+
56
+ if (isModernApi) {
57
+ return node.callee.parent.arguments[0];
58
+ }
59
+ })();
60
+
61
+ if (!styles) {
62
+ return;
63
+ }
64
+
65
+ switch (styles.type) {
66
+ case 'ObjectExpression':
67
+ return styles;
68
+ case 'ArrowFunctionExpression':
69
+ {
70
+ const { body } = styles;
71
+
72
+ switch (body.type) {
73
+ case 'ObjectExpression':
74
+ return body;
75
+ case 'BlockStatement': {
76
+ let stylesObj;
77
+
78
+ body.body.forEach(bodyNode => {
79
+ if (
80
+ bodyNode.type === 'ReturnStatement' &&
81
+ bodyNode.argument.type === 'ObjectExpression'
82
+ ) {
83
+ stylesObj = bodyNode.argument;
84
+ }
85
+ });
86
+
87
+ return stylesObj;
88
+ }
89
+ }
90
+ }
91
+ break;
92
+ }
93
+ }
94
+
95
+ function isCamelCase(value) {
96
+ return /^[a-z][a-zA-Z0-9]*$/.test(value);
97
+ }
98
+
99
+ module.exports = {
100
+ getBasicIdentifier: getBasicIdentifier,
101
+ getBaseIdentifier: getBaseIdentifier,
102
+ getStyesObj: getStyesObj,
103
+ isCamelCase: isCamelCase
104
+ };
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@agilebot/eslint-plugin",
3
+ "version": "0.1.1",
4
+ "description": "Agilebot's ESLint plugin",
5
+ "main": "lib",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "url": "sh-agilebot/frontend-toolkit",
9
+ "directory": "packages/eslint-plugin"
10
+ },
11
+ "homepage": "https://github.com/sh-agilebot/frontend-toolkit/tree/master/packages/eslint-plugin#readme",
12
+ "dependencies": {
13
+ "@typescript-eslint/utils": "^7.1.1",
14
+ "consola": "^3.2.3",
15
+ "fast-glob": "^3.3.2",
16
+ "get-tsconfig": "^4.7.3",
17
+ "jiti": "^1.21.0",
18
+ "sucrase": "^3.35.0"
19
+ },
20
+ "devDependencies": {
21
+ "@agilebot/eslint-config": "0.1.1"
22
+ },
23
+ "files": [
24
+ "lib"
25
+ ],
26
+ "scripts": {
27
+ "lint": "eslint lib --fix"
28
+ }
29
+ }