rewrite module to typescript

This commit is contained in:
2025-01-14 17:36:15 +01:00
parent 9dc24f2d7b
commit b9f7615cd0
13 changed files with 435 additions and 491 deletions

View File

@@ -20,7 +20,7 @@
"type": "node18", "type": "node18",
"api": "nodejs-ipc", "api": "nodejs-ipc",
"apiVersion": "0.0.0", "apiVersion": "0.0.0",
"entrypoint": "../main.js" "entrypoint": "../dist/main.js"
}, },
"manufacturer": "Toggl", "manufacturer": "Toggl",
"products": ["Track"], "products": ["Track"],

5
eslint.config.mjs Normal file
View File

@@ -0,0 +1,5 @@
import { generateEslintConfig } from '@companion-module/tools/eslint/config.mjs'
export default generateEslintConfig({
enableTypescript: true,
})

471
main.js
View File

@@ -1,471 +0,0 @@
// toggltrack module
// Peter Daniel
import { InstanceBase, Regex, runEntrypoint, InstanceStatus } from '@companion-module/base'
import UpdateActions from './actions.js'
import UpdatePresets from './presets.js'
import UpdateVariableDefinitions from './variables.js'
import UpgradeScripts from './upgrades.js'
import got from 'got'
class toggltrack extends InstanceBase {
constructor(internal) {
super(internal)
}
getConfigFields() {
// console.log('config fields')
return [
{
type: 'textinput',
id: 'apiToken',
label: 'Personal API Token from your Toggl user profile (required)',
width: 12,
required: true,
default: '',
},
{
type: 'checkbox',
id: 'alwaysStart',
label: 'Always start a new timer even if there is one already running',
width: 12,
required: false,
default: false,
},
]
}
async destroy() {
console.log('destroy', this.id)
}
async init(config) {
console.log('--- init toggltrack ---')
this.prefixUrl = 'https://api.track.toggl.com/api/v9/'
this.config = config
this.updateStatus(InstanceStatus.Ok)
this.gotOptions = {
responseType: 'json',
throwHttpErrors: false,
}
this.gotOptions.prefixUrl = this.prefixUrl
this.workspace = null
this.workspaceName = null
this.projects = [{ id: '0', label: 'None' }]
this.updateVariableDefinitions()
this.updatePresets()
this.setVariableValues({
timerId: null,
timerDuration: null,
timerDescription: null,
lastTimerDuration: null,
workspace: null,
})
this.gotOptions.headers = this.auth()
if (this.gotOptions.headers != null) {
this.getWorkspace().then(this.getCurrentTimer())
}
this.updateActions()
}
async configUpdated(config) {
console.log('config updated')
this.config = config
this.gotOptions.headers = this.auth()
if (this.gotOptions.headers != null) {
this.getWorkspace().then(this.getCurrentTimer())
}
this.updateActions()
this.updateVariables()
}
updateActions() {
UpdateActions(this)
}
updateFeedbacks() {
UpdateFeedbacks(this)
}
updatePresets() {
UpdatePresets(this)
}
updateVariableDefinitions() {
UpdateVariableDefinitions(this)
}
auth() {
if (this.config.apiToken !== null && this.config.apiToken.length > 0) {
let auth = Buffer.from(this.config.apiToken + ':' + 'api_token').toString('base64')
let headers = {}
headers['Content-Type'] = 'application/json'
headers['authorization'] = 'Basic ' + auth
return headers
} else {
this.log('warn', 'Please enter your toggl API token')
return null
}
// console.log(this.gotOptions)
}
async getCurrentTimer() {
console.log('function: getCurrentTimer')
if (this.gotOptions.headers == null) {
this.log('warn', 'Not authorized')
return
}
let cmd = 'me/time_entries/current'
return new Promise((resolve, reject) => {
this.sendGetCommand(cmd).then((result) => {
if (typeof result === 'object' && result !== null) {
if ('id' in result) {
this.setVariableValues({
timerId: result.id,
timerDescription: result.description,
timerDuration: result.duration,
})
this.log('info', 'Current timer id: ' + result.id)
resolve(result.id)
} else {
this.log('info', 'No current timer (no id in data)')
this.setVariableValues({
timerId: null,
timerDescription: null,
timerDuration: null,
})
resolve(null)
}
} else {
this.log('info', 'No current timer (no object)')
this.setVariableValues({
timerId: null,
timerDescription: null,
timerDuration: null,
})
resolve(null)
}
})
})
}
async getWorkspace() {
let cmd = 'workspaces'
console.log('function: getWorkspace')
if (this.gotOptions.headers == null) {
this.log('warn', 'Not authorized')
return
}
// reset
this.workspace = null
this.setVariableValues({
workspace: null,
})
// get workspace ID
this.sendGetCommand(cmd).then((result) => {
// console.log('result ' + JSON.stringify(result, null, 4))
if (typeof result === 'object' && result !== null) {
console.log('Found ' + result.length + ' workspace')
// only interested in first workspace
if ('id' in result[0]) {
this.workspace = result[0].id
this.workspaceName = result[0].name
this.log('info', 'Workspace: ' + this.workspace + ' - ' + this.workspaceName)
this.setVariableValues({
workspace: this.workspaceName,
})
this.getProjects()
}
} else {
console.log('result ' + JSON.stringify(result, null, 4))
this.log('debug', 'No workspace')
}
})
}
getProjects() {
console.log('function: getProjects')
if (this.workspace !== null) {
let cmd = 'workspaces/' + this.workspace + '/projects'
this.sendGetCommand(cmd).then((result) => {
// console.log('result ' + JSON.stringify(result, null, 4))
if (typeof result === 'object' && result !== null) {
// reset
this.projects = []
for (let p = 0; p < result.length; p++) {
if ('id' in result[p]) {
if (result[p].active === true) {
// don't add archived projects
this.projects.push({
id: result[p].id.toString(),
label: result[p].name,
})
}
// this.log('debug', 'Project ' + result[p].id + ':' + result[p].name)
}
}
this.projects.sort((a, b) => {
let fa = a.label.toLowerCase()
let fb = b.label.toLowerCase()
if (fa < fb) {
return -1
}
if (fa > fb) {
return 1
}
return 0
})
this.projects.unshift({ id: '0', label: 'None' })
console.log('Projects:')
console.log(this.projects)
this.updateActions()
} else {
console.log(result)
this.log('debug', 'No projects')
}
})
}
}
// getTimerDuration(id) {
// let cmd = 'time_entries/' + id
//
// return new Promise((resolve, reject) => {
// self.sendCommand('rest_get', cmd).then(
// (result) => {
// if (typeof result === 'object' && result.data !== null && result.data !== undefined) {
// if ('duration' in result.data) {
// self.setVariable('timerDuration', result.data.duration)
// resolve(result.data.duration)
// } else {
// self.log('debug', 'Error getting current timer duration (no id in data)')
// self.setVariable('timerDuration', null)
// resolve(null)
// }
// } else {
// self.log('debug', 'Error getting current timer duration (no object)')
// self.setVariable('timerDuration', null)
// resolve(null)
// }
// },
// (error) => {
// console.log('error ' + error)
// self.log('debug', 'Error getting current timer duration')
// }
// )
// })
// }
async startTimer(project, description) {
let body
let cmd
let timerId
const startTime = new Date()
this.getCurrentTimer().then((timerId) => {
console.log('timerId: ' + timerId)
if (timerId === null || this.config.alwaysStart === true) {
// no timer currently running or we want to restart it
cmd = 'workspaces/' + this.workspace + '/time_entries'
if (project == '0') {
body =
'{"wid":' +
this.workspace +
',"description":"' +
description +
'","created_with":"companion",' +
'"start":"' +
startTime.toISOString() +
'","duration":-1}'
} else {
body =
'{"wid":' +
this.workspace +
',"description":"' +
description +
'","created_with":"companion","project_id":' +
project +
',"start":"' +
startTime.toISOString() +
'","duration":-1}'
}
// console.log(body)
this.sendPostCommand(cmd, body).then((result) => {
if (typeof result === 'object' && result !== null) {
this.log('info', 'New timer started ' + result.id + ' ' + result.description)
this.setVariableValues({
timerId: result.id,
timerDescription: result.description,
timerDuration: result.duration,
})
} else {
this.log('warn', 'Error starting timer')
}
})
} else {
this.log('info', 'A timer is already running ' + timerId + ' not starting a new one!')
}
})
}
async stopTimer() {
console.log('function: stopTimer')
this.getCurrentTimer().then((timerId) => {
this.log('info', 'Trying to stop current timer id: ' + timerId)
// console.log(typeof timerId)
if (typeof timerId === 'number' && timerId > 0) {
let cmd = 'workspaces/' + this.workspace + '/time_entries/' + timerId + '/stop'
this.sendPatchCommand(cmd).then((result) => {
if (typeof result === 'object' && result !== null && result !== undefined) {
this.log('info', 'Stopped ' + result.id + ', duration ' + result.duration)
this.setVariableValues({
timerId: null,
timerDescription: null,
timerDuration: null,
lastTimerDuration: result.duration,
})
} else {
this.log('warn', 'Error stopping timer')
}
})
} else {
this.log('warn', 'No running timer to stop or running timer id unknown')
}
})
}
async sendGetCommand(GetURL) {
console.log('get: ' + GetURL)
let response
try {
response = await got.get(GetURL, this.gotOptions)
if (response.statusCode == 200) {
this.updateStatus(InstanceStatus.Ok)
return response.body
} else {
this.updateStatus(
InstanceStatus.UnknownError,
`Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`,
)
this.log('warn', `Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`)
return null
}
} catch (error) {
console.log(error.message)
this.processError(error)
return null
}
}
async sendPutCommand(PutURL) {
console.log('put: ' + PutURL)
let response
try {
response = await got.put(PutURL, this.gotOptions)
console.log('status: ' + response.statusCode)
if (response.statusCode == 200) {
console.log(response.body)
return response.body
} else {
this.updateStatus(
InstanceStatus.UnknownError,
`Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`,
)
this.log('warn', `Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`)
return null
}
} catch (error) {
console.log(error.message)
this.processError(error)
return null
}
}
async sendPatchCommand(PatchURL) {
console.log('patch: ' + PatchURL)
let response
try {
response = await got.patch(PatchURL, this.gotOptions)
// console.log('status: ' + response.statusCode)
if (response.statusCode == 200) {
// console.log(response.body)
return response.body
} else {
this.updateStatus(
InstanceStatus.UnknownError,
`Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`,
)
this.log('warn', `Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`)
return null
}
} catch (error) {
console.log(error.message)
this.processError(error)
return null
}
}
async sendPostCommand(cmd, body) {
console.log(body)
let response
let postdata = {}
postdata.prefixUrl = this.prefixUrl
;(postdata.responseType = 'json'), (postdata.throwHttpErrors = false)
postdata.headers = this.auth()
postdata.json = JSON.parse(body)
// console.log(postdata)
try {
response = await got.post(cmd, postdata)
// console.log(response.request.requestUrl)
// console.log(response.statusCode)
if (response.statusCode == 200) {
return response.body
} else {
this.updateStatus(
InstanceStatus.UnknownError,
`Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`,
)
this.log('warn', `Unexpected HTTP status code: ${response.statusCode} - ${response.body.error}`)
return null
}
} catch (error) {
console.log(error.message)
this.processError(error)
return null
}
}
processError(error) {
console.log('gotError: ' + error.code)
}
}
runEntrypoint(toggltrack, UpgradeScripts)

