diff --git a/README.md b/README.md index 8fc9498..57033d5 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,6 @@ options: reference: - more on dateISO - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString ``` + +## How does it work? + diff --git a/package-lock.json b/package-lock.json index 8386b29..18bd514 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,15 @@ "dotenv": "^16.4.5", "yargs": "^17.7.2" }, + "bin": { + "caloohpay": "CalOohPay.js" + }, "devDependencies": { "@commitlint/cli": "^19.5.0", "@commitlint/config-conventional": "^19.5.0", "@jest/globals": "^29.7.0", "@types/jest": "^29.5.12", + "@types/node": "^22.7.5", "@types/yargs": "^17.0.33", "husky": "^9.1.6", "jest": "^29.7.0", @@ -1499,13 +1503,13 @@ } }, "node_modules/@types/node": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.2.0.tgz", - "integrity": "sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==", + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.13.0" + "undici-types": "~6.19.2" } }, "node_modules/@types/stack-utils": { @@ -4709,9 +4713,9 @@ } }, "node_modules/undici-types": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", - "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index bb4a1cf..f2a038d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,12 @@ { "name": "pagerduty-schedules", + "bin": { + "caloohpay": "./dist/src/CalOohPay.js" + }, "version": "1.0.0", - "main": "index.js", + "main": "CalOohPay.js", "scripts": { + "dev": "tsc -w", "start": "node dist/src/pgapi.js", "build": "tsc", "test": "jest", @@ -18,6 +22,7 @@ "@commitlint/config-conventional": "^19.5.0", "@jest/globals": "^29.7.0", "@types/jest": "^29.5.12", + "@types/node": "^22.7.5", "@types/yargs": "^17.0.33", "husky": "^9.1.6", "jest": "^29.7.0", diff --git a/src/CalOohPay.ts b/src/CalOohPay.ts new file mode 100644 index 0000000..db78500 --- /dev/null +++ b/src/CalOohPay.ts @@ -0,0 +1,170 @@ +#!/usr/bin/env node +import { api } from '@pagerduty/pdjs'; +import * as dotenv from 'dotenv'; +import { hideBin } from 'yargs/helpers'; +import yargs, { Argv, ArgumentsCamelCase } from "yargs"; +import { OnCallUser } from './OnCallUser'; +import { OnCallPeriod } from './OnCallPeriod'; +import { FinalSchedule } from './FinalSchedule'; +import { KaluzaOnCallPaymentsCalculator } from './KaluzaOnCallPaymentsCalculator'; +import { ScheduleEntry } from './ScheduleEntry'; + +dotenv.config(); + +interface Environment { + API_TOKEN: string; +} + +function sanitiseEnvVariable(envVars: NodeJS.ProcessEnv): Environment { + if (!envVars.API_TOKEN) { + throw new Error("API_TOKEN not defined"); + } + return { + API_TOKEN: envVars.API_TOKEN, + }; +} + +const sanitisedEnvVars: Environment = sanitiseEnvVariable(process.env); + +const yargsInstance = yargs(hideBin(process.argv)); + +const argv: CommandLineOptions = yargsInstance + .wrap(yargsInstance.terminalWidth()) + .usage('$0 [options] ') + .option('rota-ids', { + alias: 'r', + describe: '1 scheduleId or multiple scheduleIds separated by comma', + type: 'string', + demandOption: true, + example: 'R1234567,R7654321' + }) + .option('since', { + type: 'string', + alias: 's', + description: 'start of the schedule period', + }) + .default('s', function firstDayOfPreviousMonth(): string { + let today = new Date(); + return new Date(Date.UTC(today.getUTCFullYear(), (today.getUTCMonth() - 1), 1)).toISOString(); + }) + .option('until', { + type: 'string', + alias: 'u', + description: 'end of the schedule period', + }) + .default('u', function lastDayOfPreviousMonth(): string { + let today = new Date(); + return new Date( + Date.UTC( + today.getUTCFullYear(), + today.getUTCMonth(), + 0, + 23, + 59, + 59) + ).toISOString(); + }) + .option('key', { + type: 'string', + demandOption: false, + alias: 'k', + description: 'this command line argument API_TOKEN to override environment variable API_TOKEN' + }) + .option('output-file', { + type: 'string', + demandOption: false, + alias: 'o', + description: 'the path to the file where you want the on-call payments table printed' + }) + .option('help', { + type: 'boolean', + alias: 'h', + description: 'Show help' + }) + .help() + .check((argv) => { + if (argv.since && !Date.parse(argv.since)) { + throw new Error("Invalid date format for since"); + } + if (argv.until && !Date.parse(argv.until)) { + throw new Error("Invalid date format for until"); + } + return true; + }).argv as CommandLineOptions; + +calOohPay(argv); + + +interface CommandLineOptions { + rotaIds: string; + since: string; + until: string; + key: string; + outputFile: string; + help: boolean; +} + +function getOnCallUserFromScheduleEntry(scheduleEntry: ScheduleEntry): OnCallUser { + let onCallPeriod = new OnCallPeriod(scheduleEntry.start, scheduleEntry.end); + let onCallUser = new OnCallUser( + scheduleEntry.user?.id || "", + scheduleEntry.user?.summary || "", [onCallPeriod]); + return onCallUser +} + +function extractOnCallUsersFromFinalSchedule(finalSchedule: FinalSchedule): Record { + let onCallUsers: Record = {}; + if(finalSchedule.rendered_schedule_entries){ + finalSchedule.rendered_schedule_entries.forEach(scheduleEntry => { + let onCallUser = getOnCallUserFromScheduleEntry(scheduleEntry); + if(onCallUser.id in onCallUsers){ + onCallUsers[onCallUser.id].addOnCallPeriods(onCallUser.onCallPeriods); + } else { + onCallUsers[onCallUser.id] = onCallUser; + } + }); + } + return onCallUsers; +} + +function calOohPay(cliOptions: CommandLineOptions) { + const pagerDutyApi = api({ token: sanitisedEnvVars.API_TOKEN }); + console.log("CLI Options: %s", JSON.stringify(cliOptions)); + // invoke the pd api to get schedule data + for (let rotaId of cliOptions.rotaIds.split(',')) { + console.log(`Fetching schedule data for rotaId: ${rotaId} between ${cliOptions.since} and ${cliOptions.until}`); + pagerDutyApi + .get(`/schedules/${rotaId}`, + { + data: { + overflow: false, + since: cliOptions.since, + time_zone: "Europe/London", + until: cliOptions.until + } + } + ).then( + ({ data, resource, response, next }) => { + console.log("Schedule name: %s", data.schedule.name); + console.log("Schedule URL: %s", data.schedule.html_url); + let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule); + let listOfOnCallUsers = Object.values(onCallUsers); + + let auditableRecords = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers); + console.log("User, TotalComp, Mon-Thu, Fri-Sun"); + + for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) { + console.log("%s, %d, %d, %d", + onCallCompensation.OnCallUser.name, + onCallCompensation.totalCompensation, + onCallCompensation.OnCallUser.getTotalOohWeekDays(), + onCallCompensation.OnCallUser.getTotalOohWeekendDays()); + } + } + ).catch( + (error) => { + console.error("Error: %s", error); + } + ); + } +} diff --git a/src/FinalSchedule.ts b/src/FinalSchedule.ts new file mode 100644 index 0000000..bd853bc --- /dev/null +++ b/src/FinalSchedule.ts @@ -0,0 +1,7 @@ +import { UserOncall } from './UserOncall'; + + +export interface FinalSchedule { + name: String; + rendered_schedule_entries: UserOncall[]; +} diff --git a/src/IOnCallPaymentsCalculator.ts b/src/IOnCallPaymentsCalculator.ts index c1aa51d..51fcdb0 100644 --- a/src/IOnCallPaymentsCalculator.ts +++ b/src/IOnCallPaymentsCalculator.ts @@ -5,5 +5,4 @@ import { OnCallUser } from "./OnCallUser"; export interface IOnCallPaymentsCalculator { calculateOnCallPayment(onCallUser: OnCallUser): number; calculateOnCallPayments(onCallUsers: OnCallUser[]): Record; - getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record; } diff --git a/src/KaluzaOnCallPaymentsCalculator.ts b/src/KaluzaOnCallPaymentsCalculator.ts index acc8f3d..efea0fb 100644 --- a/src/KaluzaOnCallPaymentsCalculator.ts +++ b/src/KaluzaOnCallPaymentsCalculator.ts @@ -2,35 +2,24 @@ import { IOnCallPaymentsCalculator } from "./IOnCallPaymentsCalculator"; import { OnCallCompensation } from "./OnCallCompensation"; import { OnCallUser } from "./OnCallUser"; -function wasPersonOnCallOOH(dateToCheck: Date, onCallUntilDate: Date): boolean { - var dateToCheckEvening = new Date(dateToCheck); - dateToCheckEvening.setHours(18); - return (dateToCheckEvening > dateToCheck && dateToCheckEvening < onCallUntilDate) -} - -export function dateDiffInHours(until: Date, since: Date): number { - return Math.round(Math.abs(until.getTime()) - Math.abs(since.getTime())) / (1000 * 60 * 60); -} - -function validateOnCallUser(onCallUser: OnCallUser): void { - if (!onCallUser) { - throw new Error("User undefined!"); - } - if (!onCallUser.onCallPeriods) { - throw new Error("No on call periods defined!"); - } -} - export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator { public static WeekDayRate: number = 50; public static WeekEndRate: number = 75; + static validateOnCallUser(onCallUser: OnCallUser): void { + if (!onCallUser) { + throw new Error("User undefined!"); + } + if (!onCallUser.onCallPeriods) { + throw new Error("No on call periods defined!"); + } + } /** * The calculator works on the assumption that the request was made with full date time format * i.e. since is YYYY-MM-DDT00:00:00+01:00 AND until is YYYY-MM-DDT23:59:59+01:00 */ calculateOnCallPayment(onCallUser: OnCallUser): number { - validateOnCallUser(onCallUser); + KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser); return (onCallUser.getTotalOohWeekDays() * KaluzaOnCallPaymentsCalculator.WeekDayRate) + (onCallUser.getTotalOohWeekendDays() * KaluzaOnCallPaymentsCalculator.WeekEndRate); } @@ -43,14 +32,14 @@ export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator return payments; } - getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record { + static getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record { /** * for every OnCallUser item, create an OnCallCompensation object * calculate number of weekdays and weekends that the person was on call */ let onCallCompensations: Record = {}; for (let onCallUser of onCallUsers) { - validateOnCallUser(onCallUser); + KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser); onCallCompensations[onCallUser.id] = { OnCallUser: onCallUser, totalCompensation: diff --git a/src/ScheduleEntry.ts b/src/ScheduleEntry.ts new file mode 100644 index 0000000..01cb785 --- /dev/null +++ b/src/ScheduleEntry.ts @@ -0,0 +1,7 @@ +import { User } from './User'; + +export interface ScheduleEntry { + user?: User; + start: Date; + end: Date; +} diff --git a/src/User.ts b/src/User.ts new file mode 100644 index 0000000..1b1d03b --- /dev/null +++ b/src/User.ts @@ -0,0 +1,8 @@ + +export interface User { + type: string; + id: string; + summary?: string; + self?: string; + html_url?: string; +} diff --git a/src/UserOncall.ts b/src/UserOncall.ts new file mode 100644 index 0000000..069172f --- /dev/null +++ b/src/UserOncall.ts @@ -0,0 +1,8 @@ +import { User } from './User'; + + +export interface UserOncall { + start: Date; + end: Date; + user?: User; +} diff --git a/src/calc-ooh-pay.ts b/src/calc-ooh-pay.ts deleted file mode 100644 index 43defd6..0000000 --- a/src/calc-ooh-pay.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {api} from '@pagerduty/pdjs'; -import * as dotenv from 'dotenv'; -import yargs from 'yargs/yargs'; - -dotenv.config(); - -interface Environment { - API_TOKEN: string; -} - -function sanitiseEnvVariable(envVars: NodeJS.ProcessEnv): Environment { - if (!envVars.API_TOKEN){ - throw new Error("API_TOKEN not defined"); - } - return { - API_TOKEN: envVars.API_TOKEN, - }; -} - -const sanitisedEnvVars: Environment = sanitiseEnvVariable(process.env); - -const argv = yargs(process.argv.slice(2)) - .scriptName("calc-ooh-pay") - .usage('$0 [options]') - .options({ - r: { type: 'string', demandOption: true, alias: 'rotaId(s)', description: '1 scheduleId or multiple scheduleIds separated by comma' }, - s: { type: 'string', demandOption: true, alias: 'since', description: 'start of the schedule period' }, - u: { type: 'string', demandOption: true, alias: 'until', description: 'end of the schedule period' }, - k: { type: 'string', demandOption: false, alias: 'key', description: 'this command line argument API_TOKEN to override environment variable API_TOKEN' }, - o: { type: 'string', demandOption: false, alias: 'output-file', description: 'the path to the file where you want the on-call payments table printed' }, - }) - .help() - .parse(); - -const pd = api({token: sanitisedEnvVars.API_TOKEN}); - diff --git a/src/pgapi.ts b/src/pgapi.ts index 570c79a..d3d081e 100644 --- a/src/pgapi.ts +++ b/src/pgapi.ts @@ -3,6 +3,8 @@ import * as dotenv from 'dotenv'; import { OnCallUser } from './OnCallUser'; import { OnCallPeriod } from './OnCallPeriod'; import { KaluzaOnCallPaymentsCalculator } from './KaluzaOnCallPaymentsCalculator'; +import { ScheduleEntry } from './ScheduleEntry'; +import { FinalSchedule } from './FinalSchedule'; dotenv.config(); @@ -10,24 +12,6 @@ interface Environment { API_TOKEN: string; } -export interface User { - type: string, - id: string, - summary?: string, - self?: string, - html_url?: string -} - -export interface UserOncall { - start: Date, - end: Date, - user?: User -} - -export interface FinalSchedule { - name: String, - rendered_schedule_entries: UserOncall[] -} function sanitiseEnvVariable(envVars: NodeJS.ProcessEnv): Environment { if (!envVars.API_TOKEN){ throw new Error("API_TOKEN not defined"); @@ -60,11 +44,10 @@ pd.get(`/schedules/${incidentCommanderScheduleId}`, console.log("Schedule name: %s", data.schedule.name); console.log("Schedule URL: %s", data.schedule.html_url); - let onCallUsers = getOnCallUsersInDateRange(data.schedule.final_schedule, sinceDate, untilDate); - let kOnCallPaymentsCalculator = new KaluzaOnCallPaymentsCalculator(); + let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule); let listOfOnCallUsers = Object.values(onCallUsers); - let auditableRecords = kOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers); + let auditableRecords = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers); console.log("User, TotalComp, Mon-Thu, Fri-Sun"); for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) { @@ -77,7 +60,7 @@ pd.get(`/schedules/${incidentCommanderScheduleId}`, }) .catch(console.error); - function getOnCallUsersInDateRange(finalSchedule: FinalSchedule, sinceDate: string, untilDate: string): Record { + function extractOnCallUsersFromFinalSchedule(finalSchedule: FinalSchedule): Record { let onCallUsers: Record = {}; if(finalSchedule.rendered_schedule_entries){ finalSchedule.rendered_schedule_entries.forEach(scheduleEntry => { @@ -92,44 +75,10 @@ pd.get(`/schedules/${incidentCommanderScheduleId}`, return onCallUsers; } - interface ScheduleEntry { - user?: User, - start: Date, - end: Date - } - function getOnCallUserFromScheduleEntry(scheduleEntry: ScheduleEntry): OnCallUser { let onCallPeriod = new OnCallPeriod(scheduleEntry.start, scheduleEntry.end); let onCallUser = new OnCallUser( scheduleEntry.user?.id || "", scheduleEntry.user?.summary || "", [onCallPeriod]); return onCallUser - } - - -// export function displayFinalSchedule(finalSchedule: FinalSchedule, sinceDate: string, untilDate: string){ -// if(finalSchedule == null || typeof finalSchedule == 'undefined'){ -// console.error("Could not render final schedule! It is undefined or null."); -// } -// if(finalSchedule.rendered_schedule_entries){ -// console.log("**********"); -// finalSchedule.rendered_schedule_entries -// .forEach(element => { -// console.log("%s (%s) was on call from %s to %s", element.user?.summary, element.user?.id, element.start, element.end); -// }); -// console.log("**********"); - -// } -// } - - -// function displayOnCallUsers(onCallUsers: Record){ -// console.log("On call users: "); -// for (const [userId, onCallUser] of Object.entries(onCallUsers)) { -// console.log("%s was on call for the following periods:", onCallUser.name); -// onCallUser.onCallPeriods.forEach(ocp => { -// console.log("From %s to %s", ocp.since, ocp.until); -// }); -// } -// } - + } \ No newline at end of file diff --git a/test/OnCallPaymentCalculator.test.ts b/test/OnCallPaymentCalculator.test.ts index 9130213..168639f 100644 --- a/test/OnCallPaymentCalculator.test.ts +++ b/test/OnCallPaymentCalculator.test.ts @@ -122,29 +122,13 @@ describe('should be able to audit the payment for an on call user', () => { new OnCallPeriod(new Date('2024-08-16T10:00:00+01:00'), new Date('2024-08-21T10:00:00+01:00')) ] - ), - // new OnCallUser( - // 'PINI77A', - // 'EG Oncall', - // [ - // new OnCallPeriod(new Date('2024-08-15T00:00:00+01:00'), - // new Date('2024-08-16T10:00:00+01:00')) - // ] - // ), - // new OnCallUser( - // 'PJXZDBT', - // 'CE Oncall', - // [ - // new OnCallPeriod(new Date('2024-08-21T10:00:00+01:00'), new Date('2024-08-28T10:00:00+01:00')) - // ] - // ) + ) ]; - const calculator = new KaluzaOnCallPaymentsCalculator(); expect(onCallUsers.length).toBe(2); expect(onCallUsers[0].id).toBe('1PF7DNAV'); expect(onCallUsers[0].getTotalOohWeekDays()).toBe(4); - const audit = calculator.getAuditableOnCallPaymentRecords(onCallUsers); + const audit = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(onCallUsers); expect(audit['1PF7DNAV'].OnCallUser.getTotalOohWeekDays()).toBe(4); expect(audit['1PF7DNAV'].OnCallUser.getTotalOohWeekendDays()).toBe(5); expect(audit['1PF7DNAV'].totalCompensation).toBe(575); diff --git a/tsconfig.json b/tsconfig.json index 709dc80..db87df1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,8 +11,10 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "target": "ES2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "lib": [ + "ES2023" + ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ @@ -26,10 +28,10 @@ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "Node16", /* Specify what module code is generated. */ //"rootDir": "./src", /* Specify the root folder within your source files. */ - "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "moduleResolution": "node16", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ @@ -40,7 +42,7 @@ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ + "resolveJsonModule": true, /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ @@ -50,13 +52,13 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declarationMap": true, /* Create sourcemaps for d.ts 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. */ // "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. */ // "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. */ @@ -109,6 +111,8 @@ "include": [ "src/**/*.ts", "test/**/*.ts", - "cli.ts" ], + "exclude": [ + "node_modules", "dist" + ] }