diff --git a/README.md b/README.md index 89b05d3b..7fa8a64c 100644 --- a/README.md +++ b/README.md @@ -314,6 +314,8 @@ _Syntax:_ > ?join=**relation**||**field1**,**field2**,... +> ?join=**relation1**||**field11**,**field12**,...&join=**relation1**.**relation2**||**field21**,**field22**,...&join=... + _Examples:_ > ?join=**profile** @@ -322,7 +324,9 @@ _Examples:_ > ?join=**profile**||**firstName**,**email**&join=**notifications**||**content**&join=**tasks** -**_Notice:_** `id` field always persists in relational objects. +> ?join=**relation1**&join=**relation1**.**relation2**&join=**relation1**.**relation2**.**relation3** + +**_Notice:_** `id` field always persists in relational objects. To use nested relations, the parent level **MUST** be set before the child level like example above. _Alias:_ `join[]` @@ -476,7 +480,8 @@ An Object of [relations](http://typeorm.io/#/relations) that allowed to be fetch notifications: { exclude: ['token'] }, - company: {} + company: {}, + 'company.projects': {} } } ``` diff --git a/integration/typeorm/e2e/company.entity.ts b/integration/typeorm/e2e/company.entity.ts index 0b5353f4..fbc00cd2 100644 --- a/integration/typeorm/e2e/company.entity.ts +++ b/integration/typeorm/e2e/company.entity.ts @@ -4,6 +4,8 @@ import { CrudValidate } from '../../../src/'; import { BaseEntity } from '../src/base-entity'; import { User } from './user.entity'; +import { Project } from './project.entity'; +import { Task } from './task.entity'; const { CREATE, UPDATE } = CrudValidate; @@ -34,4 +36,10 @@ export class Company extends BaseEntity { @OneToMany((type) => User, (u) => u.company) users: User[]; + + @OneToMany((type) => Project, (p) => p.company) + projects: Project[]; + + @OneToMany((type) => Task, (t) => t.company) + tasks: Task[]; } diff --git a/integration/typeorm/e2e/project.entity.ts b/integration/typeorm/e2e/project.entity.ts new file mode 100644 index 00000000..be8b6f5a --- /dev/null +++ b/integration/typeorm/e2e/project.entity.ts @@ -0,0 +1,38 @@ +/* + * Copyright under the Parsec Tech Co., Ltd. Version 1.0; + * you may not use this file except in compliance with the permit. + * Copyright (c) 2019 ChongQing Parsec Technology Corporation. All Rights Reserved. + * Version 1.0 + */ + +import { Entity, Column, ManyToOne, ManyToMany, OneToMany, JoinTable } from 'typeorm'; +import { BaseEntity } from '../src/base-entity'; +import { Company } from './company.entity'; +import { User } from './user.entity'; +import { Task } from './task.entity'; + +@Entity('projects') +export class Project extends BaseEntity { + @Column({ type: 'varchar', length: 100, nullable: false, unique: true }) + name: string; + + @Column({ type: 'text', nullable: true }) + description: string; + + @Column({ nullable: false }) + companyId: number; + + /** + * Relations + */ + + @ManyToOne((type) => Company, (c) => c.projects) + company: Company; + + @ManyToMany((type) => User, (u) => u.projects, { cascade: true }) + @JoinTable() + users: User[]; + + @OneToMany((type) => Task, (t) => t.project) + tasks: Task[]; +} diff --git a/integration/typeorm/e2e/seeds.ts b/integration/typeorm/e2e/seeds.ts index 7dae1a54..b3f8e234 100644 --- a/integration/typeorm/e2e/seeds.ts +++ b/integration/typeorm/e2e/seeds.ts @@ -66,10 +66,93 @@ export class Seeds1544303473346 implements MigrationInterface { ('fericapozzati7@k3zaraxg9t7e1f.ml', '9c81f2857e8f', false, 2, 19), ('os.s.l.ka@6-6-6.cf', '9c81f2857e8f', false, 2, 20); `); + + // projects + await queryRunner.query(` + INSERT INTO public.projects ("name", "description", "companyId") + VALUES ('project1', 'project 1 desc', 1), + ('project2', 'project 2 desc', 1), + ('project3', 'project 3 desc', 1), + ('project4', 'project 4 desc', 1), + ('project5', 'project 5 desc', 1), + ('project6', 'project 6 desc', 1), + ('project7', 'project 7 desc', 1), + ('project8', 'project 8 desc', 1), + ('project9', 'project 9 desc', 2), + ('project10', 'project 10 desc', 3), + ('project11', 'project 11 desc', 4), + ('project12', 'project 12 desc', 5), + ('project13', 'project 13 desc', 6), + ('project14', 'project 14 desc', 7), + ('project15', 'project 15 desc', 8), + ('project16', 'project 16 desc', 9); + `); + + // tasks + await queryRunner.query(` + INSERT INTO public.tasks ("name", "status", "companyId", "projectId", "userId") + VALUES ('task11', 'a', 1, 1, 1), + ('task12', 'a', 1, 1, 1), + ('task13', 'a', 1, 1, 1), + ('task14', 'a', 1, 1, 1), + ('task21', 'a', 1, 2, 2), + ('task22', 'a', 1, 2, 2), + ('task23', 'a', 1, 2, 2), + ('task24', 'a', 1, 2, 2), + ('task31', 'a', 1, 3, 3), + ('task32', 'a', 1, 3, 3), + ('task33', 'a', 1, 3, 3), + ('task34', 'a', 1, 3, 3), + ('task41', 'a', 1, 4, 4), + ('task42', 'a', 1, 4, 4), + ('task43', 'a', 1, 4, 4), + ('task44', 'a', 1, 4, 4), + ('task1', 'a', 1, 1, 5), + ('task2', 'a', 1, 1, 5), + ('task3', 'a', 1, 1, 5), + ('task4', 'a', 1, 1, 5), + ('task1', 'a', 1, 1, 6), + ('task2', 'a', 1, 1, 6), + ('task3', 'a', 1, 1, 6), + ('task4', 'a', 1, 1, 6), + ('task1', 'a', 1, 1, 7), + ('task2', 'a', 1, 1, 7), + ('task3', 'a', 1, 1, 7), + ('task4', 'a', 1, 1, 7); + `); + + // user projects + await queryRunner.query(` + INSERT INTO public.projects_users_users ("projectsId", "usersId") + VALUES (1, 1), + (1, 2), + (1, 3), + (1, 4), + (1, 5), + (1, 6), + (1, 7), + (1, 8), + (1, 9), + (2, 1), + (2, 2), + (2, 3), + (2, 4), + (2, 5), + (2, 6), + (2, 7), + (2, 8), + (2, 9); + `); } public async down(queryRunner: QueryRunner): Promise { // flush + await queryRunner.query( + `DELETE FROM public.tasks; ALTER SEQUENCE tasks_id_seq RESTART WITH 1;`, + ); + await queryRunner.query( + `DELETE FROM public.projects; ALTER SEQUENCE projects_id_seq RESTART WITH 1;`, + ); await queryRunner.query( `DELETE FROM public.users; ALTER SEQUENCE users_id_seq RESTART WITH 1;`, ); diff --git a/integration/typeorm/e2e/task.entity.ts b/integration/typeorm/e2e/task.entity.ts new file mode 100644 index 00000000..b5c59aef --- /dev/null +++ b/integration/typeorm/e2e/task.entity.ts @@ -0,0 +1,43 @@ +/* + * Copyright under the Parsec Tech Co., Ltd. Version 1.0; + * you may not use this file except in compliance with the permit. + * Copyright (c) 2019 ChongQing Parsec Technology Corporation. All Rights Reserved. + * Version 1.0 + */ + +import { Entity, Column, ManyToOne } from 'typeorm'; +import { BaseEntity } from '../src/base-entity'; +import { Company } from './company.entity'; +import { Project } from './project.entity'; +import { User } from './user.entity'; + +@Entity('tasks') +export class Task extends BaseEntity { + @Column({ type: 'varchar', length: 100, nullable: false }) + name: string; + + @Column({ type: 'varchar', nullable: false }) + status: string; + + @Column({ nullable: false }) + companyId: number; + + @Column({ nullable: false }) + projectId: number; + + @Column({ nullable: false }) + userId: number; + + /** + * Relations + */ + + @ManyToOne((type) => Company, (c) => c.tasks) + company: Company; + + @ManyToOne((type) => Project, (c) => c.tasks) + project: Project; + + @ManyToOne((type) => User, (u) => u.tasks) + user: User; +} diff --git a/integration/typeorm/e2e/user.entity.ts b/integration/typeorm/e2e/user.entity.ts index 986fbf53..07644531 100644 --- a/integration/typeorm/e2e/user.entity.ts +++ b/integration/typeorm/e2e/user.entity.ts @@ -1,4 +1,4 @@ -import { Entity, Column, JoinColumn, OneToOne, ManyToOne } from 'typeorm'; +import { Entity, Column, JoinColumn, OneToOne, ManyToOne, ManyToMany, OneToMany } from 'typeorm'; import { IsOptional, IsString, @@ -11,9 +11,11 @@ import { import { Type } from '../../../node_modules/class-transformer'; import { CrudValidate } from '../../../src/'; -import { BaseEntity } from '../src//base-entity'; +import { BaseEntity } from '../src/base-entity'; import { UserProfile } from './user-profile.entity'; import { Company } from './company.entity'; +import { Project } from './project.entity'; +import { Task } from './task.entity'; const { UPDATE, CREATE } = CrudValidate; @@ -60,4 +62,10 @@ export class User extends BaseEntity { @ManyToOne((type) => Company, (c) => c.users) company: Company; + + @ManyToMany((type) => Project, (c) => c.users) + projects: Project[]; + + @OneToMany((type) => Task, (t) => t.user) + tasks: Task[]; } diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..d4f6ce74 --- /dev/null +++ b/jest.config.js @@ -0,0 +1 @@ +module.exports = require('./jest.config.json'); diff --git a/jest.json b/jest.config.json similarity index 100% rename from jest.json rename to jest.config.json diff --git a/package-lock.json b/package-lock.json index c0cf8646..f9d93e89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@nestjsx/crud", - "version": "0.1.6", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -89,6 +89,12 @@ "node-fetch": "^2.2.0" } }, + "@types/chai": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", + "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", + "dev": true + }, "@types/cookiejar": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.0.tgz", @@ -607,6 +613,12 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -1204,6 +1216,20 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -1214,6 +1240,12 @@ "supports-color": "^5.3.0" } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", @@ -1758,6 +1790,15 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -3045,6 +3086,12 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-stream": { "version": "3.0.0", "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", @@ -5185,6 +5232,12 @@ "pinkie-promise": "^2.0.0" } }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -7279,6 +7332,12 @@ "prelude-ls": "~1.1.2" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", diff --git a/package.json b/package.json index a802c2ff..1e73bc17 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,17 @@ "scripts": { "docker:up": "docker-compose up -d", "docker:down": "docker-compose down", - "test:e2e": "node_modules/.bin/jest --verbose --coverage --config ./jest.json", + "test:e2e": "jest --verbose --coverage", "pretest:e2e": "npm run test:e2e:typeorm:prepare", "posttest:e2e": "npm run test:e2e:typeorm:clean", "test:e2e:typeorm:prepare": "cd integration/typeorm && npm run db:sync -- -f=e2e/orm && npm run db:flush -- -f=e2e/orm && npm run db:seeds -- -f=e2e/orm", "test:e2e:typeorm:clean": "cd integration/typeorm && npm run db:flush -- -f=e2e/orm", - "coverage": "node_modules/.bin/jest --verbose --coverage --config ./jest.json --coverageReporters=text-lcov | coveralls", + "coverage": "jest --verbose --coverage --coverageReporters=text-lcov | coveralls", "clean": "cd dist && rm -rf `ls | grep -v \"LICENSE\\|package.json\\|README.md\"`", "clean:typeorm": "cd integration/typeorm/node_modules/@nestjsx/crud && rm -rf *", "update:typeorm": "cp -a ./dist/. ./integration/typeorm/node_modules/@nestjsx/crud", "reset:typeorm": "cd integration/typeorm && npm i @nestjsx/crud@next", - "build": "node_modules/.bin/tsc", + "build": "tsc -b tsconfig.build.json", "prebuild": "npm run clean", "postbuild": "npm run clean:typeorm && npm run update:typeorm" }, @@ -35,9 +35,11 @@ "typeorm": "^0.2.9" }, "devDependencies": { + "@types/chai": "^4.1.7", "@types/jest": "^23.3.10", "@types/node": "^10.12.12", "@types/supertest": "^2.0.7", + "chai": "^4.2.0", "coveralls": "^3.0.2", "jest": "^23.6.0", "nodemon": "^1.18.7", diff --git a/src/typeorm/repository-service.class.ts b/src/typeorm/repository-service.class.ts index 87ac604a..bece4f80 100644 --- a/src/typeorm/repository-service.class.ts +++ b/src/typeorm/repository-service.class.ts @@ -1,18 +1,13 @@ -import { Repository, SelectQueryBuilder, Brackets, FindOneOptions, DeepPartial } from 'typeorm'; +import { Brackets, DeepPartial, Repository, SelectQueryBuilder } from 'typeorm'; import { isObject } from '@nestjs/common/utils/shared.utils'; import { plainToClass } from 'class-transformer'; import { ClassType } from 'class-transformer/ClassTransformer'; import { RestfulService } from '../classes/restful-service.class'; -import { - RestfulOptions, - JoinOptions, - RequestParamsParsed, - FilterParamParsed, - JoinParamParsed, -} from '../interfaces'; +import { FilterParamParsed, JoinOptions, JoinParamParsed, RequestParamsParsed, RestfulOptions } from '../interfaces'; import { ObjectLiteral } from '../interfaces/object-literal.interface'; import { isArrayFull } from '../utils'; +import { RelationMetadata } from 'typeorm/metadata/RelationMetadata'; export class RepositoryService extends RestfulService { protected options: RestfulOptions = {}; @@ -301,7 +296,7 @@ export class RepositoryService extends RestfulService { } if (paramsFilter.length) { - for (let filter of paramsFilter) { + for (const filter of paramsFilter) { data[filter.field] = filter.value; } } @@ -374,7 +369,48 @@ export class RepositoryService extends RestfulService { ); } + private getRelationMetadata(field: string) { + try { + const fields = field.split('.'); + const target = fields[fields.length - 1]; + const paths = fields.slice(0, fields.length - 1); + + let relations = this.repo.metadata.relations; + + for (const propertyName of paths) { + relations = relations.find(o => o.propertyName === propertyName).inverseEntityMetadata.relations; + } + + const relation: RelationMetadata & { nestedRelation?: string } = relations.find(o => o.propertyName === target); + + relation.nestedRelation = `${fields[fields.length - 2]}.${target}`; + + return relation; + } catch (e) { + return null; + } + } + private setJoin(cond: JoinParamParsed, joinOptions: JoinOptions, builder: SelectQueryBuilder) { + if (this.entityRelationsHash[cond.field] === undefined && cond.field.includes('.')) { + const curr = this.getRelationMetadata(cond.field); + if (!curr) { + this.entityRelationsHash[cond.field] = null; + return true; + } + + this.entityRelationsHash[cond.field] = { + name: curr.propertyName, + type: this.getJoinType(curr.relationType), + columns: curr.inverseEntityMetadata.columns.map((col) => col.propertyName), + referencedColumn: (curr.joinColumns.length + ? curr.joinColumns[0] + : curr.inverseRelation.joinColumns[0] + ).referencedColumn.propertyName, + nestedRelation: curr.nestedRelation, + }; + } + if (cond.field && this.entityRelationsHash[cond.field] && joinOptions[cond.field]) { const relation = this.entityRelationsHash[cond.field]; const options = joinOptions[cond.field]; @@ -395,7 +431,9 @@ export class RepositoryService extends RestfulService { ...columns, ].map((col) => `${relation.name}.${col}`); - builder[relation.type](`${this.alias}.${relation.name}`, relation.name); + const relationPath = relation.nestedRelation || `${this.alias}.${relation.name}`; + + builder[relation.type](relationPath, relation.name); builder.addSelect(select); } @@ -468,7 +506,7 @@ export class RepositoryService extends RestfulService { } private mapSort(sort: ObjectLiteral[]) { - let params: ObjectLiteral = {}; + const params: ObjectLiteral = {}; for (let i = 0; i < sort.length; i++) { this.validateHasColumn(sort[i].field); @@ -556,7 +594,7 @@ export class RepositoryService extends RestfulService { break; case 'between': - if (!Array.isArray(cond.value) || !cond.value.length || cond.value.length != 2) { + if (!Array.isArray(cond.value) || !cond.value.length || cond.value.length !== 2) { this.throwBadRequestException(`Invalid column '${cond.field}' value`); } str = `${field} BETWEEN :${param}0 AND :${param}1`; diff --git a/test/typeorm/simple-route.spec.ts b/test/typeorm/simple-route.spec.ts index 71863eee..4927a2ff 100644 --- a/test/typeorm/simple-route.spec.ts +++ b/test/typeorm/simple-route.spec.ts @@ -1,10 +1,11 @@ import * as request from 'supertest'; +import { expect } from 'chai'; import { Test } from '@nestjs/testing'; -import { TypeOrmModule, InjectRepository } from '@nestjs/typeorm'; -import { INestApplication, Injectable, Controller, Get, Param } from '@nestjs/common'; +import { InjectRepository, TypeOrmModule } from '@nestjs/typeorm'; +import { Controller, Get, INestApplication, Injectable, Param } from '@nestjs/common'; -import { UserProfile, User, Company, ormConfig } from '../../integration/typeorm/e2e'; -import { Crud, CrudController, RestfulOptions, Feature, Action, Override } from '../../src'; +import { Company, ormConfig, User, UserProfile } from '../../integration/typeorm/e2e'; +import { Action, Crud, CrudController, Feature, Override, RestfulOptions } from '../../src'; import { RepositoryService } from '../../src/typeorm'; @Injectable() @@ -26,16 +27,23 @@ class CompaniesService extends RepositoryService { cache: 1000, filter: [{ field: 'id', operator: 'notnull' }], join: { - users: { + 'users': { persist: ['id'], exclude: ['password'], }, + 'users.projects': { + exclude: ['description'], + }, + 'users.projects.tasks': { + persist: ['status'], + }, }, }, }) @Controller('companies') class CompaniesController implements CrudController { - constructor(public service: CompaniesService) {} + constructor(public service: CompaniesService) { + } @Action('test') @Get('test') @@ -75,7 +83,8 @@ describe('Simple base routes', () => { // Get Many - describe('', () => {}); + describe('', () => { + }); it('/GET / (200)', () => { return request(server) @@ -389,4 +398,22 @@ describe('Simple base routes', () => { .get('/companies/test') .expect(200); }); + + describe('nested relations', () => { + it('nested relations', () => { + return request(server) + .get('/companies/1?join=users||email&join=users.projects&join=users.projects.tasks') + .expect(200) + .expect(res => { + expect(res.body).to.have.nested.property('users[0].projects[0].tasks[0].name'); + }); + }); + + it('when missing fields', () => { + return request(server) + .get('/companies/1?join=users||email&join=users.projects1&join=users.projects1.tasks') + .expect(200); + }); + }); + }); diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 00000000..8c0f74bb --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["**/*.spec.ts"] +} diff --git a/tsconfig.jest.json b/tsconfig.jest.json index 71dedf82..bc4554da 100644 --- a/tsconfig.jest.json +++ b/tsconfig.jest.json @@ -1,5 +1,5 @@ { - "extends": "./tsconfig", + "extends": "./tsconfig.json", "compilerOptions": { "removeComments": false } diff --git a/tsconfig.json b/tsconfig.json index 5a9e143d..a52603f7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,5 @@ "skipLibCheck": true }, "include": ["src/**/*"], - "exclude": ["node_modules", "**/*.spec.ts"] + "exclude": ["node_modules"] } diff --git a/tslint.json b/tslint.json index 914cce90..8da1e607 100644 --- a/tslint.json +++ b/tslint.json @@ -24,7 +24,9 @@ "variable-name": [false], "one-line": [false], "one-variable-per-declaration": [false], - "no-console": false + "no-console": false, + "prefer-for-of": false, + "no-string-literal": false }, "rulesDirectory": [] }