View File

@@ -1,11 +1,16 @@
{ {
"name": "toggl-track", "name": "toggl-track",
"version": "2.0.2", "version": "2.1.0",
"main": "main.js", "main": "dist/main.js",
"type": "module", "type": "module",
"scripts": { "scripts": {
"format": "prettier -w .", "format": "prettier -w .",
"package": "companion-module-build", "package": "yarn run build && companion-module-build",
"build": "rimraf dist && yarn run build:main",
"build:main": "tsc -p tsconfig.build.json",
"dev": "tsc -p tsconfig.build.json --watch",
"lint:raw": "eslint",
"lint": "yarn run lint:raw .",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
@@ -15,11 +20,24 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@companion-module/base": "~1.11", "@companion-module/base": "~1.11",
"got": "~13.0.0" "toggl-track": "^0.8.0"
}, },
"devDependencies": { "devDependencies": {
"@companion-module/tools": "~2.1.0", "@companion-module/tools": "~2.1.1",
"prettier": "^3.4.2" "@types/node": "^22.10.2",
"eslint": "^9.17.0",
"prettier": "^3.4.2",
"rimraf": "^5.0.10",
"typescript": "~5.5.4",
"typescript-eslint": "^8.18.1"
}, },
"prettier": "@companion-module/tools/.prettierrc.json" "prettier": "@companion-module/tools/.prettierrc.json",
"lint-staged": {
"*.{css,json,md,scss}": [
"prettier --write"
],
"*.{ts,tsx,js,jsx}": [
"yarn lint:raw --fix"
]
}
} }

