Compare commits

..

No commits in common. "9a4f621f6987b76aa8ad5e0d093372718ecdf925" and "40e99a9f9cdbd2f990bdb67e4a92dc4464cbfedf" have entirely different histories.

16 changed files with 83 additions and 114 deletions

4
app.js
View File

@ -52,12 +52,12 @@ const limiter = rateLimit({
logger.logger.info(`Starting version ${version.app} in ${mode} mode`); logger.logger.info(`Starting version ${version.app} in ${mode} mode`);
// Remove X-Powered-By header: // Remove X-Powered-By header:
app.disable("x-powered-by"); app.disable('x-powered-by');
// Express Error Handling: // Express Error Handling:
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
const statusCode = err.statuscode || 500; const statusCode = err.statuscode || 500;
logger.logger.error(err, "Express Error"); logger.logger.error(err, "Express Error")
res.status(statusCode).json({ message: err.message }); res.status(statusCode).json({ message: err.message });
return; return;
}); });

View File

@ -54,8 +54,7 @@
<h1>Register for OwlBoard</h1> <h1>Register for OwlBoard</h1>
<br /> <br />
<p> <p>
Tap the button to register this device, or scan the barcode with Tap the button to register this device, or scan the barcode with another device.
another device.
</p> </p>
<br /> <br />
<a <a

View File

