agenda 4.3.0 → 5.0.0

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.
Files changed (89) hide show
  1. package/History.md +12 -3
  2. package/README.md +38 -9
  3. package/dist/agenda/create.d.ts +2 -2
  4. package/dist/agenda/create.d.ts.map +1 -1
  5. package/dist/agenda/create.js.map +1 -1
  6. package/dist/agenda/define.d.ts +2 -2
  7. package/dist/agenda/define.d.ts.map +1 -1
  8. package/dist/agenda/define.js.map +1 -1
  9. package/dist/agenda/drain.d.ts +9 -0
  10. package/dist/agenda/drain.d.ts.map +1 -0
  11. package/dist/agenda/drain.js +46 -0
  12. package/dist/agenda/drain.js.map +1 -0
  13. package/dist/agenda/every.d.ts +2 -1
  14. package/dist/agenda/every.d.ts.map +1 -1
  15. package/dist/agenda/every.js +1 -1
  16. package/dist/agenda/every.js.map +1 -1
  17. package/dist/agenda/find-and-lock-next-job.d.ts.map +1 -1
  18. package/dist/agenda/find-and-lock-next-job.js +3 -4
  19. package/dist/agenda/find-and-lock-next-job.js.map +1 -1
  20. package/dist/agenda/index.d.ts +2 -0
  21. package/dist/agenda/index.d.ts.map +1 -1
  22. package/dist/agenda/index.js +2 -0
  23. package/dist/agenda/index.js.map +1 -1
  24. package/dist/agenda/now.d.ts +2 -2
  25. package/dist/agenda/now.d.ts.map +1 -1
  26. package/dist/agenda/now.js.map +1 -1
  27. package/dist/agenda/schedule.d.ts +3 -3
  28. package/dist/agenda/schedule.d.ts.map +1 -1
  29. package/dist/agenda/schedule.js.map +1 -1
  30. package/dist/job/compute-next-run-at.js +2 -2
  31. package/dist/job/compute-next-run-at.js.map +1 -1
  32. package/dist/job/index.d.ts +6 -3
  33. package/dist/job/index.d.ts.map +1 -1
  34. package/dist/job/index.js.map +1 -1
  35. package/lib/agenda/cancel.ts +28 -0
  36. package/lib/agenda/close.ts +37 -0
  37. package/lib/agenda/create.ts +22 -0
  38. package/lib/agenda/database.ts +63 -0
  39. package/lib/agenda/db-init.ts +45 -0
  40. package/lib/agenda/default-concurrency.ts +19 -0
  41. package/lib/agenda/default-lock-lifetime.ts +17 -0
  42. package/lib/agenda/default-lock-limit.ts +17 -0
  43. package/lib/agenda/define.ts +85 -0
  44. package/lib/agenda/disable.ts +28 -0
  45. package/lib/agenda/drain.ts +30 -0
  46. package/lib/agenda/enable.ts +29 -0
  47. package/lib/agenda/every.ts +86 -0
  48. package/lib/agenda/find-and-lock-next-job.ts +78 -0
  49. package/lib/agenda/has-mongo-protocol.ts +8 -0
  50. package/lib/agenda/index.ts +227 -0
  51. package/lib/agenda/job-processing-queue.ts +99 -0
  52. package/lib/agenda/jobs.ts +31 -0
  53. package/lib/agenda/lock-limit.ts +17 -0
  54. package/lib/agenda/max-concurrency.ts +20 -0
  55. package/lib/agenda/mongo.ts +21 -0
  56. package/lib/agenda/name.ts +16 -0
  57. package/lib/agenda/now.ts +31 -0
  58. package/lib/agenda/process-every.ts +18 -0
  59. package/lib/agenda/purge.ts +19 -0
  60. package/lib/agenda/save-job.ts +185 -0
  61. package/lib/agenda/schedule.ts +79 -0
  62. package/lib/agenda/sort.ts +17 -0
  63. package/lib/agenda/start.ts +30 -0
  64. package/lib/agenda/stop.ts +49 -0
  65. package/lib/cjs.ts +5 -0
  66. package/lib/index.ts +11 -0
  67. package/lib/job/compute-next-run-at.ts +191 -0
  68. package/lib/job/disable.ts +11 -0
  69. package/lib/job/enable.ts +11 -0
  70. package/lib/job/fail.ts +29 -0
  71. package/lib/job/index.ts +221 -0
  72. package/lib/job/is-running.ts +29 -0
  73. package/lib/job/priority.ts +11 -0
  74. package/lib/job/remove.ts +10 -0
  75. package/lib/job/repeat-at.ts +12 -0
  76. package/lib/job/repeat-every.ts +40 -0
  77. package/lib/job/run.ts +125 -0
  78. package/lib/job/save.ts +11 -0
  79. package/lib/job/schedule.ts +15 -0
  80. package/lib/job/set-shouldsaveresult.ts +10 -0
  81. package/lib/job/to-json.ts +36 -0
  82. package/lib/job/touch.ts +11 -0
  83. package/lib/job/unique.ts +18 -0
  84. package/lib/utils/create-job.ts +13 -0
  85. package/lib/utils/index.ts +3 -0
  86. package/lib/utils/parse-priority.ts +37 -0
  87. package/lib/utils/process-jobs.ts +379 -0
  88. package/package.json +14 -12
  89. package/tsconfig.json +72 -0