View File

@@ -1,4 +1,6 @@
export default function (self) { import { TogglTrack } from './main.js'
export default function (self: TogglTrack): void {
self.setActionDefinitions({ self.setActionDefinitions({
startNewTimer: { startNewTimer: {
name: 'Start New Timer', name: 'Start New Timer',
@@ -14,35 +16,35 @@ export default function (self) {
label: 'Project', label: 'Project',
id: 'project', id: 'project',
default: '0', default: '0',
choices: self.projects, choices: self.projects!,
}, },
], ],
callback: ({ options }) => { callback: async ({ options }) => {
self.startTimer(options.project, options.description) return self.startTimer(Number(options.project), options.description as string)
}, },
}, },
getCurrentTimer: { getCurrentTimer: {
name: 'Get Current Timer', name: 'Get Current Timer',
options: [], options: [],
callback: (action) => { callback: async () => {
self.getCurrentTimer() await self.getCurrentTimer()
}, },
}, },
stopCurrentTimer: { stopCurrentTimer: {
name: 'Stop Current Timer', name: 'Stop Current Timer',
options: [], options: [],
callback: (action) => { callback: async () => {
self.stopTimer() return self.stopTimer()
}, },
}, },
refreshProjects: { refreshProjects: {
name: 'Refresh Project List', name: 'Refresh Project List',
options: [], options: [],
callback: (action) => { callback: async () => {
self.getWorkspace() await self.getWorkspace()
}, },
}, },
}) })