@ -13,8 +13,7 @@
"build": "tsc", "build": "tsc",
"run": "tsc && node dist/app.js", "run": "tsc && node dist/app.js",
"start": "node app.js", "start": "node app.js",
"test": "jest", "test": "jest"
"format": "npx prettier -w ."
}, },
"dependencies": { "dependencies": {
"axios": "^1.2.1", "axios": "^1.2.1",

View File

@ -14,18 +14,12 @@ export const statusCodes = {
951: "unknown server error", 951: "unknown server error",
}; };
export const msgCodes = new Map<string, string>([ export const msgCodes = new Map <string, string>([
[ ["LOC_NOT_FOUND", "Location not found. If you are sure that the location exists, there may be a fault with the data provider."],
"LOC_NOT_FOUND", ["USR_NOT_FOUND", "User is not registered, consider regeristering for access to this resource"],
"Location not found. If you are sure that the location exists, there may be a fault with the data provider.",
],
[
"USR_NOT_FOUND",
"User is not registered, consider regeristering for access to this resource",
],
["AUTH_ERR", "Authentication Error"], ["AUTH_ERR", "Authentication Error"],
["OK", "OK"], ["OK", "OK"]
]); ])
module.exports = statusCodes; module.exports = statusCodes;
//export { statusCodes }; //export { statusCodes };

View File

@ -3,11 +3,11 @@ const logger = require("../utils/logger.utils");
module.exports = async function authCheck(req, res, next) { module.exports = async function authCheck(req, res, next) {
//log.out("authMiddlewares: Checking authentication", "dbug"); //log.out("authMiddlewares: Checking authentication", "dbug");
logger.logger.debug("Auth check starting"); logger.logger.debug("Auth check starting")
try { try {
var uuid = req.headers.uuid; var uuid = req.headers.uuid;
} catch (err) { } catch (err) {
logger.logger.warn("Unable to read UUID header - Not authenticated"); logger.logger.warn("Unable to read UUID header - Not authenticated")
req.isAuthed = false; req.isAuthed = false;
return next(); return next();
} }
@ -16,11 +16,11 @@ module.exports = async function authCheck(req, res, next) {
if (!result) { if (!result) {
req.isAuthed = false; req.isAuthed = false;
//log.out("authMiddlewares: User !isAuthed", "dbug"); //log.out("authMiddlewares: User !isAuthed", "dbug");
logger.logger.debug("Auth denied"); logger.logger.debug("Auth denied")
} else { } else {
req.isAuthed = true; req.isAuthed = true;
//log.out("authMiddlewares: User isAuthed", "dbug"); //log.out("authMiddlewares: User isAuthed", "dbug");
logger.logger.debug("Auth successful"); logger.logger.debug("Auth successful")
} }
return next(); return next();
} catch (err) { } catch (err) {
@ -28,7 +28,7 @@ module.exports = async function authCheck(req, res, next) {
"authMiddlewares: Unable to check auth, default to !isAuthed", "authMiddlewares: Unable to check auth, default to !isAuthed",
"warn" "warn"
);*/ );*/
logger.logger.error(err, `Auth check failed`); logger.logger.error(err, `Auth check failed`)
req.isAuthed = false; req.isAuthed = false;
return next(err); return next(err);
} }

View File

@ -16,15 +16,13 @@ const db = client.db(dbName);
async function query(collection, query, returnId = false) { async function query(collection, query, returnId = false) {
await client.connect(); await client.connect();
logger.logger.trace( logger.logger.trace(`dbAccess.query: Connecting to collection: '${collection}'`)
`dbAccess.query: Connecting to collection: '${collection}'`
);
var qcoll = db.collection(collection); var qcoll = db.collection(collection);
var qcursor = qcoll.find(query); var qcursor = qcoll.find(query);
if (!returnId) { if (!returnId) {
qcursor.project({ _id: 0 }); qcursor.project({ _id: 0 });
} }
logger.logger.trace(query, "dbAccess.query: Runnung Query"); logger.logger.trace(query, "dbAccess.query: Runnung Query")
increment(collection); increment(collection);
let result = await qcursor.toArray(); let result = await qcursor.toArray();
logger.logger.trace(result, "dbAccess.query: Response"); logger.logger.trace(result, "dbAccess.query: Response");
@ -58,9 +56,7 @@ async function queryAggregate(collection, pipeline) {
} }
async function increment(target) { async function increment(target) {
logger.logger.debug( logger.logger.debug(`dbAccess.increment: Incrementing counter for: ${target}`)
`dbAccess.increment: Incrementing counter for: ${target}`
);
await client.connect(); await client.connect();
let col = db.collection("meta"); let col = db.collection("meta");
let update = {}; let update = {};

View File

@ -18,7 +18,7 @@ async function get(id, staff = false) {
const obj = await util.checkCrs(cleanId); const obj = await util.checkCrs(cleanId);
try { try {
const crs = obj[0]["3ALPHA"]; const crs = obj[0]["3ALPHA"];
logger.debug(`ldbService.get: Determined CRS for lookup to be: ${crs}`); logger.debug(`ldbService.get: Determined CRS for lookup to be: ${crs}`)
if (staff) { if (staff) {
const data = arrDepBoardStaff(crs); const data = arrDepBoardStaff(crs);
db.increment("ldbsvws"); db.increment("ldbsvws");
@ -29,7 +29,7 @@ async function get(id, staff = false) {
return await data; return await data;
} }
} catch (err) { } catch (err) {
logger.error(err, "ldbService.get: Error, Unable to find CRS"); logger.error(err, "ldbService.get: Error, Unable to find CRS")
return { return {
obStatus: "LOC_NOT_FOUND", obStatus: "LOC_NOT_FOUND",
obMsg: "UNABLE TO FIND MESSAGE", obMsg: "UNABLE TO FIND MESSAGE",
@ -38,7 +38,7 @@ async function get(id, staff = false) {
} }
async function arrDepBoard(CRS) { async function arrDepBoard(CRS) {
logger.trace(`ldbService.arrDepBoard: Trying to fetch board for ${CRS}`); logger.trace(`ldbService.arrDepBoard: Trying to fetch board for ${CRS}`)
try { try {
const options = { const options = {
numRows: 10, numRows: 10,
@ -48,7 +48,7 @@ async function arrDepBoard(CRS) {
let d = await api.call("GetArrDepBoardWithDetails", options, false, false); let d = await api.call("GetArrDepBoardWithDetails", options, false, false);
return await util.cleanData(d); return await util.cleanData(d);
} catch (err) { } catch (err) {
logger.error(err, "ldbService.arrDepBoard: Lookup Failed"); logger.error(err, "ldbService.arrDepBoard: Lookup Failed")
return { return {
GetStationBoardResult: "not available", GetStationBoardResult: "not available",
Reason: `The CRS code ${CRS} is not valid`, Reason: `The CRS code ${CRS} is not valid`,
@ -57,7 +57,7 @@ async function arrDepBoard(CRS) {
} }
async function arrDepBoardStaff(CRS) { async function arrDepBoardStaff(CRS) {
logger.debug(`ldbService.arrDepBoardStaff: Try to fetch board for ${CRS}`); logger.debug(`ldbService.arrDepBoardStaff: Try to fetch board for ${CRS}`)
try { try {
const options = { const options = {
numRows: 40, numRows: 40,
@ -75,24 +75,24 @@ async function arrDepBoardStaff(CRS) {
false, false,
false false
); );
console.log("\n\n\nORIGINAL DATA"); console.log("\n\n\nORIGINAL DATA")
console.log("\n" + JSON.stringify(result) + "\n\n\n"); console.log("\n" + JSON.stringify(result) + "\n\n\n")
console.timeEnd(`Fetch Staff LDB for ${CRS.toUpperCase()}`); console.timeEnd(`Fetch Staff LDB for ${CRS.toUpperCase()}`);
try { try {
const _staffLdb = staffStationTransform(result); const _staffLdb = staffStationTransform(result);
logger.debug("StaffLDB Transformed"); logger.debug("StaffLDB Transformed")
logger.trace(_staffLdb, "StaffLDB Transformed"); logger.trace(_staffLdb, "StaffLDB Transformed")
return { return {
obStatus: "OK", obStatus: "OK",
obMsg: "OK", obMsg: "OK",
data: _staffLdb, data: _staffLdb,
}; };
} catch (err) { } catch (err) {
logger.error(err, "Transformation Error"); logger.error(err, "Transformation Error")
} }
return result; return result;
} catch (err) { } catch (err) {
logger.error(err, "ldbService.arrDepBoardStaff error"); logger.error(err, "ldbService.arrDepBoardStaff error")
return { return {
GetStationBoardResult: "not available", GetStationBoardResult: "not available",
Reason: `The CRS code ${CRS} is not valid`, Reason: `The CRS code ${CRS} is not valid`,
@ -123,18 +123,18 @@ async function getServicesByOther(id) {
const api = new ldb(ldbsvKey, true); const api = new ldb(ldbsvKey, true);
return await api.call("QueryServices", options, false, false); return await api.call("QueryServices", options, false, false);
} catch (err) { } catch (err) {
logger.error(err, "ldbService.getServiceByOther"); logger.error(err, "ldbService.getServiceByOther")
return false; return false;
} }
} }
async function getReasonCodeList() { async function getReasonCodeList() {
logger.debug("ldbService.getReasonCodeList: Fetching reason code list"); logger.debug("ldbService.getReasonCodeList: Fetching reason code list")
try { try {
const dbFilter = {}; const dbFilter = {};
return await db.query("reasonCodes", dbFilter, false); return await db.query("reasonCodes", dbFilter, false);
} catch (err) { } catch (err) {
logger.error(err, "ldbService.getReasonCodeList"); logger.error(err, "ldbService.getReasonCodeList")
} }
} }
@ -146,7 +146,7 @@ async function getReasonCode(code) {
}; };
return await db.query("reasonCodes", dbFilter, false); return await db.query("reasonCodes", dbFilter, false);
} catch (err) { } catch (err) {
logger.error(err, "ldbService.getReasonCode"); logger.error(err, "ldbService.getReasonCode")
} }
} }

View File

@ -9,22 +9,21 @@ import { logger } from "./logger.utils";
async function isAuthed(uuid: string): Promise<boolean> { async function isAuthed(uuid: string): Promise<boolean> {
// Needs testing // Needs testing
const q = { const q = {
uuid: uuid, uuid: uuid
}; };
const res = await db.query("users", q); const res = await db.query("users", q);
logger.debug(res, "checkUser: DB Query Result"); logger.debug(res, "checkUser: DB Query Result")
const authorized = res && res[0] && res[0].domain; const authorized = res && res[0] && res[0].domain;
if (authorized) db.userAtime(uuid); if (authorized) db.userAtime(uuid);
return authorized; return authorized;
} }
// Checks whether a registration request key is valid // Checks whether a registration request key is valid
async function checkRequest(key: string) { async function checkRequest(key: string) { // For some reason db.query seems to return correctly, but the second logs.out statement prints []??? so registration fails!!
// For some reason db.query seems to return correctly, but the second logs.out statement prints []??? so registration fails!!
const collection = "registrations"; const collection = "registrations";
const query = { uuid: key }; const query = { uuid: key };
const res = await db.query(collection, query); const res = await db.query(collection, query);
logger.debug(res, "checkRequest: DB Lookup result"); logger.debug(res, "checkRequest: DB Lookup result")
const result = const result =
res.length > 0 && res[0].time res.length > 0 && res[0].time
? { result: true, domain: res[0].domain } ? { result: true, domain: res[0].domain }
@ -51,10 +50,7 @@ async function generateConfirmationEmail(eml: string, uuid: string) {
html: htmlMin, html: htmlMin,
}; };
} catch (err) { } catch (err) {
logger.error( logger.error(err, "generateConfirmationEmail: Error rendering email templates")
err,
"generateConfirmationEmail: Error rendering email templates"
);
return false; return false;
} }
} }

View File

@ -1,19 +1,19 @@
import pino from "pino"; import pino from "pino";
const runtime = process.env.NODE_ENV; const runtime = process.env.NODE_ENV
let level: string; let level: string
if (runtime === "production") { if (runtime === "production") {
level = "info"; level = "info"
} else { } else {
level = "debug"; level = "debug"
} }
export const logger = pino({ export const logger = pino({
level: level, level: level,
formatters: { formatters: {
level: (label) => { level: (label) => {
return { level: label.toUpperCase() }; return { level: label.toUpperCase()}
}
}, },
}, timestamp: pino.stdTimeFunctions.isoTime,
timestamp: pino.stdTimeFunctions.isoTime, });
});

View File

@ -5,7 +5,7 @@ const juice = require("juice");
// Inlines styles and minifies the inlined HTML // Inlines styles and minifies the inlined HTML
async function minifyMail(input: string): Promise<string> { async function minifyMail(input: string): Promise<string> {
logger.trace("minifyMail: Minifying mail output"); logger.trace("minifyMail: Minifying mail output")
const inlined: string = juice(input); const inlined: string = juice(input);
return htmlShrink(inlined, { return htmlShrink(inlined, {
removeComments: true, removeComments: true,

View File

@ -1,7 +1,7 @@
import { logger } from "./logger.utils"; import { logger } from "./logger.utils";
export function removeNewlineAndPTag(input: string): string { export function removeNewlineAndPTag(input: string): string {
logger.debug("removeNewlineAndPTag: Cleaning string"); logger.debug("removeNewlineAndPTag: Cleaning string")
const regex = /[\n\r]|<\/?p[^>]*>/g; const regex = /[\n\r]|<\/?p[^>]*>/g;
return input.replace(regex, function (match) { return input.replace(regex, function (match) {
if (match === "\n" || match === "\r") { if (match === "\n" || match === "\r") {

View File

@ -3,17 +3,17 @@
import { logger } from "./logger.utils"; import { logger } from "./logger.utils";
function removeNonAlphanumeric(inputString: string) { function removeNonAlphanumeric(inputString: string) {
logger.debug("removeNonAlphanumeric: Sanitizing string"); logger.debug("removeNonAlphanumeric: Sanitizing string")
return inputString.replace(/[^a-zA-Z0-9]/g, ""); return inputString.replace(/[^a-zA-Z0-9]/g, "");
} }
function removeNonAlpha(inputString: string) { function removeNonAlpha(inputString: string) {
logger.debug("removeNonAlpha: Sanitizing string"); logger.debug("removeNonAlpha: Sanitizing string")
return inputString.replace(/[^a-zA-Z]/g, ""); return inputString.replace(/[^a-zA-Z]/g, "");
} }
function removeNonNumeric(inputString: string) { function removeNonNumeric(inputString: string) {
logger.debug("removeNonNumeric: Sanitizing string"); logger.debug("removeNonNumeric: Sanitizing string")
return inputString.replace(/[^0-9]/g, ""); return inputString.replace(/[^0-9]/g, "");
} }
@ -21,14 +21,14 @@ const cleanApiEndpointTxt = removeNonAlpha;
const cleanApiEndpointNum = removeNonAlphanumeric; const cleanApiEndpointNum = removeNonAlphanumeric;
function cleanNrcc(input: string) { function cleanNrcc(input: string) {
logger.error("DEPRECATED FUNCTION", "cleanNrcc: Converting NRCC Data"); logger.error("DEPRECATED FUNCTION","cleanNrcc: Converting NRCC Data")
// Remove newlines and then <p> tags from input // Remove newlines and then <p> tags from input
const cleanInput = input.replace(/[\n\r]/g, "").replace(/<\/?p[^>]*>/g, ""); const cleanInput = input.replace(/[\n\r]/g, "").replace(/<\/?p[^>]*>/g, "");
return cleanInput; return cleanInput;
} }
function getDomainFromEmail(mail: string) { function getDomainFromEmail(mail: string) {
logger.debug("getDomainFromEmail: Obtaining domain from email address"); logger.debug("getDomainFromEmail: Obtaining domain from email address")
// Needs testing // Needs testing
let split = mail.split("@"); let split = mail.split("@");
return split[1].toLowerCase(); return split[1].toLowerCase();

View File

@ -1,18 +1,18 @@
import { logger } from "./logger.utils"; import { logger } from "./logger.utils";
function unixLocal(unix: number): string { function unixLocal(unix: number): string {
logger.trace(`unixLocal: Converting time: ${unix}`); logger.trace(`unixLocal: Converting time: ${unix}`)
var jsTime = unix * 1000; var jsTime = unix * 1000;
var dt = new Date(jsTime); var dt = new Date(jsTime);
return dt.toLocaleString(); return dt.toLocaleString();
} }
function jsUnix(js: number): number { function jsUnix(js: number): number {
logger.trace(`jsUnix: Converting time: ${js}`); logger.trace(`jsUnix: Converting time: ${js}`)
return Math.floor(js / 1000); return Math.floor(js / 1000);
} }
export { jsUnix, unixLocal }; export { jsUnix, unixLocal }
module.exports = { module.exports = {
unixLocal, unixLocal,

View File

@ -16,7 +16,7 @@ export function transform(input: any): StaffLdb | null {
try { try {
output = { output = {
generatedAt: transformDateTime(data?.generatedAt) || new Date(), generatedAt: transformDateTime(data?.generatedAt) || new Date(),
locationName: data?.locationName || "Not Found", locationName: data?.locationName || 'Not Found',
stationManagerCode: data?.stationManagerCode || "UK", stationManagerCode: data?.stationManagerCode || "UK",
nrccMessages: transformNrcc(data?.nrccMessages) || undefined, nrccMessages: transformNrcc(data?.nrccMessages) || undefined,
trainServices: transformTrainServices(data?.trainServices) || undefined, trainServices: transformTrainServices(data?.trainServices) || undefined,
@ -24,7 +24,7 @@ export function transform(input: any): StaffLdb | null {
ferryServices: transformTrainServices(data?.ferryServices) || undefined, ferryServices: transformTrainServices(data?.ferryServices) || undefined,
}; };
console.timeEnd("StaffLdb Transformation"); console.timeEnd("StaffLdb Transformation");
if (output.locationName !== "Not Found") { if (output.locationName !== 'Not Found') {
return output; return output;
} }
} catch (err) { } catch (err) {
@ -43,7 +43,7 @@ function transformDateTime(input: string): Date {
function transformNrcc(input: any): NrccMessage[] | undefined { function transformNrcc(input: any): NrccMessage[] | undefined {
//console.log("Transform Nrcc Running") //console.log("Transform Nrcc Running")
if (input === undefined) { if (input === undefined) {
return input; return input
} }
let output: NrccMessage[] = []; let output: NrccMessage[] = [];
let messages = input; let messages = input;
@ -74,7 +74,7 @@ function transformTrainServices(input: any): TrainServices[] {
services = [input.service]; services = [input.service];
} }
for (const service of services) { for (const service of services) {
const times = parseTimes(service); const times = parseTimes(service)
const trainService: TrainServices = { const trainService: TrainServices = {
rid: service?.rid, rid: service?.rid,
uid: service?.uid, uid: service?.uid,
@ -157,12 +157,9 @@ function transformUnspecifiedDateTime(input: string): Date | undefined {
} }
function parseTimes(service: TrainServices) { function parseTimes(service: TrainServices) {
let { sta, eta, ata, std, etd, atd } = Object.fromEntries( let {sta, eta, ata, std, etd, atd} = Object.fromEntries(
Object.entries(service).map(([key, value]) => [ Object.entries(service).map(([key, value]) => [key, transformUnspecifiedDateTime(value)])
key, )
transformUnspecifiedDateTime(value),
])
);
let etaResult: Date | undefined | string = eta; let etaResult: Date | undefined | string = eta;
let ataResult: Date | undefined | string = ata; let ataResult: Date | undefined | string = ata;
@ -170,31 +167,19 @@ function parseTimes(service: TrainServices) {
let atdResult: Date | undefined | string = atd; let atdResult: Date | undefined | string = atd;
if (sta) { if (sta) {
if ( if (eta !== undefined && Math.abs(eta.getTime() - sta.getTime()) / 60000 <= 1.5) {
eta !== undefined &&
Math.abs(eta.getTime() - sta.getTime()) / 60000 <= 1.5
) {
etaResult = "RT"; etaResult = "RT";
} }
if ( if (ata !== undefined && Math.abs(ata.getTime() - sta.getTime()) / 60000 <= 1.5) {
ata !== undefined &&
Math.abs(ata.getTime() - sta.getTime()) / 60000 <= 1.5
) {
ataResult = "RT"; ataResult = "RT";
} }
} }
if (std) { if (std) {
if ( if (etd !== undefined && Math.abs(etd.getTime() - std.getTime()) / 60000 <= 1.5) {
etd !== undefined &&
Math.abs(etd.getTime() - std.getTime()) / 60000 <= 1.5
) {
etdResult = "RT"; etdResult = "RT";
} }
if ( if (atd !== undefined && Math.abs(atd.getTime() - std.getTime()) / 60000 <= 1.5) {
atd !== undefined &&
Math.abs(atd.getTime() - std.getTime()) / 60000 <= 1.5
) {
atdResult = "RT"; atdResult = "RT";
} }
} }
@ -206,5 +191,5 @@ function parseTimes(service: TrainServices) {
std: std, std: std,
etd: etdResult, etd: etdResult,
atd: atdResult, atd: atdResult,
}; }
} }

View File

@ -1,17 +1,17 @@
import { jsUnix, unixLocal } from "../../src/utils/timeConvert.utils"; import { jsUnix, unixLocal } from "../../src/utils/timeConvert.utils";
describe("Time Conversion", () => { describe("Time Conversion", () => {
test("Should return unix time (seconds)", () => { test('Should return unix time (seconds)', () => {
const now = new Date(); const now = new Date();
const nowJs = now.getTime(); const nowJs = now.getTime();
const nowUnix = Math.floor(now.getTime() / 1000); const nowUnix = Math.floor(now.getTime() / 1000);
expect(jsUnix(nowJs)).toEqual(nowUnix); expect(jsUnix(nowJs)).toEqual(nowUnix);
}); })
test("Should return locale date string", () => { test('Should return locale date string', () => {
const now = new Date(); const now = new Date();
const nowUnix = Math.floor(now.getTime() / 1000); const nowUnix = Math.floor(now.getTime() / 1000);
const result = now.toLocaleString(); const result = now.toLocaleString();
expect(unixLocal(nowUnix)).toEqual(result); expect(unixLocal(nowUnix)).toEqual(result);
}); })
}); });

View File

@ -52,11 +52,11 @@
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true /* Create source map files for emitted JavaScript files. */, "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
"outDir": "./dist" /* Specify an output folder for all emitted files. */, "outDir": "./dist" /* Specify an output folder for all emitted files. */,
"removeComments": true /* Disable emitting comments. */, "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */ // "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */