Skip to content

Commit

Permalink
chore: use private fields (#8506)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrandolf committed Jun 13, 2022
1 parent 733cbec commit 6c96011
Show file tree
Hide file tree
Showing 46 changed files with 1,824 additions and 1,751 deletions.
37 changes: 27 additions & 10 deletions .eslintrc.js
@@ -1,3 +1,12 @@
// TODO: Enable this at some point.
// const RESTRICTED_UNDERSCORED_IDENTIFIERS = [
// 'PropertyDefinition > Identifier[name=/^_[a-z].*$/]',
// ].map((selector) => ({
// selector,
// message:
// 'Use private fields (fields prefixed with #) and an appropriate getter/setter.',
// }));

module.exports = {
root: true,
env: {
Expand All @@ -15,14 +24,6 @@ module.exports = {
// Error if files are not formatted with Prettier correctly.
'prettier/prettier': 2,
// syntax preferences
quotes: [
2,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true,
},
],
'spaced-comment': [
2,
'always',
Expand Down Expand Up @@ -116,6 +117,12 @@ module.exports = {
},
],
'import/extensions': ['error', 'ignorePackages'],

'no-restricted-syntax': [
'error',
// Don't allow underscored declarations on camelCased variables/properties.
// ...RESTRICTED_UNDERSCORED_IDENTIFIERS,
],
},
overrides: [
{
Expand Down Expand Up @@ -144,8 +151,6 @@ module.exports = {
// We don't require explicit return types on basic functions or
// dummy functions in tests, for example
'@typescript-eslint/explicit-function-return-type': 0,
// We know it's bad and use it very sparingly but it's needed :(
'@typescript-eslint/ban-ts-ignore': 0,
// We allow non-null assertions if the value was asserted using `assert` API.
'@typescript-eslint/no-non-null-assertion': 0,
/**
Expand Down Expand Up @@ -176,6 +181,18 @@ module.exports = {
],
// By default this is a warning but we want it to error.
'@typescript-eslint/explicit-module-boundary-types': 2,

'no-restricted-syntax': [
'error',
{
// Never use `require` in TypeScript since they are transpiled out.
selector: "CallExpression[callee.name='require']",
message: '`require` statements are not allowed. Use `import`.',
},

// Don't allow underscored declarations on camelCased variables/properties.
// ...RESTRICTED_UNDERSCORED_IDENTIFIERS,
],
},
},
],
Expand Down
86 changes: 43 additions & 43 deletions src/common/Accessibility.ts
Expand Up @@ -130,13 +130,13 @@ export interface SnapshotOptions {
* @public
*/
export class Accessibility {
private _client: CDPSession;
#client: CDPSession;

/**
* @internal
*/
constructor(client: CDPSession) {
this._client = client;
this.#client = client;
}

/**
Expand Down Expand Up @@ -182,10 +182,10 @@ export class Accessibility {
options: SnapshotOptions = {}
): Promise<SerializedAXNode | null> {
const { interestingOnly = true, root = null } = options;
const { nodes } = await this._client.send('Accessibility.getFullAXTree');
const { nodes } = await this.#client.send('Accessibility.getFullAXTree');
let backendNodeId: number | undefined;
if (root) {
const { node } = await this._client.send('DOM.describeNode', {
const { node } = await this.#client.send('DOM.describeNode', {
objectId: root._remoteObject.objectId,
});
backendNodeId = node.backendNodeId;
Expand Down Expand Up @@ -238,53 +238,53 @@ class AXNode {
public payload: Protocol.Accessibility.AXNode;
public children: AXNode[] = [];

private _richlyEditable = false;
private _editable = false;
private _focusable = false;
private _hidden = false;
private _name: string;
private _role: string;
private _ignored: boolean;
private _cachedHasFocusableChild?: boolean;
#richlyEditable = false;
#editable = false;
#focusable = false;
#hidden = false;
#name: string;
#role: string;
#ignored: boolean;
#cachedHasFocusableChild?: boolean;

constructor(payload: Protocol.Accessibility.AXNode) {
this.payload = payload;
this._name = this.payload.name ? this.payload.name.value : '';
this._role = this.payload.role ? this.payload.role.value : 'Unknown';
this._ignored = this.payload.ignored;
this.#name = this.payload.name ? this.payload.name.value : '';
this.#role = this.payload.role ? this.payload.role.value : 'Unknown';
this.#ignored = this.payload.ignored;

for (const property of this.payload.properties || []) {
if (property.name === 'editable') {
this._richlyEditable = property.value.value === 'richtext';
this._editable = true;
this.#richlyEditable = property.value.value === 'richtext';
this.#editable = true;
}
if (property.name === 'focusable') this._focusable = property.value.value;
if (property.name === 'hidden') this._hidden = property.value.value;
if (property.name === 'focusable') this.#focusable = property.value.value;
if (property.name === 'hidden') this.#hidden = property.value.value;
}
}

private _isPlainTextField(): boolean {
if (this._richlyEditable) return false;
if (this._editable) return true;
return this._role === 'textbox' || this._role === 'searchbox';
#isPlainTextField(): boolean {
if (this.#richlyEditable) return false;
if (this.#editable) return true;
return this.#role === 'textbox' || this.#role === 'searchbox';
}

private _isTextOnlyObject(): boolean {
const role = this._role;
#isTextOnlyObject(): boolean {
const role = this.#role;
return role === 'LineBreak' || role === 'text' || role === 'InlineTextBox';
}

private _hasFocusableChild(): boolean {
if (this._cachedHasFocusableChild === undefined) {
this._cachedHasFocusableChild = false;
#hasFocusableChild(): boolean {
if (this.#cachedHasFocusableChild === undefined) {
this.#cachedHasFocusableChild = false;
for (const child of this.children) {
if (child._focusable || child._hasFocusableChild()) {
this._cachedHasFocusableChild = true;
if (child.#focusable || child.#hasFocusableChild()) {
this.#cachedHasFocusableChild = true;
break;
}
}
}
return this._cachedHasFocusableChild;
return this.#cachedHasFocusableChild;
}

public find(predicate: (x: AXNode) => boolean): AXNode | null {
Expand All @@ -303,13 +303,13 @@ class AXNode {
// implementation details, but we want to expose them as leaves to platform
// accessibility APIs because screen readers might be confused if they find
// any children.
if (this._isPlainTextField() || this._isTextOnlyObject()) return true;
if (this.#isPlainTextField() || this.#isTextOnlyObject()) return true;

// Roles whose children are only presentational according to the ARIA and
// HTML5 Specs should be hidden from screen readers.
// (Note that whilst ARIA buttons can have only presentational children, HTML5
// buttons are allowed to have content.)
switch (this._role) {
switch (this.#role) {
case 'doc-cover':
case 'graphics-symbol':
case 'img':
Expand All @@ -324,14 +324,14 @@ class AXNode {
}

// Here and below: Android heuristics
if (this._hasFocusableChild()) return false;
if (this._focusable && this._name) return true;
if (this._role === 'heading' && this._name) return true;
if (this.#hasFocusableChild()) return false;
if (this.#focusable && this.#name) return true;
if (this.#role === 'heading' && this.#name) return true;
return false;
}

public isControl(): boolean {
switch (this._role) {
switch (this.#role) {
case 'button':
case 'checkbox':
case 'ColorWell':
Expand Down Expand Up @@ -360,18 +360,18 @@ class AXNode {
}

public isInteresting(insideControl: boolean): boolean {
const role = this._role;
if (role === 'Ignored' || this._hidden || this._ignored) return false;
const role = this.#role;
if (role === 'Ignored' || this.#hidden || this.#ignored) return false;

if (this._focusable || this._richlyEditable) return true;
if (this.#focusable || this.#richlyEditable) return true;

// If it's not focusable but has a control role, then it's interesting.
if (this.isControl()) return true;

// A non focusable child of a control is not interesting
if (insideControl) return false;

return this.isLeafNode() && !!this._name;
return this.isLeafNode() && !!this.#name;
}

public serialize(): SerializedAXNode {
Expand All @@ -384,7 +384,7 @@ class AXNode {
properties.set('description', this.payload.description.value);

const node: SerializedAXNode = {
role: this._role,
role: this.#role,
};

type UserStringProperty =
Expand Down Expand Up @@ -440,7 +440,7 @@ class AXNode {
// RootWebArea's treat focus differently than other nodes. They report whether
// their frame has focus, not whether focus is specifically on the root
// node.
if (booleanProperty === 'focused' && this._role === 'RootWebArea')
if (booleanProperty === 'focused' && this.#role === 'RootWebArea')
continue;
const value = getBooleanPropertyValue(booleanProperty);
if (!value) continue;
Expand Down
4 changes: 2 additions & 2 deletions src/common/AriaQueryHandler.ts
Expand Up @@ -107,7 +107,7 @@ const waitFor = async (
return element;
},
};
return domWorld.waitForSelectorInPage(
return domWorld._waitForSelectorInPage(
(_: Element, selector: string) =>
(
globalThis as unknown as { ariaQuerySelector(selector: string): void }
Expand Down Expand Up @@ -146,7 +146,7 @@ const queryAllArray = async (
/**
* @internal
*/
export const ariaHandler: InternalQueryHandler = {
export const _ariaHandler: InternalQueryHandler = {
queryOne,
waitFor,
queryAll,
Expand Down

0 comments on commit 6c96011

Please sign in to comment.