cleanenv-v1 0.9.2
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.
- package/LICENSE +21 -0
- package/README.md +56 -0
- package/dist/audit.d.ts +8 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +29 -0
- package/dist/audit.js.map +1 -0
- package/dist/discovery.d.ts +7 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +52 -0
- package/dist/discovery.js.map +1 -0
- package/dist/fixer.d.ts +10 -0
- package/dist/fixer.d.ts.map +1 -0
- package/dist/fixer.js +30 -0
- package/dist/fixer.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +2 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +36 -0
- package/dist/parser.js.map +1 -0
- package/dist/reporter.d.ts +4 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +35 -0
- package/dist/reporter.js.map +1 -0
- package/package.json +33 -0
- package/resources/logo-light.svg +1 -0
- package/resources/logo.svg +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dr. Floofers
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<br>
|
|
3
|
+
<a href="https://github.com/Dr-Floofers/Cleanenv">
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="./resources/logo.svg">
|
|
6
|
+
<source media="(prefers-color-scheme: light)" srcset="./resources/logo-light.svg">
|
|
7
|
+
<img src="./resources/logo.svg" alt="Cleanenv">
|
|
8
|
+
</picture>
|
|
9
|
+
</a>
|
|
10
|
+
<br>
|
|
11
|
+
<br>
|
|
12
|
+
<span>Audit and fix your .env files in seconds</span>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx cleanenv-v1
|
|
19
|
+
```
|
|
20
|
+
No install needed. Just run it from your project root.
|
|
21
|
+
|
|
22
|
+
### Example Output
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
scanning project...
|
|
26
|
+
found 2 env file(s)
|
|
27
|
+
|
|
28
|
+
.env vs .env.example
|
|
29
|
+
├─ missing SECRET_KEY, DEBUG
|
|
30
|
+
├─ empty API_KEY
|
|
31
|
+
├─ unused OLD_TOKEN
|
|
32
|
+
└─ ok DATABASE_URL
|
|
33
|
+
|
|
34
|
+
.env.staging vs .env.staging.example
|
|
35
|
+
└─ ok
|
|
36
|
+
|
|
37
|
+
────────────────────────────────────────
|
|
38
|
+
summary 1 clean 3 warnings 1 errors
|
|
39
|
+
|
|
40
|
+
3 issues can be fixed automatically (2 missing, 1 unused)
|
|
41
|
+
1 issue needs manual attention: empty values (API_KEY)
|
|
42
|
+
|
|
43
|
+
! This will write to your .env files.
|
|
44
|
+
Fix automatically? (Y/n) › y
|
|
45
|
+
+ .env — added SECRET_KEY=change_me, DEBUG=false (placeholder — fill in your real value), removed OLD_TOKEN
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## How it Works
|
|
49
|
+
|
|
50
|
+
- Scans your project for all `.env*` files
|
|
51
|
+
- Pairs each one with its matching example file
|
|
52
|
+
- Detects and reports missing, unused, and empty variables
|
|
53
|
+
- (Optional) Automatically fix issues by scaffolding missing keys and removing unused ones
|
|
54
|
+
|
|
55
|
+
> [!NOTE]
|
|
56
|
+
> If no specific example is found for any `.env*`, it will use `.env.example` instead
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,EAAE,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CA4BvE"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { parseEnvFile } from "./parser";
|
|
2
|
+
export function audit(envPath, examplePath) {
|
|
3
|
+
const env = parseEnvFile(envPath);
|
|
4
|
+
const example = parseEnvFile(examplePath);
|
|
5
|
+
const result = {
|
|
6
|
+
ok: [],
|
|
7
|
+
missing: [],
|
|
8
|
+
unused: [],
|
|
9
|
+
empty: [],
|
|
10
|
+
};
|
|
11
|
+
for (const [key] of example) {
|
|
12
|
+
if (!env.has(key)) {
|
|
13
|
+
result.missing.push(key);
|
|
14
|
+
}
|
|
15
|
+
else if (env.get(key) === "") {
|
|
16
|
+
result.empty.push(key);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
result.ok.push(key);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const [key] of env) {
|
|
23
|
+
if (!example.has(key)) {
|
|
24
|
+
result.unused.push(key);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AASvC,MAAM,UAAU,KAAK,CAAC,OAAe,EAAE,WAAmB;IACxD,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;IACjC,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;IAEzC,MAAM,MAAM,GAAgB;QAC1B,EAAE,EAAE,EAAE;QACN,OAAO,EAAE,EAAE;QACX,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;KACV,CAAA;IAED,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC1B,CAAC;aAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;YAC/B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACxB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACrB,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,OAAO;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;CACpB;AAiCD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,EAAE,CAuBpD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
function getExampleFiles(dir) {
|
|
3
|
+
const files = fs.readdirSync(dir);
|
|
4
|
+
const examples = new Set();
|
|
5
|
+
for (const file of files) {
|
|
6
|
+
if (file.startsWith(".env") && file.includes("example")) {
|
|
7
|
+
examples.add(file);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
return examples;
|
|
11
|
+
}
|
|
12
|
+
function findMatchingExample(envFile, examples) {
|
|
13
|
+
if (envFile === ".env") {
|
|
14
|
+
return examples.has(".env.example") ? ".env.example" : null;
|
|
15
|
+
}
|
|
16
|
+
const suffix = envFile.replace(/^\.env\.?/, "");
|
|
17
|
+
const candidates = [
|
|
18
|
+
`.env.${suffix}.example`,
|
|
19
|
+
`.env.example.${suffix}`,
|
|
20
|
+
].filter(c => c !== ".env..example" && c !== ".env.example.");
|
|
21
|
+
for (const candidate of candidates) {
|
|
22
|
+
if (examples.has(candidate))
|
|
23
|
+
return candidate;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
export function discoverPairs(dir) {
|
|
28
|
+
const files = fs.readdirSync(dir);
|
|
29
|
+
const examples = getExampleFiles(dir);
|
|
30
|
+
const hasFallback = examples.has(".env.example");
|
|
31
|
+
const pairs = [];
|
|
32
|
+
for (const file of files) {
|
|
33
|
+
if (!file.startsWith(".env"))
|
|
34
|
+
continue;
|
|
35
|
+
if (file.includes("example"))
|
|
36
|
+
continue;
|
|
37
|
+
if (file === ".envrc")
|
|
38
|
+
continue;
|
|
39
|
+
const match = findMatchingExample(file, examples);
|
|
40
|
+
if (match) {
|
|
41
|
+
pairs.push({ envFile: file, exampleFile: match, fallback: false });
|
|
42
|
+
}
|
|
43
|
+
else if (hasFallback) {
|
|
44
|
+
pairs.push({ envFile: file, exampleFile: ".env.example", fallback: true });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
pairs.push({ envFile: file, exampleFile: "", fallback: false });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return pairs;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AASxB,SAAS,eAAe,CAAC,GAAW;IAChC,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAA;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACtD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QACtB,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAA;AACnB,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe,EAAE,QAAqB;IACjE,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7D,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;IAE/C,MAAM,UAAU,GAAG;QACjB,QAAQ,MAAM,UAAU;QACxB,gBAAgB,MAAM,EAAE;KACzB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,eAAe,IAAI,CAAC,KAAK,eAAe,CAAC,CAAA;IAE7D,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAA;IAC/C,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AACD,MAAM,UAAU,aAAa,CAAC,GAAW;IACrC,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IACjC,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAA;IACrC,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAChD,MAAM,KAAK,GAAc,EAAE,CAAA;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;YAAE,SAAQ;QACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAAE,SAAQ;QACtC,IAAI,IAAI,KAAK,QAAQ;YAAE,SAAQ;QAE/B,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;QAEjD,IAAI,KAAK,EAAE,CAAC;YACR,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QACtE,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACrB,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9E,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QACnE,CAAC;IACL,CAAC;IAED,OAAO,KAAK,CAAA;AAChB,CAAC"}
|
package/dist/fixer.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AuditResult } from "./audit";
|
|
2
|
+
export interface FixResult {
|
|
3
|
+
added: {
|
|
4
|
+
key: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}[];
|
|
7
|
+
removed: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function fix(envPath: string, examplePath: string, result: AuditResult): FixResult;
|
|
10
|
+
//# sourceMappingURL=fixer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixer.d.ts","sourceRoot":"","sources":["../src/fixer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAGrC,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACvC,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAWD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,CAoBxF"}
|
package/dist/fixer.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import { parseEnvFile } from "./parser";
|
|
3
|
+
function lineKey(line) {
|
|
4
|
+
const trimmed = line.trim();
|
|
5
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
6
|
+
return null;
|
|
7
|
+
const eqIdx = trimmed.indexOf("=");
|
|
8
|
+
if (eqIdx === -1)
|
|
9
|
+
return null;
|
|
10
|
+
const rawKey = trimmed.slice(0, eqIdx).trim();
|
|
11
|
+
return rawKey.startsWith("export ") ? rawKey.slice(7).trim() : rawKey;
|
|
12
|
+
}
|
|
13
|
+
export function fix(envPath, examplePath, result) {
|
|
14
|
+
const exampleValues = parseEnvFile(examplePath);
|
|
15
|
+
const unusedSet = new Set(result.unused);
|
|
16
|
+
const lines = fs.readFileSync(envPath, "utf-8").split("\n");
|
|
17
|
+
const kept = lines.filter(line => {
|
|
18
|
+
const key = lineKey(line);
|
|
19
|
+
return key === null || !unusedSet.has(key);
|
|
20
|
+
});
|
|
21
|
+
const added = [];
|
|
22
|
+
for (const key of result.missing) {
|
|
23
|
+
const value = exampleValues.get(key) ?? "";
|
|
24
|
+
kept.push(`${key}=${value}`);
|
|
25
|
+
added.push({ key, value });
|
|
26
|
+
}
|
|
27
|
+
fs.writeFileSync(envPath, kept.join("\n"), "utf-8");
|
|
28
|
+
return { added, removed: result.unused };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=fixer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixer.js","sourceRoot":"","sources":["../src/fixer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAOvC,SAAS,OAAO,CAAC,IAAY;IAC3B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;IAC3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IACpD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAClC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7C,OAAO,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;AACvE,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,WAAmB,EAAE,MAAmB;IAC3E,MAAM,aAAa,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;IAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAExC,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC3D,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QAC/B,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QACzB,OAAO,GAAG,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,MAAM,KAAK,GAAuB,EAAE,CAAA;IACpC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;QAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC,CAAA;QAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;IAEnD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;AAC1C,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as readline from "readline";
|
|
5
|
+
import { audit } from "./audit";
|
|
6
|
+
import { report, summary } from "./reporter";
|
|
7
|
+
import { discoverPairs } from "./discovery";
|
|
8
|
+
import { fix } from "./fixer";
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
console.log(chalk.dim("\n scanning project..."));
|
|
11
|
+
const pairs = discoverPairs(cwd);
|
|
12
|
+
if (pairs.length === 0) {
|
|
13
|
+
console.log(chalk.redBright("\n No .env files found in " + cwd));
|
|
14
|
+
console.log(chalk.dim(" Make sure you're running cleanenv from your project root\n"));
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
console.log(chalk.dim(` found ${pairs.length} env file(s)\n`));
|
|
18
|
+
let totalClean = 0;
|
|
19
|
+
let totalWarnings = 0;
|
|
20
|
+
let totalErrors = 0;
|
|
21
|
+
const fixable = [];
|
|
22
|
+
const allEmpty = [];
|
|
23
|
+
for (const pair of pairs) {
|
|
24
|
+
if (!pair.exampleFile) {
|
|
25
|
+
console.log(chalk.red(` x ${pair.envFile}`) + chalk.dim(" — no example file found, skipping\n"));
|
|
26
|
+
totalErrors++;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const envPath = path.join(cwd, pair.envFile);
|
|
30
|
+
const examplePath = path.join(cwd, pair.exampleFile);
|
|
31
|
+
const result = audit(envPath, examplePath);
|
|
32
|
+
const isClean = !result.missing.length && !result.empty.length && !result.unused.length;
|
|
33
|
+
if (isClean)
|
|
34
|
+
totalClean++;
|
|
35
|
+
totalWarnings += result.missing.length + result.empty.length;
|
|
36
|
+
totalErrors += result.unused.length;
|
|
37
|
+
report(result, pair.envFile, pair.exampleFile, pair.fallback);
|
|
38
|
+
if (result.missing.length || result.unused.length) {
|
|
39
|
+
fixable.push({ envPath, examplePath, envFile: pair.envFile, result });
|
|
40
|
+
}
|
|
41
|
+
allEmpty.push(...result.empty);
|
|
42
|
+
}
|
|
43
|
+
summary(totalClean, totalWarnings, totalErrors);
|
|
44
|
+
if (fixable.length === 0)
|
|
45
|
+
process.exit(0);
|
|
46
|
+
const totalMissing = fixable.reduce((n, p) => n + p.result.missing.length, 0);
|
|
47
|
+
const totalUnused = fixable.reduce((n, p) => n + p.result.unused.length, 0);
|
|
48
|
+
const autoCount = totalMissing + totalUnused;
|
|
49
|
+
const parts = [
|
|
50
|
+
totalMissing && `${totalMissing} missing`,
|
|
51
|
+
totalUnused && `${totalUnused} unused`,
|
|
52
|
+
].filter(Boolean).join(", ");
|
|
53
|
+
console.log(chalk.dim(` ${autoCount} issue${autoCount !== 1 ? "s" : ""} can be fixed automatically (${parts})`));
|
|
54
|
+
if (allEmpty.length) {
|
|
55
|
+
console.log(chalk.dim(` ${allEmpty.length} issue${allEmpty.length !== 1 ? "s" : ""} need${allEmpty.length === 1 ? "s" : ""} manual attention: empty values (${allEmpty.join(", ")})`));
|
|
56
|
+
}
|
|
57
|
+
console.log();
|
|
58
|
+
console.log(chalk.yellow(" ! This will write to your .env files."));
|
|
59
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
60
|
+
const answer = await new Promise(resolve => {
|
|
61
|
+
rl.question(chalk.dim(" Fix automatically? (Y/n) › "), resolve);
|
|
62
|
+
});
|
|
63
|
+
rl.close();
|
|
64
|
+
if (!["y", "yes"].includes(answer.trim().toLowerCase()) && answer.trim() !== "") {
|
|
65
|
+
console.log();
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
console.log();
|
|
69
|
+
for (const { envPath, examplePath, envFile, result } of fixable) {
|
|
70
|
+
const fixResult = fix(envPath, examplePath, result);
|
|
71
|
+
const segments = [];
|
|
72
|
+
if (fixResult.added.length) {
|
|
73
|
+
const keys = fixResult.added.map(({ key, value }) => `${key}=${value}`).join(", ");
|
|
74
|
+
segments.push(`added ${keys} (placeholder — fill in your real value)`);
|
|
75
|
+
}
|
|
76
|
+
if (fixResult.removed.length) {
|
|
77
|
+
segments.push(`removed ${fixResult.removed.join(", ")}`);
|
|
78
|
+
}
|
|
79
|
+
console.log(chalk.green(" + ") + chalk.blueBright(envFile) + chalk.dim(" — " + segments.join(", ")));
|
|
80
|
+
}
|
|
81
|
+
console.log();
|
|
82
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAeA,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA0BlE"}
|
package/dist/parser.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
function parseValue(raw) {
|
|
4
|
+
if ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'"))) {
|
|
5
|
+
return raw.slice(1, -1);
|
|
6
|
+
}
|
|
7
|
+
if (raw.startsWith("#"))
|
|
8
|
+
return "";
|
|
9
|
+
const commentIdx = raw.indexOf(" #");
|
|
10
|
+
if (commentIdx !== -1) {
|
|
11
|
+
return raw.slice(0, commentIdx).trim();
|
|
12
|
+
}
|
|
13
|
+
return raw;
|
|
14
|
+
}
|
|
15
|
+
export function parseEnvFile(filePath) {
|
|
16
|
+
const fullPath = path.resolve(filePath);
|
|
17
|
+
const result = new Map();
|
|
18
|
+
if (!fs.existsSync(fullPath)) {
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
const lines = fs.readFileSync(fullPath, "utf-8").split("\n");
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
const trimmed = line.trim();
|
|
24
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
25
|
+
continue;
|
|
26
|
+
const eqIndex = trimmed.indexOf("=");
|
|
27
|
+
if (eqIndex === -1)
|
|
28
|
+
continue;
|
|
29
|
+
const rawKey = trimmed.slice(0, eqIndex).trim();
|
|
30
|
+
const key = rawKey.startsWith("export ") ? rawKey.slice(7).trim() : rawKey;
|
|
31
|
+
const value = parseValue(trimmed.slice(eqIndex + 1).trim());
|
|
32
|
+
result.set(key, value);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAA;AACxB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACzB,CAAC;IACD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAClC,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IACpC,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE,CAAA;IACxC,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IAExC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAA;IACf,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAE5D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAE3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAEjD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACpC,IAAI,OAAO,KAAK,CAAC,CAAC;YAAE,SAAQ;QAE5B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;QAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAA;QAC1E,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAE3D,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACxB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { AuditResult } from "./audit";
|
|
2
|
+
export declare function report(result: AuditResult, envFile: string, exampleFile: string, fallback: boolean): void;
|
|
3
|
+
export declare function summary(totalClean: number, totalWarnings: number, totalErrors: number): void;
|
|
4
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAErC,wBAAgB,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,QA4BlG;AAED,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,QASrF"}
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
export function report(result, envFile, exampleFile, fallback) {
|
|
3
|
+
const header = chalk.blueBright(envFile) + chalk.dim(" vs ") + chalk.dim(exampleFile);
|
|
4
|
+
const fallbackTag = fallback ? chalk.yellow(" (fallback)") : "";
|
|
5
|
+
console.log(header + fallbackTag);
|
|
6
|
+
if (result.missing.length) {
|
|
7
|
+
console.log(chalk.dim(" ├─ ") + chalk.yellow("missing ") + chalk.white(result.missing.join(", ")));
|
|
8
|
+
}
|
|
9
|
+
if (result.empty.length) {
|
|
10
|
+
console.log(chalk.dim(" ├─ ") + chalk.yellow("empty ") + chalk.white(result.empty.join(", ")));
|
|
11
|
+
}
|
|
12
|
+
if (result.unused.length) {
|
|
13
|
+
console.log(chalk.dim(" ├─ ") + chalk.red("unused ") + chalk.white(result.unused.join(", ")));
|
|
14
|
+
}
|
|
15
|
+
const isClean = !result.missing.length && !result.empty.length && !result.unused.length;
|
|
16
|
+
if (isClean) {
|
|
17
|
+
console.log(chalk.dim(" └─ ") + chalk.green("ok"));
|
|
18
|
+
}
|
|
19
|
+
else if (result.ok.length) {
|
|
20
|
+
console.log(chalk.dim(" └─ ") + chalk.green("ok ") + chalk.dim(result.ok.join(", ")));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.log(chalk.dim(" └─ ") + chalk.dim("none ok"));
|
|
24
|
+
}
|
|
25
|
+
console.log();
|
|
26
|
+
}
|
|
27
|
+
export function summary(totalClean, totalWarnings, totalErrors) {
|
|
28
|
+
console.log(chalk.dim("─".repeat(40)));
|
|
29
|
+
console.log(chalk.dim("summary ") +
|
|
30
|
+
chalk.greenBright(`${totalClean} clean`) + " " +
|
|
31
|
+
chalk.yellowBright(`${totalWarnings} warnings`) + " " +
|
|
32
|
+
chalk.redBright(`${totalErrors} errors`));
|
|
33
|
+
console.log();
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cleanenv-v1",
|
|
3
|
+
"version": "0.9.2",
|
|
4
|
+
"description": "Audit and fix your .env files",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"keywords": ["env", "dotenv", "cli", "devtools", "environment", "audit"],
|
|
7
|
+
"author": "Dr. Floofers",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"chalk": "^5.6.2"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^25.6.2",
|
|
15
|
+
"ts-node": "^10.9.2",
|
|
16
|
+
"tsx": "^4.21.0",
|
|
17
|
+
"typescript": "^6.0.3"
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"cleanenv": "dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev": "tsx src/index.ts",
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"postbuild": "node -e \"const fs=require('fs');const f='dist/index.js';fs.writeFileSync(f,'#!/usr/bin/env node\\n'+fs.readFileSync(f,'utf8'))\""
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"LICENSE",
|
|
30
|
+
"resources/logo.svg",
|
|
31
|
+
"resources/logo-light.svg"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="433.211" height="78.223" viewBox="0 0 433.211 78.223" xmlns="http://www.w3.org/2000/svg"><g id="svgGroup" stroke-linecap="round" fill-rule="nonzero" font-size="9pt" stroke="#000000" stroke-width="0.5" fill="#000000" style="stroke:#000000;stroke-width:0.5;fill:#000000"><path d="M 32.817 64.795 Q 36.381 64.795 38.408 64.063 Q 40.434 63.33 41.557 62.256 Q 42.68 61.182 43.51 60.107 Q 44.291 59.131 44.804 58.643 Q 45.317 58.154 46.244 57.959 Q 47.026 57.715 48.759 57.642 Q 50.492 57.568 52.226 57.568 Q 53.959 57.568 54.643 57.666 Q 55.668 57.715 56.059 58.057 Q 56.45 58.398 56.547 59.521 Q 56.694 61.084 56.718 63.232 Q 56.742 65.381 56.645 66.943 Q 56.596 67.432 56.474 67.773 Q 56.352 68.115 55.961 68.799 Q 55.473 69.58 54.057 71.069 Q 52.641 72.559 49.907 74.146 Q 47.172 75.732 42.851 76.855 Q 38.53 77.979 32.231 77.979 Q 25.492 77.979 19.633 76.245 Q 13.774 74.512 9.355 70.41 Q 4.936 66.309 2.47 59.326 Q 0.004 52.344 0.004 41.895 Q 0.004 30.273 4.033 22.144 Q 8.061 14.014 15.483 9.766 Q 22.905 5.518 33.061 5.518 Q 40.19 5.518 44.511 6.982 Q 48.832 8.447 51.078 10.425 Q 53.325 12.402 54.252 13.867 Q 54.594 14.404 54.741 14.819 Q 54.887 15.234 54.936 16.113 Q 55.082 17.285 55.009 19.531 Q 54.936 21.777 54.643 23.486 Q 54.448 24.561 54.008 24.902 Q 53.813 25.098 53.325 25.244 Q 52.836 25.391 51.86 25.391 Q 50.297 25.391 48.344 25.269 Q 46.391 25.146 45.414 25 Q 44.242 24.805 43.705 24.438 Q 43.168 24.072 42.631 23.291 Q 41.752 22.021 39.604 20.361 Q 37.455 18.701 32.524 18.701 Q 25.59 18.701 21.098 24.048 Q 16.606 29.395 16.606 41.357 Q 16.606 53.271 21.318 59.033 Q 26.03 64.795 32.817 64.795 Z M 255.717 45.654 L 255.717 74.17 Q 255.717 75.635 255.107 76.196 Q 254.496 76.758 253.032 76.758 L 242.973 76.758 Q 241.508 76.758 240.898 76.196 Q 240.287 75.635 240.287 74.17 L 240.287 48.193 Q 240.287 42.871 238.041 40.43 Q 235.795 37.988 231.938 37.988 Q 228.08 37.988 226.005 39.648 Q 223.93 41.309 222.807 43.848 L 222.807 74.17 Q 222.807 75.635 222.197 76.196 Q 221.586 76.758 220.121 76.758 L 210.063 76.758 Q 208.598 76.758 207.988 76.196 Q 207.377 75.635 207.377 74.17 L 207.377 33.252 Q 207.377 32.08 207.866 31.445 Q 208.891 30.078 210.331 28.662 Q 211.772 27.246 213.871 25.635 Q 214.506 25.146 215.092 25.146 Q 215.629 25.146 216.313 25.635 Q 218.364 27.246 219.828 28.711 Q 221.293 30.176 222.416 31.738 L 222.66 31.738 Q 223.491 30.664 225.151 29.224 Q 226.811 27.783 229.814 26.66 Q 232.817 25.537 237.504 25.537 Q 242.094 25.537 246.244 27.393 Q 250.395 29.248 253.056 33.643 Q 255.717 38.037 255.717 45.654 Z M 373.198 45.654 L 373.198 74.17 Q 373.198 75.635 372.587 76.196 Q 371.977 76.758 370.512 76.758 L 360.453 76.758 Q 358.989 76.758 358.378 76.196 Q 357.768 75.635 357.768 74.17 L 357.768 48.193 Q 357.768 42.871 355.522 40.43 Q 353.276 37.988 349.418 37.988 Q 345.561 37.988 343.486 39.648 Q 341.41 41.309 340.287 43.848 L 340.287 74.17 Q 340.287 75.635 339.677 76.196 Q 339.067 76.758 337.602 76.758 L 327.543 76.758 Q 326.078 76.758 325.468 76.196 Q 324.858 75.635 324.858 74.17 L 324.858 33.252 Q 324.858 32.08 325.346 31.445 Q 326.371 30.078 327.812 28.662 Q 329.252 27.246 331.352 25.635 Q 331.987 25.146 332.573 25.146 Q 333.11 25.146 333.793 25.635 Q 335.844 27.246 337.309 28.711 Q 338.774 30.176 339.897 31.738 L 340.141 31.738 Q 340.971 30.664 342.631 29.224 Q 344.291 27.783 347.294 26.66 Q 350.297 25.537 354.985 25.537 Q 359.575 25.537 363.725 27.393 Q 367.875 29.248 370.536 33.643 Q 373.198 38.037 373.198 45.654 Z M 128.617 56.445 L 107.67 56.445 Q 108.061 61.475 111.357 64.111 Q 114.653 66.748 120.317 66.748 Q 124.809 66.748 127.519 65.405 Q 130.229 64.063 131.303 63.281 Q 132.231 62.598 133.403 62.646 Q 134.33 62.646 136.064 63.013 Q 137.797 63.379 139.506 64.355 Q 140.727 64.99 140.727 66.113 Q 140.727 66.748 140.483 67.92 Q 140.336 68.604 139.994 69.897 Q 139.653 71.191 139.116 72.314 Q 138.823 72.852 138.188 73.34 Q 137.211 74.023 135.038 75.146 Q 132.866 76.27 129.106 77.124 Q 125.346 77.979 119.584 77.979 Q 111.332 77.979 105.229 75.317 Q 99.125 72.656 95.756 67.041 Q 92.387 61.426 92.387 52.539 Q 92.387 39.209 99.223 32.373 Q 106.059 25.537 117.387 25.537 Q 124.76 25.537 129.863 28.174 Q 134.965 30.811 137.626 35.449 Q 140.287 40.088 140.287 46.045 Q 140.287 51.855 137.309 54.15 Q 134.33 56.445 128.617 56.445 Z M 107.573 46.436 L 123.491 46.436 Q 125.981 46.436 125.981 44.141 Q 125.981 40.674 123.808 38.306 Q 121.635 35.938 117.289 35.938 Q 112.553 35.938 110.331 38.965 Q 108.11 41.992 107.573 46.436 Z M 302.446 56.445 L 281.498 56.445 Q 281.889 61.475 285.185 64.111 Q 288.481 66.748 294.145 66.748 Q 298.637 66.748 301.347 65.405 Q 304.057 64.063 305.131 63.281 Q 306.059 62.598 307.231 62.646 Q 308.158 62.646 309.892 63.013 Q 311.625 63.379 313.334 64.355 Q 314.555 64.99 314.555 66.113 Q 314.555 66.748 314.311 67.92 Q 314.164 68.604 313.823 69.897 Q 313.481 71.191 312.944 72.314 Q 312.651 72.852 312.016 73.34 Q 311.039 74.023 308.867 75.146 Q 306.694 76.27 302.934 77.124 Q 299.174 77.979 293.412 77.979 Q 285.16 77.979 279.057 75.317 Q 272.953 72.656 269.584 67.041 Q 266.215 61.426 266.215 52.539 Q 266.215 39.209 273.051 32.373 Q 279.887 25.537 291.215 25.537 Q 298.588 25.537 303.691 28.174 Q 308.793 30.811 311.454 35.449 Q 314.116 40.088 314.116 46.045 Q 314.116 51.855 311.137 54.15 Q 308.158 56.445 302.446 56.445 Z M 281.401 46.436 L 297.319 46.436 Q 299.809 46.436 299.809 44.141 Q 299.809 40.674 297.636 38.306 Q 295.463 35.938 291.117 35.938 Q 286.381 35.938 284.159 38.965 Q 281.938 41.992 281.401 46.436 Z M 194.194 46.875 L 194.194 74.512 Q 194.194 75.439 193.681 76.099 Q 193.168 76.758 191.948 76.758 L 184.623 76.758 Q 183.842 76.758 183.232 76.538 Q 182.621 76.318 182.084 75.684 L 179.057 71.777 L 178.715 71.777 Q 176.469 75.049 172.685 76.514 Q 168.901 77.979 163.969 77.979 Q 156.791 77.979 152.568 73.95 Q 148.344 69.922 148.344 62.842 Q 148.344 59.18 149.687 56.03 Q 151.03 52.881 154.374 50.464 Q 157.719 48.047 163.749 46.582 Q 169.78 45.117 179.155 44.873 Q 179.155 40.43 176.933 38.477 Q 174.711 36.523 170.268 36.523 Q 166.264 36.523 163.725 37.891 Q 161.186 39.258 160.551 39.746 Q 159.867 40.332 158.891 40.186 Q 157.573 39.99 156.083 39.502 Q 154.594 39.014 152.885 38.379 Q 152.641 38.281 152.348 38.062 Q 152.055 37.842 152.006 37.402 Q 152.006 37.158 152.055 36.792 Q 152.104 36.426 152.299 35.449 Q 152.494 34.473 152.885 33.032 Q 153.276 31.592 153.617 30.811 Q 154.057 29.98 155.082 29.248 Q 155.912 28.564 160.112 27.051 Q 164.311 25.537 172.27 25.537 Q 194.194 25.537 194.194 46.875 Z M 179.057 59.619 L 179.057 54.199 Q 172.27 54.199 168.876 55.249 Q 165.483 56.299 164.36 57.983 Q 163.237 59.668 163.237 61.621 Q 163.237 64.453 164.994 65.552 Q 166.752 66.65 169.34 66.65 Q 173.832 66.65 176.127 64.355 Q 178.422 62.061 179.057 59.619 Z M 398.735 33.74 L 398.735 33.496 Q 398.735 36.67 399.882 41.821 Q 401.03 46.973 403.032 52.686 Q 405.033 58.398 407.67 63.184 L 407.914 63.184 Q 410.112 59.57 411.821 55.371 Q 413.53 51.172 414.701 46.973 Q 415.873 42.773 416.484 39.258 Q 417.094 35.742 417.094 33.545 L 417.094 33.74 Q 417.094 32.568 417.582 31.934 Q 418.705 30.566 420.219 29.15 Q 421.733 27.734 423.881 26.123 Q 424.565 25.635 425.151 25.635 Q 425.834 25.635 426.42 26.123 Q 428.617 27.734 430.131 29.15 Q 431.645 30.566 432.719 31.934 Q 433.207 32.568 433.207 33.643 L 433.207 33.74 L 433.207 33.545 L 433.207 33.643 Q 433.158 36.279 431.84 41.04 Q 430.522 45.801 428.3 51.489 Q 426.078 57.178 423.344 62.671 Q 420.61 68.164 417.778 72.217 Q 416.069 74.707 414.701 75.732 Q 413.334 76.758 409.965 76.758 L 404.789 76.758 Q 401.274 76.758 399.931 75.781 Q 398.588 74.805 396.928 72.217 Q 394.242 67.969 391.63 62.427 Q 389.018 56.885 386.894 51.196 Q 384.77 45.508 383.5 40.796 Q 382.231 36.084 382.231 33.545 L 382.231 33.496 L 382.231 33.74 L 382.231 33.545 Q 382.231 32.568 382.768 31.934 Q 385.014 29.15 389.164 26.123 Q 389.897 25.635 390.483 25.635 Q 391.117 25.635 391.801 26.123 Q 394.047 27.734 395.585 29.15 Q 397.123 30.566 398.198 31.934 Q 398.735 32.568 398.735 33.74 Z M 82.866 73.096 L 72.66 77.783 Q 71.635 78.223 71.196 78.223 Q 70.756 78.223 70.268 77.881 Q 69.145 77.1 67.704 74.048 Q 66.264 70.996 66.264 64.648 L 66.264 8.105 Q 66.264 6.934 66.752 6.299 Q 68.803 3.613 72.758 0.488 Q 73.442 0 73.979 0 Q 74.614 0 75.2 0.488 Q 77.299 2.1 78.74 3.516 Q 80.18 4.932 81.205 6.299 Q 81.694 6.934 81.694 8.105 L 81.694 61.67 Q 81.694 64.893 82.231 67.163 Q 82.768 69.434 83.5 70.801 Q 84.33 72.412 82.866 73.096 Z"/></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg width="433.211" height="78.223" viewBox="0 0 433.211 78.223" xmlns="http://www.w3.org/2000/svg"><g id="svgGroup" stroke-linecap="round" fill-rule="nonzero" font-size="9pt" stroke="#000000" stroke-width="0.5" fill="#ffffff" style="stroke:#000000;stroke-width:0.5;fill:#ffffff"><path d="M 32.817 64.795 Q 36.381 64.795 38.408 64.063 Q 40.434 63.33 41.557 62.256 Q 42.68 61.182 43.51 60.107 Q 44.291 59.131 44.804 58.643 Q 45.317 58.154 46.244 57.959 Q 47.026 57.715 48.759 57.642 Q 50.492 57.568 52.226 57.568 Q 53.959 57.568 54.643 57.666 Q 55.668 57.715 56.059 58.057 Q 56.45 58.398 56.547 59.521 Q 56.694 61.084 56.718 63.232 Q 56.742 65.381 56.645 66.943 Q 56.596 67.432 56.474 67.773 Q 56.352 68.115 55.961 68.799 Q 55.473 69.58 54.057 71.069 Q 52.641 72.559 49.907 74.146 Q 47.172 75.732 42.851 76.855 Q 38.53 77.979 32.231 77.979 Q 25.492 77.979 19.633 76.245 Q 13.774 74.512 9.355 70.41 Q 4.936 66.309 2.47 59.326 Q 0.004 52.344 0.004 41.895 Q 0.004 30.273 4.033 22.144 Q 8.061 14.014 15.483 9.766 Q 22.905 5.518 33.061 5.518 Q 40.19 5.518 44.511 6.982 Q 48.832 8.447 51.078 10.425 Q 53.325 12.402 54.252 13.867 Q 54.594 14.404 54.741 14.819 Q 54.887 15.234 54.936 16.113 Q 55.082 17.285 55.009 19.531 Q 54.936 21.777 54.643 23.486 Q 54.448 24.561 54.008 24.902 Q 53.813 25.098 53.325 25.244 Q 52.836 25.391 51.86 25.391 Q 50.297 25.391 48.344 25.269 Q 46.391 25.146 45.414 25 Q 44.242 24.805 43.705 24.438 Q 43.168 24.072 42.631 23.291 Q 41.752 22.021 39.604 20.361 Q 37.455 18.701 32.524 18.701 Q 25.59 18.701 21.098 24.048 Q 16.606 29.395 16.606 41.357 Q 16.606 53.271 21.318 59.033 Q 26.03 64.795 32.817 64.795 Z M 255.717 45.654 L 255.717 74.17 Q 255.717 75.635 255.107 76.196 Q 254.496 76.758 253.032 76.758 L 242.973 76.758 Q 241.508 76.758 240.898 76.196 Q 240.287 75.635 240.287 74.17 L 240.287 48.193 Q 240.287 42.871 238.041 40.43 Q 235.795 37.988 231.938 37.988 Q 228.08 37.988 226.005 39.648 Q 223.93 41.309 222.807 43.848 L 222.807 74.17 Q 222.807 75.635 222.197 76.196 Q 221.586 76.758 220.121 76.758 L 210.063 76.758 Q 208.598 76.758 207.988 76.196 Q 207.377 75.635 207.377 74.17 L 207.377 33.252 Q 207.377 32.08 207.866 31.445 Q 208.891 30.078 210.331 28.662 Q 211.772 27.246 213.871 25.635 Q 214.506 25.146 215.092 25.146 Q 215.629 25.146 216.313 25.635 Q 218.364 27.246 219.828 28.711 Q 221.293 30.176 222.416 31.738 L 222.66 31.738 Q 223.491 30.664 225.151 29.224 Q 226.811 27.783 229.814 26.66 Q 232.817 25.537 237.504 25.537 Q 242.094 25.537 246.244 27.393 Q 250.395 29.248 253.056 33.643 Q 255.717 38.037 255.717 45.654 Z M 373.198 45.654 L 373.198 74.17 Q 373.198 75.635 372.587 76.196 Q 371.977 76.758 370.512 76.758 L 360.453 76.758 Q 358.989 76.758 358.378 76.196 Q 357.768 75.635 357.768 74.17 L 357.768 48.193 Q 357.768 42.871 355.522 40.43 Q 353.276 37.988 349.418 37.988 Q 345.561 37.988 343.486 39.648 Q 341.41 41.309 340.287 43.848 L 340.287 74.17 Q 340.287 75.635 339.677 76.196 Q 339.067 76.758 337.602 76.758 L 327.543 76.758 Q 326.078 76.758 325.468 76.196 Q 324.858 75.635 324.858 74.17 L 324.858 33.252 Q 324.858 32.08 325.346 31.445 Q 326.371 30.078 327.812 28.662 Q 329.252 27.246 331.352 25.635 Q 331.987 25.146 332.573 25.146 Q 333.11 25.146 333.793 25.635 Q 335.844 27.246 337.309 28.711 Q 338.774 30.176 339.897 31.738 L 340.141 31.738 Q 340.971 30.664 342.631 29.224 Q 344.291 27.783 347.294 26.66 Q 350.297 25.537 354.985 25.537 Q 359.575 25.537 363.725 27.393 Q 367.875 29.248 370.536 33.643 Q 373.198 38.037 373.198 45.654 Z M 128.617 56.445 L 107.67 56.445 Q 108.061 61.475 111.357 64.111 Q 114.653 66.748 120.317 66.748 Q 124.809 66.748 127.519 65.405 Q 130.229 64.063 131.303 63.281 Q 132.231 62.598 133.403 62.646 Q 134.33 62.646 136.064 63.013 Q 137.797 63.379 139.506 64.355 Q 140.727 64.99 140.727 66.113 Q 140.727 66.748 140.483 67.92 Q 140.336 68.604 139.994 69.897 Q 139.653 71.191 139.116 72.314 Q 138.823 72.852 138.188 73.34 Q 137.211 74.023 135.038 75.146 Q 132.866 76.27 129.106 77.124 Q 125.346 77.979 119.584 77.979 Q 111.332 77.979 105.229 75.317 Q 99.125 72.656 95.756 67.041 Q 92.387 61.426 92.387 52.539 Q 92.387 39.209 99.223 32.373 Q 106.059 25.537 117.387 25.537 Q 124.76 25.537 129.863 28.174 Q 134.965 30.811 137.626 35.449 Q 140.287 40.088 140.287 46.045 Q 140.287 51.855 137.309 54.15 Q 134.33 56.445 128.617 56.445 Z M 107.573 46.436 L 123.491 46.436 Q 125.981 46.436 125.981 44.141 Q 125.981 40.674 123.808 38.306 Q 121.635 35.938 117.289 35.938 Q 112.553 35.938 110.331 38.965 Q 108.11 41.992 107.573 46.436 Z M 302.446 56.445 L 281.498 56.445 Q 281.889 61.475 285.185 64.111 Q 288.481 66.748 294.145 66.748 Q 298.637 66.748 301.347 65.405 Q 304.057 64.063 305.131 63.281 Q 306.059 62.598 307.231 62.646 Q 308.158 62.646 309.892 63.013 Q 311.625 63.379 313.334 64.355 Q 314.555 64.99 314.555 66.113 Q 314.555 66.748 314.311 67.92 Q 314.164 68.604 313.823 69.897 Q 313.481 71.191 312.944 72.314 Q 312.651 72.852 312.016 73.34 Q 311.039 74.023 308.867 75.146 Q 306.694 76.27 302.934 77.124 Q 299.174 77.979 293.412 77.979 Q 285.16 77.979 279.057 75.317 Q 272.953 72.656 269.584 67.041 Q 266.215 61.426 266.215 52.539 Q 266.215 39.209 273.051 32.373 Q 279.887 25.537 291.215 25.537 Q 298.588 25.537 303.691 28.174 Q 308.793 30.811 311.454 35.449 Q 314.116 40.088 314.116 46.045 Q 314.116 51.855 311.137 54.15 Q 308.158 56.445 302.446 56.445 Z M 281.401 46.436 L 297.319 46.436 Q 299.809 46.436 299.809 44.141 Q 299.809 40.674 297.636 38.306 Q 295.463 35.938 291.117 35.938 Q 286.381 35.938 284.159 38.965 Q 281.938 41.992 281.401 46.436 Z M 194.194 46.875 L 194.194 74.512 Q 194.194 75.439 193.681 76.099 Q 193.168 76.758 191.948 76.758 L 184.623 76.758 Q 183.842 76.758 183.232 76.538 Q 182.621 76.318 182.084 75.684 L 179.057 71.777 L 178.715 71.777 Q 176.469 75.049 172.685 76.514 Q 168.901 77.979 163.969 77.979 Q 156.791 77.979 152.568 73.95 Q 148.344 69.922 148.344 62.842 Q 148.344 59.18 149.687 56.03 Q 151.03 52.881 154.374 50.464 Q 157.719 48.047 163.749 46.582 Q 169.78 45.117 179.155 44.873 Q 179.155 40.43 176.933 38.477 Q 174.711 36.523 170.268 36.523 Q 166.264 36.523 163.725 37.891 Q 161.186 39.258 160.551 39.746 Q 159.867 40.332 158.891 40.186 Q 157.573 39.99 156.083 39.502 Q 154.594 39.014 152.885 38.379 Q 152.641 38.281 152.348 38.062 Q 152.055 37.842 152.006 37.402 Q 152.006 37.158 152.055 36.792 Q 152.104 36.426 152.299 35.449 Q 152.494 34.473 152.885 33.032 Q 153.276 31.592 153.617 30.811 Q 154.057 29.98 155.082 29.248 Q 155.912 28.564 160.112 27.051 Q 164.311 25.537 172.27 25.537 Q 194.194 25.537 194.194 46.875 Z M 179.057 59.619 L 179.057 54.199 Q 172.27 54.199 168.876 55.249 Q 165.483 56.299 164.36 57.983 Q 163.237 59.668 163.237 61.621 Q 163.237 64.453 164.994 65.552 Q 166.752 66.65 169.34 66.65 Q 173.832 66.65 176.127 64.355 Q 178.422 62.061 179.057 59.619 Z M 398.735 33.74 L 398.735 33.496 Q 398.735 36.67 399.882 41.821 Q 401.03 46.973 403.032 52.686 Q 405.033 58.398 407.67 63.184 L 407.914 63.184 Q 410.112 59.57 411.821 55.371 Q 413.53 51.172 414.701 46.973 Q 415.873 42.773 416.484 39.258 Q 417.094 35.742 417.094 33.545 L 417.094 33.74 Q 417.094 32.568 417.582 31.934 Q 418.705 30.566 420.219 29.15 Q 421.733 27.734 423.881 26.123 Q 424.565 25.635 425.151 25.635 Q 425.834 25.635 426.42 26.123 Q 428.617 27.734 430.131 29.15 Q 431.645 30.566 432.719 31.934 Q 433.207 32.568 433.207 33.643 L 433.207 33.74 L 433.207 33.545 L 433.207 33.643 Q 433.158 36.279 431.84 41.04 Q 430.522 45.801 428.3 51.489 Q 426.078 57.178 423.344 62.671 Q 420.61 68.164 417.778 72.217 Q 416.069 74.707 414.701 75.732 Q 413.334 76.758 409.965 76.758 L 404.789 76.758 Q 401.274 76.758 399.931 75.781 Q 398.588 74.805 396.928 72.217 Q 394.242 67.969 391.63 62.427 Q 389.018 56.885 386.894 51.196 Q 384.77 45.508 383.5 40.796 Q 382.231 36.084 382.231 33.545 L 382.231 33.496 L 382.231 33.74 L 382.231 33.545 Q 382.231 32.568 382.768 31.934 Q 385.014 29.15 389.164 26.123 Q 389.897 25.635 390.483 25.635 Q 391.117 25.635 391.801 26.123 Q 394.047 27.734 395.585 29.15 Q 397.123 30.566 398.198 31.934 Q 398.735 32.568 398.735 33.74 Z M 82.866 73.096 L 72.66 77.783 Q 71.635 78.223 71.196 78.223 Q 70.756 78.223 70.268 77.881 Q 69.145 77.1 67.704 74.048 Q 66.264 70.996 66.264 64.648 L 66.264 8.105 Q 66.264 6.934 66.752 6.299 Q 68.803 3.613 72.758 0.488 Q 73.442 0 73.979 0 Q 74.614 0 75.2 0.488 Q 77.299 2.1 78.74 3.516 Q 80.18 4.932 81.205 6.299 Q 81.694 6.934 81.694 8.105 L 81.694 61.67 Q 81.694 64.893 82.231 67.163 Q 82.768 69.434 83.5 70.801 Q 84.33 72.412 82.866 73.096 Z"/></g></svg>
|