36
src/config.ts Normal file
View File

@@ -0,0 +1,36 @@
import { type SomeCompanionConfigField } from '@companion-module/base'
export interface ModuleConfig {
apiToken?: string
workspaceName: string
alwaysStart?: boolean
}
export function GetConfigFields(): SomeCompanionConfigField[] {
// console.log('config fields')
return [
{
type: 'textinput',
id: 'apiToken',
label: 'Personal API Token from your Toggl user profile (required)',
width: 12,
required: true,
default: '',
},
{
type: 'textinput',
id: 'workspaceName',
label: 'Workspace to default to (first found if unset)',
width: 12,
required: false,
default: '',
},
{
type: 'checkbox',
id: 'alwaysStart',
label: 'Always start a new timer even if there is one already running',
width: 12,
default: false,
},
]
}

318
src/main.ts Normal file
View File

@@ -0,0 +1,318 @@
// toggltrack module
// Peter Daniel
import { InstanceBase, runEntrypoint, InstanceStatus, SomeCompanionConfigField } from '@companion-module/base'
import { GetConfigFields, type ModuleConfig } from './config.js'
import UpdateActions from './actions.js'
import UpdatePresets from './presets.js'
import UpdateVariableDefinitions from './variables.js'
import UpgradeScripts from './upgrades.js'
import { Toggl, ITimeEntry, IWorkspaceProject } from 'toggl-track'
import { togglGetWorkspaces } from './toggl-extend.js'
export class TogglTrack extends InstanceBase<ModuleConfig> {
config!: ModuleConfig // Setup in init()
toggl?: Toggl
workspaceId?: number // current active workspace id
workspaceName: string = '' // name of workspace
projects?: { id: string; label: string }[]
constructor(internal: unknown) {
super(internal)
}
getConfigFields(): SomeCompanionConfigField[] {
return GetConfigFields()
}
async destroy(): Promise<void> {
console.log('destroy', this.id)
}
async init(config: ModuleConfig): Promise<void> {
console.log('--- init toggltrack ---')
this.config = config
this.updateStatus(InstanceStatus.Ok)
this.workspaceId = undefined
this.projects = [{ id: '0', label: 'None' }]
this.updateVariableDefinitions()
this.updatePresets()
this.setVariableValues({
timerId: undefined,
timerDuration: undefined,
timerDescription: undefined,
lastTimerDuration: undefined,
workspace: undefined,
})
await this.initToggleConnection()
this.updateActions()
}
async configUpdated(config: ModuleConfig): Promise<void> {
console.log('config updated')
const apiTokenChanged: boolean = this.config.apiToken != config.apiToken
const workSpaceDefaultChanged: boolean = this.config.workspaceName != config.workspaceName
this.config = config
if (apiTokenChanged) {
this.log('debug', 'api token changed. init new toggle connection')
this.toggl = undefined
await this.initToggleConnection()
}
if (workSpaceDefaultChanged) {
this.log('debug', 'workspace default changed. reload workspaces')
await this.getWorkspace()
}
this.updateActions()
this.updateVariables()
}
updateVariables(): void {
throw new Error('Method not implemented.')
}
updateActions(): void {
UpdateActions(this)
}
/*updateFeedbacks() {
UpdateFeedbacks(this)
}*/
updatePresets(): void {
UpdatePresets(this)
}
updateVariableDefinitions(): void {
UpdateVariableDefinitions(this)
}
async initToggleConnection(): Promise<void> {
if (this.config.apiToken!.length > 0) {
this.toggl = new Toggl({
auth: {
token: this.config.apiToken!,
},
})
const logged: string = await this.toggl.me.logged()
this.log('debug', logged)
if (logged === 'OK') {
await this.getWorkspace()
await this.getCurrentTimer()
}
}
return
}
async getCurrentTimer(): Promise<number | null> {
console.log('function: getCurrentTimer')
if (!this.toggl) {
this.log('warn', 'Not authorized')
return null
}
const entry: ITimeEntry = await this.toggl.timeEntry.current()
this.log('debug', 'response for timer id ' + JSON.stringify(entry))
if (entry) {
this.log('info', 'Current timer id: ' + entry.id)
this.setVariableValues({
timerId: entry.id,
timerDescription: entry.description,
timerDuration: entry.duration,
})
return entry.id
} else {
this.log('info', 'No current timer')
this.setVariableValues({
timerId: undefined,
timerDescription: undefined,
timerDuration: undefined,
})
return null
}
}
async getWorkspace(): Promise<void> {
console.log('function: getWorkspace')
if (!this.toggl) {
this.log('warn', 'Not authorized')
return
}
// reset
this.workspaceId = undefined
this.setVariableValues({
workspace: undefined,
})
const workspaces = await togglGetWorkspaces(this.toggl)
this.log('info', 'Found ' + workspaces.length + ' workspace')
for (const ws of workspaces) {
if (this.config.workspaceName == '' || this.config.workspaceName == ws.name) {
// take the first or matching one and continue
this.workspaceId = ws.id
this.workspaceName = ws.name
break
}
// workspaceName does not match => continue with next
continue
}
if (this.workspaceId == undefined) {
// no workspace found
//console.log('result ' + JSON.stringify(workspaces, null, 4))
this.log('debug', 'No workspace found')
return
}
this.log('info', 'Workspace: ' + this.workspaceId + ' - ' + this.workspaceName)
this.setVariableValues({
workspace: this.workspaceName,
})
return this.getProjects()
}
async getProjects(): Promise<void> {
console.log('function: getProjects ' + this.workspaceId)
if (!this.workspaceId) {
this.log('warn', 'workspaceId undefined')
return
}
const projects: IWorkspaceProject[] = await this.toggl!.projects.list(this.workspaceId)
//const projects: IWorkspaceProject[] = await togglGetProjects(this.toggl!, this.workspaceId!)
if (typeof projects === 'string' || projects.length == 0) {
this.projects = [{ id: '0', label: 'None' }]
console.log(projects)
this.log('debug', 'No projects')
return
}
this.projects = projects
.filter((p) => p.active)
.map((p) => {
return {
id: p.id.toString(),
label: p.name,
}
})
.sort((a, b) => {
const fa = a.label.toLowerCase()
const fb = b.label.toLowerCase()
if (fa < fb) {
return -1
}
if (fa > fb) {
return 1
}
return 0
})
console.log('Projects:')
console.log(this.projects)
}
// getTimerDuration(id) {
// let cmd = 'time_entries/' + id
//
// return new Promise((resolve, reject) => {
// self.sendCommand('rest_get', cmd).then(
// (result) => {
// if (typeof result === 'object' && result.data !== null && result.data !== undefined) {
// if ('duration' in result.data) {
// self.setVariable('timerDuration', result.data.duration)
// resolve(result.data.duration)
// } else {
// self.log('debug', 'Error getting current timer duration (no id in data)')
// self.setVariable('timerDuration', null)
// resolve(null)
// }
// } else {
// self.log('debug', 'Error getting current timer duration (no object)')
// self.setVariable('timerDuration', null)
// resolve(null)
// }
// },
// (error) => {
// console.log('error ' + error)
// self.log('debug', 'Error getting current timer duration')
// }
// )
// })
// }
async startTimer(project: number, description: string): Promise<void> {
if (!this.toggl || !this.workspaceId) {
this.log('error', 'toggle not initialized. Do not start time')
return
}
const currentId = await this.getCurrentTimer()
let newEntry: ITimeEntry
if (currentId === null || this.config.alwaysStart === true) {
// there is no running time entry or alwaysStart is true
newEntry = await this.toggl.timeEntry.create(this.workspaceId, {
description: description,
workspace_id: this.workspaceId,
created_with: 'companion',
start: new Date().toISOString(),
duration: -1,
project_id: project != 0 ? project : undefined,
})
this.log('info', 'New timer started ' + newEntry.id + ' ' + newEntry.description)
this.setVariableValues({
timerId: newEntry.id,
timerDescription: newEntry.description,
timerDuration: newEntry.duration,
})
} else {
this.log('info', 'A timer is already running ' + currentId + ' not starting a new one!')
}
}
async stopTimer(): Promise<void> {
this.log('debug', 'function: stopTimer')
if (!this.toggl || !this.workspaceId) {
this.log('error', 'toggle not initialized. Do not start time')
return
}
const currentId = await this.getCurrentTimer()
this.log('info', 'Trying to stop current timer id: ' + currentId)
// console.log(typeof timerId)
if (currentId !== null) {
const updated: ITimeEntry = await this.toggl.timeEntry.stop(currentId, this.workspaceId)
this.log('info', 'Stopped ' + updated.id + ', duration ' + updated.duration)
this.setVariableValues({
timerId: undefined,
timerDescription: undefined,
timerDuration: undefined,
lastTimerDuration: updated.duration,
})
} else {
this.log('warn', 'No running timer to stop or running timer id unknown')
}
}
}
runEntrypoint(TogglTrack, UpgradeScripts)

