Skip to content

Commit 2316513

Browse files
committed
Lint with eslint
1 parent 9c2cd82 commit 2316513

File tree

13 files changed

+7672
-555
lines changed

13 files changed

+7672
-555
lines changed

.github/workflows/build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ jobs:
2525
run: |
2626
npm ci
2727
28+
- name: Analyze the code
29+
run: |
30+
npm run lint
31+
2832
- name: Check source code formatting
2933
run: |
3034
npm run format

app.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import cors from 'cors';
22
import express from 'express';
33
import createError from 'http-errors';
44
import log4js from 'log4js';
5-
import { join as joinPath } from 'path';
5+
import { join as joinPath } from 'node:path';
66

7-
import { root } from './config.js';
87
import router from './app/routes.js';
8+
import { root } from './config.js';
99

1010
export function createApplication(config, db) {
1111
const app = express();
@@ -33,10 +33,11 @@ export function createApplication(config, db) {
3333
// Allow cross origin requests (if enabled).
3434
if (config.cors) {
3535
const corsOptions = {};
36-
if (config.corsOrigins.length) {
36+
if (config.corsOrigins.length !== 0) {
3737
corsOptions.origin = config.corsOrigins;
3838
}
3939

40+
// eslint-disable-next-line sonarjs/cors
4041
app.use(cors(corsOptions));
4142
}
4243

@@ -52,7 +53,13 @@ export function createApplication(config, db) {
5253
});
5354

5455
// Global error handler
55-
app.use((err, req, res, next) => {
56+
app.use(createGlobalErrorHandler(config, logger));
57+
58+
return app;
59+
}
60+
61+
function createGlobalErrorHandler(config, logger) {
62+
return (err, req, res, _next) => {
5663
logger.warn(err);
5764

5865
// Set locals, only providing error in development.
@@ -63,9 +70,7 @@ export function createApplication(config, db) {
6370
// Render the error page.
6471
res.status(err.status || 500);
6572
res.render('error');
66-
});
67-
68-
return app;
73+
};
6974
}
7075

7176
function provideDefaultLocals(config) {

app/express.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export function route(func) {
2-
return (req, res, next) => {
3-
return Promise.resolve()
2+
return (req, res, next) =>
3+
Promise.resolve()
44
.then(() => func(req, res, next))
55
.catch(next);
6-
};
76
}

app/share/share.middlewares.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { createComment, getComments } from '../../db.js';
22
import { route } from '../express.js';
33
import { getValidationErrors } from '../validation.js';
44

5-
export const sharePage = route(async (req, res) => {
5+
export const sharePage = route((req, res) => {
66
res.render('share/share', {
77
pageTitle: 'Share your experience'
88
});
@@ -11,7 +11,8 @@ export const sharePage = route(async (req, res) => {
1111
export const share = route(async (req, res) => {
1212
const errors = getValidationErrors(req.body, 'comment');
1313
if (errors) {
14-
return res.redirect('/');
14+
res.redirect('/');
15+
return;
1516
}
1617

1718
const { name, text } = req.body;
@@ -31,8 +32,11 @@ export const listComments = route(async (req, res) => {
3132

3233
res.send(
3334
comments
34-
.sort((a, b) => b.date.valueOf() - a.date.valueOf())
35-
.map(commentToJson)
35+
.sort(
36+
(firstComment, secondComment) =>
37+
secondComment.date.valueOf() - firstComment.date.valueOf()
38+
)
39+
.map(comment => commentToJson(comment))
3640
);
3741
});
3842

app/validation.js

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Ajv from 'ajv';
22
import ajvErrors from 'ajv-errors';
33
import glob from 'fast-glob';
4-
import { readFile } from 'fs/promises';
5-
import { basename, join as joinPath } from 'path';
4+
import { readFile } from 'node:fs/promises';
5+
import { basename, join as joinPath } from 'node:path';
66

77
import { root } from '../config.js';
88

@@ -14,18 +14,24 @@ ajvErrors(ajv);
1414

1515
export async function loadSchemas(config) {
1616
const logger = config.createLogger('validation');
17-
for (const file of await findSchemas(logger)) {
18-
const { name, schema } = await loadSchema(file);
19-
ajv.addSchema(schema, name);
20-
logger.trace(`Loaded "${name}" JSON schema from ${file}`);
21-
}
17+
18+
const files = await findSchemas(logger);
19+
await Promise.all(
20+
files.map(async file => {
21+
const { name, schema } = await loadSchema(file);
22+
ajv.addSchema(schema, name);
23+
logger.trace(`Loaded "${name}" JSON schema from ${file}`);
24+
})
25+
);
2226
}
2327

2428
export function getValidationErrors(data, schemaName) {
2529
const validate = getSchema(schemaName);
2630
if (!validate(data)) {
2731
return validate.errors;
2832
}
33+
34+
return undefined;
2935
}
3036

3137
async function findSchemas(logger) {
@@ -50,7 +56,7 @@ function getSchema(name) {
5056
}
5157

5258
async function loadSchema(file) {
53-
const schemaName = basename(file).replace(/\..*$/, '');
59+
const schemaName = basename(file).replace(/\.schema\.json$/u, '');
5460
if (ajv.getSchema(schemaName)) {
5561
throw new Error(
5662
`JSON schema ${schemaName} (from file ${file}) has already been defined`

bin.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ import chalk from 'chalk';
33

44
import start from './start.js';
55

6-
Promise.resolve()
7-
.then(start)
8-
.catch(err => {
9-
console.error(chalk.red(err.stack));
10-
process.exit(1);
11-
});
6+
try {
7+
await start();
8+
} catch (err) {
9+
// eslint-disable-next-line no-console
10+
console.error(chalk.red(err.stack));
11+
process.exit(1);
12+
}

config.js

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,45 @@
11
import { identity, isInteger } from 'lodash-es';
22
import log4js from 'log4js';
3-
import { dirname, resolve as resolvePath } from 'path';
4-
import { fileURLToPath } from 'url';
3+
import { dirname, resolve as resolvePath } from 'node:path';
4+
import { fileURLToPath } from 'node:url';
55

66
const logLevels = ['FATAL', 'ERROR', 'WARN', 'INFO', 'DEBUG', 'TRACE'];
77

88
export const root = dirname(fileURLToPath(import.meta.url));
99

10+
// eslint-disable-next-line max-lines-per-function
1011
export async function loadConfig() {
1112
await loadDotenv();
1213

13-
const env = process.env.NODE_ENV ?? 'development';
14+
const environment = process.env.NODE_ENV ?? 'development';
1415

1516
const dbFile = resolvePath(
1617
root,
17-
parseEnvString('REVPROD_DB_FILE', 'db.json')
18+
parseEnvironmentString('REVPROD_DB_FILE', 'db.json')
1819
);
1920

20-
const host = parseEnvString('REVPROD_LISTEN_HOST', '0.0.0.0');
21-
const port = parseEnvPort('REVPROD_LISTEN_PORT', 3000);
21+
const host = parseEnvironmentString('REVPROD_LISTEN_HOST', '0.0.0.0');
22+
const port = parseEnvironmentPort('REVPROD_LISTEN_PORT', 3000);
2223

23-
const logLevel = parseEnvEnum(
24+
const logLevel = parseEnvironmentEnum(
2425
'REVPROD_LOG_LEVEL',
2526
logLevels,
26-
env === 'production' ? 'DEBUG' : 'TRACE',
27+
environment === 'production' ? 'DEBUG' : 'TRACE',
2728
value => value.toUpperCase()
2829
);
2930

30-
const cors = parseEnvBoolean('REVPROD_CORS', false);
31-
const corsOrigins = parseEnvString('REVPROD_CORS_ORIGINS', [], origins =>
32-
origins.split(',')
31+
const cors = parseEnvironmentBoolean('REVPROD_CORS', false);
32+
const corsOrigins = parseEnvironmentString(
33+
'REVPROD_CORS_ORIGINS',
34+
[],
35+
origins => origins.split(',')
3336
);
3437

35-
const title = parseEnvString('REVPROD_TITLE', 'The Revolutionary Product');
36-
const landingPageBaseUrl = parseEnvString(
38+
const title = parseEnvironmentString(
39+
'REVPROD_TITLE',
40+
'The Revolutionary Product'
41+
);
42+
const landingPageBaseUrl = parseEnvironmentString(
3743
'REVPROD_LANDING_PAGE_BASE_URL',
3844
''
3945
);
@@ -45,20 +51,20 @@ export async function loadConfig() {
4551
}
4652

4753
const logger = createLogger('config');
48-
logger.info(`Environment: ${env}`);
54+
logger.info(`Environment: ${environment}`);
4955
logger.info(`Log level: ${logLevel}`);
5056
logger.info(`CORS enabled: ${cors}`);
5157
logger.info(
5258
`CORS allowed origins: ${
53-
corsOrigins.length ? corsOrigins.join(', ') : 'all'
59+
corsOrigins.length === 0 ? 'all' : corsOrigins.join(', ')
5460
}`
5561
);
5662

5763
return {
5864
// Paths
5965
dbFile,
6066
// Environment,
61-
env,
67+
env: environment,
6268
// Server
6369
host,
6470
port,
@@ -77,7 +83,7 @@ async function loadDotenv() {
7783
let dotenv;
7884
try {
7985
dotenv = await import('dotenv');
80-
} catch (err) {
86+
} catch {
8187
// Ignore
8288
}
8389

@@ -86,40 +92,45 @@ async function loadDotenv() {
8692
}
8793
}
8894

89-
function getEnvString(varName, required = true) {
90-
const value = process.env[varName];
95+
function getEnvironmentString(variableName, required = true) {
96+
const value = process.env[variableName];
9197
if (required && value === undefined) {
92-
throw new Error(`$${varName} is required`);
98+
throw new Error(`$${variableName} is required`);
9399
}
94100

95101
return value;
96102
}
97103

98-
function parseEnvBoolean(varName, defaultValue) {
99-
const value = getEnvString(varName, defaultValue === undefined);
104+
function parseEnvironmentBoolean(variableName, defaultValue) {
105+
const value = getEnvironmentString(variableName, defaultValue === undefined);
100106
if (value === undefined) {
101107
return defaultValue;
102-
} else if (value.match(/^(?:1|y|yes|t|true)$/u)) {
108+
} else if (/^(?:1|y|yes|t|true)$/u.text(value)) {
103109
return true;
104-
} else if (value.match(/^(?:0|n|no|f|false)$/u)) {
110+
} else if (/^(?:0|n|no|f|false)$/u.test(value)) {
105111
return false;
106-
} else {
107-
throw new Error(
108-
`$${varName} must be a boolean, but its value is ${JSON.stringify(value)}`
109-
);
110112
}
113+
114+
throw new Error(
115+
`$${variableName} must be a boolean, but its value is ${JSON.stringify(value)}`
116+
);
111117
}
112118

113-
function parseEnvEnum(varName, allowedValues, defaultValue, coerce = identity) {
114-
const value = getEnvString(varName, defaultValue === undefined);
119+
function parseEnvironmentEnum(
120+
variableName,
121+
allowedValues,
122+
defaultValue,
123+
coerce = identity
124+
) {
125+
const value = getEnvironmentString(variableName, defaultValue === undefined);
115126
if (value === undefined) {
116127
return defaultValue;
117128
}
118129

119130
const coerced = coerce(value);
120131
if (!allowedValues.includes(coerced)) {
121132
throw new Error(
122-
`$${varName} must be one of ${allowedValues
133+
`$${variableName} must be one of ${allowedValues
123134
.map(allowed => JSON.stringify(allowed))
124135
.join(', ')}, but its value is ${JSON.stringify(coerced)}`
125136
);
@@ -128,20 +139,20 @@ function parseEnvEnum(varName, allowedValues, defaultValue, coerce = identity) {
128139
return coerced;
129140
}
130141

131-
function parseEnvInt(varName, defaultValue, min, max) {
132-
const value = getEnvString(varName, defaultValue === undefined);
142+
function parseEnvironmentInt(variableName, defaultValue, min, max) {
143+
const value = getEnvironmentString(variableName, defaultValue === undefined);
133144
if (value === undefined) {
134145
return defaultValue;
135146
}
136147

137-
const parsed = parseInt(value, 10);
148+
const parsed = Number.parseInt(value, 10);
138149
if (
139150
!isInteger(parsed) ||
140151
(min !== undefined && value < min) ||
141152
(max !== undefined && value > max)
142153
) {
143154
throw new Error(
144-
`$${varName} must be an integer between ${min ?? '-Infinity'} and ${
155+
`$${variableName} must be an integer between ${min ?? '-Infinity'} and ${
145156
max ?? 'Infinity'
146157
}, but its value is ${JSON.stringify(value)}`
147158
);
@@ -150,12 +161,12 @@ function parseEnvInt(varName, defaultValue, min, max) {
150161
return parsed;
151162
}
152163

153-
function parseEnvPort(varName, defaultValue) {
154-
return parseEnvInt(varName, defaultValue, 1, 65_535);
164+
function parseEnvironmentPort(variableName, defaultValue) {
165+
return parseEnvironmentInt(variableName, defaultValue, 1, 65_535);
155166
}
156167

157-
function parseEnvString(varName, defaultValue, coerce = identity) {
158-
const value = getEnvString(varName, defaultValue === undefined);
168+
function parseEnvironmentString(variableName, defaultValue, coerce = identity) {
169+
const value = getEnvironmentString(variableName, defaultValue === undefined);
159170
if (value === undefined) {
160171
return defaultValue;
161172
}

0 commit comments

Comments
 (0)