@akinon/eslint-plugin-projectzero 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,78 +1,78 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
- import * as path from 'path';
3
- import * as fs from 'fs';
4
-
5
- const MONOREPO_LOCALES_DIR = path.resolve(
6
- __dirname,
7
- '../../../../apps/projectzeropwa/public/locales/en'
8
- );
9
-
10
- const STANDARD_REPO_LOCALES_DIR = path.join(process.cwd(), 'public/locales/en');
11
-
12
- const LOCALES_DIR = fs.existsSync(MONOREPO_LOCALES_DIR)
13
- ? MONOREPO_LOCALES_DIR
14
- : STANDARD_REPO_LOCALES_DIR;
15
-
16
- const getAllKeysFromObject = (obj: any, prefix = ''): string[] => {
17
- return Object.keys(obj).reduce((result, key) => {
18
- if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
19
- return result.concat(getAllKeysFromObject(obj[key], `${prefix}${key}.`));
20
- }
21
- return result.concat(`${prefix}${key}`);
22
- }, [] as string[]);
23
- };
24
-
25
- export default ESLintUtils.RuleCreator.withoutDocs({
26
- create(context: any) {
27
- return {
28
- CallExpression(node: any) {
29
- if (node.callee.type !== 'Identifier' || node.callee.name !== 't') {
30
- return;
31
- }
32
-
33
- const [firstArg] = node.arguments;
34
-
35
- if (
36
- firstArg &&
37
- firstArg.type === 'Literal' &&
38
- typeof firstArg.value === 'string'
39
- ) {
40
- const key = firstArg.value;
41
-
42
- const filename = `${key.split('.')[0]}.json`;
43
- const filepath = path.join(LOCALES_DIR, filename);
44
-
45
- if (fs.existsSync(filepath)) {
46
- const jsonContent = JSON.parse(fs.readFileSync(filepath, 'utf-8'));
47
- const allKeys = getAllKeysFromObject(
48
- jsonContent,
49
- filename.replace('.json', '.')
50
- );
51
-
52
- if (!allKeys.includes(key)) {
53
- context.report({
54
- node: firstArg,
55
- messageId: 'missingLocalizationKey'
56
- });
57
- }
58
- } else {
59
- context.report({
60
- node: firstArg,
61
- messageId: 'missingLocalizationFile'
62
- });
63
- }
64
- }
65
- }
66
- };
67
- },
68
- meta: {
69
- messages: {
70
- missingLocalizationKey:
71
- 'The localization key does not exist in the JSON files.',
72
- missingLocalizationFile: 'The localization file does not exist.'
73
- },
74
- type: 'problem',
75
- schema: []
76
- },
77
- defaultOptions: []
78
- });
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+
5
+ const MONOREPO_LOCALES_DIR = path.resolve(
6
+ __dirname,
7
+ '../../../../apps/projectzeropwa/public/locales/en'
8
+ );
9
+
10
+ const STANDARD_REPO_LOCALES_DIR = path.join(process.cwd(), 'public/locales/en');
11
+
12
+ const LOCALES_DIR = fs.existsSync(MONOREPO_LOCALES_DIR)
13
+ ? MONOREPO_LOCALES_DIR
14
+ : STANDARD_REPO_LOCALES_DIR;
15
+
16
+ const getAllKeysFromObject = (obj: any, prefix = ''): string[] => {
17
+ return Object.keys(obj).reduce((result, key) => {
18
+ if (typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
19
+ return result.concat(getAllKeysFromObject(obj[key], `${prefix}${key}.`));
20
+ }
21
+ return result.concat(`${prefix}${key}`);
22
+ }, [] as string[]);
23
+ };
24
+
25
+ export default ESLintUtils.RuleCreator.withoutDocs({
26
+ create(context: any) {
27
+ return {
28
+ CallExpression(node: any) {
29
+ if (node.callee.type !== 'Identifier' || node.callee.name !== 't') {
30
+ return;
31
+ }
32
+
33
+ const [firstArg] = node.arguments;
34
+
35
+ if (
36
+ firstArg &&
37
+ firstArg.type === 'Literal' &&
38
+ typeof firstArg.value === 'string'
39
+ ) {
40
+ const key = firstArg.value;
41
+
42
+ const filename = `${key.split('.')[0]}.json`;
43
+ const filepath = path.join(LOCALES_DIR, filename);
44
+
45
+ if (fs.existsSync(filepath)) {
46
+ const jsonContent = JSON.parse(fs.readFileSync(filepath, 'utf-8'));
47
+ const allKeys = getAllKeysFromObject(
48
+ jsonContent,
49
+ filename.replace('.json', '.')
50
+ );
51
+
52
+ if (!allKeys.includes(key)) {
53
+ context.report({
54
+ node: firstArg,
55
+ messageId: 'missingLocalizationKey'
56
+ });
57
+ }
58
+ } else {
59
+ context.report({
60
+ node: firstArg,
61
+ messageId: 'missingLocalizationFile'
62
+ });
63
+ }
64
+ }
65
+ }
66
+ };
67
+ },
68
+ meta: {
69
+ messages: {
70
+ missingLocalizationKey:
71
+ 'The localization key does not exist in the JSON files.',
72
+ missingLocalizationFile: 'The localization file does not exist.'
73
+ },
74
+ type: 'problem',
75
+ schema: []
76
+ },
77
+ defaultOptions: []
78
+ });
@@ -1,64 +1,64 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
-
3
- const correctOrder = [
4
- 'withOauthLogin',
5
- 'withLocale',
6
- 'withCurrency',
7
- 'withPrettyUrl',
8
- 'withRedirectionPayment',
9
- 'withThreeDRedirection',
10
- 'withUrlRedirection'
11
- ];
12
-
13
- export default ESLintUtils.RuleCreator.withoutDocs({
14
- create(context: any) {
15
- return {
16
- CallExpression(node: any) {
17
- if (
18
- node.callee.type === 'Identifier' &&
19
- correctOrder.includes(node.callee.name)
20
- ) {
21
- let current = node;
22
- const callSequence = [];
23
-
24
- while (
25
- current.type === 'CallExpression' &&
26
- current.callee.type === 'Identifier'
27
- ) {
28
- if (correctOrder.includes(current.callee.name)) {
29
- callSequence.unshift(current.callee.name);
30
- }
31
- current = current.parent;
32
- }
33
-
34
- let isValidOrder = true;
35
- for (let i = 0; i < callSequence.length; i++) {
36
- if (callSequence[i] !== correctOrder[i]) {
37
- isValidOrder = false;
38
- break;
39
- }
40
- }
41
-
42
- // Report an error if the order is incorrect
43
- if (!isValidOrder) {
44
- context.report({
45
- node,
46
- message: `Incorrect order of middleware functions. Expected order: ${correctOrder.join(
47
- ', '
48
- )}. Found order: ${callSequence.join(', ')}.`
49
- });
50
- }
51
- }
52
- }
53
- };
54
- },
55
- meta: {
56
- type: 'problem',
57
- schema: [],
58
- messages: {
59
- incorrectMiddlewareOrder:
60
- 'Incorrect middleware order. Expected {{expected}}, found {{found}}.'
61
- }
62
- },
63
- defaultOptions: []
64
- });
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ const correctOrder = [
4
+ 'withOauthLogin',
5
+ 'withLocale',
6
+ 'withCurrency',
7
+ 'withPrettyUrl',
8
+ 'withRedirectionPayment',
9
+ 'withThreeDRedirection',
10
+ 'withUrlRedirection'
11
+ ];
12
+
13
+ export default ESLintUtils.RuleCreator.withoutDocs({
14
+ create(context: any) {
15
+ return {
16
+ CallExpression(node: any) {
17
+ if (
18
+ node.callee.type === 'Identifier' &&
19
+ correctOrder.includes(node.callee.name)
20
+ ) {
21
+ let current = node;
22
+ const callSequence = [];
23
+
24
+ while (
25
+ current.type === 'CallExpression' &&
26
+ current.callee.type === 'Identifier'
27
+ ) {
28
+ if (correctOrder.includes(current.callee.name)) {
29
+ callSequence.unshift(current.callee.name);
30
+ }
31
+ current = current.parent;
32
+ }
33
+
34
+ let isValidOrder = true;
35
+ for (let i = 0; i < callSequence.length; i++) {
36
+ if (callSequence[i] !== correctOrder[i]) {
37
+ isValidOrder = false;
38
+ break;
39
+ }
40
+ }
41
+
42
+ // Report an error if the order is incorrect
43
+ if (!isValidOrder) {
44
+ context.report({
45
+ node,
46
+ message: `Incorrect order of middleware functions. Expected order: ${correctOrder.join(
47
+ ', '
48
+ )}. Found order: ${callSequence.join(', ')}.`
49
+ });
50
+ }
51
+ }
52
+ }
53
+ };
54
+ },
55
+ meta: {
56
+ type: 'problem',
57
+ schema: [],
58
+ messages: {
59
+ incorrectMiddlewareOrder:
60
+ 'Incorrect middleware order. Expected {{expected}}, found {{found}}.'
61
+ }
62
+ },
63
+ defaultOptions: []
64
+ });
@@ -1,44 +1,44 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
-
3
- export default ESLintUtils.RuleCreator.withoutDocs({
4
- create(context) {
5
- if (!context.getFilename().includes('urls.ts')) {
6
- return {};
7
- }
8
-
9
- return {
10
- Literal(node) {
11
- const value = node.value?.toString();
12
- const isStrLiteral = value?.includes('${');
13
-
14
- if (!value) {
15
- return;
16
- }
17
-
18
- if (value.endsWith('/')) {
19
- context.report({
20
- messageId: 'clientUrl',
21
- node,
22
- fix: (fixer) =>
23
- fixer.replaceText(
24
- node,
25
- `${isStrLiteral ? '`' : `'`}${value.substring(
26
- 0,
27
- value.length - 1
28
- )}${isStrLiteral ? '`' : `'`}`
29
- )
30
- });
31
- }
32
- }
33
- };
34
- },
35
- meta: {
36
- messages: {
37
- clientUrl: 'Client URLs must not end with slash(/).'
38
- },
39
- type: 'problem',
40
- fixable: 'code',
41
- schema: []
42
- },
43
- defaultOptions: []
44
- });
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ export default ESLintUtils.RuleCreator.withoutDocs({
4
+ create(context) {
5
+ if (!context.getFilename().includes('urls.ts')) {
6
+ return {};
7
+ }
8
+
9
+ return {
10
+ Literal(node) {
11
+ const value = node.value?.toString();
12
+ const isStrLiteral = value?.includes('${');
13
+
14
+ if (!value) {
15
+ return;
16
+ }
17
+
18
+ if (value.endsWith('/')) {
19
+ context.report({
20
+ messageId: 'clientUrl',
21
+ node,
22
+ fix: (fixer) =>
23
+ fixer.replaceText(
24
+ node,
25
+ `${isStrLiteral ? '`' : `'`}${value.substring(
26
+ 0,
27
+ value.length - 1
28
+ )}${isStrLiteral ? '`' : `'`}`
29
+ )
30
+ });
31
+ }
32
+ }
33
+ };
34
+ },
35
+ meta: {
36
+ messages: {
37
+ clientUrl: 'Client URLs must not end with slash(/).'
38
+ },
39
+ type: 'problem',
40
+ fixable: 'code',
41
+ schema: []
42
+ },
43
+ defaultOptions: []
44
+ });
@@ -1,44 +1,44 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
-
3
- export default ESLintUtils.RuleCreator.withoutDocs({
4
- create(context) {
5
- if (context.getFilename().includes('components/image.tsx')) {
6
- return {};
7
- }
8
-
9
- return {
10
- ImportDeclaration(node) {
11
- if (node.source.value === 'next/image') {
12
- context.report({
13
- messageId: 'imageImport',
14
- node,
15
- fix: (fixer) => {
16
- if (node.specifiers.find((s) => s.type === 'ImportSpecifier')) {
17
- return null;
18
- }
19
-
20
- return fixer.replaceText(
21
- node,
22
- node.specifiers
23
- .map(
24
- (specifier) =>
25
- `import { ${specifier.local.name} } from 'components';`
26
- )
27
- .join('\n')
28
- );
29
- }
30
- });
31
- }
32
- }
33
- };
34
- },
35
- meta: {
36
- messages: {
37
- imageImport: "Import 'Image' component from 'components'."
38
- },
39
- type: 'problem',
40
- fixable: 'code',
41
- schema: []
42
- },
43
- defaultOptions: []
44
- });
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ export default ESLintUtils.RuleCreator.withoutDocs({
4
+ create(context) {
5
+ if (context.getFilename().includes('components/image.tsx')) {
6
+ return {};
7
+ }
8
+
9
+ return {
10
+ ImportDeclaration(node) {
11
+ if (node.source.value === 'next/image') {
12
+ context.report({
13
+ messageId: 'imageImport',
14
+ node,
15
+ fix: (fixer) => {
16
+ if (node.specifiers.find((s) => s.type === 'ImportSpecifier')) {
17
+ return null;
18
+ }
19
+
20
+ return fixer.replaceText(
21
+ node,
22
+ node.specifiers
23
+ .map(
24
+ (specifier) =>
25
+ `import { ${specifier.local.name} } from 'components';`
26
+ )
27
+ .join('\n')
28
+ );
29
+ }
30
+ });
31
+ }
32
+ }
33
+ };
34
+ },
35
+ meta: {
36
+ messages: {
37
+ imageImport: "Import 'Image' component from 'components'."
38
+ },
39
+ type: 'problem',
40
+ fixable: 'code',
41
+ schema: []
42
+ },
43
+ defaultOptions: []
44
+ });
package/rules/index.ts CHANGED
@@ -1,21 +1,23 @@
1
- import clientUrl from './client-url';
2
- import imageImport from './image-import';
3
- import linkImport from './link-import';
4
- import routerImport from './router-import';
5
- import skipTrailingSlashRedirect from './skip-trailing-slash-redirect';
6
- import checkLocale from './check-locale';
7
- import metaDataImport from './meta-data-import';
8
- import checkMiddlewareOrder from './check-middleware-order';
9
-
10
- const rules = {
11
- 'client-url': clientUrl,
12
- 'image-import': imageImport,
13
- 'link-import': linkImport,
14
- 'router-import': routerImport,
15
- 'skip-trailing-slash-redirect': skipTrailingSlashRedirect,
16
- 'check-locale': checkLocale,
17
- 'meta-data-import': metaDataImport,
18
- 'check-middleware-order': checkMiddlewareOrder
19
- };
20
-
21
- export { rules };
1
+ import clientUrl from './client-url';
2
+ import imageImport from './image-import';
3
+ import linkImport from './link-import';
4
+ import routerImport from './router-import';
5
+ import skipTrailingSlashRedirect from './skip-trailing-slash-redirect';
6
+ import checkLocale from './check-locale';
7
+ import metaDataImport from './meta-data-import';
8
+ import checkMiddlewareOrder from './check-middleware-order';
9
+ import urlsWithoutSlash from './urls-without-slash';
10
+
11
+ const rules = {
12
+ 'client-url': clientUrl,
13
+ 'image-import': imageImport,
14
+ 'link-import': linkImport,
15
+ 'router-import': routerImport,
16
+ 'skip-trailing-slash-redirect': skipTrailingSlashRedirect,
17
+ 'check-locale': checkLocale,
18
+ 'meta-data-import': metaDataImport,
19
+ 'check-middleware-order': checkMiddlewareOrder,
20
+ 'urls-without-slash': urlsWithoutSlash
21
+ };
22
+
23
+ export { rules };
@@ -1,44 +1,44 @@
1
- import { ESLintUtils } from '@typescript-eslint/utils';
2
-
3
- export default ESLintUtils.RuleCreator.withoutDocs({
4
- create(context) {
5
- if (context.getFilename().includes('components/link.tsx')) {
6
- return {};
7
- }
8
-
9
- return {
10
- ImportDeclaration(node) {
11
- if (node.source.value === 'next/link') {
12
- context.report({
13
- messageId: 'linkImport',
14
- node,
15
- fix: (fixer) => {
16
- if (node.specifiers.find((s) => s.type === 'ImportSpecifier')) {
17
- return null;
18
- }
19
-
20
- return fixer.replaceText(
21
- node,
22
- node.specifiers
23
- .map(
24
- (specifier) =>
25
- `import { ${specifier.local.name} } from 'components';`
26
- )
27
- .join('\n')
28
- );
29
- }
30
- });
31
- }
32
- }
33
- };
34
- },
35
- meta: {
36
- messages: {
37
- linkImport: "Import 'Link' component from 'components'."
38
- },
39
- type: 'problem',
40
- fixable: 'code',
41
- schema: []
42
- },
43
- defaultOptions: []
44
- });
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+
3
+ export default ESLintUtils.RuleCreator.withoutDocs({
4
+ create(context) {
5
+ if (context.getFilename().includes('components/link.tsx')) {
6
+ return {};
7
+ }
8
+
9
+ return {
10
+ ImportDeclaration(node) {
11
+ if (node.source.value === 'next/link') {
12
+ context.report({
13
+ messageId: 'linkImport',
14
+ node,
15
+ fix: (fixer) => {
16
+ if (node.specifiers.find((s) => s.type === 'ImportSpecifier')) {
17
+ return null;
18
+ }
19
+
20
+ return fixer.replaceText(
21
+ node,
22
+ node.specifiers
23
+ .map(
24
+ (specifier) =>
25
+ `import { ${specifier.local.name} } from 'components';`
26
+ )
27
+ .join('\n')
28
+ );
29
+ }
30
+ });
31
+ }
32
+ }
33
+ };
34
+ },
35
+ meta: {
36
+ messages: {
37
+ linkImport: "Import 'Link' component from 'components'."
38
+ },
39
+ type: 'problem',
40
+ fixable: 'code',
41
+ schema: []
42
+ },
43
+ defaultOptions: []
44
+ });