Skip to content

Commit 134ab7e

Browse files
feat: add use-env-prefix rules (#113)
* feat: add initial rule file * feat: create rule * feat(tests): add util load-fixture-creator * feat(utils): add env-parse * feat: refactor use-env-prefix rule * feat: improve error message
1 parent 3734f6d commit 134ab7e

File tree

24 files changed

+488
-53
lines changed

24 files changed

+488
-53
lines changed

.eslintrc.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,8 @@ module.exports = {
2121
"@typescript-eslint/explicit-module-boundary-types": "off",
2222
"@typescript-eslint/ban-types": "off",
2323
"@typescript-eslint/no-explicit-any": "off",
24+
"no-irregular-whitespace": ["error", {
25+
"skipRegExps": true
26+
}]
2427
},
2528
};

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ typings/
8989
.yarn-integrity
9090

9191
# dotenv environment variables file
92-
.env
92+
/.env
9393

9494
# parcel-bundler cache (https://parceljs.org/)
9595
.cache

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ title: Rules
1313
| [gridsome/format-query-block](/rules/format-query-block) | Format fix for `<page-query>` and `<static-query>` in .vue. Using Prettier API | :wrench: |
1414
| [gridsome/require-g-image-src](/rules/require-g-image-src) | Require v-bind:src or src of `<g-image>` elements | |
1515
| [gridsome/require-g-link-to](/rules/require-g-link-to) | Require v-bind:to or to of `<g-link>` elements | |
16+
| [gridsome/use-env-prefix](/rules/use-env-prefix) | Use prefix `GRIDSOME_` when using process.env in browser | |

docs/rules/use-env-prefix.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
title: use-env-prefix
3+
sidebarDepth: 0
4+
description: Use prefix `GRIDSOME_` when using process.env in browser
5+
---
6+
7+
## Use prefix `GRIDSOME_` when using process.env in browser (gridsome/use-env-prefix)
8+
9+
## :book: Rule Details
10+
11+
- This rule reports the `process.env` expression which do not include prefix `GRIDSOME_`.
12+
13+
If you want to know more information, see: [Environment variables](https://gridsome.org/docs/environment-variables/)
14+
15+
:-1: Examples of **incorrect** code for this rule:
16+
17+
```html
18+
<template></template>
19+
20+
<script>
21+
export default {
22+
data() {
23+
return {
24+
url: process.env.API_URL, // Possible error
25+
};
26+
},
27+
};
28+
</script>
29+
```
30+
31+
:+1: Examples of **correct** code for this rule:
32+
33+
```html
34+
<template></template>
35+
36+
<script>
37+
export default {
38+
data() {
39+
return {
40+
url: process.env.GRIDSOME_API_URL,
41+
};
42+
},
43+
};
44+
</script>
45+
```
46+
47+
## :wrench: Options
48+
49+
```json
50+
{
51+
"gridsome/use-env-prefix": [
52+
"warn",
53+
{
54+
{
55+
"pathsForBrowserfile": ["src/**/*"],
56+
"envPath": ".env",
57+
},
58+
}
59+
]
60+
}
61+
```
62+
63+
- `pathsForBrowserfile` (`string[]`) ... This option can specify paths for browser.
64+
- default ... ["src/**/*"]
65+
- `envPath` (`string`) ... This option can specify path for env file.
66+
- default ... ".env"

lib/configs/recommended.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ export = {
44
"gridsome/format-query-block": "warn",
55
"gridsome/require-g-image-src": "error",
66
"gridsome/require-g-link-to": "warn",
7+
"gridsome/use-env-prefix": "warn",
78
},
89
};

lib/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
import formatQueryBlock from "./rules/format-query-block";
33
import requireGImageSrc from "./rules/require-g-image-src";
44
import requireGLinkTo from "./rules/require-g-link-to";
5+
import useEnvPrefix from "./rules/use-env-prefix";
56

67
export const rules = {
78
"format-query-block": formatQueryBlock,
89
"require-g-image-src": requireGImageSrc,
910
"require-g-link-to": requireGLinkTo,
11+
"use-env-prefix": useEnvPrefix,
1012
};

