diff --git a/.gitignore b/.gitignore index d84736f4131..9ebcf941e71 100644 --- a/.gitignore +++ b/.gitignore @@ -153,7 +153,7 @@ vowpalwabbit/parser/flatbuffer/generated/example_generated.h test/flatbuffer/*.predict test/flatbuffer/*.stderr node_modules -wasm/vw-wasm.js +wasm/vw.js wasm/package-lock.json /.vs diff --git a/wasm/.npmignore b/wasm/.npmignore index 06c8b6cd329..0f6b9c51162 100644 --- a/wasm/.npmignore +++ b/wasm/.npmignore @@ -4,3 +4,5 @@ example.js node_modules *.txt *.cc +*.ts +!*.d.ts diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index 65f1841f145..02c1741b5c3 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -2,8 +2,8 @@ if(VW_INSTALL) message(FATAL_ERROR "Install not supported for WASM build" ) endif() -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/out/") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/dist/") -add_executable(vw-wasm wasm_wrapper.cc) +add_executable(vw-wasm src/wasm_wrapper.cc) set_target_properties(vw-wasm PROPERTIES LINK_FLAGS "-fexceptions -s WASM=1 -s SINGLE_FILE=1 -s NO_DYNAMIC_EXECUTION=1 --bind -s ALLOW_MEMORY_GROWTH=1 -s MAXIMUM_MEMORY=4GB -s EXPORTED_FUNCTIONS=\"['_malloc', '_free']\" -s MODULARIZE=1 -s EXPORT_NAME=\"vwWasmModule\"") target_link_libraries(vw-wasm PUBLIC vw_explore vw_core "-fexceptions") \ No newline at end of file diff --git a/wasm/documentation.md b/wasm/documentation.md index cb70061b589..6a6d22f83f1 100644 --- a/wasm/documentation.md +++ b/wasm/documentation.md @@ -67,7 +67,7 @@ Closes the logging stream. Logs a warning to the console if there is no logging ### vwExampleLogger.logLineSync(log_file, line) -Takes a string and appends it to the log file. Line is logged in a synchronous manner. +Takes a string and appends it to the log file. Line is logged in a synchronous manner. Every call to this function will open a new file handle, append the line and close the file handle. **Kind**: instance method of [VWExampleLogger](#VWExampleLogger) @@ -175,8 +175,8 @@ Can accept either or both string arguments and a model file. ### workspace.parse(line) ⇒ -Parse a line of text into a VW example. -The example can then be used for prediction or learning. +Parse a line of text into a VW example. +The example can then be used for prediction or learning. finishExample() must be called and then delete() on the example, when it is no longer needed. **Kind**: instance method of [Workspace](#Workspace) @@ -252,7 +252,7 @@ Takes a file location and stores the VW model in binary format in the file. ### workspace.getModelAsArray() ⇒ Uint8Array Gets the VW model in binary format as a Uint8Array that can be saved to a file. -There is no need to delete or free the array returned by this function. +There is no need to delete or free the array returned by this function. If the same array is however used to re-load the model into VW, then the array needs to be stored in wasm memory (see loadModelFromArray) **Kind**: instance method of [Workspace](#Workspace) @@ -281,7 +281,7 @@ The memory must be allocated via the WebAssembly module's _malloc function and s | Param | Type | Description | | --- | --- | --- | -| model_array_ptr | \* | the pre-loaded model's array pointer The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. | +| model_array_ptr | number | the pre-loaded model's array pointer The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. | | model_array_len | number | the pre-loaded model's array length | @@ -300,7 +300,6 @@ A Wrapper around the Wowpal Wabbit C++ library for Contextual Bandit exploration **Extends**: WorkspaceBase * [CbWorkspace](#CbWorkspace) ⇐ WorkspaceBase - * [new CbWorkspace([args_str], [model_file], [model_array])](#new_CbWorkspace_new) * [.predict(example)](#CbWorkspace+predict) ⇒ array * [.learn(example)](#CbWorkspace+learn) * [.addLine(line)](#CbWorkspace+addLine) @@ -317,62 +316,6 @@ A Wrapper around the Wowpal Wabbit C++ library for Contextual Bandit exploration * [.loadModelFromArray(model_array_ptr, model_array_len)](#WorkspaceBase+loadModelFromArray) * [.delete()](#WorkspaceBase+delete) - - -### new CbWorkspace([args_str], [model_file], [model_array]) -Creates a new Vowpal Wabbit workspace for Contextual Bandit exploration algorithms. -Can accept either or both string arguments and a model file. - -**Throws**: - -- Error Throws an error if: -- no argument is provided -- both string arguments and a model file are provided, and the string arguments and arguments defined in the model clash -- both string arguments and a model array are provided, and the string arguments and arguments defined in the model clash -- both a model file and a model array are provided - - -| Param | Type | Description | -| --- | --- | --- | -| [args_str] | string | The arguments that are used to initialize Vowpal Wabbit (optional) | -| [model_file] | string | The path to the file where the model will be loaded from (optional) | -| [model_array] | tuple | The pre-loaded model's array pointer and length (optional). The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. | - -**Example** -```js -const vwPromise = require('./vw.js'); -// require returns a promise because we need to wait for the wasm module to be initialized - -vwPromise.then((vw) => { - let model = new vw.CbWorkspace({ args_str: "--cb_explore_adf" }); - let vwLogger = new vw.VWExampleLogger(); - - vwLogger.startLogStream("mylogfile.txt"); - - let example = { - text_context: `shared | s_1 s_2 - | a_1 b_1 c_1 - | a_2 b_2 c_2 - | a_3 b_3 c_3`, - }; - - let prediction = model.predictAndSample(example); - - example.labels = [{ action: prediction["action"], cost: 1.0, probability: prediction["score"] }]; - - model.learn(example); - vwLogger.logCBExampleToStream(example); - - model.saveModelToFile("my_model.vw"); - vwLogger.endLogStream(); - model.delete(); - - let model2 = new vw.CbWorkspace({ model_file: "my_model.vw" }); - console.log(model2.predict(example)); - console.log(model2.predictAndSample(example)); - model2.delete(); -}); -``` ### cbWorkspace.predict(example) ⇒ array @@ -551,7 +494,7 @@ Takes a file location and stores the VW model in binary format in the file. ### cbWorkspace.getModelAsArray() ⇒ Uint8Array Gets the VW model in binary format as a Uint8Array that can be saved to a file. -There is no need to delete or free the array returned by this function. +There is no need to delete or free the array returned by this function. If the same array is however used to re-load the model into VW, then the array needs to be stored in wasm memory (see loadModelFromArray) **Kind**: instance method of [CbWorkspace](#CbWorkspace) @@ -580,7 +523,7 @@ The memory must be allocated via the WebAssembly module's _malloc function and s | Param | Type | Description | | --- | --- | --- | -| model_array_ptr | \* | the pre-loaded model's array pointer The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. | +| model_array_ptr | number | the pre-loaded model's array pointer The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. | | model_array_len | number | the pre-loaded model's array length | diff --git a/wasm/package.json b/wasm/package.json index 8370d35099e..5828228cd65 100644 --- a/wasm/package.json +++ b/wasm/package.json @@ -3,16 +3,25 @@ "version": "0.0.1", "description": "wasm bindings for vowpal wabbit", "exports": { - "require": "./vw.js" + "require": "./dist/vw.js" }, - "main": "\"\"", + "main": "dist/vw.js", + "files": [ + "dist/", + "src/**/*.ts", + "!src/**/*.cc" + ], "devDependencies": { + "@types/node": "^20.2.1", "jsdoc-to-markdown": "^8.0.0", - "mocha": "^9.1.2" + "mocha": "^9.1.2", + "typescript": "^5.0.4" }, "scripts": { + "postinstall": "npm run build", + "build": "tsc", "test": "node --experimental-wasm-threads ./node_modules/mocha/bin/mocha --delay", - "docs": "jsdoc2md ./vw.js > documentation.md" + "docs": "jsdoc2md ./dist/vw.js > documentation.md" }, "dependencies": { "out": "^1.1.0" diff --git a/wasm/vw.js b/wasm/src/vw.ts similarity index 89% rename from wasm/vw.js rename to wasm/src/vw.ts index 547ff87d360..7470cb9c683 100644 --- a/wasm/vw.js +++ b/wasm/src/vw.ts @@ -1,6 +1,7 @@ -const fs = require('fs'); -const crypto = require('crypto'); -const VWWasmModule = require('./out/vw-wasm.js'); +import fs from 'fs'; +import crypto from 'crypto'; + +const VWWasmModule = require('./vw-wasm.js'); // internals @@ -17,6 +18,9 @@ const ProblemType = * @class */ class VWExampleLogger { + _outputLogStream: fs.WriteStream | null; + _log_file: string | null; + constructor() { this._outputLogStream = null; this._log_file = null; @@ -29,7 +33,7 @@ class VWExampleLogger { * @param {string} log_file the path to the file where the log will be appended to * @throws {Error} Throws an error if another logging stream has already been started */ - startLogStream(log_file) { + startLogStream(log_file: string) { if (this._outputLogStream !== null) { throw new Error("Can not start log stream, another log stream is currently active. Call endLogStream first if you want to change the log file. Current log file: " + this._log_file); } @@ -45,7 +49,7 @@ class VWExampleLogger { * @param {string} line the line to be appended to the log file * @throws {Error} Throws an error if no logging stream has been started */ - logLineToStream(line) { + logLineToStream(line: string) { if (this._outputLogStream !== null) { this._outputLogStream.write(line); } @@ -77,7 +81,7 @@ class VWExampleLogger { * @param {string} line the line to be appended to the log file * @throws {Error} Throws an error if another logging stream has already been started */ - logLineSync(log_file, line) { + logLineSync(log_file: string, line: string) { if (this._outputLogStream !== null && this._log_file === log_file) { throw new Error("Can not call logLineSync on log file while the same file has an async log writer active. Call endLogStream first. Log file: " + log_file); } @@ -92,7 +96,7 @@ class VWExampleLogger { * @returns {string} the string representation of the CB example * @throws {Error} Throws an error if the example is malformed */ - CBExampleToString(example) { + CBExampleToString(example: { text_context: string, labels: Array<{ action: number, cost: number, probability: number }> }): string { let context = "" if (example.hasOwnProperty('text_context')) { context = example.text_context; @@ -101,7 +105,8 @@ class VWExampleLogger { throw new Error("Can not log example, there is no context available"); } - const lines = context.split("\n").map((substr) => substr.trim()); + const lines = context.trim().split("\n").map((substr) => substr.trim()); + lines.push(""); lines.push(""); if (example.hasOwnProperty("labels") && example["labels"].length > 0) { @@ -129,7 +134,7 @@ class VWExampleLogger { * @param {object} example a CB example that will be stringified and appended to the log file * @throws {Error} Throws an error if no logging stream has been started */ - logCBExampleToStream(example) { + logCBExampleToStream(example: { text_context: string, labels: Array<{ action: number, cost: number, probability: number }> }) { let ex_str = this.CBExampleToString(example); this.logLineToStream(ex_str); } @@ -143,17 +148,21 @@ class VWExampleLogger { * @param {object} example a CB example that will be stringified and appended to the log file * @throws {Error} Throws an error if another logging stream has already been started */ - logCBExampleSync(log_file, example) { + logCBExampleSync(log_file: string, example: { text_context: string, labels: Array<{ action: number, cost: number, probability: number }> }) { let ex_str = this.CBExampleToString(example); this.logLineSync(log_file, ex_str); } }; module.exports = new Promise((resolve) => { - VWWasmModule().then(moduleInstance => { + VWWasmModule().then((moduleInstance: any) => { class WorkspaceBase { - constructor(type, { args_str, model_file, model_array = [] } = {}) { - + _args_str: string | undefined; + _instance: any; + + constructor(type: string, { args_str, model_file, model_array }: + { args_str?: string, model_file?: string, model_array?: [number | undefined, number | undefined] } = {}) { + let vwModelConstructor = null; if (type === ProblemType.All) { vwModelConstructor = moduleInstance.VWModel; @@ -163,32 +172,36 @@ module.exports = new Promise((resolve) => { else { throw new Error("Unknown model type"); } - - const [model_array_ptr, model_array_len] = model_array; - + + let model_array_ptr: number | undefined = undefined; + let model_array_len: number | undefined = undefined; + if (model_array !== undefined) { + [model_array_ptr, model_array_len] = model_array; + } + let model_array_defined = model_array_ptr !== undefined && model_array_len !== undefined && model_array_ptr !== null && model_array_len > 0; - + if (args_str === undefined && model_file === undefined && !model_array_defined) { throw new Error("Can not initialize vw object without args_str or a model_file or a model_array"); } - + if (model_file !== undefined && model_array_defined) { throw new Error("Can not initialize vw object with both model_file and model_array"); } - + this._args_str = args_str; if (args_str === undefined) { this._args_str = ""; } - + if (model_file !== undefined) { let modelBuffer = fs.readFileSync(model_file); let ptr = moduleInstance._malloc(modelBuffer.byteLength); let heapBytes = new Uint8Array(moduleInstance.HEAPU8.buffer, ptr, modelBuffer.byteLength); heapBytes.set(new Uint8Array(modelBuffer)); - + this._instance = new vwModelConstructor(this._args_str, ptr, modelBuffer.byteLength); - + moduleInstance._free(ptr); } else if (model_array_defined) { @@ -197,10 +210,10 @@ module.exports = new Promise((resolve) => { else { this._instance = new vwModelConstructor(this._args_str); } - + return this; } - + /** * Returns the enum value of the prediction type corresponding to the problem type of the model * @returns enum value of prediction type @@ -208,37 +221,37 @@ module.exports = new Promise((resolve) => { predictionType() { return this._instance.predictionType(); } - + /** * The current total sum of the progressive validation loss * * @returns {number} the sum of all losses accumulated by the model */ - sumLoss() { + sumLoss(): number { return this._instance.sumLoss(); } - + /** * * Takes a file location and stores the VW model in binary format in the file. * * @param {string} model_file the path to the file where the model will be saved */ - saveModelToFile(model_file) { + saveModelToFile(model_file: string) { let char_vector = this._instance.getModel(); const size = char_vector.size(); const uint8Array = new Uint8Array(size); - + for (let i = 0; i < size; ++i) { uint8Array[i] = char_vector.get(i); } - + fs.writeFileSync(model_file, Buffer.from(uint8Array)); - + char_vector.delete(); } - - + + /** * Gets the VW model in binary format as a Uint8Array that can be saved to a file. * There is no need to delete or free the array returned by this function. @@ -246,7 +259,7 @@ module.exports = new Promise((resolve) => { * * @returns {Uint8Array} the VW model in binary format */ - getModelAsArray() { + getModelAsArray(): Uint8Array { let char_vector = this._instance.getModel(); const size = char_vector.size(); const uint8Array = new Uint8Array(size); @@ -254,17 +267,17 @@ module.exports = new Promise((resolve) => { uint8Array[i] = char_vector.get(i); } char_vector.delete(); - + return uint8Array; } - + /** * * Takes a file location and loads the VW model from the file. * * @param {string} model_file the path to the file where the model will be loaded from */ - loadModelFromFile(model_file) { + loadModelFromFile(model_file: string) { let modelBuffer = fs.readFileSync(model_file); let ptr = moduleInstance._malloc(modelBuffer.byteLength); let heapBytes = new Uint8Array(moduleInstance.HEAPU8.buffer, ptr, modelBuffer.byteLength); @@ -272,19 +285,19 @@ module.exports = new Promise((resolve) => { this._instance.loadModelFromBuffer(ptr, modelBuffer.byteLength); moduleInstance._free(ptr); } - + /** * Takes a model in an array binary format and loads it into the VW instance. * The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. * - * @param {*} model_array_ptr the pre-loaded model's array pointer + * @param {number} model_array_ptr the pre-loaded model's array pointer * The memory must be allocated via the WebAssembly module's _malloc function and should later be freed via the _free function. * @param {number} model_array_len the pre-loaded model's array length */ - loadModelFromArray(model_array_ptr, model_array_len) { + loadModelFromArray(model_array_ptr: number, model_array_len: number) { this._instance.loadModelFromBuffer(model_array_ptr, model_array_len); } - + /** * Deletes the underlying VW instance. This function should be called when the instance is no longer needed. */ @@ -292,7 +305,7 @@ module.exports = new Promise((resolve) => { this._instance.delete(); } }; - + /** * A Wrapper around the Wowpal Wabbit C++ library. * @class @@ -314,10 +327,11 @@ module.exports = new Promise((resolve) => { * - both string arguments and a model array are provided, and the string arguments and arguments defined in the model clash * - both a model file and a model array are provided */ - constructor({ args_str, model_file, model_array } = {}) { + constructor({ args_str, model_file, model_array }: + { args_str?: string, model_file?: string, model_array?: [number | undefined, number | undefined] } = {}) { super(ProblemType.All, { args_str, model_file, model_array }); } - + /** * Parse a line of text into a VW example. * The example can then be used for prediction or learning. @@ -326,39 +340,39 @@ module.exports = new Promise((resolve) => { * @param {string} line * @returns a parsed vw example that can be used for prediction or learning */ - parse(line) { + parse(line: string): object { return this._instance.parse(line); } - + /** * Calls vw predict on the example and returns the prediction. * * @param {object} example returned from parse() * @returns the prediction with a type corresponding to the reduction that was used */ - predict(example) { + predict(example: object) { return this._instance.predict(example); } - + /** * Calls vw learn on the example and updates the model * * @param {object} example returned from parse() */ - learn(example) { + learn(example: object) { return this._instance.learn(example); } - + /** * Cleans the example and returns it to the pool of available examples. delete() must also be called on the example object * * @param {object} example returned from parse() */ - finishExample(example) { + finishExample(example: object) { return this._instance.finishExample(example); } }; - + /** * A Wrapper around the Wowpal Wabbit C++ library for Contextual Bandit exploration algorithms. * @class @@ -380,12 +394,14 @@ module.exports = new Promise((resolve) => { * - both string arguments and a model array are provided, and the string arguments and arguments defined in the model clash * - both a model file and a model array are provided */ - - constructor({ args_str, model_file, model_array } = {}) { + + _ex: string; + constructor({ args_str, model_file, model_array }: + { args_str?: string, model_file?: string, model_array?: [number | undefined, number | undefined] } = {}) { super(ProblemType.CB, { args_str, model_file, model_array }); this._ex = ""; } - + /** * Takes a CB example and returns an array of (action, score) pairs, representing the probability mass function over the available actions * The returned pmf can be used with samplePmf to sample an action @@ -396,10 +412,10 @@ module.exports = new Promise((resolve) => { * @param {object} example the example object that will be used for prediction * @returns {array} probability mass function, an array of action,score pairs that was returned by predict */ - predict(example) { + predict(example: object) { return this._instance.predict(example); } - + /** * Takes a CB example and uses it to update the model * @@ -415,17 +431,17 @@ module.exports = new Promise((resolve) => { * * @param {object} example the example object that will be used for prediction */ - learn(example) { + learn(example: object) { return this._instance.learn(example); } - + /** * Accepts a CB example (in text format) line by line. Once a full CB example is passed in it will call learnFromString. * This is intended to be used with files that have CB examples, that were logged using logCBExampleToStream and are being read line by line. * * @param {string} line a string representing a line from a CB example in text Vowpal Wabbit format */ - addLine(line) { + addLine(line: string) { if (line.trim() === '') { this.learnFromString(this._ex); this._ex = ""; @@ -433,27 +449,27 @@ module.exports = new Promise((resolve) => { else { this._ex = this._ex + line + "\n"; } - + } - + /** * Takes a full multiline CB example in text format and uses it to update the model. This is intended to be used with examples that are logged to a file using logCBExampleToStream. * * @param {string} example a string representing the CB example in text Vowpal Wabbit format * @throws {Error} Throws an error if the example is an object with a label and/or a text_context */ - learnFromString(example) { + learnFromString(example: string) { if (example.hasOwnProperty("labels") || example.hasOwnProperty("text_context")) { throw new Error("Example should not have a label or a text_context when using learnFromString, the label and context should just be in the string"); } - + let ex = { text_context: example } - + return this._instance.learnFromString(ex); } - + /** * * Takes an exploration prediction (array of action, score pairs) and returns a single action and score, @@ -466,13 +482,13 @@ module.exports = new Promise((resolve) => { * - uuid: the uuid that was passed to the predict function * @throws {Error} Throws an error if the input is not an array of action,score pairs */ - samplePmf(pmf) { + samplePmf(pmf: Array): object { let uuid = crypto.randomUUID(); let ret = this._instance._samplePmf(pmf, uuid); ret["uuid"] = uuid; return ret; } - + /** * * Takes an exploration prediction (array of action, score pairs) and a unique id that is used to seed the sampling, @@ -486,12 +502,12 @@ module.exports = new Promise((resolve) => { * - uuid: the uuid that was passed to the predict function * @throws {Error} Throws an error if the input is not an array of action,score pairs */ - samplePmfWithUUID(pmf, uuid) { + samplePmfWithUUID(pmf: Array, uuid: string): object { let ret = this._instance._samplePmf(pmf, uuid); ret["uuid"] = uuid; return ret; } - + /** * * Takes an example with a text_context field and calls predict. The prediction (a probability mass function over the available actions) @@ -505,13 +521,13 @@ module.exports = new Promise((resolve) => { * - uuid: the uuid that was passed to the predict function * @throws {Error} if there is no text_context field in the example */ - predictAndSample(example) { + predictAndSample(example: object): object { let uuid = crypto.randomUUID(); let ret = this._instance._predictAndSample(example, uuid); ret["uuid"] = uuid; return ret; } - + /** * * Takes an example with a text_context field and calls predict, and a unique id that is used to seed the sampling. @@ -525,14 +541,14 @@ module.exports = new Promise((resolve) => { * - uuid: the uuid that was passed to the predict function * @throws {Error} if there is no text_context field in the example */ - predictAndSampleWithUUID(example, uuid) { + predictAndSampleWithUUID(example: object, uuid: string): object { let ret = this._instance._predictAndSample(example, uuid); ret["uuid"] = uuid; return ret; } }; - - function getExceptionMessage(exception) { + + function getExceptionMessage(exception: number): string { return moduleInstance.getExceptionMessage(exception) }; @@ -558,10 +574,10 @@ module.exports = new Promise((resolve) => { Workspace: Workspace, CbWorkspace: CbWorkspace, Prediction: Prediction, - VWExampleLogger, VWExampleLogger, + VWExampleLogger: VWExampleLogger, getExceptionMessage: getExceptionMessage, wasmModule: moduleInstance } ) }) -}) +}); diff --git a/wasm/wasm_wrapper.cc b/wasm/src/wasm_wrapper.cc similarity index 100% rename from wasm/wasm_wrapper.cc rename to wasm/src/wasm_wrapper.cc diff --git a/wasm/example.js b/wasm/test/example.js similarity index 98% rename from wasm/example.js rename to wasm/test/example.js index aff1af9e161..db8577d728d 100644 --- a/wasm/example.js +++ b/wasm/test/example.js @@ -1,4 +1,4 @@ -const vwPromise = require('./vw.js'); +const vwPromise = require('vowpalwabbit'); const fs = require('fs'); // Delay test execution until the WASM VWModule is ready diff --git a/wasm/test/test.js b/wasm/test/test.js index f3c0cef8347..16b6adaae5f 100644 --- a/wasm/test/test.js +++ b/wasm/test/test.js @@ -4,7 +4,7 @@ const fs = require('fs'); const readline = require('readline'); const path = require('path'); -const vwPromise = require('../vw.js'); +const vwPromise = require('vowpalwabbit'); let vw; async function run() { diff --git a/wasm/tsconfig.json b/wasm/tsconfig.json new file mode 100644 index 00000000000..1b23c5bb354 --- /dev/null +++ b/wasm/tsconfig.json @@ -0,0 +1,110 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "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. */ + // "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. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* 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. */ + // "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'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "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. */ + // "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. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "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. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not 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. */ + // "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. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "exclude": ["node_modules", "**/*.spec.ts", "test/example.js", "**/*.md"] +}