Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/elastic-eslint-config-kibana/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ module.exports = {
'@kbn/eslint/no_async_promise_body': 'error',
'@kbn/eslint/no_async_foreach': 'error',
'@kbn/eslint/no_trailing_import_slash': 'error',
'@kbn/eslint/no_constructor_args_in_property_initializers': 'error',
},
};
20 changes: 11 additions & 9 deletions packages/kbn-cli-dev-mode/src/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,18 @@ export interface Log {
}

export class CliLog implements Log {
public toolingLog = new ToolingLog({
level: this.silent ? 'silent' : this.quiet ? 'error' : 'info',
writeTo: {
write: (msg) => {
this.write(msg);
public toolingLog: ToolingLog;

constructor(private readonly quiet: boolean, private readonly silent: boolean) {
this.toolingLog = new ToolingLog({
level: this.silent ? 'silent' : this.quiet ? 'error' : 'info',
writeTo: {
write: (msg) => {
this.write(msg);
},
},
},
});

constructor(private readonly quiet: boolean, private readonly silent: boolean) {}
});
}

good(label: string, ...args: any[]) {
if (this.quiet || this.silent) {
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-eslint-plugin-eslint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ module.exports = {
no_async_promise_body: require('./rules/no_async_promise_body'),
no_async_foreach: require('./rules/no_async_foreach'),
no_trailing_import_slash: require('./rules/no_trailing_import_slash'),
no_constructor_args_in_property_initializers: require('./rules/no_constructor_args_in_property_initializers'),
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@ const esTypes = tsEstree.AST_NODE_TYPES;
const babelTypes = require('@babel/types');

/** @typedef {import("eslint").Rule.RuleModule} Rule */
/** @typedef {import("@typescript-eslint/parser").ParserServices} ParserServices */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Expression} Expression */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.ArrowFunctionExpression} ArrowFunctionExpression */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.FunctionExpression} FunctionExpression */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.TryStatement} TryStatement */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.NewExpression} NewExpression */
/** @typedef {import("typescript").ExportDeclaration} ExportDeclaration */
/** @typedef {import("eslint").Rule.RuleFixer} Fixer */

const ERROR_MSG =
'Passing an async function to the Promise constructor leads to a hidden promise being created and prevents handling rejections';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

const tsEstree = require('@typescript-eslint/typescript-estree');
const traverse = require('eslint-traverse');
const esTypes = tsEstree.AST_NODE_TYPES;

/** @typedef {import("eslint").Rule.RuleModule} Rule */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Node} Node */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.ClassBody} ClassBody */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.Parameter} Parameter */
/** @typedef {import("@typescript-eslint/typescript-estree").TSESTree.TSParameterProperty} TSParameterProperty */

/**
* @param {Parameter} param
* @returns {param is TSParameterProperty}
*/
function isTsParameterProperty(param) {
return param.type === esTypes.TSParameterProperty;
}

/**
* @param {string} arg
*/
const errorMsg = (arg) =>
`The constructor argument "${arg}" can't be used in a class property intializer, define the property in the constructor instead`;

/** @type {Rule} */
module.exports = {
meta: {
schema: [],
},
create: (context) => ({
ClassBody(_) {
const node = /** @type {ClassBody} */ (_);

const constructor = node.body.find(
(n) => n.type === esTypes.MethodDefinition && n.kind === 'constructor'
);

if (!constructor || constructor.type !== esTypes.MethodDefinition) {
return;
}

const constructorArgProps = constructor.value.params
.filter(isTsParameterProperty)
.map((p) => {
if (p.parameter.type === esTypes.Identifier) {
return p.parameter.name;
}

if (
p.parameter.type === esTypes.AssignmentPattern &&
p.parameter.left.type === esTypes.Identifier
) {
return p.parameter.left.name;
}
});

if (!constructorArgProps.length) {
return;
}

for (const prop of node.body) {
if (prop.type !== esTypes.PropertyDefinition) {
continue;
}

const visitor = (path) => {
/** @type {Node} node */
const node = path.node;

if (
node.type === esTypes.FunctionExpression ||
node.type === esTypes.ArrowFunctionExpression
) {
return traverse.STOP;
}

if (
node.type === esTypes.MemberExpression &&
node.object.type === esTypes.ThisExpression &&
node.property.type === esTypes.Identifier &&
node.property.name &&
constructorArgProps.includes(node.property.name)
) {
context.report({
message: errorMsg(node.property.name),
loc: node.property.loc,
});
}
};

traverse(context, prop, visitor);
}
},
}),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

const { RuleTester } = require('eslint');
const rule = require('./no_constructor_args_in_property_initializers');
const dedent = require('dedent');

const ruleTester = new RuleTester({
parser: require.resolve('@typescript-eslint/parser'),
parserOptions: {
sourceType: 'module',
ecmaVersion: 2018,
ecmaFeatures: {
jsx: true,
},
},
});

ruleTester.run('@kbn/eslint/no_constructor_args_in_property_initializers', rule, {
valid: [
{
code: dedent`
class Foo {
bar = 'baz'
}
`,
},
{
code: dedent`
class Foo {
bar = 'baz'
constructor(private readonly foo: Box) {}
}
`,
},
{
code: dedent`
class Foo {
bar = 'baz'
constructor(private readonly foo: () => void) {}

get = () => {
return this.foo()
}
}
`,
},
],

invalid: [
// no catch
{
code: dedent`
class Foo {
bar = this.foo.split().reverse()
constructor(private readonly foo: string) {}
}
`,
errors: [
{
line: 2,
message: `The constructor argument "foo" can't be used in a class property intializer, define the property in the constructor instead`,
},
],
},
{
code: dedent`
class Foo {
bar = this.foo()
constructor(private readonly foo: () => void) {}
}
`,
errors: [
{
line: 2,
message: `The constructor argument "foo" can't be used in a class property intializer, define the property in the constructor instead`,
},
],
},
{
code: dedent`
class Foo {
bar = this.foo()
constructor(private readonly foo: (() => void) = defaultValue) {}
}
`,
errors: [
{
line: 2,
message: `The constructor argument "foo" can't be used in a class property intializer, define the property in the constructor instead`,
},
],
},
],
});
6 changes: 4 additions & 2 deletions packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ type ModuleFactory = (data: RequestData, callback: Callback<BundleRefModule>) =>
export class BundleRefsPlugin {
private readonly resolvedRefEntryCache = new Map<BundleRef, Promise<string>>();
private readonly resolvedRequestCache = new Map<string, Promise<string | undefined>>();
private readonly ignorePrefix = Path.resolve(this.bundle.contextDir) + Path.sep;
private readonly ignorePrefix: string;
private allowedBundleIds = new Set<string>();

constructor(private readonly bundle: Bundle, private readonly bundleRefs: BundleRefs) {}
constructor(private readonly bundle: Bundle, private readonly bundleRefs: BundleRefs) {
this.ignorePrefix = Path.resolve(this.bundle.contextDir) + Path.sep;
}

/**
* Called by webpack when the plugin is passed in the webpack config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,27 @@ export type GetArgsType<T extends LifecycleEvent<any>> = T extends LifecycleEven
export class LifecycleEvent<Args extends readonly any[]> {
private readonly handlers: Array<(...args: Args) => Promise<void> | void> = [];

private readonly beforeSubj = this.options.singular
? new Rx.BehaviorSubject(undefined)
: new Rx.Subject<void>();
public readonly before$ = this.beforeSubj.asObservable();
private readonly beforeSubj: Rx.Subject<void>;
public readonly before$: Rx.Observable<void>;

private readonly afterSubj = this.options.singular
? new Rx.BehaviorSubject(undefined)
: new Rx.Subject<void>();
public readonly after$ = this.afterSubj.asObservable();
private readonly afterSubj: Rx.Subject<void>;
public readonly after$: Rx.Observable<void>;

constructor(
private readonly options: {
singular?: boolean;
} = {}
) {}
) {
this.beforeSubj = this.options.singular
? new Rx.BehaviorSubject<void>(undefined)
: new Rx.Subject<void>();
this.before$ = this.beforeSubj.asObservable();

this.afterSubj = this.options.singular
? new Rx.BehaviorSubject<void>(undefined)
: new Rx.Subject<void>();
this.after$ = this.afterSubj.asObservable();
}

public add(fn: (...args: Args) => Promise<void> | void) {
this.handlers.push(fn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,23 @@ export class LifecyclePhase<Args extends readonly any[]> {

public triggered = false;

private readonly beforeSubj = new Rx.Subject<void>();
public readonly before$ = this.beforeSubj.asObservable();
private readonly beforeSubj: Rx.Subject<void>;
public readonly before$: Rx.Observable<void>;

private readonly afterSubj = this.options.singular
? new Rx.ReplaySubject<void>(1)
: new Rx.Subject<void>();
public readonly after$ = this.afterSubj.asObservable();
private readonly afterSubj: Rx.Subject<void>;
public readonly after$: Rx.Observable<void>;

constructor(
private readonly options: {
singular?: boolean;
} = {}
) {}
) {
this.beforeSubj = new Rx.Subject<void>();
this.before$ = this.beforeSubj.asObservable();

this.afterSubj = this.options.singular ? new Rx.ReplaySubject<void>(1) : new Rx.Subject<void>();
this.after$ = this.afterSubj.asObservable();
}

public add(fn: (...args: Args) => Promise<void> | void) {
this.handlers.push(fn);
Expand Down
6 changes: 4 additions & 2 deletions src/core/public/chrome/chrome_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@ import { ChromeService } from './chrome_service';
import { getAppInfo } from '../application/utils';

class FakeApp implements App {
public title = `${this.id} App`;
public title: string;
public mount = () => () => {};

constructor(public id: string, public chromeless?: boolean) {}
constructor(public id: string, public chromeless?: boolean) {
this.title = `${this.id} App`;
}
}

const store = new Map();
Expand Down
10 changes: 6 additions & 4 deletions src/core/public/injected_metadata/injected_metadata_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ export interface InjectedMetadataParams {
* @internal
*/
export class InjectedMetadataService {
private state = deepFreeze(
this.params.injectedMetadata
) as InjectedMetadataParams['injectedMetadata'];
private state: InjectedMetadataParams['injectedMetadata'];

constructor(private readonly params: InjectedMetadataParams) {}
constructor(private readonly params: InjectedMetadataParams) {
this.state = deepFreeze(
this.params.injectedMetadata
) as InjectedMetadataParams['injectedMetadata'];
}

public start(): InjectedMetadataStart {
return this.setup();
Expand Down
6 changes: 4 additions & 2 deletions src/core/server/plugins/plugins_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ export interface PluginsServiceDiscoverDeps {
/** @internal */
export class PluginsService implements CoreService<PluginsServiceSetup, PluginsServiceStart> {
private readonly log: Logger;
private readonly prebootPluginsSystem = new PluginsSystem(this.coreContext, PluginType.preboot);
private readonly prebootPluginsSystem: PluginsSystem<PluginType.preboot>;
private arePrebootPluginsStopped = false;
private readonly prebootUiPluginInternalInfo = new Map<PluginName, InternalPluginInfo>();
private readonly standardPluginsSystem = new PluginsSystem(this.coreContext, PluginType.standard);
private readonly standardPluginsSystem: PluginsSystem<PluginType.standard>;
private readonly standardUiPluginInternalInfo = new Map<PluginName, InternalPluginInfo>();
private readonly configService: IConfigService;
private readonly config$: Observable<PluginsConfig>;
Expand All @@ -105,6 +105,8 @@ export class PluginsService implements CoreService<PluginsServiceSetup, PluginsS
this.config$ = coreContext.configService
.atPath<PluginsConfigType>('plugins')
.pipe(map((rawConfig) => new PluginsConfig(rawConfig, coreContext.env)));
this.prebootPluginsSystem = new PluginsSystem(this.coreContext, PluginType.preboot);
this.standardPluginsSystem = new PluginsSystem(this.coreContext, PluginType.standard);
}

public async discover({ environment }: PluginsServiceDiscoverDeps): Promise<DiscoveredPlugins> {
Expand Down
Loading