lib/rules/use-env-prefix.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @author tyankatsu
3+
* @copyright 2020 tyankatsu. All rights reserved.
4+
* See LICENSE file in root directory for full license.
5+
*/
6+
import { AST } from "vue-eslint-parser";
7+
import minimatch from "minimatch";
8+
import { createRule, Env } from "../utils";
9+
import * as Fs from "fs";
10+
11+
const PREFIX = "GRIDSOME_";
12+
13+
type Options = {
14+
pathsForBrowserfile?: string[];
15+
envPath?: string;
16+
};
17+
18+
const defaultOptions: [Options] = [{}];
19+
20+
type MessageIds = "useEnvPrefix";
21+
export = createRule<[Options], MessageIds>({
22+
name: "use-env-prefix",
23+
meta: {
24+
docs: {
25+
description: "Use prefix `GRIDSOME_` when using process.env in browser",
26+
category: "Possible Errors",
27+
recommended: false,
28+
},
29+
type: "problem",
30+
messages: {
31+
useEnvPrefix: "Use `process.env.{{ addedPrefixEnv }}`.",
32+
},
33+
schema: [
34+
{
35+
type: "object",
36+
properties: {
37+
pathsForBrowserfile: {
38+
type: "array",
39+
items: {
40+
type: "string",
41+
},
42+
},
43+
envPath: {
44+
type: "string",
45+
},
46+
},
47+
},
48+
],
49+
},
50+
defaultOptions,
51+
create(context) {
52+
const filename = context.getFilename();
53+
54+
const pathsForBrowserfileOption = context.options[0]
55+
?.pathsForBrowserfile || ["src/**/*"];
56+
const envPathOption = context.options[0]?.envPath || ".env";
57+
58+
const isClientfile = pathsForBrowserfileOption.some((clientPath) =>
59+
minimatch(filename, clientPath)
60+
);
61+
62+
const envSource = Fs.readFileSync(envPathOption, { encoding: "utf8" });
63+
const parsedEnvSource = new Env(envSource).parse();
64+
65+
return {
66+
"MemberExpression[object.object.name='process'][object.property.name='env']"(
67+
node: AST.ESLintMemberExpression
68+
) {
69+
if (!isClientfile) return;
70+
if (node.property.type !== "Identifier") return;
71+
if (node.property.name.includes(PREFIX)) return;
72+
73+
const envName = node.property.name;
74+
75+
if (parsedEnvSource.has(envName)) {
76+
context.report({
77+
node,
78+
loc: node.loc,
79+
messageId: "useEnvPrefix",
80+
data: {
81+
addedPrefixEnv: `${PREFIX}${envName}`,
82+
},
83+
});
84+
}
85+
},
86+
};
87+
},
88+
});

lib/utils/env.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const COMMENT_PREFIX = "#";
2+
const SEPARATER_COMMENT = "=";
3+
const SEPARATER_SPACE = /( | )+/;
4+
const NEWLINES = /\n|\r|\r\n/;
5+
6+
const isCommentCode = (line: string) => line.charAt(0) === COMMENT_PREFIX;
7+
8+
export class Env {
9+
constructor(private source: string) {}
10+
11+
public parse() {
12+
const result = new Map<string, string>();
13+
14+
this.source
15+
.toString()
16+
.trim()
17+
.split(NEWLINES)
18+
.forEach((line) => {
19+
const trimmedLine = line.trim();
20+
21+
if (isCommentCode(trimmedLine)) return;
22+
23+
const [key, ...value] = trimmedLine.split(SEPARATER_COMMENT);
24+
const joinedValue = value
25+
.join(SEPARATER_COMMENT)
26+
.split(SEPARATER_SPACE)[0];
27+
28+
result.set(key, joinedValue);
29+
});
30+
31+
return result;
32+
}
33+
}

lib/utils/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,8 @@ export * from "./get-code-wrap-indent-info";
1313
// ====================================================
1414
export * from "./attribute";
1515
export * from "./directive";
16+
17+
// ====================================================
18+
// env
19+
// ====================================================
20+
export * from "./env";

package-lock.json

Lines changed: 20 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)