View File

@@ -1,6 +1,7 @@
import { combineRgb } from '@companion-module/base' import { combineRgb } from '@companion-module/base'
import { TogglTrack } from './main.js'
export default function (self) { export default function (self: TogglTrack): void {
self.setPresetDefinitions({ self.setPresetDefinitions({
Start: { Start: {
type: 'button', type: 'button',

11
src/toggl-extend.ts Normal file
View File

@@ -0,0 +1,11 @@
import { Toggl } from 'toggl-track'
export interface IWorkspace {
id: number
name: string
}
export async function togglGetWorkspaces(toggl: Toggl): Promise<IWorkspace[]> {
const resp: IWorkspace[] = await toggl.request<IWorkspace[]>('workspaces', {})
return resp
}

View File

@@ -1,4 +1,6 @@
export default function (self) { import { TogglTrack } from './main.js'
export default function (self: TogglTrack): void {
self.setVariableDefinitions([ self.setVariableDefinitions([
{ {
name: 'Workspace', name: 'Workspace',

14
tsconfig.build.json Normal file
View File

@@ -0,0 +1,14 @@
{
"extends": "@companion-module/tools/tsconfig/node18/recommended",
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**", "src/**/*spec.ts", "src/**/__tests__/*", "src/**/__mocks__/*"],
"compilerOptions": {
"outDir": "./dist",
"baseUrl": "./",
"paths": {
"*": ["./node_modules/*"]
},
"module": "Node16",
"moduleResolution": "Node16"
}
}

8
tsconfig.json Normal file
View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.build.json",
"include": ["src/**/*.ts"],
"exclude": ["node_modules/**"],
"compilerOptions": {
"types": ["jest", "node"]
}
}