mirror of
https://github.com/usatiuk/writer.git
synced 2025-10-28 16:07:49 +01:00
init
This commit is contained in:
3
.eslintrc.js
Normal file
3
.eslintrc.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
"extends": ["airbnb", "plugin:prettier/recommended"]
|
||||
};
|
||||
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
node_modules/
|
||||
build/
|
||||
tmp/
|
||||
temp/
|
||||
dist/
|
||||
ormconfig.json
|
||||
ormconfig.test.json
|
||||
.env
|
||||
.directory
|
||||
23
.gitlab-ci.yml
Normal file
23
.gitlab-ci.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
image: node:10
|
||||
|
||||
stages:
|
||||
- test-backend
|
||||
|
||||
variables:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
|
||||
MYSQL_DATABASE: writer_test
|
||||
MYSQL_USER: writer
|
||||
MYSQL_PASSWORD: writer
|
||||
|
||||
cache:
|
||||
paths:
|
||||
- node_modules/
|
||||
- frontend/node_modules
|
||||
|
||||
test-backend:
|
||||
stage: test-backend
|
||||
services:
|
||||
- mariadb:10
|
||||
script:
|
||||
- npm i
|
||||
- npm test
|
||||
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 4
|
||||
}
|
||||
7
README.md
Normal file
7
README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Awesome Project Build with TypeORM
|
||||
|
||||
Steps to run this project:
|
||||
|
||||
1. Run `npm i` command
|
||||
2. Setup database settings inside `ormconfig.json` file
|
||||
3. Run `npm start` command
|
||||
12
frontend/.gitignore
vendored
Normal file
12
frontend/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
.idea/
|
||||
.vscode/
|
||||
node_modules/
|
||||
build/
|
||||
tmp/
|
||||
temp/
|
||||
dist/
|
||||
ormconfig.json
|
||||
ormconfig.test.json
|
||||
.env
|
||||
.cache
|
||||
.directory
|
||||
8990
frontend/package-lock.json
generated
Normal file
8990
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
frontend/package.json
Normal file
30
frontend/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "writer-frontend",
|
||||
"scripts": {
|
||||
"start": "parcel src/index.html",
|
||||
"build": "parcel build src/index.html",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node-sass": "^3.10.32",
|
||||
"@types/parcel-bundler": "^1.10.1",
|
||||
"@types/react": "^16.7.18",
|
||||
"@types/react-dom": "^16.0.11",
|
||||
"@types/react-redux": "^6.0.11",
|
||||
"@types/react-router": "^4.4.3",
|
||||
"@types/react-router-dom": "^4.3.1",
|
||||
"node-sass": "^4.11.0",
|
||||
"parcel-bundler": "^1.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "^3.10.0",
|
||||
"@blueprintjs/icons": "^3.4.0",
|
||||
"react": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-redux": "^6.0.0",
|
||||
"react-router": "^4.3.1",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"redux": "^4.0.1",
|
||||
"redux-saga": "^0.16.2"
|
||||
}
|
||||
}
|
||||
15
frontend/src/App.tsx
Normal file
15
frontend/src/App.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import * as React from "react";
|
||||
import { Route, Switch } from "react-router";
|
||||
import { Login } from "~Auth/Login";
|
||||
import { Home } from "~Home";
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Switch>
|
||||
<Route exact={true} path="/" component={Home} />
|
||||
<Route path="/login" component={Login} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
21
frontend/src/Auth/Auth.scss
Normal file
21
frontend/src/Auth/Auth.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.AuthForm {
|
||||
margin: auto;
|
||||
margin-top: 10rem;
|
||||
width: 20rem;
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
h2 {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
button.submit {
|
||||
margin-left: auto;
|
||||
justify-self: flex-end;
|
||||
align-self: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
27
frontend/src/Auth/Login.tsx
Normal file
27
frontend/src/Auth/Login.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import "./Auth.scss";
|
||||
|
||||
import { Button, Card, FormGroup, H2, InputGroup } from "@blueprintjs/core";
|
||||
import * as React from "react";
|
||||
|
||||
export function Login() {
|
||||
return (
|
||||
<>
|
||||
<Card className="AuthForm" elevation={2}>
|
||||
<form>
|
||||
<H2>Login</H2>
|
||||
<FormGroup label="Username">
|
||||
<InputGroup leftIcon="person" />
|
||||
</FormGroup>
|
||||
<FormGroup label="Password">
|
||||
<InputGroup leftIcon="key" />
|
||||
</FormGroup>
|
||||
<div className="buttons">
|
||||
<Button className="submit" intent="primary">
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
}
|
||||
26
frontend/src/Home.tsx
Normal file
26
frontend/src/Home.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Alignment, Button, Classes, Navbar } from "@blueprintjs/core";
|
||||
import * as React from "react";
|
||||
|
||||
export function Home() {
|
||||
return (
|
||||
<>
|
||||
{" "}
|
||||
<Navbar>
|
||||
<Navbar.Group align={Alignment.LEFT}>
|
||||
<Navbar.Heading>Writer</Navbar.Heading>
|
||||
<Navbar.Divider />
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon="home"
|
||||
text="Home"
|
||||
/>
|
||||
<Button
|
||||
className={Classes.MINIMAL}
|
||||
icon="document"
|
||||
text="Files"
|
||||
/>
|
||||
</Navbar.Group>
|
||||
</Navbar>
|
||||
</>
|
||||
);
|
||||
}
|
||||
15
frontend/src/index.html
Normal file
15
frontend/src/index.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Writer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body">
|
||||
|
||||
</div>
|
||||
<script src="./index.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
19
frontend/src/index.tsx
Normal file
19
frontend/src/index.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import "@blueprintjs/core/lib/css/blueprint.css";
|
||||
import "@blueprintjs/icons/lib/css/blueprint-icons.css";
|
||||
import "normalize.css/normalize.css";
|
||||
|
||||
import * as React from "react";
|
||||
import { render } from "react-dom";
|
||||
import { Provider } from "react-redux";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import { App } from "~App";
|
||||
import { store } from "~redux/store";
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>,
|
||||
document.getElementById("body"),
|
||||
);
|
||||
10
frontend/src/redux/auth/actions.ts
Normal file
10
frontend/src/redux/auth/actions.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Action } from "redux";
|
||||
|
||||
export const AUTH_SUCCESS = "AUTH_SUCCESS";
|
||||
|
||||
class AuthSuccessAction implements Action {
|
||||
public readonly type = AUTH_SUCCESS;
|
||||
constructor(public jwt: string) {}
|
||||
}
|
||||
|
||||
export type AuthAction = AuthSuccessAction;
|
||||
27
frontend/src/redux/auth/reducer.ts
Normal file
27
frontend/src/redux/auth/reducer.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Reducer } from "react";
|
||||
|
||||
import { AUTH_SUCCESS, AuthAction } from "./actions";
|
||||
|
||||
export interface IAuthState {
|
||||
jwt: string | null;
|
||||
inProgress: boolean;
|
||||
}
|
||||
|
||||
const defaultAuthState: IAuthState = {
|
||||
jwt: null,
|
||||
inProgress: false,
|
||||
};
|
||||
|
||||
export const auth: Reducer<IAuthState, AuthAction> = (
|
||||
state: IAuthState = defaultAuthState,
|
||||
action: AuthAction,
|
||||
) => {
|
||||
switch (action.type) {
|
||||
case AUTH_SUCCESS:
|
||||
return { ...state, jwt: action.jwt, inProgress: false };
|
||||
break;
|
||||
default:
|
||||
return state;
|
||||
break;
|
||||
}
|
||||
};
|
||||
4
frontend/src/redux/reducers.ts
Normal file
4
frontend/src/redux/reducers.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { combineReducers } from "redux";
|
||||
import { auth } from "~redux/auth/reducer";
|
||||
|
||||
export const rootReducer = combineReducers({ auth });
|
||||
4
frontend/src/redux/store.ts
Normal file
4
frontend/src/redux/store.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { createStore } from "redux";
|
||||
import { rootReducer } from "~redux/reducers";
|
||||
|
||||
export const store = createStore(rootReducer);
|
||||
0
frontend/src/redux/types.ts
Normal file
0
frontend/src/redux/types.ts
Normal file
23
frontend/tsconfig.json
Normal file
23
frontend/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
],
|
||||
"jsx": "react",
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"~*": [
|
||||
"./*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
24
ormconfig.ci.json
Normal file
24
ormconfig.ci.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"type": "mariadb",
|
||||
"host": "mariadb",
|
||||
"port": 3306,
|
||||
"username": "writer",
|
||||
"password": "writer",
|
||||
"database": "writer_test",
|
||||
"synchronize": true,
|
||||
"logging": false,
|
||||
"entities": [
|
||||
"src/entity/**/*.ts"
|
||||
],
|
||||
"migrations": [
|
||||
"src/migration/**/*.ts"
|
||||
],
|
||||
"subscribers": [
|
||||
"src/subscriber/**/*.ts"
|
||||
],
|
||||
"cli": {
|
||||
"entitiesDir": "src/entity",
|
||||
"migrationsDir": "src/migration",
|
||||
"subscribersDir": "src/subscriber"
|
||||
}
|
||||
}
|
||||
24
ormconfig.example.json
Normal file
24
ormconfig.example.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"type": "mariadb",
|
||||
"host": "localhost",
|
||||
"port": 3306,
|
||||
"username": "writer",
|
||||
"password": "writer",
|
||||
"database": "writer_test",
|
||||
"synchronize": true,
|
||||
"logging": false,
|
||||
"entities": [
|
||||
"src/entity/**/*.ts"
|
||||
],
|
||||
"migrations": [
|
||||
"src/migration/**/*.ts"
|
||||
],
|
||||
"subscribers": [
|
||||
"src/subscriber/**/*.ts"
|
||||
],
|
||||
"cli": {
|
||||
"entitiesDir": "src/entity",
|
||||
"migrationsDir": "src/migration",
|
||||
"subscribersDir": "src/subscriber"
|
||||
}
|
||||
}
|
||||
4531
package-lock.json
generated
Normal file
4531
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
package.json
Normal file
56
package.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "writer-backend",
|
||||
"devDependencies": {
|
||||
"@blueprintjs/tslint-config": "^1.7.0",
|
||||
"@types/bcrypt": "^3.0.0",
|
||||
"@types/chai": "^4.1.7",
|
||||
"@types/eslint": "^4.16.5",
|
||||
"@types/eslint-plugin-prettier": "^2.2.0",
|
||||
"@types/jsonwebtoken": "^8.3.0",
|
||||
"@types/koa": "^2.0.48",
|
||||
"@types/koa-logger": "^3.1.1",
|
||||
"@types/koa-router": "^7.0.35",
|
||||
"@types/lodash": "^4.14.119",
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/mysql": "^2.15.5",
|
||||
"@types/node": "^10.12.18",
|
||||
"@types/prettier": "^1.15.2",
|
||||
"chai": "^4.2.0",
|
||||
"concurrently": "^4.1.0",
|
||||
"cross-env": "^5.2.0",
|
||||
"eslint": "^5.11.1",
|
||||
"eslint-config-airbnb": "^17.1.0",
|
||||
"eslint-config-prettier": "^3.3.0",
|
||||
"eslint-plugin-import": "^2.14.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.1.2",
|
||||
"eslint-plugin-prettier": "^3.0.1",
|
||||
"eslint-plugin-react": "^7.12.0",
|
||||
"mocha": "^5.2.0",
|
||||
"prettier": "^1.15.3",
|
||||
"ts-node": "7.0.1",
|
||||
"ts-node-dev": "^1.0.0-pre.32",
|
||||
"tsconfig-paths": "^3.7.0",
|
||||
"tslint": "^5.12.0",
|
||||
"tslint-config-prettier": "^1.17.0",
|
||||
"tslint-no-unused-expression-chai": "^0.1.4",
|
||||
"tslint-plugin-prettier": "^2.0.1",
|
||||
"typescript": "3.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt": "^3.0.3",
|
||||
"jsonwebtoken": "^8.4.0",
|
||||
"koa": "^2.6.2",
|
||||
"koa-logger": "^3.2.0",
|
||||
"koa-router": "^7.4.0",
|
||||
"lodash": "^4.17.11",
|
||||
"mysql": "^2.16.0",
|
||||
"reflect-metadata": "^0.1.12",
|
||||
"typeorm": "0.2.9"
|
||||
},
|
||||
"scripts": {
|
||||
"ts-node-dev": "ts-node-dev -r tsconfig-paths/register src/server.ts",
|
||||
"frontend": "cd frontend && npm start",
|
||||
"dev": "cross-env NODE_ENV=development concurrently npm:ts-node-dev npm:frontend",
|
||||
"test": "cross-env NODE_ENV=test mocha --timeout 15000 -r ts-node/register -r tsconfig-paths/register 'tests/**/*.ts' "
|
||||
}
|
||||
}
|
||||
8
src/app.ts
Normal file
8
src/app.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import "reflect-metadata";
|
||||
|
||||
import * as Koa from "koa";
|
||||
import * as logger from "koa-logger";
|
||||
|
||||
export const app = new Koa();
|
||||
|
||||
app.use(logger());
|
||||
8
src/config/database.ts
Normal file
8
src/config/database.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import "~entity/User";
|
||||
|
||||
import { Connection, createConnection } from "typeorm";
|
||||
import { config } from "~config";
|
||||
|
||||
export async function connect(): Promise<Connection> {
|
||||
return createConnection(config.dbConnectionOptions);
|
||||
}
|
||||
33
src/config/index.ts
Normal file
33
src/config/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import * as fs from "fs";
|
||||
import { ConnectionOptions } from "typeorm";
|
||||
|
||||
export interface IConfig {
|
||||
port: number;
|
||||
jwtSecret: string;
|
||||
dbConnectionOptions: ConnectionOptions | null;
|
||||
}
|
||||
|
||||
const production: IConfig = {
|
||||
port: parseInt(process.env.PORT, 10) || 3000,
|
||||
jwtSecret: process.env.JWT_SECRET,
|
||||
dbConnectionOptions: null,
|
||||
};
|
||||
|
||||
const development: IConfig = {
|
||||
...production,
|
||||
jwtSecret: "DEVSECRET",
|
||||
};
|
||||
|
||||
const test: IConfig = {
|
||||
...production,
|
||||
jwtSecret: "TESTSECRET",
|
||||
dbConnectionOptions: process.env.CI
|
||||
? JSON.parse(fs.readFileSync("./ormconfig.ci.json").toString())
|
||||
: JSON.parse(fs.readFileSync("./ormconfig.test.json").toString()),
|
||||
};
|
||||
|
||||
const envs: { [key: string]: IConfig } = { production, development, test };
|
||||
const env = process.env.NODE_ENV;
|
||||
const currentConfig = envs[env];
|
||||
|
||||
export { currentConfig as config };
|
||||
61
src/entity/User.ts
Normal file
61
src/entity/User.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import * as bcrypt from "bcrypt";
|
||||
import * as jwt from "jsonwebtoken";
|
||||
import {
|
||||
BaseEntity,
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
PrimaryGeneratedColumn,
|
||||
} from "typeorm";
|
||||
import { config } from "~config";
|
||||
|
||||
export type IUserJSON = Pick<User, "id" | "username">;
|
||||
|
||||
export interface IUserJWT extends IUserJSON {
|
||||
ext: number;
|
||||
iat: number;
|
||||
}
|
||||
|
||||
export interface IUserAuthJSON extends IUserJSON {
|
||||
jwt: string;
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class User extends BaseEntity {
|
||||
@PrimaryGeneratedColumn()
|
||||
public id: number;
|
||||
|
||||
@Column()
|
||||
@Index({ unique: true })
|
||||
public username: string;
|
||||
|
||||
@Column()
|
||||
public passwordHash: string;
|
||||
|
||||
constructor(username: string) {
|
||||
super();
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public async verifyPassword(password: string) {
|
||||
return bcrypt.compare(password, this.passwordHash);
|
||||
}
|
||||
|
||||
public async setPassword(password: string) {
|
||||
this.passwordHash = await bcrypt.hash(password, 10);
|
||||
}
|
||||
|
||||
public toJSON(): IUserJSON {
|
||||
const { id, username } = this;
|
||||
return { id, username };
|
||||
}
|
||||
|
||||
public toAuthJSON(): IUserAuthJSON {
|
||||
const { id, username } = this;
|
||||
return { id, username, jwt: this.toJWT() };
|
||||
}
|
||||
|
||||
public toJWT() {
|
||||
return jwt.sign(this.toJSON(), config.jwtSecret, { expiresIn: "31d" });
|
||||
}
|
||||
}
|
||||
11
src/server.ts
Normal file
11
src/server.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { app } from "~app";
|
||||
import { config } from "~config";
|
||||
import { connect } from "~config/database";
|
||||
|
||||
connect()
|
||||
.then(async connection => {
|
||||
console.log(`connected to ${connection.name}`);
|
||||
app.listen(config.port);
|
||||
console.log(`listening at ${config.port}`);
|
||||
})
|
||||
.catch(error => console.log(error));
|
||||
30
tests/integration/users.test.ts
Normal file
30
tests/integration/users.test.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { connect } from "config/database";
|
||||
import { getConnection } from "typeorm";
|
||||
|
||||
import { ISeed, seedDB } from "./util";
|
||||
|
||||
let seed: ISeed;
|
||||
|
||||
describe("users", () => {
|
||||
before(async () => {
|
||||
await connect();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await getConnection().close();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
seed = await seedDB();
|
||||
});
|
||||
|
||||
it("should get user", async () => {});
|
||||
|
||||
it("should login user", async () => {});
|
||||
|
||||
it("should not login user with wrong password", async () => {});
|
||||
|
||||
it("should signup user", async () => {});
|
||||
|
||||
it("should not signup user with duplicate username", async () => {});
|
||||
});
|
||||
20
tests/integration/util.ts
Normal file
20
tests/integration/util.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { User } from "entity/User";
|
||||
|
||||
export interface ISeed {
|
||||
user1: User;
|
||||
user2: User;
|
||||
}
|
||||
|
||||
export async function seedDB(): Promise<ISeed> {
|
||||
await User.remove(await User.find());
|
||||
|
||||
const user1 = new User("User1");
|
||||
await user1.setPassword("User1");
|
||||
await user1.save();
|
||||
|
||||
const user2 = new User("User2");
|
||||
await user2.setPassword("User2");
|
||||
await user2.save();
|
||||
|
||||
return { user1, user2 };
|
||||
}
|
||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"es2017"
|
||||
],
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"~*": [
|
||||
"./*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
"frontend"
|
||||
]
|
||||
}
|
||||
15
tslint.json
Normal file
15
tslint.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": [
|
||||
"@blueprintjs/tslint-config",
|
||||
"tslint-plugin-prettier",
|
||||
"tslint-no-unused-expression-chai"
|
||||
],
|
||||
"rules": {
|
||||
"prettier": true,
|
||||
"no-console": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"no-implicit-dependencies": false,
|
||||
"no-submodule-imports": false,
|
||||
"no-this-assignment": false
|
||||
}
|
||||
}
|
||||
16
writer.code-workspace
Normal file
16
writer.code-workspace
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "frontend"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"typescriptHero.imports.stringQuoteStyle": "\"",
|
||||
"files.exclude": {
|
||||
"**/node_modules": true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user