@@ -0,0 +1,379 @@
1
+ import createDebugger from "debug";
2
+ import { createJob } from "./create-job";
3
+ import { Job } from "../job";
4
+ import { Agenda } from "../agenda";
5
+
6
+ const debug = createDebugger("agenda:internal:processJobs");
7
+
8
+ /**
9
+ * Process methods for jobs
10
+ * @param {Job} extraJob job to run immediately
11
+ */
12
+ export const processJobs = async function (
13
+ this: Agenda,
14
+ extraJob: Job
15
+ ): Promise<void> {
16
+ debug(
17
+ "starting to process jobs: [%s:%s]",
18
+ extraJob?.attrs?.name ?? "unknownName",
19
+ extraJob?.attrs?._id ?? "unknownId"
20
+ );
21
+ // Make sure an interval has actually been set
22
+ // Prevents race condition with 'Agenda.stop' and already scheduled run
23
+ if (!this._processInterval) {
24
+ debug("no _processInterval set when calling processJobs, returning");
25
+ return;
26
+ }
27
+
28
+ const self = this; // eslint-disable-line @typescript-eslint/no-this-alias
29
+ const definitions = this._definitions;
30
+ const jobQueue = this._jobQueue;
31
+ let jobName;
32
+
33
+ // Determine whether or not we have a direct process call!
34
+ if (!extraJob) {
35
+ // Go through each jobName set in 'Agenda.process' and fill the queue with the next jobs
36
+ const parallelJobQueueing = [];
37
+ for (jobName in definitions) {
38
+ if ({}.hasOwnProperty.call(definitions, jobName)) {
39
+ debug("queuing up job to process: [%s]", jobName);
40
+ parallelJobQueueing.push(jobQueueFilling(jobName));
41
+ }
42
+ }
43
+
44
+ await Promise.all(parallelJobQueueing);
45
+ } else if (definitions[extraJob.attrs.name]) {
46
+ // Add the job to list of jobs to lock and then lock it immediately!
47
+ debug(
48
+ "job [%s:%s] was passed directly to processJobs(), locking and running immediately",
49
+ extraJob.attrs.name,
50
+ extraJob.attrs._id
51
+ );
52
+ self._jobsToLock.push(extraJob);
53
+ await lockOnTheFly();
54
+ }
55
+
56
+ /**
57
+ * Returns true if a job of the specified name can be locked.
58
+ * Considers maximum locked jobs at any time if self._lockLimit is > 0
59
+ * Considers maximum locked jobs of the specified name at any time if jobDefinition.lockLimit is > 0
60
+ * @param name name of job to check if we should lock or not
61
+ * @returns whether or not you should lock job
62
+ */
63
+ function shouldLock(name: string): boolean {
64
+ const jobDefinition = definitions[name];
65
+ let shouldLock = true;
66
+ if (self._lockLimit && self._lockLimit <= self._lockedJobs.length) {
67
+ shouldLock = false;
68
+ }
69
+
70
+ if (
71
+ jobDefinition.lockLimit &&
72
+ jobDefinition.lockLimit <= jobDefinition.locked
73
+ ) {
74
+ shouldLock = false;
75
+ }
76
+
77
+ debug("job [%s] lock status: shouldLock = %s", name, shouldLock);
78
+ return shouldLock;
79
+ }
80
+
81
+ /**
82
+ * Internal method that adds jobs to be processed to the local queue
83
+ * @param jobs Jobs to queue
84
+ */
85
+ function enqueueJobs(jobs: Job[] | Job) {
86
+ if (!Array.isArray(jobs)) {
87
+ jobs = [jobs];
88
+ }
89
+
90
+ jobs.forEach((job: Job) => {
91
+ jobQueue.insert(job);
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Internal method that will lock a job and store it on MongoDB
97
+ * This method is called when we immediately start to process a job without using the process interval
98
+ * We do this because sometimes jobs are scheduled but will be run before the next process time
99
+ */
100
+ async function lockOnTheFly() {
101
+ debug("lockOnTheFly: isLockingOnTheFly: %s", self._isLockingOnTheFly);
102
+ // Already running this? Return
103
+ if (self._isLockingOnTheFly) {
104
+ debug("lockOnTheFly() already running, returning");
105
+ return;
106
+ }
107
+
108
+ // Set that we are running this
109
+ self._isLockingOnTheFly = true;
110
+
111
+ // Don't have any jobs to run? Return
112
+ if (self._jobsToLock.length === 0) {
113
+ debug("no jobs to current lock on the fly, returning");
114
+ self._isLockingOnTheFly = false;
115
+ return;
116
+ }
117
+
118
+ // Grab a job that needs to be locked
119
+ const now = new Date();
120
+ const job = self._jobsToLock.pop();
121
+ if (job === undefined) {
122
+ debug(
123
+ "no job was popped from _jobsToLock, extremly unlikely but not impossible concurrency issue"
124
+ );
125
+ self._isLockingOnTheFly = false;
126
+ return;
127
+ }
128
+
129
+ if (self._isJobQueueFilling.has(job.attrs.name)) {
130
+ debug(
131
+ "lockOnTheFly: jobQueueFilling already running for: %s",
132
+ job.attrs.name
133
+ );
134
+ self._isLockingOnTheFly = false;
135
+ return;
136
+ }
137
+
138
+ // If locking limits have been hit, stop locking on the fly.
139
+ // Jobs that were waiting to be locked will be picked up during a
140
+ // future locking interval.
141
+ if (!shouldLock(job.attrs.name)) {
142
+ debug("lock limit hit for: [%s:%s]", job.attrs.name, job.attrs._id);
143
+ self._jobsToLock = [];
144
+ self._isLockingOnTheFly = false;
145
+ return;
146
+ }
147
+
148
+ // Query to run against collection to see if we need to lock it
149
+ const criteria = {
150
+ _id: job.attrs._id,
151
+ lockedAt: null,
152
+ nextRunAt: job.attrs.nextRunAt,
153
+ disabled: { $ne: true },
154
+ };
155
+
156
+ // Update / options for the MongoDB query
157
+ const update = { $set: { lockedAt: now } };
158
+
159
+ // Lock the job in MongoDB!
160
+ const resp = await self._collection.findOneAndUpdate(criteria, update, {
161
+ returnDocument: "after",
162
+ });
163
+
164
+ if (resp.value) {
165
+ // @ts-ignore
166
+ const job = createJob(self, resp.value);
167
+ debug(
168
+ "found job [%s:%s] that can be locked on the fly",
169
+ job.attrs.name,
170
+ job.attrs._id
171
+ );
172
+ self._lockedJobs.push(job);
173
+ definitions[job.attrs.name].locked++;
174
+ enqueueJobs(job);
175
+ jobProcessing();
176
+ }
177
+
178
+ // Mark lock on fly is done for now
179
+ self._isLockingOnTheFly = false;
180
+
181
+ // Re-run in case anything is in the queue
182
+ await lockOnTheFly();
183
+ }
184
+
185
+ /**
186
+ * Internal method used to fill a queue with jobs that can be run
187
+ * @param {String} name fill a queue with specific job name
188
+ * @returns {undefined}
189
+ */
190
+ async function jobQueueFilling(name: string): Promise<void> {
191
+ debug(
192
+ "jobQueueFilling: %s isJobQueueFilling: %s",
193
+ name,
194
+ self._isJobQueueFilling.has(name)
195
+ );
196
+ self._isJobQueueFilling.set(name, true);
197
+
198
+ try {
199
+ // Don't lock because of a limit we have set (lockLimit, etc)
200
+ if (!shouldLock(name)) {
201
+ debug("lock limit reached in queue filling for [%s]", name);
202
+ return; // Goes to finally block
203
+ }
204
+
205
+ // Set the date of the next time we are going to run _processEvery function
206
+ const now = new Date();
207
+ self._nextScanAt = new Date(now.valueOf() + self._processEvery);
208
+
209
+ // For this job name, find the next job to run and lock it!
210
+ const job = await self._findAndLockNextJob(name, definitions[name]);
211
+ // Still have the job?
212
+ // 1. Add it to lock list
213
+ // 2. Add count of locked jobs
214
+ // 3. Queue the job to actually be run now that it is locked
215
+ // 4. Recursively run this same method we are in to check for more available jobs of same type!
216
+ if (job) {
217
+ // Before en-queing job make sure we haven't exceed our lock limits
218
+ if (!shouldLock(name)) {
219
+ debug(
220
+ "lock limit reached before job was returned. Releasing lock on [%s]",
221
+ name
222
+ );
223
+ job.attrs.lockedAt = null;
224
+ await self.saveJob(job);
225
+ return;
226
+ }
227
+
228
+ debug("[%s:%s] job locked while filling queue", name, job.attrs._id);
229
+ self._lockedJobs.push(job);
230
+ definitions[job.attrs.name].locked++;
231
+ enqueueJobs(job);
232
+ await jobQueueFilling(name);
233
+ jobProcessing();
234
+ }
235
+ } catch (error) {
236
+ debug("[%s] job lock failed while filling queue", name, error);
237
+ } finally {
238
+ self._isJobQueueFilling.delete(name);
239
+ }
240
+ }
241
+
242
+ /**
243
+ * Internal method that processes any jobs in the local queue (array)
244
+ * @returns {undefined}
245
+ */
246
+ function jobProcessing() {
247
+ // Ensure we have jobs
248
+ if (jobQueue.length === 0) {
249
+ return;
250
+ }
251
+
252
+ // Store for all sorts of things
253
+ const now = new Date();
254
+
255
+ // Get the next job that is not blocked by concurrency
256
+ const job = jobQueue.returnNextConcurrencyFreeJob(definitions);
257
+
258
+ debug("[%s:%s] about to process job", job.attrs.name, job.attrs._id);
259
+
260
+ // If the 'nextRunAt' time is older than the current time, run the job
261
+ // Otherwise, setTimeout that gets called at the time of 'nextRunAt'
262
+ if (!job.attrs.nextRunAt || job.attrs.nextRunAt <= now) {
263
+ debug(
264
+ "[%s:%s] nextRunAt is in the past, run the job immediately",
265
+ job.attrs.name,
266
+ job.attrs._id
267
+ );
268
+ runOrRetry();
269
+ } else {
270
+ // @ts-expect-error linter complains about Date-arithmetic
271
+ const runIn = job.attrs.nextRunAt - now;
272
+ debug(
273
+ "[%s:%s] nextRunAt is in the future, calling setTimeout(%d)",
274
+ job.attrs.name,
275
+ job.attrs._id,
276
+ runIn
277
+ );
278
+ setTimeout(jobProcessing, runIn);
279
+ }
280
+
281
+ /**
282
+ * Internal method that tries to run a job and if it fails, retries again!
283
+ * @returns {undefined}
284
+ */
285
+ function runOrRetry() {
286
+ if (self._processInterval) {
287
+ // @todo: We should check if job exists
288
+ const job = jobQueue.pop()!;
289
+ const jobDefinition = definitions[job.attrs.name];
290
+ if (
291
+ jobDefinition.concurrency > jobDefinition.running &&
292
+ self._runningJobs.length < self._maxConcurrency
293
+ ) {
294
+ // Get the deadline of when the job is not supposed to go past for locking
295
+ const lockDeadline = new Date(
296
+ Date.now() - jobDefinition.lockLifetime
297
+ );
298
+
299
+ // This means a job has "expired", as in it has not been "touched" within the lockoutTime
300
+ // Remove from local lock
301
+ // NOTE: Shouldn't we update the 'lockedAt' value in MongoDB so it can be picked up on restart?
302
+ if (!job.attrs.lockedAt || job.attrs.lockedAt < lockDeadline) {
303
+ debug(
304
+ "[%s:%s] job lock has expired, freeing it up",
305
+ job.attrs.name,
306
+ job.attrs._id
307
+ );
308
+ self._lockedJobs.splice(self._lockedJobs.indexOf(job), 1);
309
+ jobDefinition.locked--;
310
+
311
+ // If you have few thousand jobs for one worker it would throw "RangeError: Maximum call stack size exceeded"
312
+ // every 5 minutes (using the default options).
313
+ // We need to utilise the setImmedaite() to break the call stack back to 0.
314
+ setImmediate(jobProcessing);
315
+ return;
316
+ }
317
+
318
+ // Add to local "running" queue
319
+ self._runningJobs.push(job);
320
+ jobDefinition.running++;
321
+
322
+ // CALL THE ACTUAL METHOD TO PROCESS THE JOB!!!
323
+ debug("[%s:%s] processing job", job.attrs.name, job.attrs._id);
324
+
325
+ job
326
+ .run()
327
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
328
+ .then((job: any) => processJobResult(job))
329
+ .catch((error: Error) => {
330
+ return job.agenda.emit("error", error);
331
+ });
332
+ } else {
333
+ // Run the job immediately by putting it on the top of the queue
334
+ debug(
335
+ "[%s:%s] concurrency preventing immediate run, pushing job to top of queue",
336
+ job.attrs.name,
337
+ job.attrs._id
338
+ );
339
+ enqueueJobs(job);
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Internal method used to run the job definition
347
+ * @param {Error} err thrown if can't process job
348
+ * @param {Job} job job to process
349
+ */
350
+ function processJobResult(job: Job) {
351
+ const { name } = job.attrs;
352
+
353
+ // Job isn't in running jobs so throw an error
354
+ if (!self._runningJobs.includes(job)) {
355
+ debug(
356
+ "[%s] callback was called, job must have been marked as complete already",
357
+ job.attrs._id
358
+ );
359
+ throw new Error(
360
+ `callback already called - job ${name} already marked complete`
361
+ );
362
+ }
363
+
364
+ // Remove the job from the running queue
365
+ self._runningJobs.splice(self._runningJobs.indexOf(job), 1);
366
+ if (definitions[name].running > 0) {
367
+ definitions[name].running--;
368
+ }
369
+
370
+ // Remove the job from the locked queue
371
+ self._lockedJobs.splice(self._lockedJobs.indexOf(job), 1);
372
+ if (definitions[name].locked > 0) {
373
+ definitions[name].locked--;
374
+ }
375
+
376
+ // Re-process jobs now that one has finished
377
+ jobProcessing();
378
+ }
379
+ };
package/package.json CHANGED
@@ -1,12 +1,14 @@
1
1
  {
2
2
  "name": "agenda",
3
- "version": "4.3.0",
3
+ "version": "5.0.0",
4
4
  "description": "Light weight job scheduler for Node.js",
5
5
  "main": "dist/cjs.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
8
  "es.js",
9
- "dist"
9
+ "dist",
10
+ "lib",
11
+ "tsconfig.json"
10
12
  ],
11
13
  "engines": {
12
14
  "node": ">=12.9.0"
@@ -15,15 +17,15 @@
15
17
  "prepublishOnly": "npm run build",
16
18
  "build": "tsc",
17
19
  "pretest": "npm run build",
18
- "test": "npm run mocha",
20
+ "test": "USE_MONGODB=true npm run mocha",
19
21
  "lint": "eslint --cache --fix lib/**",
20
- "mocha": "USE_MONGODB=true mocha --reporter spec --timeout 8000 --exit -b",
22
+ "mocha": "mocha --reporter spec --timeout 8000 --exit -b",
21
23
  "premocha-debug": "npm run build",
22
- "mocha-debug": "USE_MONGODB=true DEBUG=agenda:**,-agenda:internal:** mocha --reporter spec --timeout 8000 -b",
24
+ "mocha-debug": "DEBUG=agenda:**,-agenda:internal:** mocha --reporter spec --timeout 8000 -b",
23
25
  "premocha-debug-internal": "npm run build",
24
- "mocha-debug-internal": "USE_MONGODB=true DEBUG=agenda:internal:** mocha --reporter spec --timeout 8000 -b",
26
+ "mocha-debug-internal": "DEBUG=agenda:internal:** mocha --reporter spec --timeout 8000 -b",
25
27
  "premocha-debug-all": "npm run build",
26
- "mocha-debug-all": "USE_MONGODB=true DEBUG=agenda:** mocha --reporter spec --timeout 8000 -b",
28
+ "mocha-debug-all": "DEBUG=agenda:** mocha --reporter spec --timeout 8000 -b",
27
29
  "postversion": "npm run docs",
28
30
  "predocs": "npm run build",
29
31
  "docs": "jsdoc --configure .jsdoc.json --verbose ./dist"
@@ -52,12 +54,12 @@
52
54
  "url": "https://github.com/agenda/agenda/issues"
53
55
  },
54
56
  "dependencies": {
55
- "cron-parser": "^3.0.0",
57
+ "cron-parser": "^3.5.0",
56
58
  "date.js": "~0.3.3",
57
- "debug": "~4.3.0",
58
- "human-interval": "~2.0.0",
59
- "moment-timezone": "~0.5.27",
60
- "mongodb": "^4.1.0"
59
+ "debug": "~4.3.4",
60
+ "human-interval": "~2.0.1",
61
+ "moment-timezone": "~0.5.37",
62
+ "mongodb": "^4.11.0"
61
63
  },
62
64
  "devDependencies": {
63
65
  "@types/debug": "4.1.5",
package/tsconfig.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "include": [
3
+ "lib"
4
+ ],
5
+ "compilerOptions": {
6
+ /* Visit https://aka.ms/tsconfig.json to read more about this file */
7
+
8
+ /* Basic Options */
9
+ // "incremental": true, /* Enable incremental compilation */
10
+ "target": "es2016", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
11
+ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
12
+ // "lib": [], /* Specify library files to be included in the compilation. */
13
+ "allowJs": true, /* Allow javascript files to be compiled. */
14
+ // "checkJs": true, /* Report errors in .js files. */
15
+ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
16
+ "declaration": true, /* Generates corresponding '.d.ts' file. */
17
+ "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
18
+ "sourceMap": true, /* Generates corresponding '.map' file. */
19
+ // "outFile": "./", /* Concatenate and emit output to single file. */
20
+ "outDir": "./dist", /* Redirect output structure to the directory. */
21
+ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
22
+ // "composite": true, /* Enable project compilation */
23
+ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
24
+ // "removeComments": true, /* Do not emit comments to output. */
25
+ // "noEmit": true, /* Do not emit outputs. */
26
+ // "importHelpers": true, /* Import emit helpers from 'tslib'. */
27
+ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
28
+ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
29
+
30
+ /* Strict Type-Checking Options */
31
+ "strict": true, /* Enable all strict type-checking options. */
32
+ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
33
+ // "strictNullChecks": true, /* Enable strict null checks. */
34
+ // "strictFunctionTypes": true, /* Enable strict checking of function types. */
35
+ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
36
+ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
37
+ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
38
+ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
39
+
40
+ /* Additional Checks */
41
+ // "noUnusedLocals": true, /* Report errors on unused locals. */
42
+ // "noUnusedParameters": true, /* Report errors on unused parameters. */
43
+ // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
44
+ // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
45
+
46
+ /* Module Resolution Options */
47
+ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
48
+ // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
49
+ // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
50
+ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
51
+ // "typeRoots": [], /* List of folders to include type definitions from. */
52
+ // "types": [], /* Type declaration files to be included in compilation. */
53
+ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
54
+ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
55
+ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
56
+ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
57
+
58
+ /* Source Map Options */
59
+ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
60
+ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
61
+ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
62
+ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
63
+
64
+ /* Experimental Options */
65
+ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
66
+ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
67
+
68
+ /* Advanced Options */
69
+ // "skipLibCheck": true, /* Skip type checking of declaration files. */
70
+ "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
71
+ }
72
+ }