зеркало из https://github.com/mozilla/fxa.git
chore(hooks): turn on prettier hook for typescript
This commit is contained in:
Родитель
8d087d850d
Коммит
7e69761f05
|
@ -74,6 +74,10 @@
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"git add"
|
"git add"
|
||||||
],
|
],
|
||||||
|
"*.ts": [
|
||||||
|
"prettier --write",
|
||||||
|
"git add"
|
||||||
|
],
|
||||||
"*.css": [
|
"*.css": [
|
||||||
"prettier --write",
|
"prettier --write",
|
||||||
"git add"
|
"git add"
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["tslint:recommended", "tslint-config-prettier"],
|
||||||
"tslint:recommended",
|
"rulesDirectory": ["tslint-plugin-prettier"],
|
||||||
"tslint-config-prettier"
|
"rules": {
|
||||||
],
|
"interface-name": [true, "never-prefix"],
|
||||||
"rulesDirectory": ["tslint-plugin-prettier"],
|
"interface-over-type-literal": false,
|
||||||
"rules": {
|
"prettier": [true, ".prettierrc"]
|
||||||
"interface-name": [true, "never-prefix"],
|
}
|
||||||
"interface-over-type-literal": false,
|
|
||||||
"prettier": [true, ".prettierrc"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
|
||||||
"dom.iterable",
|
|
||||||
"esnext"
|
|
||||||
],
|
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
@ -19,7 +15,5 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "preserve"
|
"jsx": "preserve"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src"]
|
||||||
"src"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,61 +11,61 @@ const conf = convict({
|
||||||
default: 'oidc-claim-id-token-email',
|
default: 'oidc-claim-id-token-email',
|
||||||
doc: 'Authentication header that should be logged for the user',
|
doc: 'Authentication header that should be logged for the user',
|
||||||
env: 'AUTH_HEADER',
|
env: 'AUTH_HEADER',
|
||||||
format: String
|
format: String,
|
||||||
},
|
},
|
||||||
authdbUrl: {
|
authdbUrl: {
|
||||||
default: 'http://localhost:8000',
|
default: 'http://localhost:8000',
|
||||||
doc: 'fxa-auth-db-mysql url',
|
doc: 'fxa-auth-db-mysql url',
|
||||||
env: 'AUTHDB_URL',
|
env: 'AUTHDB_URL',
|
||||||
format: String
|
format: String,
|
||||||
},
|
},
|
||||||
env: {
|
env: {
|
||||||
default: 'production',
|
default: 'production',
|
||||||
doc: 'The current node.js environment',
|
doc: 'The current node.js environment',
|
||||||
env: 'NODE_ENV',
|
env: 'NODE_ENV',
|
||||||
format: ['development', 'stage', 'production']
|
format: ['development', 'stage', 'production'],
|
||||||
},
|
},
|
||||||
listen: {
|
listen: {
|
||||||
host: {
|
host: {
|
||||||
default: '127.0.0.1',
|
default: '127.0.0.1',
|
||||||
doc: 'The ip address the server should bind',
|
doc: 'The ip address the server should bind',
|
||||||
env: 'IP_ADDRESS',
|
env: 'IP_ADDRESS',
|
||||||
format: 'ipaddress'
|
format: 'ipaddress',
|
||||||
},
|
},
|
||||||
port: {
|
port: {
|
||||||
default: 7100,
|
default: 7100,
|
||||||
doc: 'The port the server should bind',
|
doc: 'The port the server should bind',
|
||||||
env: 'PORT',
|
env: 'PORT',
|
||||||
format: 'port'
|
format: 'port',
|
||||||
},
|
},
|
||||||
publicUrl: {
|
publicUrl: {
|
||||||
default: 'http://127.0.0.1:3031',
|
default: 'http://127.0.0.1:3031',
|
||||||
env: 'PUBLIC_URL',
|
env: 'PUBLIC_URL',
|
||||||
format: 'url'
|
format: 'url',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
logging: {
|
logging: {
|
||||||
app: { default: 'fxa-support-panel' },
|
app: { default: 'fxa-support-panel' },
|
||||||
fmt: {
|
fmt: {
|
||||||
default: 'heka',
|
default: 'heka',
|
||||||
env: 'LOGGING_FORMAT',
|
env: 'LOGGING_FORMAT',
|
||||||
format: ['heka', 'pretty']
|
format: ['heka', 'pretty'],
|
||||||
},
|
},
|
||||||
level: {
|
level: {
|
||||||
default: 'info',
|
default: 'info',
|
||||||
env: 'LOG_LEVEL'
|
env: 'LOG_LEVEL',
|
||||||
},
|
},
|
||||||
routes: {
|
routes: {
|
||||||
enabled: {
|
enabled: {
|
||||||
default: true,
|
default: true,
|
||||||
doc: 'Enable route logging. Set to false to trimming CI logs.',
|
doc: 'Enable route logging. Set to false to trimming CI logs.',
|
||||||
env: 'ENABLE_ROUTE_LOGGING'
|
env: 'ENABLE_ROUTE_LOGGING',
|
||||||
},
|
},
|
||||||
format: {
|
format: {
|
||||||
default: 'default_fxa',
|
default: 'default_fxa',
|
||||||
format: ['default_fxa', 'dev_fxa', 'default', 'dev', 'short', 'tiny']
|
format: ['default_fxa', 'dev_fxa', 'default', 'dev', 'short', 'tiny'],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
security: {
|
security: {
|
||||||
csp: {
|
csp: {
|
||||||
|
@ -73,10 +73,10 @@ const conf = convict({
|
||||||
default: 'none',
|
default: 'none',
|
||||||
doc:
|
doc:
|
||||||
'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors',
|
'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors',
|
||||||
env: 'CSP_FRAME_ANCESTORS'
|
env: 'CSP_FRAME_ANCESTORS',
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// handle configuration files. you can specify a CSV list of configuration
|
// handle configuration files. you can specify a CSV list of configuration
|
||||||
|
|
|
@ -29,7 +29,7 @@ const queryValidator = joi
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.hex()
|
.hex()
|
||||||
.length(32)
|
.length(32),
|
||||||
})
|
})
|
||||||
.required();
|
.required();
|
||||||
|
|
||||||
|
@ -95,22 +95,31 @@ class SupportController {
|
||||||
const uid = query.uid;
|
const uid = query.uid;
|
||||||
const requestTicket = query.requestTicket || 'ticket-unknown';
|
const requestTicket = query.requestTicket || 'ticket-unknown';
|
||||||
const opts = {
|
const opts = {
|
||||||
json: true
|
json: true,
|
||||||
};
|
};
|
||||||
// This is the user who is asking for the information:
|
// This is the user who is asking for the information:
|
||||||
this.logger.info('infoRequest', {
|
this.logger.info('infoRequest', {
|
||||||
authUser: request.headers[this.config.authHeader.toLowerCase()],
|
authUser: request.headers[this.config.authHeader.toLowerCase()],
|
||||||
requestTicket,
|
requestTicket,
|
||||||
uid
|
uid,
|
||||||
});
|
});
|
||||||
let account: AccountResponse;
|
let account: AccountResponse;
|
||||||
let devices: DevicesResponse;
|
let devices: DevicesResponse;
|
||||||
let subscriptions: SubscriptionResponse;
|
let subscriptions: SubscriptionResponse;
|
||||||
try {
|
try {
|
||||||
[account, devices, subscriptions] = await P.all([
|
[account, devices, subscriptions] = await P.all([
|
||||||
requests.get({ ...opts, url: `${this.config.authdbUrl}/account/${uid}` }),
|
requests.get({
|
||||||
requests.get({ ...opts, url: `${this.config.authdbUrl}/account/${uid}/devices` }),
|
...opts,
|
||||||
requests.get({ ...opts, url: `${this.config.authdbUrl}/account/${uid}/subscriptions` })
|
url: `${this.config.authdbUrl}/account/${uid}`,
|
||||||
|
}),
|
||||||
|
requests.get({
|
||||||
|
...opts,
|
||||||
|
url: `${this.config.authdbUrl}/account/${uid}/devices`,
|
||||||
|
}),
|
||||||
|
requests.get({
|
||||||
|
...opts,
|
||||||
|
url: `${this.config.authdbUrl}/account/${uid}/subscriptions`,
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error('infoFetch', { err });
|
this.logger.error('infoFetch', { err });
|
||||||
|
@ -122,7 +131,7 @@ class SupportController {
|
||||||
totpResponse = await requests.get({
|
totpResponse = await requests.get({
|
||||||
json: true,
|
json: true,
|
||||||
resolveWithFullResponse: true,
|
resolveWithFullResponse: true,
|
||||||
url: `${this.config.authdbUrl}/totp/${uid}`
|
url: `${this.config.authdbUrl}/totp/${uid}`,
|
||||||
});
|
});
|
||||||
totpEnabled = (totpResponse.body as TotpTokenResponse).enabled;
|
totpEnabled = (totpResponse.body as TotpTokenResponse).enabled;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -137,21 +146,29 @@ class SupportController {
|
||||||
const context: PanelTemplateContext = {
|
const context: PanelTemplateContext = {
|
||||||
created: String(new Date(account.createdAt)),
|
created: String(new Date(account.createdAt)),
|
||||||
devices: devices.map(d => {
|
devices: devices.map(d => {
|
||||||
return { name: d.name, type: d.type, created: String(new Date(d.createdAt)) };
|
return {
|
||||||
|
created: String(new Date(d.createdAt)),
|
||||||
|
name: d.name,
|
||||||
|
type: d.type,
|
||||||
|
};
|
||||||
}),
|
}),
|
||||||
email: account.email,
|
email: account.email,
|
||||||
emailVerified: !!account.emailVerified,
|
emailVerified: !!account.emailVerified,
|
||||||
locale: account.locale,
|
locale: account.locale,
|
||||||
subscriptionStatus: hasSubscriptions,
|
subscriptionStatus: hasSubscriptions,
|
||||||
twoFactorAuth: totpEnabled,
|
twoFactorAuth: totpEnabled,
|
||||||
uid
|
uid,
|
||||||
};
|
};
|
||||||
const payload = this.template(context);
|
const payload = this.template(context);
|
||||||
return h.response(payload).code(200);
|
return h.response(payload).code(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function init(logger: Logger, config: SupportConfig, server: hapi.Server) {
|
export function init(
|
||||||
|
logger: Logger,
|
||||||
|
config: SupportConfig,
|
||||||
|
server: hapi.Server
|
||||||
|
) {
|
||||||
let rootDir;
|
let rootDir;
|
||||||
// Check to see if we're running in a compiled form for prod/dev or testing
|
// Check to see if we're running in a compiled form for prod/dev or testing
|
||||||
if (__dirname.includes('/dist/')) {
|
if (__dirname.includes('/dist/')) {
|
||||||
|
@ -163,7 +180,7 @@ export function init(logger: Logger, config: SupportConfig, server: hapi.Server)
|
||||||
}
|
}
|
||||||
const templateDir = path.join(rootDir, 'lib', 'templates');
|
const templateDir = path.join(rootDir, 'lib', 'templates');
|
||||||
const pageTemplate = fs.readFileSync(path.join(templateDir, 'index.html'), {
|
const pageTemplate = fs.readFileSync(path.join(templateDir, 'index.html'), {
|
||||||
encoding: 'UTF-8'
|
encoding: 'UTF-8',
|
||||||
});
|
});
|
||||||
const template = handlebars.compile(pageTemplate);
|
const template = handlebars.compile(pageTemplate);
|
||||||
|
|
||||||
|
@ -174,17 +191,17 @@ export function init(logger: Logger, config: SupportConfig, server: hapi.Server)
|
||||||
{
|
{
|
||||||
handler: supportController.heartbeat,
|
handler: supportController.heartbeat,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/__lbheartbeat__'
|
path: '/__lbheartbeat__',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
options: {
|
options: {
|
||||||
handler: supportController.displayUser,
|
handler: supportController.displayUser,
|
||||||
validate: {
|
validate: {
|
||||||
query: queryValidator as hapiJoi.ObjectSchema
|
query: queryValidator as hapiJoi.ObjectSchema,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
path: '/'
|
path: '/',
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,10 @@ export type ServerConfig = api.SupportConfig & {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function init(serverConfig: ServerConfig, logger: Logger): Promise<hapi.Server> {
|
export async function init(
|
||||||
|
serverConfig: ServerConfig,
|
||||||
|
logger: Logger
|
||||||
|
): Promise<hapi.Server> {
|
||||||
const server = new hapi.Server({
|
const server = new hapi.Server({
|
||||||
debug: serverConfig.env === 'production' ? false : { request: ['error'] },
|
debug: serverConfig.env === 'production' ? false : { request: ['error'] },
|
||||||
host: serverConfig.listen.host,
|
host: serverConfig.listen.host,
|
||||||
|
@ -30,19 +33,19 @@ export async function init(serverConfig: ServerConfig, logger: Logger): Promise<
|
||||||
hsts: {
|
hsts: {
|
||||||
includeSubDomains: true,
|
includeSubDomains: true,
|
||||||
maxAge: 31536000,
|
maxAge: 31536000,
|
||||||
preload: false
|
preload: false,
|
||||||
},
|
},
|
||||||
xss: true
|
xss: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.register([
|
await server.register([
|
||||||
Scooter,
|
Scooter,
|
||||||
{
|
{
|
||||||
options: Config.get('security.csp'),
|
options: Config.get('security.csp'),
|
||||||
plugin: Blankie
|
plugin: Blankie,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
api.init(logger, serverConfig, server);
|
api.init(logger, serverConfig, server);
|
||||||
|
|
|
@ -16,7 +16,7 @@ import {
|
||||||
AccountResponse,
|
AccountResponse,
|
||||||
DevicesResponse,
|
DevicesResponse,
|
||||||
SubscriptionResponse,
|
SubscriptionResponse,
|
||||||
TotpTokenResponse
|
TotpTokenResponse,
|
||||||
} from '../../lib/api';
|
} from '../../lib/api';
|
||||||
import * as supportServer from '../../lib/server';
|
import * as supportServer from '../../lib/server';
|
||||||
|
|
||||||
|
@ -42,27 +42,27 @@ function createDefaults(): MockCallsResponse {
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
email: 'test@example.com',
|
email: 'test@example.com',
|
||||||
emailVerified: true,
|
emailVerified: true,
|
||||||
locale: 'en-us'
|
locale: 'en-us',
|
||||||
},
|
},
|
||||||
status: 200
|
status: 200,
|
||||||
},
|
},
|
||||||
devices: {
|
devices: {
|
||||||
response: [],
|
response: [],
|
||||||
status: 200
|
status: 200,
|
||||||
},
|
},
|
||||||
subscriptions: {
|
subscriptions: {
|
||||||
response: [],
|
response: [],
|
||||||
status: 200
|
status: 200,
|
||||||
},
|
},
|
||||||
totp: {
|
totp: {
|
||||||
response: {
|
response: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
epoch: now,
|
epoch: now,
|
||||||
sharedSecret: '',
|
sharedSecret: '',
|
||||||
verified: true
|
verified: true,
|
||||||
},
|
},
|
||||||
status: 200
|
status: 200,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ describe('Support Controller', () => {
|
||||||
env: 'development',
|
env: 'development',
|
||||||
listen: {
|
listen: {
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 8099
|
port: 8099,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
|
@ -111,7 +111,7 @@ describe('Support Controller', () => {
|
||||||
it('has a heartbeat', async () => {
|
it('has a heartbeat', async () => {
|
||||||
const result = await server.inject({
|
const result = await server.inject({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/__lbheartbeat__'
|
url: '/__lbheartbeat__',
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 200);
|
cassert.equal(result.statusCode, 200);
|
||||||
});
|
});
|
||||||
|
@ -124,10 +124,10 @@ describe('Support Controller', () => {
|
||||||
const getWithUrl = (url: string): Promise<hapi.ServerInjectResponse> => {
|
const getWithUrl = (url: string): Promise<hapi.ServerInjectResponse> => {
|
||||||
return server.inject({
|
return server.inject({
|
||||||
headers: {
|
headers: {
|
||||||
testing: 'example@example.com'
|
testing: 'example@example.com',
|
||||||
},
|
},
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url
|
url,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -160,7 +160,9 @@ describe('Support Controller', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rejects a uid that is too long', async () => {
|
it('rejects a uid that is too long', async () => {
|
||||||
const result = await getWithUrl('/?uid=4a0f70e0e32a435e8066d353e8577d22a');
|
const result = await getWithUrl(
|
||||||
|
'/?uid=4a0f70e0e32a435e8066d353e8577d22a'
|
||||||
|
);
|
||||||
cassert.equal(result.statusCode, 400);
|
cassert.equal(result.statusCode, 400);
|
||||||
assertValidateErrorMessage(result.payload);
|
assertValidateErrorMessage(result.payload);
|
||||||
});
|
});
|
||||||
|
@ -198,10 +200,10 @@ describe('Support Controller', () => {
|
||||||
mockCalls(createDefaults());
|
mockCalls(createDefaults());
|
||||||
const result = await server.inject({
|
const result = await server.inject({
|
||||||
headers: {
|
headers: {
|
||||||
testing: 'example@example.com'
|
testing: 'example@example.com',
|
||||||
},
|
},
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/?uid=${uid}`
|
url: `/?uid=${uid}`,
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 200);
|
cassert.equal(result.statusCode, 200);
|
||||||
const calls = (logger.info as SinonSpy).getCalls();
|
const calls = (logger.info as SinonSpy).getCalls();
|
||||||
|
@ -211,8 +213,8 @@ describe('Support Controller', () => {
|
||||||
{
|
{
|
||||||
authUser: 'example@example.com',
|
authUser: 'example@example.com',
|
||||||
requestTicket: 'ticket-unknown',
|
requestTicket: 'ticket-unknown',
|
||||||
uid: '4a0f70e0e32a435e8066d353e8577d2a'
|
uid: '4a0f70e0e32a435e8066d353e8577d2a',
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -222,7 +224,7 @@ describe('Support Controller', () => {
|
||||||
mockCalls(defaults);
|
mockCalls(defaults);
|
||||||
let result = await server.inject({
|
let result = await server.inject({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/?uid=${uid}`
|
url: `/?uid=${uid}`,
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 500);
|
cassert.equal(result.statusCode, 500);
|
||||||
|
|
||||||
|
@ -232,7 +234,7 @@ describe('Support Controller', () => {
|
||||||
mockCalls(defaults);
|
mockCalls(defaults);
|
||||||
result = await server.inject({
|
result = await server.inject({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/?uid=${uid}`
|
url: `/?uid=${uid}`,
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 500);
|
cassert.equal(result.statusCode, 500);
|
||||||
});
|
});
|
||||||
|
@ -243,10 +245,12 @@ describe('Support Controller', () => {
|
||||||
mockCalls(defaults);
|
mockCalls(defaults);
|
||||||
const result = await server.inject({
|
const result = await server.inject({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/?uid=${uid}`
|
url: `/?uid=${uid}`,
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 200);
|
cassert.equal(result.statusCode, 200);
|
||||||
const payloadMatch = result.payload.match(/2FA enabled\?<\/th>\s*<td>\s*no/g);
|
const payloadMatch = result.payload.match(
|
||||||
|
/2FA enabled\?<\/th>\s*<td>\s*no/g
|
||||||
|
);
|
||||||
cassert.isTrue(payloadMatch && payloadMatch.length === 1);
|
cassert.isTrue(payloadMatch && payloadMatch.length === 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -256,7 +260,7 @@ describe('Support Controller', () => {
|
||||||
mockCalls(defaults);
|
mockCalls(defaults);
|
||||||
const result = await server.inject({
|
const result = await server.inject({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/?uid=${uid}`
|
url: `/?uid=${uid}`,
|
||||||
});
|
});
|
||||||
cassert.equal(result.statusCode, 500);
|
cassert.equal(result.statusCode, 500);
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,5 @@
|
||||||
"./test/**/*",
|
"./test/**/*",
|
||||||
"./types/**/*"
|
"./types/**/*"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": ["node_modules"]
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
{
|
{
|
||||||
"extends": [
|
"extends": ["tslint:recommended", "tslint-config-prettier"],
|
||||||
"tslint:recommended",
|
"rulesDirectory": ["tslint-plugin-prettier"],
|
||||||
"tslint-config-prettier"
|
"rules": {
|
||||||
],
|
"interface-name": [true, "never-prefix"],
|
||||||
"rulesDirectory": ["tslint-plugin-prettier"],
|
"interface-over-type-literal": false,
|
||||||
"rules": {
|
"prettier": [true, ".prettierrc"]
|
||||||
"interface-name": [true, "never-prefix"],
|
}
|
||||||
"interface-over-type-literal": false,
|
|
||||||
"prettier": [true, ".prettierrc"]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче