diff --git a/docker-compose.yml b/docker-compose.yml index e5ec067..abadae2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -45,5 +45,5 @@ services: # ports: # - "1521:1521" # environment: -# DB_SID: "ORCLCDB" -# SYS_PASSWORD: "Oradoc_db1" +# DB_SID: "sys" +# SYS_PASSWORD: "ORCLCDB" diff --git a/package-lock.json b/package-lock.json index ae0859b..a8f0405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6056,9 +6056,9 @@ } }, "oracledb": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-2.0.15.tgz", - "integrity": "sha1-9+IBtp+ngjUIFV6fNKumXVdCbx0=" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/oracledb/-/oracledb-2.2.0.tgz", + "integrity": "sha512-ywwalyryeJYb5dr1JScyPcNxCeN0zExrKLtorSdptBZqhfS5Dp9KLgGOExc+XMMfEejXGtC/RfiDxKaGn6+VJA==" }, "orchestrator": { "version": "0.3.8", diff --git a/package.json b/package.json index aaf54a8..a493eae 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "handlebars": "^4.0.11", "mssql": "^4.0.4", "mysql": "^2.15.0", - "oracledb": "^2.0.15", + "oracledb": "^2.2.0", "pg": "^7.4.0", "reflect-metadata": "^0.1.10", "typeorm": "0.2.0-alpha.44", diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 337fc4d..8f33fe9 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -23,13 +23,13 @@ export class OracleDriver extends AbstractDriver { } async GetAllTables(schema: string): Promise { - let response: any[][] = (await this.Connection.execute( + let response: { TABLE_NAME: string }[] = (await this.Connection.execute( ` SELECT TABLE_NAME FROM all_tables WHERE owner = (select user from dual)` )).rows!; let ret: EntityInfo[] = []; response.forEach(val => { let ent: EntityInfo = new EntityInfo(); - ent.EntityName = val[0]; + ent.EntityName = val.TABLE_NAME; ent.Columns = []; ent.Indexes = []; ret.push(ent); @@ -40,39 +40,153 @@ export class OracleDriver extends AbstractDriver { entities: EntityInfo[], schema: string ): Promise { - let response: any[][] = (await this.Connection - .execute(`SELECT TABLE_NAME, COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH, - DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN - FROM USER_TAB_COLUMNS`)).rows!; + let response: { + TABLE_NAME: string; + COLUMN_NAME: string; + DATA_DEFAULT: string; + NULLABLE: string; + DATA_TYPE: string; + DATA_LENGTH: number; + DATA_PRECISION: number; + DATA_SCALE: number; + IDENTITY_COLUMN: string; + IS_UNIQUE: Number; + }[] = (await this.Connection + .execute(`SELECT utc.TABLE_NAME, utc.COLUMN_NAME, DATA_DEFAULT, NULLABLE, DATA_TYPE, DATA_LENGTH, + DATA_PRECISION, DATA_SCALE, IDENTITY_COLUMN, + (select count(*) from USER_CONS_COLUMNS ucc + JOIN USER_CONSTRAINTS uc ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME and uc.CONSTRAINT_TYPE='U' + where ucc.column_name = utc.COLUMN_NAME AND ucc.table_name = utc.TABLE_NAME) IS_UNIQUE + FROM USER_TAB_COLUMNS utc`)).rows!; entities.forEach(ent => { response .filter(filterVal => { - return filterVal[0] == ent.EntityName; + return filterVal.TABLE_NAME == ent.EntityName; }) .forEach(resp => { let colInfo: ColumnInfo = new ColumnInfo(); - colInfo.name = resp[1]; - colInfo.is_nullable = resp[3] == "Y" ? true : false; - colInfo.is_generated = resp[8] == "YES" ? true : false; - colInfo.default = resp[2]; - switch (resp[4].toLowerCase()) { - case "number": - colInfo.ts_type = "number"; - colInfo.sql_type = "int"; - colInfo.lenght = resp[5] > 0 ? resp[5] : null; + colInfo.name = resp.COLUMN_NAME; + colInfo.is_nullable = resp.NULLABLE == "Y" ? true : false; + colInfo.is_generated = + resp.IDENTITY_COLUMN == "YES" ? true : false; + colInfo.default = + !resp.DATA_DEFAULT || resp.DATA_DEFAULT.includes('"') + ? null + : resp.DATA_DEFAULT; + colInfo.is_unique = resp.IS_UNIQUE > 0; + resp.DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); + colInfo.sql_type = resp.DATA_TYPE.toLowerCase(); + switch (resp.DATA_TYPE.toLowerCase()) { + case "char": + colInfo.ts_type = "string"; + break; + case "nchar": + colInfo.ts_type = "string"; + break; + case "nvarchar2": + colInfo.ts_type = "string"; break; case "varchar2": + colInfo.ts_type = "string"; + break; + case "long": + colInfo.ts_type = "string"; + break; + case "raw": + colInfo.ts_type = "Buffer"; + break; + case "long raw": + colInfo.ts_type = "Buffer"; + break; + case "number": + colInfo.ts_type = "number"; + break; + case "numeric": + colInfo.ts_type = "number"; + break; + case "float": + colInfo.ts_type = "number"; + break; + case "dec": + colInfo.ts_type = "number"; + break; + case "decimal": + colInfo.ts_type = "number"; + break; + case "integer": + colInfo.ts_type = "number"; + break; + case "int": + colInfo.ts_type = "number"; + break; + case "smallint": + colInfo.ts_type = "number"; + break; + case "real": + colInfo.ts_type = "number"; + break; + case "double precision": + colInfo.ts_type = "number"; + break; + case "date": + colInfo.ts_type = "Date"; + break; + case "timestamp": + colInfo.ts_type = "Date"; + break; + case "timestamp with time zone": + colInfo.ts_type = "Date"; + break; + case "timestamp with local time zone": + colInfo.ts_type = "Date"; + break; + case "interval year to month": + colInfo.ts_type = "string"; + break; + case "interval day to second": + colInfo.ts_type = "string"; + break; + case "bfile": + colInfo.ts_type = "Buffer"; + break; + case "blob": + colInfo.ts_type = "Buffer"; + break; + case "clob": + colInfo.ts_type = "string"; + break; + case "nclob": + colInfo.ts_type = "string"; + break; + case "rowid": + colInfo.ts_type = "number"; + break; + case "urowid": colInfo.ts_type = "number"; - colInfo.sql_type = "smallint"; - colInfo.lenght = resp[5] > 0 ? resp[5] : null; break; default: TomgUtils.LogError( - "Unknown column type:" + resp[4] + "Unknown column type:" + resp.DATA_TYPE ); break; } + if ( + this.ColumnTypesWithPrecision.some( + v => v == colInfo.sql_type + ) + ) { + colInfo.numericPrecision = resp.DATA_PRECISION; + colInfo.numericScale = resp.DATA_SCALE; + } + if ( + this.ColumnTypesWithLength.some( + v => v == colInfo.sql_type + ) + ) { + colInfo.lenght = + resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : null; + } if (colInfo.sql_type) ent.Columns.push(colInfo); }); @@ -83,8 +197,14 @@ export class OracleDriver extends AbstractDriver { entities: EntityInfo[], schema: string ): Promise { - let response: any[][] = (await this.Connection - .execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END + let response: { + COLUMN_NAME: string; + TABLE_NAME: string; + INDEX_NAME: string; + UNIQUENESS: string; + ISPRIMARYKEY: number; + }[] = (await this.Connection + .execute(`SELECT ind.TABLE_NAME, ind.INDEX_NAME, col.COLUMN_NAME,ind.UNIQUENESS, CASE WHEN uc.CONSTRAINT_NAME IS NULL THEN 0 ELSE 1 END ISPRIMARYKEY FROM USER_INDEXES ind JOIN USER_IND_COLUMNS col ON ind.INDEX_NAME=col.INDEX_NAME LEFT JOIN USER_CONSTRAINTS uc ON uc.INDEX_NAME = ind.INDEX_NAME @@ -93,29 +213,27 @@ export class OracleDriver extends AbstractDriver { entities.forEach(ent => { response .filter(filterVal => { - return filterVal[0] == ent.EntityName; + return filterVal.TABLE_NAME == ent.EntityName; }) .forEach(resp => { let indexInfo: IndexInfo = {}; let indexColumnInfo: IndexColumnInfo = {}; if ( ent.Indexes.filter(filterVal => { - return filterVal.name == resp[1]; + return filterVal.name == resp.INDEX_NAME; }).length > 0 ) { indexInfo = ent.Indexes.filter(filterVal => { - return filterVal.name == resp[1]; + return filterVal.name == resp.INDEX_NAME; })[0]; } else { indexInfo.columns = []; - indexInfo.name = resp[1]; - indexInfo.isUnique = resp[3] == "UNIQUE" ? true : false; - indexInfo.isPrimaryKey = resp[4] == 1 ? true : false; + indexInfo.name = resp.INDEX_NAME; + indexInfo.isUnique = resp.UNIQUENESS == "UNIQUE"; + indexInfo.isPrimaryKey = resp.ISPRIMARYKEY == 1; ent.Indexes.push(indexInfo); } - indexColumnInfo.name = resp[2]; - // indexColumnInfo.isIncludedColumn = resp.is_included_column == 1 ? true : false; - // indexColumnInfo.isDescending = resp.is_descending_key == 1 ? true : false; + indexColumnInfo.name = resp.COLUMN_NAME; indexInfo.columns.push(indexColumnInfo); }); }); @@ -126,36 +244,44 @@ export class OracleDriver extends AbstractDriver { entities: EntityInfo[], schema: string ): Promise { - let response: any[][] = (await this.Connection - .execute(`select owner.TABLE_NAME ownTbl,ownCol.POSITION,ownCol.COLUMN_NAME, - child.TABLE_NAME,childCol.COLUMN_NAME, + let response: { + OWNER_TABLE_NAME: string; + OWNER_POSITION: string; + OWNER_COLUMN_NAME: string; + CHILD_TABLE_NAME: string; + CHILD_COLUMN_NAME: string; + DELETE_RULE: "RESTRICT" | "CASCADE" | "SET NULL" | "NO ACTION"; + CONSTRAINT_NAME: string; + }[] = (await this.Connection + .execute(`select owner.TABLE_NAME OWNER_TABLE_NAME,ownCol.POSITION OWNER_POSITION,ownCol.COLUMN_NAME OWNER_COLUMN_NAME, + child.TABLE_NAME CHILD_TABLE_NAME ,childCol.COLUMN_NAME CHILD_COLUMN_NAME, owner.DELETE_RULE, - 4,owner.CONSTRAINT_NAME + owner.CONSTRAINT_NAME from user_constraints owner join user_constraints child on owner.r_constraint_name=child.CONSTRAINT_NAME and child.constraint_type in ('P','U') JOIN USER_CONS_COLUMNS ownCol ON owner.CONSTRAINT_NAME = ownCol.CONSTRAINT_NAME JOIN USER_CONS_COLUMNS childCol ON child.CONSTRAINT_NAME = childCol.CONSTRAINT_NAME AND ownCol.POSITION=childCol.POSITION - ORDER BY ownTbl ASC, owner.CONSTRAINT_NAME ASC, ownCol.POSITION ASC`)) + ORDER BY OWNER_TABLE_NAME ASC, owner.CONSTRAINT_NAME ASC, OWNER_POSITION ASC`)) .rows!; let relationsTemp: RelationTempInfo[] = []; response.forEach(resp => { let rels = relationsTemp.find(val => { - return val.object_id == resp[6]; + return val.object_id == resp.CONSTRAINT_NAME; }); if (rels == undefined) { rels = {}; rels.ownerColumnsNames = []; rels.referencedColumnsNames = []; - rels.actionOnDelete = resp[5]; + rels.actionOnDelete = resp.DELETE_RULE; rels.actionOnUpdate = "NO ACTION"; - rels.object_id = resp[6]; - rels.ownerTable = resp[0]; - rels.referencedTable = resp[3]; + rels.object_id = resp.CONSTRAINT_NAME; + rels.ownerTable = resp.OWNER_TABLE_NAME; + rels.referencedTable = resp.CHILD_TABLE_NAME; relationsTemp.push(rels); } - rels.ownerColumnsNames.push(resp[2]); - rels.referencedColumnsNames.push(resp[4]); + rels.ownerColumnsNames.push(resp.OWNER_COLUMN_NAME); + rels.referencedColumnsNames.push(resp.CHILD_COLUMN_NAME); }); relationsTemp.forEach(relationTmp => { let ownerEntity = entities.find(entitity => { @@ -298,20 +424,32 @@ export class OracleDriver extends AbstractDriver { password: string, ssl: boolean ) { - let config: any /*Oracle.IConnectionAttributes*/ = { - user: user, - password: password, - // connectString: `${server}:${port}/ORCLCDB.localdomain/${database}`, - connectString: `${server}:${port}/${database}`, - externalAuth: ssl - }; - + let config: any; + if (user == String(process.env.ORACLE_UsernameSys)) { + config /*Oracle.IConnectionAttributes*/ = { + user: user, + password: password, + // connectString: `${server}:${port}/ORCLCDB.localdomain/${database}`, + connectString: `${server}:${port}/${database}`, + externalAuth: ssl, + privilege: this.Oracle.SYSDBA + }; + } else { + config /*Oracle.IConnectionAttributes*/ = { + user: user, + password: password, + // connectString: `${server}:${port}/ORCLCDB.localdomain/${database}`, + connectString: `${server}:${port}/${database}`, + externalAuth: ssl + }; + } let that = this; let promise = new Promise((resolve, reject) => { this.Oracle.getConnection(config, function(err, connection) { if (!err) { //Connection successfull that.Connection = connection; + resolve(true); } else { TomgUtils.LogError( @@ -327,10 +465,23 @@ export class OracleDriver extends AbstractDriver { await promise; } - async CreateDB(dbName: string) {} + async CreateDB(dbName: string) { + var x = await this.Connection.execute( + `CREATE USER ${dbName} IDENTIFIED BY ${String( + process.env.ORACLE_Password + )}` + ); + + var y = await this.Connection.execute(`GRANT CONNECT TO ${dbName}`); + } async UseDB(dbName: string) {} - async DropDB(dbName: string) {} + async DropDB(dbName: string) { + var x = await this.Connection.execute(`DROP USER ${dbName} CASCADE`); + } async CheckIfDBExists(dbName: string): Promise { - return true; + var x = await this.Connection.execute( + `select count(*) as CNT from dba_users where username='${dbName.toUpperCase()}'` + ); + return x.rows[0][0] > 0 || x.rows[0].CNT; } } diff --git a/src/entity.mst b/src/entity.mst index a04bd48..e252dbb 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -11,7 +11,8 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Man {{^relations}} @Column("{{sql_type}}",{ {{#is_generated}} generated:true,{{/is_generated}}{{#is_nullable}} nullable:true,{{/is_nullable}}{{^is_nullable}} - nullable:false,{{/is_nullable}}{{#lenght}} + nullable:false,{{/is_nullable}}{{#is_unique}} + unique: true,{{/is_unique}}{{#lenght}} length:{{.}},{{/lenght}}{{#width}} width:{{.}},{{/width}}{{#default}} default:"{{.}}",{{/default}}{{#numericPrecision}} diff --git a/src/index.ts b/src/index.ts index cac693e..a2a0804 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,7 @@ var argv = Yargs.usage( .option("e", { alias: "engine", describe: "Database engine.", - choices: ["mssql", "postgres", "mysql", "mariadb"], + choices: ["mssql", "postgres", "mysql", "mariadb", "oracle"], default: "mssql" }) .option("o", { diff --git a/src/models/ColumnInfo.ts b/src/models/ColumnInfo.ts index ab22efc..6abea04 100644 --- a/src/models/ColumnInfo.ts +++ b/src/models/ColumnInfo.ts @@ -7,6 +7,7 @@ export class ColumnInfo { name: string = ""; default: string | null = null; is_nullable: boolean = false; + is_unique: boolean = false; ts_type: | "number" | "string" diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index bb48c1e..7ca892a 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -106,6 +106,7 @@ describe('MssqlDriver', function () { sql_type: 'int', ts_type: 'number', enumOptions: null, + is_unique:false, relations: [] }) let result = await driver.GetCoulmnsFromEntity(entities, 'schema'); diff --git a/test/integration/entityTypes.test.ts b/test/integration/entityTypes.test.ts index 6e33b2c..9a7bd0d 100644 --- a/test/integration/entityTypes.test.ts +++ b/test/integration/entityTypes.test.ts @@ -24,6 +24,7 @@ describe("Platform specyfic types", async function () { if (process.env.MYSQL_Skip == '0') dbDrivers.push('mysql') if (process.env.MARIADB_Skip == '0') dbDrivers.push('mariadb') if (process.env.MSSQL_Skip == '0') dbDrivers.push('mssql') + if (process.env.ORACLE_Skip == '0') dbDrivers.push('oracle') let examplesPathJS = path.resolve(process.cwd(), 'dist/test/integration/entityTypes') @@ -55,6 +56,9 @@ describe("Platform specyfic types", async function () { case 'mariadb': engine = await GTU.createMariaDBModels(filesOrgPathJS, resultsPath) break; + case 'oracle': + engine = await GTU.createOracleDBModels(filesOrgPathJS, resultsPath) + break; default: console.log(`Unknown engine type`); diff --git a/test/integration/entityTypes/oracle/entity/Post.ts b/test/integration/entityTypes/oracle/entity/Post.ts new file mode 100644 index 0000000..ea69e96 --- /dev/null +++ b/test/integration/entityTypes/oracle/entity/Post.ts @@ -0,0 +1,99 @@ +import { Entity, PrimaryColumn, Column } from "typeorm"; + +@Entity("Post") +export class Post { + + @PrimaryColumn() + id: number; + + @Column() + name: string; + + @Column("char") + char: string; + + @Column("nchar") + nchar: string; + + @Column("nvarchar2") + nvarchar2: string; + + @Column("varchar2") + varchar2: string; + + @Column("long") + long: string; + + @Column("raw") + raw: Buffer; + + // @Column("long raw") + // long_raw: Buffer; + + @Column("number") + number: number; + + @Column("numeric") + numeric: number; + + @Column("float") + float: number; + + @Column("dec") + dec: number; + + @Column("decimal") + decimal: number; + + @Column("integer") + integer: number; + + @Column("int") + int: number; + + @Column("smallint") + smallint: number; + + @Column("real") + real: number; + + @Column("double precision") + double_precision: number; + + @Column("date") + date: Date; + + @Column("timestamp") + timestamp: Date; + + @Column("timestamp with time zone") + timestamp_with_time_zone: Date; + + @Column("timestamp with local time zone") + timestamp_with_local_time_zone: Date; + + @Column("interval year to month") + interval_year_to_month: string; + + @Column("interval day to second") + interval_day_to_second: string; + + @Column("bfile") + bfile: Buffer; + + @Column("blob") + blob: Buffer; + + @Column("clob") + clob: string; + + @Column("nclob") + nclob: string; + + @Column("rowid") + rowid: number; + + @Column("urowid") + urowid: number; + +} diff --git a/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts b/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts index a627625..a0f1a1e 100644 --- a/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts +++ b/test/integration/examples/sample11-all-types-entity/entity/EverythingEntity.ts @@ -9,8 +9,8 @@ export class EverythingEntity { @Column() name: string; - @Column("text") - text: string; + // @Column("text") + // text: string; @Column({ length: 32 }) shortTextColumn: string; diff --git a/test/integration/examples/sample2-one-to-one/entity/Post.ts b/test/integration/examples/sample2-one-to-one/entity/Post.ts index f715c0a..59b47ce 100644 --- a/test/integration/examples/sample2-one-to-one/entity/Post.ts +++ b/test/integration/examples/sample2-one-to-one/entity/Post.ts @@ -24,7 +24,7 @@ export class Post { onDelete: 'CASCADE' }) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) category: PostCategory; // post has relation with details. cascade inserts here means if new PostDetails instance will be set to this @@ -33,7 +33,7 @@ export class Post { cascade: true }) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) details: PostDetails; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation @@ -42,7 +42,7 @@ export class Post { cascade: true, }) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) image: PostImage; // post has relation with details. cascade update here means if new PostDetail instance will be set to this relation @@ -51,7 +51,7 @@ export class Post { onDelete: 'CASCADE' }) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) metadata: PostMetadata | null; // post has relation with details. full cascades here @@ -60,13 +60,13 @@ export class Post { onDelete: 'CASCADE' }) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) information: PostInformation; // post has relation with details. not cascades here. means cannot be persisted, updated or removed @OneToOne(type => PostAuthor, author => author.post) @JoinColumn() - @Index({ unique: true }) + // @Index({ unique: true }) author: PostAuthor; } diff --git a/test/utils/GeneralTestUtils.ts b/test/utils/GeneralTestUtils.ts index a00aca9..191a07f 100644 --- a/test/utils/GeneralTestUtils.ts +++ b/test/utils/GeneralTestUtils.ts @@ -241,10 +241,11 @@ export async function createMariaDBModels(filesOrgPath: string, resultsPath: str export async function createOracleDBModels(filesOrgPath: string, resultsPath: string): Promise { let driver: AbstractDriver; driver = new OracleDriver(); - await driver.ConnectToServer(String(process.env.ORACLE_Database), String(process.env.ORACLE_Host), Number(process.env.ORACLE_Port), String(process.env.ORACLE_Username), String(process.env.ORACLE_Password), yn(process.env.ORACLE_SSL)); + await driver.ConnectToServer(String(process.env.ORACLE_Database), String(process.env.ORACLE_Host), Number(process.env.ORACLE_Port), String(process.env.ORACLE_UsernameSys), String(process.env.ORACLE_PasswordSys), yn(process.env.ORACLE_SSL)); - if (! await driver.CheckIfDBExists(String(process.env.ORACLE_Database))) - await driver.CreateDB(String(process.env.ORACLE_Database)); + if (await driver.CheckIfDBExists(String(process.env.ORACLE_Username))) + await driver.DropDB(String(process.env.ORACLE_Username)); + await driver.CreateDB(String(process.env.ORACLE_Username)); await driver.DisconnectFromServer(); let connOpt: ConnectionOptions = { @@ -281,11 +282,8 @@ export async function createOracleDBModels(filesOrgPath: string, resultsPath: st convertCaseEntity: 'none', convertCaseFile: 'none', convertCaseProperty: 'none', - }); - - return engine; } diff --git a/tsconfig.json b/tsconfig.json index d8e44e0..e6f689d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,10 @@ "strictNullChecks": true, "moduleResolution": "node", "outDir": "dist", - "newLine": "LF" + "newLine": "LF", + "lib": [ + "es2017" + ] }, "include": [ "src",