CCA: Add back ESLint for camera_app_ui

Same as CL:5895433, adds the ESLint config back from before CL:5844045.

The eslint.config.mjs is basically the same one as the one in
recorder_app_ui, with names changed from cra to cca, and one CCA
specific rule `cca/string-enum-order` added.

Also fix all lint warning found, notably rename all variables /
functions to use the strictCamelCase style.

Currently the lint is only run manually on `cca.py lint`. Presubmit
check will be added in the next CL.

METRICS_DOCUMENTATION_UPDATED=true

Bug: 368085620
Test: cca.py lint
Test: manually on device, check camera app works
Test: tast run <ip> camera.CCAUIStress*
Change-Id: I2facb039171de229e4134287e763027669eeddb0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5897536
Commit-Queue: Pi-Hsun Shih <pihsun@chromium.org>
Reviewed-by: Shik Chen <shik@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1363499}
diff --git a/ash/webui/camera_app_ui/resources/eslint.config.mjs b/ash/webui/camera_app_ui/resources/eslint.config.mjs
new file mode 100644
index 0000000..488f403
--- /dev/null
+++ b/ash/webui/camera_app_ui/resources/eslint.config.mjs
@@ -0,0 +1,855 @@
+// Copyright 2024 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Note: ESLint Config inspector (https://github.com/eslint/config-inspector)
+// can be used to find duplicate / conflict rules.
+
+// This file is also checked by ESLint, and some of the property in the
+// settings doesn't follow naming convention.
+/* eslint-disable @typescript-eslint/naming-convention */
+
+/* eslint-disable @stylistic/max-len */
+
+import eslint from
+  '../../../../third_party/node/node_modules/@eslint/js/src/index.js';
+import stylistic from
+  '../../../../third_party/node/node_modules/@stylistic/eslint-plugin/dist/index.js';
+// TODO(pihsun): Using the @typescript-eslint package is a bit awkward now
+// since we don't have the new typescript-eslint (without the @) package that
+// supports flat config better, so we need to glue it by ourselves. Use the new
+// package when it's available in Chromium.
+import tseslintOverride from
+  '../../../../third_party/node/node_modules/@typescript-eslint/eslint-plugin/dist/configs/eslint-recommended-raw.js';
+import tseslint from
+  '../../../../third_party/node/node_modules/@typescript-eslint/eslint-plugin/dist/index.js';
+import tseslintParser from
+  '../../../../third_party/node/node_modules/@typescript-eslint/parser/dist/index.js';
+import jsdoc from
+  '../../../../third_party/node/node_modules/eslint-plugin-jsdoc/dist/index.cjs';
+
+/* eslint-enable @stylistic/max-len */
+
+import cca from './eslint_plugin/index.js';
+
+// This is the rules at the root .eslintrc.js, copied at commit
+// a5013fa3b4980a473f187dc6aedd97fc7577af79 with long lines wrapped. We avoid
+// directly importing the config for now since the config is still in old format
+// and is expected to change to the new flat config pretty soon, and importing
+// it would block the migration.
+// TODO(pihsun): Import the config directly and customize upon it after the
+// base config is also migrate to ESLint flat config.
+const chromiumRules = {
+  // Enabled checks.
+  'brace-style': ['error', '1tbs'],
+
+  // https://google.github.io/styleguide/jsguide.html#features-arrays-trailing-comma
+  // https://google.github.io/styleguide/jsguide.html#features-objects-use-trailing-comma
+  'comma-dangle': ['error', 'always-multiline'],
+
+  'curly': ['error', 'multi-line', 'consistent'],
+  'new-parens': 'error',
+  'no-array-constructor': 'error',
+  'no-console': ['error', {allow: ['info', 'warn', 'error', 'assert']}],
+  'no-debugger': 'error',
+  'no-extra-boolean-cast': 'error',
+  'no-extra-semi': 'error',
+  'no-new-wrappers': 'error',
+  'no-restricted-imports': [
+    'error',
+    {
+      paths: [
+        {
+          name:
+            'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js',
+          importNames: ['Polymer'],
+          message: 'Use PolymerElement instead.',
+        },
+        {
+          name: '//resources/polymer/v3_0/polymer/polymer_bundled.min.js',
+          importNames: ['Polymer'],
+          message: 'Use PolymerElement instead.',
+        },
+      ],
+    },
+  ],
+  'no-restricted-properties': [
+    'error',
+    {
+      property: '__lookupGetter__',
+      message: 'Use Object.getOwnPropertyDescriptor',
+    },
+    {
+      property: '__lookupSetter__',
+      message: 'Use Object.getOwnPropertyDescriptor',
+    },
+    {
+      property: '__defineGetter__',
+      message: 'Use Object.defineProperty',
+    },
+    {
+      property: '__defineSetter__',
+      message: 'Use Object.defineProperty',
+    },
+    {
+      object: 'cr',
+      property: 'exportPath',
+      message: 'Use ES modules or cr.define() instead',
+    },
+  ],
+  'no-restricted-syntax': [
+    'error',
+    {
+      selector:
+        'CallExpression[callee.object.name=JSON][callee.property.name=parse]' +
+        ' > CallExpression[callee.object.name=JSON]' +
+        '[callee.property.name=stringify]',
+      message: `Don't use JSON.parse(JSON.stringify(...)) to clone objects.` +
+        ' Use structuredClone() instead.',
+    },
+    {
+      // https://google.github.io/styleguide/tsguide.html#return-type-only-generics
+      selector: 'TSAsExpression > CallExpression' +
+        ' > MemberExpression[property.name=/^querySelector$/]',
+      message: `Don't use 'querySelector(...) as Type'.` +
+        ` Use the type parameter, 'querySelector<Type>(...)' instead`,
+    },
+    {
+      // https://google.github.io/styleguide/tsguide.html#return-type-only-generics
+      selector: 'TSAsExpression > TSNonNullExpression > CallExpression' +
+        ' > MemberExpression[property.name=/^querySelector$/]',
+      message: `Don't use 'querySelector(...)! as Type'.` +
+        ` Use the type parameter, 'querySelector<Type>(...)',` +
+        ' followed by an assertion instead',
+    },
+    {
+      // https://google.github.io/styleguide/tsguide.html#return-type-only-generics
+      selector: 'TSAsExpression > CallExpression' +
+        ' > MemberExpression[property.name=/^querySelectorAll$/]',
+      message: `Don't use 'querySelectorAll(...) as Type'.` +
+        ` Use the type parameter, 'querySelectorAll<Type>(...)' instead`,
+    },
+    {
+      // Prevent a common misuse of "!" operator.
+      selector: 'TSNonNullExpression > CallExpression' +
+        ' > MemberExpression[property.name=/^querySelectorAll$/]',
+      message:
+        'Remove unnecessary "!" non-null operator after querySelectorAll().' +
+        ' It always returns a non-null result',
+    },
+    {
+      // https://google.github.io/styleguide/jsguide.html#es-module-imports
+      //  1) Matching only import URLs that have at least one '/' slash, to
+      //     avoid false positives for NodeJS imports like
+      //     `import fs from 'fs';`.
+      //     Using '\u002F' instead of '/' as the suggested workaround for
+      //     https://github.com/eslint/eslint/issues/16555
+      //  2) Allowing extensions that have a length between 2-4 characters
+      //     (for example js, css, json)
+      selector: 'ImportDeclaration[' +
+        'source.value=/^.*\\u002F.*(?<!\\.[a-z]{2}|\\.[a-z]{3}|\\.[a-z]{4})$/]',
+      message: 'Disallowed extensionless import.' +
+        ' Explicitly specify the extension suffix.',
+    },
+  ],
+  'no-throw-literal': 'error',
+  'no-trailing-spaces': 'error',
+  'no-var': 'error',
+  'prefer-const': 'error',
+  'quotes': ['error', 'single', {allowTemplateLiterals: true}],
+  'semi': ['error', 'always'],
+
+  // https://google.github.io/styleguide/jsguide.html#features-one-variable-per-declaration
+  'one-var': [
+    'error',
+    {
+      'let': 'never',
+      'const': 'never',
+    },
+  ],
+};
+
+const chromiumTsRules = {
+  'no-unused-vars': 'off',
+  '@typescript-eslint/no-unused-vars': [
+    'error',
+    {
+      argsIgnorePattern: '^_',
+      varsIgnorePattern: '^_',
+      caughtErrorsIgnorePattern: '.*',
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#array-constructor
+  // Note: The rule below only partially enforces the styleguide, since it
+  // it does not flag invocations of the constructor with a single
+  // parameter.
+  'no-array-constructor': 'off',
+  '@typescript-eslint/no-array-constructor': 'error',
+
+  // https://google.github.io/styleguide/tsguide.html#automatic-semicolon-insertion
+  'semi': 'off',
+  '@stylistic/semi': ['error'],
+
+  // https://google.github.io/styleguide/tsguide.html#arrayt-type
+  '@typescript-eslint/array-type': [
+    'error',
+    {
+      'default': 'array-simple',
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#type-assertions-syntax
+  '@typescript-eslint/consistent-type-assertions': [
+    'error',
+    {
+      assertionStyle: 'as',
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#interfaces-vs-type-aliases
+  '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
+
+  // https://google.github.io/styleguide/tsguide.html#import-type
+  '@typescript-eslint/consistent-type-imports': 'error',
+
+  // https://google.github.io/styleguide/tsguide.html#visibility
+  '@typescript-eslint/explicit-member-accessibility': [
+    'error',
+    {
+      accessibility: 'no-public',
+      overrides: {
+        parameterProperties: 'off',
+      },
+    },
+  ],
+
+  // https://google.github.io/styleguide/jsguide.html#naming
+  '@typescript-eslint/naming-convention': [
+    'error',
+    {
+      selector: ['class', 'interface', 'typeAlias', 'enum', 'typeParameter'],
+      format: ['StrictPascalCase'],
+      filter: {
+        regex: '^(' +
+          // Exclude TypeScript defined interfaces HTMLElementTagNameMap
+          // and HTMLElementEventMap.
+          'HTMLElementTagNameMap|HTMLElementEventMap|' +
+          // Exclude native DOM types which are always named like
+          // HTML<Foo>Element.
+          'HTML[A-Za-z]{0,}Element|' +
+          // Exclude native DOM interfaces.
+          'UIEvent|UIEventInit|DOMError|' +
+          // Exclude the deprecated WebUIListenerBehavior interface.
+          'WebUIListenerBehavior)$',
+        match: false,
+      },
+    },
+    {
+      selector: 'enumMember',
+      format: ['UPPER_CASE'],
+    },
+    {
+      selector: 'classMethod',
+      format: ['strictCamelCase'],
+      modifiers: ['public'],
+    },
+    {
+      selector: 'classMethod',
+      format: ['strictCamelCase'],
+      modifiers: ['private'],
+      trailingUnderscore: 'allow',
+
+      // Disallow the 'Tap_' suffix, in favor of 'Click_' in event handlers.
+      // Note: Unfortunately this ESLint rule does not provide a way to
+      // customize the error message to better inform developers.
+      custom: {
+        regex: '^on[a-zA-Z0-9]+Tap$',
+        match: false,
+      },
+    },
+    {
+      selector: 'classProperty',
+      format: ['UPPER_CASE'],
+      modifiers: ['private', 'static', 'readonly'],
+    },
+    {
+      selector: 'classProperty',
+      format: ['UPPER_CASE'],
+      modifiers: ['public', 'static', 'readonly'],
+    },
+    {
+      selector: 'classProperty',
+      format: ['camelCase'],
+      modifiers: ['public'],
+    },
+    {
+      selector: 'classProperty',
+      format: ['camelCase'],
+      modifiers: ['private'],
+      trailingUnderscore: 'allow',
+    },
+    {
+      selector: 'parameter',
+      format: ['camelCase'],
+      leadingUnderscore: 'allow',
+    },
+    {
+      selector: 'function',
+      format: ['camelCase'],
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#member-property-declarations
+  '@stylistic/member-delimiter-style': [
+    'error',
+    {
+      multiline: {
+        delimiter: 'comma',
+        requireLast: true,
+      },
+      singleline: {
+        delimiter: 'comma',
+        requireLast: false,
+      },
+      overrides: {
+        'interface': {
+          multiline: {
+            delimiter: 'semi',
+            requireLast: true,
+          },
+          singleline: {
+            delimiter: 'semi',
+            requireLast: false,
+          },
+        },
+      },
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#wrapper-types
+  '@typescript-eslint/no-restricted-types': [
+    'error',
+    {
+      types: {
+        String: {
+          message: 'Use string instead',
+          fixWith: 'string',
+        },
+        Boolean: {
+          message: 'Use boolean instead',
+          fixWith: 'boolean',
+        },
+        Number: {
+          message: 'Use number instead',
+          fixWith: 'number',
+        },
+        Symbol: {
+          message: 'Use symbol instead',
+          fixWith: 'symbol',
+        },
+        BigInt: {
+          message: 'Use bigint instead',
+          fixWith: 'bigint',
+        },
+      },
+    },
+  ],
+
+  // https://google.github.io/styleguide/tsguide.html#ts-ignore
+  '@typescript-eslint/ban-ts-comment': ['error', {'ts-ignore': true}],
+};
+
+export default [
+  {
+    ignores: [
+      // dist/ is generated by `cca.py bundle <board>`.
+      'dist/',
+      // mojom is symbolic linked by `cca.py tsc <board>` to board specific
+      // generated TypeScript mojom bindings.
+      'mojom',
+    ],
+  },
+  {
+    languageOptions: {
+      sourceType: 'module',
+      parser: tseslintParser,
+    },
+  },
+  {
+    files: ['**/*.ts'],
+    languageOptions: {
+      parserOptions: {
+        project: './tsconfig_base.json',
+        tsconfigRootDir: import.meta.dirname,
+      },
+    },
+  },
+  {
+    plugins: {
+      '@typescript-eslint': tseslint,
+      '@stylistic': stylistic,
+      jsdoc,
+      cca,
+    },
+  },
+  {
+    settings: {
+      jsdoc: {
+        tagNamePreference: {
+          returns: 'return',
+          file: 'fileoverview',
+        },
+      },
+    },
+  },
+  {
+    name: 'eslint/recommended',
+    ...eslint.configs.recommended,
+  },
+  {
+    name: '@typescript-eslint/eslint-recommended',
+    ...tseslintOverride.default('minimatch'),
+  },
+  {
+    name: '@typescript-eslint/recommended',
+    rules: tseslint.configs['recommended'].rules,
+  },
+  {
+    name: '@typescript-eslint/stylistic',
+    rules: tseslint.configs['stylistic'].rules,
+  },
+  // We don't use @typescript-eslint/recommended-type-checked-only since
+  // there's no full type information from Lit and mojo when linting, resulting
+  // in a large amount of false negative.
+  {
+    name: '@typescript-eslint/stylistic-type-checked-only',
+    files: ['**/*.ts'],
+    rules: tseslint.configs['stylistic-type-checked-only'].rules,
+  },
+  {
+    name: 'chromium/base',
+    rules: chromiumRules,
+  },
+  {
+    name: 'chromium/ts',
+    files: ['**/*.ts'],
+    rules: chromiumTsRules,
+  },
+  // Generally, the rules should be compatible to both bundled and the newest,
+  // stable eslint, so it's easier to upgrade and develop without the full
+  // Chromium tree.
+  // These are the rules that are based on the chromiumRules and are more
+  // strict. We move these to a separate set to make it easier to see which
+  // rules are intended to override Chromium rules.
+  {
+    name: 'cca/chromium-override',
+    rules: {
+      // Upgrade several deprecated rules to the @stylistic counterpart.
+      ...Object.fromEntries(
+        [
+          'brace-style',
+          'comma-dangle',
+          'new-parens',
+          'no-extra-semi',
+          'no-trailing-spaces',
+          'quotes',
+          'semi',
+        ].flatMap((r) => {
+          return [
+            [r, 'off'],
+            [`@stylistic/${r}`, chromiumRules[r]],
+          ];
+        }),
+      ),
+
+      // Using "as" type assertion should be rare and as a last resort if it's
+      // really too complicated to put the constraint in type system, and it's
+      // not easy to do a runtime assertion (assertInstanceof) either.
+      //
+      // If it's the case, please have a eslint-disable-next-line to disable the
+      // lint together with some comment explaining why the assertion is safe.
+      //
+      // See also:
+      // go/tsstyle#type-and-non-nullability-assertions
+      // go/tsstyle#type-assertions-syntax
+      // go/tsstyle#type-assertions-and-object-literals
+      '@typescript-eslint/consistent-type-assertions': [
+        'error',
+        {
+          assertionStyle: 'never',
+        },
+      ],
+
+      'no-restricted-syntax': [
+        ...chromiumRules['no-restricted-syntax'],
+        // Disallow parseInt. (go/tsstyle#type-coercion)
+        {
+          selector: 'CallExpression[callee.name="parseInt"]',
+          message: 'parseInt are not allowed, use Number() instead. ' +
+            '(go/tsstyle#type-coercion)',
+        },
+        // Disallow Array constructor. (go/tsstyle#array-constructor)
+        {
+          selector: 'NewExpression[callee.name="Array"], ' +
+            'CallExpression[callee.name="Array"]',
+          message: 'Array constructor are not allowed. ' +
+            '(go/tsstyle#array-constructor)',
+        },
+        // Disallow calling Error without new. (go/tsstyle#exceptions)
+        {
+          selector: 'CallExpression[callee.name="Error"]',
+          message: 'Error constructor should be called with new Error(...). ' +
+            '(go/tsstyle#exceptions)',
+        },
+        // Disallow for (... in ...). (go/tsstyle#iterating-objects)
+        {
+          selector: 'ForInStatement',
+          message: 'for (... in ...) is not allowed. ' +
+            '(go/tsstyle#iterating-objects)',
+        },
+        // Disallow forEach. (go/tsjs-practices/iteration)
+        // TODO(pihsun): This was relaxed in style guide in cl/430720959,
+        // consider relaxing this if there's place where forEach makes the code
+        // much simpler.
+        {
+          selector: 'CallExpression[callee.property.name="forEach"]',
+          message: 'forEach are not allowed. (go/tsstyle#iterating-containers)',
+        },
+        // Disallow function() {...}. (go/tsstyle#function-declarations)
+        {
+          selector: ':not(:matches(MethodDefinition, Property))' +
+            ' > FunctionExpression:not([id])',
+          message: 'Use named function or arrow function instead. ' +
+            '(go/tsstyle#function-declarations)',
+        },
+        // Disallow local function declaration with arrow function without
+        // accessing this. This might have some false negative if the "this" is
+        // accessed deep inside the function in another scope, but should be
+        // rare. (go/tsstyle#function-declarations)
+        {
+          selector: 'VariableDeclarator:not(:has(.id[typeAnnotation]))' +
+            ' > ArrowFunctionExpression.init:not(:has(ThisExpression))',
+          message: 'Use named function to declare local function. ' +
+            '(go/tsstyle#function-declarations)',
+        },
+        // Disallow private fields. (go/tsstyle#private-fields)
+        {
+          selector: 'TSPrivateIdentifier',
+          message:
+            'Private fields are not allowed. (go/tsstyle#private-fields)',
+        },
+        // Disallow explicit boolean coercions in condition.
+        // (go/tsstyle#type-coercion-implicit)
+        {
+          selector: ':matches(IfStatement, WhileStatement)' +
+            ' > UnaryExpression.test[operator="!"]' +
+            ' > UnaryExpression.argument[operator="!"]',
+          message: 'Explicit boolean coercion is not needed in conditions. ' +
+            '(go/tsstyle#type-coercion-implicit)',
+        },
+      ],
+
+      '@typescript-eslint/naming-convention': [
+        ...chromiumTsRules['@typescript-eslint/naming-convention'],
+        {
+          selector: 'default',
+          format: ['strictCamelCase'],
+        },
+        // Allows leading underscore only for unused parameters.
+        {
+          selector: 'parameter',
+          format: ['strictCamelCase'],
+        },
+        {
+          selector: 'parameter',
+          modifiers: ['unused'],
+          format: ['strictCamelCase'],
+          leadingUnderscore: 'allow',
+        },
+        {
+          selector: 'variable',
+          format: ['strictCamelCase', 'UPPER_CASE'],
+        },
+        // This is a copy from the Chromium default TypeScript rules, but with
+        // more strict requirement from camelCase to strictCamelCase.
+        {
+          selector: 'classProperty',
+          format: ['strictCamelCase'],
+          modifiers: ['public'],
+        },
+        {
+          selector: 'classProperty',
+          format: ['strictCamelCase'],
+          modifiers: ['private'],
+          trailingUnderscore: 'allow',
+        },
+        {
+          selector: 'parameter',
+          format: ['strictCamelCase'],
+          leadingUnderscore: 'allow',
+        },
+        {
+          selector: 'function',
+          format: ['strictCamelCase'],
+        },
+        {
+          // This is used in all lit file. Since the HTMLElementTagNameMap name
+          // is not defined by us, ignore naming-convention lint check on it.
+          selector: 'interface',
+          format: [],
+          filter: {
+            regex: '^HTMLElementTagNameMap$',
+            match: true,
+          },
+        },
+        {
+          // This is for the tag name declaration in all lit file. Added here
+          // since it's cumbersome to have eslint disable in all lit files, and
+          // it feels quite hard to accidentally triggers this rule.
+          selector: 'typeProperty',
+          format: [],
+          filter: {
+            regex: '^[a-z-]*$',
+            match: true,
+          },
+        },
+        {
+          // This is for having CSS class names in the classMap arguments. Since
+          // CSS classes use -, it doesn't follow the typical strictCamelCase
+          // object literal property rule. Since it's not easy to accidentally
+          // have those by mistake, and there's no good way of telling whether
+          // an object literal property is used as CSS class name, we allow all
+          // object literal property to match /[a-z-]*/.
+          selector: 'objectLiteralProperty',
+          format: [],
+          filter: {
+            regex: '^[a-z-]*$',
+            match: true,
+          },
+        },
+      ],
+
+      // go/tsstyle#import-export-type
+      '@typescript-eslint/consistent-type-imports': [
+        'error',
+        {
+          // TODO(b/369962714): Chromium wide default is always write "import
+          // type", but that cause clang-format to crash under our current
+          // .clang-format, and without those settings all import are on the
+          // same line which is really unreadable for longer imports.
+          // We should remove this lint customization and align with Chromium
+          // settings when the clang-format crash is fixed.
+          prefer: 'no-type-imports',
+        },
+      ],
+    },
+  },
+  {
+    name: 'cca/extra',
+    rules: {
+      // go/tsstyle#switch-statements
+      'default-case': 'error',
+
+      'eqeqeq': 'error',
+      'new-cap': 'error',
+      'no-caller': 'error',
+
+      'no-constant-condition': ['error', {checkLoops: false}],
+      'no-extend-native': 'error',
+      'no-extra-bind': 'error',
+      'no-multi-str': 'error',
+      'no-new-native-nonconstructor': 'error',
+      'no-object-constructor': 'error',
+      'prefer-promise-reject-errors': 'error',
+
+      // @typescript-eslint rules
+
+      // go/tsstyle#return-types
+      '@typescript-eslint/explicit-module-boundary-types': 'error',
+
+      '@typescript-eslint/no-invalid-this': 'error',
+      '@typescript-eslint/no-non-null-assertion': 'error',
+
+      // TODO(pihsun): This rule is deprecated, remove this after considering if
+      // it's beneficial to add eslint-plugin-perfectionist.
+      '@typescript-eslint/sort-type-constituents': 'error',
+    },
+  },
+  {
+    name: 'cca/jsdoc',
+    rules: {
+      'jsdoc/check-access': 'error',
+      'jsdoc/check-alignment': 'error',
+      'jsdoc/check-param-names': 'error',
+      'jsdoc/check-property-names': 'error',
+      'jsdoc/check-tag-names': 'error',
+      'jsdoc/check-types': 'error',
+      'jsdoc/check-values': 'error',
+      'jsdoc/empty-tags': 'error',
+      'jsdoc/implements-on-classes': 'error',
+      'jsdoc/multiline-blocks': [
+        'error',
+        {
+          noSingleLineBlocks: true,
+        },
+      ],
+      'jsdoc/no-bad-blocks': [
+        'error',
+        {
+          // The first four are default values, and the last one is added since
+          // the lint name is too long and the eslint-disable-next-line is
+          // frequently line wrapped, which cause jsdoc/no-bad-blocks to think
+          // that it should be a docstring.
+          ignore: [
+            'ts-check',
+            'ts-expect-error',
+            'ts-ignore',
+            'ts-nocheck',
+            'typescript-eslint/consistent-type-assertions',
+          ],
+        },
+      ],
+      'jsdoc/no-defaults': 'error',
+      'jsdoc/no-multi-asterisks': [
+        'error',
+        {
+          allowWhitespace: true,
+        },
+      ],
+      'jsdoc/no-undefined-types': 'error',
+      'jsdoc/require-asterisk-prefix': 'error',
+      'jsdoc/require-description-complete-sentence': [
+        'error',
+        {
+          abbreviations: ['e.g.'],
+        },
+      ],
+      'jsdoc/require-jsdoc': [
+        'error',
+        {
+          publicOnly: true,
+        },
+      ],
+      'jsdoc/require-param': 'off',
+      'jsdoc/require-param-description': 'error',
+      'jsdoc/require-param-name': 'error',
+      'jsdoc/require-param-type': 'off',
+      'jsdoc/require-property': 'error',
+      'jsdoc/require-property-description': 'error',
+      'jsdoc/require-property-name': 'error',
+      'jsdoc/require-property-type': 'error',
+      'jsdoc/require-returns': 'off',
+      'jsdoc/require-returns-check': 'error',
+      'jsdoc/require-returns-description': 'error',
+      'jsdoc/require-returns-type': 'off',
+      'jsdoc/require-yields': 'off',
+      'jsdoc/require-yields-check': 'error',
+      'jsdoc/tag-lines': ['error', 'never', {startLines: 1}],
+      'jsdoc/valid-types': 'error',
+    },
+  },
+  {
+    name: 'cca/stylistic',
+    rules: {
+      '@stylistic/arrow-parens': 'error',
+      '@stylistic/eol-last': 'error',
+      '@stylistic/linebreak-style': 'error',
+      '@stylistic/lines-between-class-members': 'error',
+      '@stylistic/max-len': [
+        'error',
+        {
+          code: 80,
+          tabWidth: 2,
+          ignoreUrls: true,
+        },
+      ],
+      '@stylistic/no-multi-spaces': ['error', {ignoreEOLComments: true}],
+      '@stylistic/no-multiple-empty-lines': ['error', {max: 2}],
+      '@stylistic/operator-linebreak': ['error', 'after'],
+      '@stylistic/padded-blocks': ['error', 'never'],
+      '@stylistic/quote-props': [
+        'error',
+        'consistent-as-needed',
+        {keywords: true},
+      ],
+      '@stylistic/spaced-comment': ['error', 'always'],
+    },
+  },
+  {
+    name: 'cca/custom',
+    rules: {
+      'cca/parameter-comment-format': 'error',
+      'cca/generic-parameter-on-declaration-type': 'error',
+      'cca/string-enum-order': 'error',
+      'cca/todo-format': 'error',
+    },
+  },
+  {
+    name: 'cca/ts',
+    files: ['**/*.ts'],
+    // TODO(pihsun): extends @typescript-eslint/recommended-type-checked when
+    // we can really have the board dependent types to be correct. Currently
+    // there's a lot of false negative because of unrecognized types treated
+    // as `any`. We should be able to refer most used types of lit / mwc from
+    // source instead of from gen folder, and exclude mojo related things from
+    // the checks.
+    rules: {
+      // go/tsstyle#omit-comments-that-are-redundant-with-typescript
+      'jsdoc/check-tag-names': ['error', {typed: true}],
+      'jsdoc/no-types': 'error',
+
+      // go/tsstyle#optimization-compatibility-for-property-access
+      '@typescript-eslint/dot-notation': 'error',
+
+      '@typescript-eslint/prefer-nullish-coalescing': 'error',
+      '@typescript-eslint/prefer-optional-chain': 'error',
+
+      // go/tsstyle#use-readonly
+      '@typescript-eslint/prefer-readonly': 'error',
+
+      '@typescript-eslint/require-array-sort-compare': 'error',
+      '@typescript-eslint/return-await': 'error',
+      '@typescript-eslint/strict-boolean-expressions': [
+        'error',
+        {
+          allowString: false,
+          allowNumber: false,
+          allowNullableObject: false,
+          // `any` is allowed here since our .eslintrc doesn't use the full
+          // tsconfig.json (contains reference to board specific files), which
+          // cause this rule to have some false negative on unrecognized
+          // types.
+          // TODO(pihsun): Change the lint action to be board dependent if we
+          // can find a way to keep running it on presubmit check.
+          allowAny: true,
+        },
+      ],
+
+      // Prevent floating promises, since promises that are not awaited
+      // usually indicates improper sequencing that might cause race, and if
+      // the promise is rejected, the error is only logged by unhandled
+      // promise rejection, and not propagated to caller.
+      //
+      // There are several potential ways to fix the lint error if you
+      // encounter this:
+      // * If the caller should wait for the promise, make the caller async
+      //   and await the promise.
+      // * If the caller doesn't want to wait for the promise, and the promise
+      //   is some kind of "job" that should be run independently but multiple
+      //   jobs shouldn't be run at the same time, consider using
+      //   AsyncJobQueue in async_job_queue.ts.
+      // * As a last resort, add "void" before the promise to suppress the
+      //   lint, ideally with a comment explaining why that is needed, check
+      //   that there won't be issue if multiple of those promises got created
+      //   at the same time, and check that error handling with unhandled
+      //   promise rejection is sufficient.
+      '@typescript-eslint/no-floating-promises': 'error',
+      '@typescript-eslint/require-await': 'error',
+      '@typescript-eslint/await-thenable': 'error',
+      '@typescript-eslint/no-meaningless-void-operator': 'error',
+      // TODO(b/172336355): This is currently not ready to be enabled in CCA.
+      // '@typescript-eslint/no-misused-promises': 'error',
+    },
+  },
+];
diff --git a/ash/webui/camera_app_ui/resources/eslint_plugin/index.js b/ash/webui/camera_app_ui/resources/eslint_plugin/index.js
index e061e7f..c2eaf00f 100644
--- a/ash/webui/camera_app_ui/resources/eslint_plugin/index.js
+++ b/ash/webui/camera_app_ui/resources/eslint_plugin/index.js
@@ -13,13 +13,13 @@
 
 const parameterCommentFormatRule = {
   create: (context) => {
-    const sourceCode = context.getSourceCode();
+    const {sourceCode} = context;
     return {
       /* eslint-disable-next-line @typescript-eslint/naming-convention */
       CallExpression(node) {
         for (const arg of node.arguments) {
-          const comments = sourceCode.getComments(arg);
-          for (const comment of comments.leading) {
+          const comments = sourceCode.getCommentsBefore(arg);
+          for (const comment of comments) {
             const {type, value} = comment;
             if (type !== 'Block') {
               continue;
@@ -91,7 +91,7 @@
       return !/TODO(?!\((b\/\d+|crbug\.com\/\d+|[a-z]+)\))/g.test(comment);
     }
 
-    const sourceCode = context.getSourceCode();
+    const {sourceCode} = context;
     return {
       /* eslint-disable-next-line @typescript-eslint/naming-convention */
       Program: function() {
@@ -144,12 +144,10 @@
 
 /* global module */
 module.exports = {
-  /* eslint-disable @typescript-eslint/naming-convention */
   rules: {
     'parameter-comment-format': parameterCommentFormatRule,
     'generic-parameter-on-declaration-type': genericParameterOnDeclarationType,
     'todo-format': todoFormatRule,
     'string-enum-order': stringEnumOrder,
   },
-  /* eslint-enable @typescript-eslint/naming-convention */
 };
diff --git a/ash/webui/camera_app_ui/resources/js/assert.ts b/ash/webui/camera_app_ui/resources/js/assert.ts
index f87d78c3..90f58f56 100644
--- a/ash/webui/camera_app_ui/resources/js/assert.ts
+++ b/ash/webui/camera_app_ui/resources/js/assert.ts
@@ -152,7 +152,7 @@
  * @return The value if it's an enum variant, null otherwise.
  */
 export function checkEnumVariant<T extends string>(
-    enumType: {[key: string]: T}, value: unknown): T|null {
+    enumType: Record<string, T>, value: unknown): T|null {
   if (value === null || value === undefined || typeof value !== 'string' ||
       !Object.values<string>(enumType).includes(value)) {
     return null;
@@ -171,7 +171,7 @@
  * @return The value if it's an enum variant, throws assertion error otherwise.
  */
 export function assertEnumVariant<T extends string>(
-    enumType: {[key: string]: T}, value: unknown): T {
+    enumType: Record<string, T>, value: unknown): T {
   const ret = checkEnumVariant(enumType, value);
   assert(ret !== null, `${value} is not a valid enum variant`);
   return ret;
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts b/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
index fdb79fe..ee143329 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera3_device_info.ts
@@ -55,7 +55,7 @@
    * @param videoResolutionFpses Supported available video
    *     resolutions and maximal capture fps of the video device.
    * @param fpsRanges Supported fps ranges of the video device.
-   * @param builtinPTZSupport Is PTZ controls supported by the camera.
+   * @param builtinPtzSupport Is PTZ controls supported by the camera.
    */
   constructor(
       deviceInfo: MediaDeviceInfo,
@@ -63,7 +63,7 @@
       readonly photoResolutions: ResolutionList,
       videoResolutionFpses: VideoConfig[],
       readonly fpsRanges: FpsRangeList,
-      readonly builtinPTZSupport: boolean,
+      readonly builtinPtzSupport: boolean,
   ) {
     this.deviceId = deviceInfo.deviceId;
     // If all fps supported by the camera is lower than 24, use the maximum
@@ -137,7 +137,7 @@
     const facing = await deviceOperator.getCameraFacing(deviceId);
     // Check if the camera has PTZ support, not the PTZ support through stream
     // manipulators, by checking with USB HAL vendor tags.
-    const builtinPTZSupport =
+    const builtinPtzSupport =
         !(await deviceOperator.isDigitalZoomSupported(deviceId)) &&
         ((await deviceOperator.getPanDefault(deviceId)) !== undefined ||
          (await deviceOperator.getTiltDefault(deviceId)) !== undefined ||
@@ -150,6 +150,6 @@
 
     return new Camera3DeviceInfo(
         deviceInfo, facing, photoResolution, filteredVideoConfigs,
-        supportedFpsRanges, builtinPTZSupport);
+        supportedFpsRanges, builtinPtzSupport);
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts b/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
index 3327368..71f2656 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera_manager.ts
@@ -35,12 +35,12 @@
 import {EventListener, OperationScheduler} from './camera_operation.js';
 import {VideoCaptureCandidate} from './capture_candidate.js';
 import {Preview} from './preview.js';
-import {PTZController} from './ptz_controller.js';
+import {PtzController} from './ptz_controller.js';
 import {
   CameraConfig,
   CameraInfo,
-  CameraUI,
-  CameraViewUI,
+  CameraUi,
+  CameraViewUi,
   ModeConstraints,
   PhotoAspectRatioOptionListener,
   PhotoResolutionOptionListener,
@@ -101,7 +101,7 @@
 
   private watchdog: ResumeStateWatchdog|null = null;
 
-  private readonly cameraUIs: CameraUI[] = [];
+  private readonly cameraUis: CameraUi[] = [];
 
   private readonly preview: Preview;
 
@@ -199,25 +199,25 @@
   }
 
   async onUpdateConfig(config: CameraConfig): Promise<void> {
-    for (const ui of this.cameraUIs) {
+    for (const ui of this.cameraUis) {
       await ui.onUpdateConfig?.(config);
     }
   }
 
   onTryingNewConfig(config: CameraConfig): void {
-    for (const ui of this.cameraUIs) {
+    for (const ui of this.cameraUis) {
       ui.onTryingNewConfig?.(config);
     }
   }
 
   onUpdateCapability(cameraInfo: CameraInfo): void {
-    for (const ui of this.cameraUIs) {
+    for (const ui of this.cameraUis) {
       ui.onUpdateCapability?.(cameraInfo);
     }
   }
 
-  registerCameraUI(ui: CameraUI): void {
-    this.cameraUIs.push(ui);
+  registerCameraUi(ui: CameraUi): void {
+    this.cameraUis.push(ui);
   }
 
   /**
@@ -236,7 +236,7 @@
     return this.screenOffAuto && !this.hasExternalScreen;
   }
 
-  async initialize(cameraViewUI: CameraViewUI): Promise<void> {
+  async initialize(cameraViewUI: CameraViewUi): Promise<void> {
     const helper = ChromeHelper.getInstance();
 
     function setTablet(isTablet: boolean) {
@@ -251,12 +251,12 @@
     const lidState = await helper.initLidStateMonitor(setLidClosed);
     setLidClosed(lidState);
 
-    function setSWPirvacySwitchOn(isSWPrivacySwitchOn: boolean) {
+    function setSwPirvacySwitchOn(isSWPrivacySwitchOn: boolean) {
       state.set(state.State.SW_PRIVACY_SWITCH_ON, isSWPrivacySwitchOn);
     }
-    const isSWPrivacySwitchOn =
-        await helper.initSWPrivacySwitchMonitor(setSWPirvacySwitchOn);
-    setSWPirvacySwitchOn(isSWPrivacySwitchOn);
+    const isSwPrivacySwitchOn =
+        await helper.initSwPrivacySwitchMonitor(setSwPirvacySwitchOn);
+    setSwPirvacySwitchOn(isSwPrivacySwitchOn);
 
     const handleScreenLockedChange = async (isScreenLocked: boolean) => {
       this.locked = isScreenLocked;
@@ -481,12 +481,12 @@
     return this.preview.setPointOfInterest(point);
   }
 
-  getPTZController(): PTZController {
-    return this.preview.getPTZController();
+  getPtzController(): PtzController {
+    return this.preview.getPtzController();
   }
 
-  resetPTZ(): Promise<void> {
-    return this.preview.resetPTZ();
+  resetPtz(): Promise<void> {
+    return this.preview.resetPtz();
   }
 
   /**
@@ -500,7 +500,7 @@
       return false;
     }
     return state.get(state.State.ENABLE_PTZ) &&
-        this.getCameraInfo().hasBuiltinPTZSupport(deviceId);
+        this.getCameraInfo().hasBuiltinPtzSupport(deviceId);
   }
 
   /**
@@ -550,7 +550,7 @@
       return;
     }
     this.cameraAvailable = available;
-    for (const ui of this.cameraUIs) {
+    for (const ui of this.cameraUis) {
       if (this.cameraAvailable) {
         ui.onCameraAvailable?.();
       } else {
diff --git a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
index 2827f01..3e857ca 100644
--- a/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/camera_operation.ts
@@ -38,7 +38,7 @@
   CameraConfig,
   CameraConfigCandidate,
   CameraInfo,
-  CameraViewUI,
+  CameraViewUi,
   ModeConstraints,
 } from './type.js';
 
@@ -76,7 +76,7 @@
 
   private readonly failedDevices = new Set<string>();
 
-  private failedBySWPrivacySwitch = false;
+  private failedBySwPrivacySwitch = false;
 
   constructor(
       private readonly preview: Preview,
@@ -206,31 +206,31 @@
   /**
    * Checks if PTZ can be enabled.
    */
-  private async checkEnablePTZ(
-      c: ConfigureCandidate, builtinPTZSupport: boolean): Promise<void> {
-    const enablePTZ = await (async () => {
-      if (!this.preview.isSupportPTZ()) {
+  private async checkEnablePtz(
+      c: ConfigureCandidate, builtinPtzSupport: boolean): Promise<void> {
+    const enablePtz = await (async () => {
+      if (!this.preview.isSupportPtz()) {
         return false;
       }
       // In case of digital zoom PTZ or fake camera, PTZ is supported in all
       // capture and preview resolutions.
-      if (!builtinPTZSupport) {
+      if (!builtinPtzSupport) {
         return true;
       }
       const modeSupport = state.get(state.State.USE_FAKE_CAMERA) ||
           (c.captureCandidate.resolution !== null &&
-           this.modes.isSupportPTZ(
+           this.modes.isSupportPtz(
                c.mode,
                c.captureCandidate.resolution,
                this.preview.getResolution(),
                ));
       if (!modeSupport) {
-        await this.preview.resetPTZ();
+        await this.preview.resetPtz();
         return false;
       }
       return true;
     })();
-    state.set(state.State.ENABLE_PTZ, enablePTZ);
+    state.set(state.State.ENABLE_PTZ, enablePtz);
   }
 
   async start(cameraInfo: CameraInfo): Promise<void> {
@@ -245,7 +245,7 @@
    */
 
   resetConfigurationFailure(): void {
-    this.failedBySWPrivacySwitch = false;
+    this.failedBySwPrivacySwitch = false;
     this.failedDevices.clear();
   }
 
@@ -256,7 +256,7 @@
     // CCA should attempt to open device at least once, even if the SW privacy
     // switch is on, to ensure the user receives a notification about the SW
     // privacy setting.
-    if (this.failedBySWPrivacySwitch && util.isSWPrivacySwitchOn()) {
+    if (this.failedBySwPrivacySwitch && util.isSWPrivacySwitchOn()) {
       // If a previous configuration failed due to the SW privacy switch being
       // on, and the switch is still on, skip this configuration attempt.
       throw new NoCameraError();
@@ -309,8 +309,8 @@
         facing = this.preview.getFacing();
         const deviceId = assertString(this.preview.getDeviceId());
 
-        const builtinPTZSupport = cameraInfo.hasBuiltinPTZSupport(c.deviceId);
-        await this.checkEnablePTZ(c, builtinPTZSupport);
+        const builtinPtzSupport = cameraInfo.hasBuiltinPtzSupport(c.deviceId);
+        await this.checkEnablePtz(c, builtinPtzSupport);
         factory.setPreviewVideo(this.preview.getVideo());
         factory.setFacing(facing);
         await this.modes.updateMode(factory);
@@ -351,7 +351,7 @@
             // TODO(b/187879603): Remove this hacked once we understand more
             // about such error.
             if (util.isSWPrivacySwitchOn()) {
-              this.failedBySWPrivacySwitch = true;
+              this.failedBySwPrivacySwitch = true;
               break;
             }
             let facing: Facing|null = null;
@@ -469,7 +469,7 @@
     this.capturer = new Capturer(this.modes);
   }
 
-  async initialize(cameraViewUI: CameraViewUI): Promise<void> {
+  async initialize(cameraViewUI: CameraViewUi): Promise<void> {
     this.modes.initialize(cameraViewUI);
     await this.deviceMonitor.deviceUpdate();
     await this.firstInfoUpdate.wait();
diff --git a/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts b/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
index f96d890..424cd1b 100644
--- a/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/capture_candidate.ts
@@ -95,7 +95,7 @@
       deviceId: string,
       resolution: Resolution,
       previewResolutions: Resolution[],
-      private readonly builtinPTZSupport: boolean,
+      private readonly builtinPtzSupport: boolean,
   ) {
     super(deviceId, resolution, previewResolutions);
   }
@@ -104,7 +104,7 @@
     let previewResolutions = this.previewResolutions;
     // Use workaround for b/184089334 on PTZ camera to use preview frame
     // as photo result.
-    if (this.builtinPTZSupport &&
+    if (this.builtinPtzSupport &&
         previewResolutions.find((r) => this.resolution.equals(r)) !==
             undefined) {
       previewResolutions = [this.resolution];
diff --git a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
index 0d64fd2..7b89d48 100644
--- a/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/capture_candidate_preferrer.ts
@@ -411,7 +411,7 @@
         const candidatesByLevel = option.resolutions.map(
             (r) => new PhotoCaptureCandidate(
                 deviceId, r, photoPreviewPair.previewResolutions,
-                cameraInfo.builtinPTZSupport));
+                cameraInfo.builtinPtzSupport));
         if (showAllResolutions &&
             option.resolutions[0].equals(prefResolution)) {
           candidatesByAspectRatio.unshift(...candidatesByLevel);
@@ -443,7 +443,7 @@
         expert.isEnabled(expert.ExpertOption.SHOW_ALL_RESOLUTIONS);
     assert(options !== undefined);
     for (const option of options) {
-      const prefFps = this.getFallbackFPS(deviceId, option.resolutionLevel);
+      const prefFps = this.getFallbackFps(deviceId, option.resolutionLevel);
       const targetFpsCandidates = [];
       const otherFpsCandidates = [];
       const videoPreviewPair = cameraInfo.videoPreviewPairs.find(
@@ -869,7 +869,7 @@
         if (this.cameraConfig === null) {
           continue;
         }
-        const prefFps = this.getFallbackFPS(deviceId, option.resolutionLevel);
+        const prefFps = this.getFallbackFps(deviceId, option.resolutionLevel);
         const captureCandidate = this.cameraConfig.captureCandidate;
         const configuredResolution = captureCandidate?.resolution;
         const isRunningCameraOption = deviceId === this.cameraConfig.deviceId &&
@@ -906,7 +906,7 @@
     }
   }
 
-  private getFallbackFPS(deviceId: string, level: VideoResolutionLevel):
+  private getFallbackFps(deviceId: string, level: VideoResolutionLevel):
       number {
     return this.prefVideoFpsesMap[deviceId]?.[level] ?? 30;
   }
diff --git a/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts b/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts
index a5881bc0..8f69aba 100644
--- a/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/device_monitor.ts
@@ -40,7 +40,7 @@
    * Indicates whether the device list has been updated at least once
    * since initialization.
    */
-  private hasUpdated: boolean = false;
+  private hasUpdated = false;
 
   constructor(private readonly listener: (devices: DeviceInfo[]) => void) {
     if (loadTimeData.getBoard() === 'grunt') {
diff --git a/ash/webui/camera_app_ui/resources/js/device/index.ts b/ash/webui/camera_app_ui/resources/js/device/index.ts
index 0efee99..29c7752 100644
--- a/ash/webui/camera_app_ui/resources/js/device/index.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/index.ts
@@ -5,7 +5,6 @@
 
 export {CameraManager} from './camera_manager.js';
 export {getDefaultScanCorners, setAvc1Parameters} from './mode/index.js';
-export type{GifResult, PhotoResult, VideoResult} from './mode/index.js';
+export type {GifResult, PhotoResult, VideoResult} from './mode/index.js';
 export {CameraInfo} from './type.js';
-export type{CameraUI, CameraViewUI} from './type.js';
-export type{CameraConfig} from './type.js';
+export type {CameraConfig, CameraUi, CameraViewUi} from './type.js';
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
index 6b26b7c9f..cdb70733 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/index.ts
@@ -71,7 +71,7 @@
    */
   isSupported(deviceId: string|null): Promise<boolean>;
 
-  isSupportPTZ(captureResolution: Resolution, previewResolution: Resolution):
+  isSupportPtz(captureResolution: Resolution, previewResolution: Resolution):
       boolean;
 
   /**
@@ -117,7 +117,7 @@
   constructor() {
     // Workaround for b/184089334 on PTZ camera to use preview frame as photo
     // result.
-    function checkSupportPTZForPhotoMode(
+    function checkSupportPtzForPhotoMode(
         captureResolution: Resolution, previewResolution: Resolution) {
       return captureResolution.equals(previewResolution);
     }
@@ -146,7 +146,7 @@
               params.videoSnapshotResolution, assertExists(this.handler));
         },
         isSupported: () => Promise.resolve(true),
-        isSupportPTZ: () => true,
+        isSupportPtz: () => true,
         prepareDevice: async (constraints) => {
           const deviceOperator = DeviceOperator.getInstance();
           if (deviceOperator === null) {
@@ -179,7 +179,7 @@
               assertExists(this.handler));
         },
         isSupported: () => Promise.resolve(true),
-        isSupportPTZ: checkSupportPTZForPhotoMode,
+        isSupportPtz: checkSupportPtzForPhotoMode,
         prepareDevice: async (constraints, resolution) => prepareDeviceForPhoto(
             constraints, resolution, CaptureIntent.kStillCapture),
         fallbackMode: Mode.SCAN,
@@ -201,7 +201,7 @@
           }
           return deviceOperator.isPortraitModeSupported(deviceId);
         },
-        isSupportPTZ: checkSupportPTZForPhotoMode,
+        isSupportPtz: checkSupportPtzForPhotoMode,
         prepareDevice: async (constraints, resolution) => prepareDeviceForPhoto(
             constraints, resolution, CaptureIntent.kPortraitCapture),
         fallbackMode: Mode.PHOTO,
@@ -214,7 +214,7 @@
               assertExists(this.handler));
         },
         isSupported: async () => Promise.resolve(true),
-        isSupportPTZ: checkSupportPTZForPhotoMode,
+        isSupportPtz: checkSupportPtzForPhotoMode,
         prepareDevice: async (constraints, resolution) => prepareDeviceForPhoto(
             constraints, resolution, CaptureIntent.kStillCapture),
         fallbackMode: Mode.PHOTO,
@@ -292,10 +292,10 @@
     return this.allModes[mode].isSupported(deviceId);
   }
 
-  isSupportPTZ(
+  isSupportPtz(
       mode: Mode, captureResolution: Resolution,
       previewResolution: Resolution): boolean {
-    return this.allModes[mode].isSupportPTZ(
+    return this.allModes[mode].isSupportPtz(
         captureResolution, previewResolution);
   }
 
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/mode_base.ts b/ash/webui/camera_app_ui/resources/js/device/mode/mode_base.ts
index 93c24f9..7a4a3d8 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/mode_base.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/mode_base.ts
@@ -64,7 +64,8 @@
   async stopCapture(): Promise<void> {
     this.stop();
     try {
-      await this.capture;
+      // We're intentionally ignoring the returned [Promise<void>].
+      void await this.capture;
     } catch (e) {
       if (e instanceof CanceledError) {
         return;
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/record_time.ts b/ash/webui/camera_app_ui/resources/js/device/mode/record_time.ts
index 7585e62..fb4ba7c 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/record_time.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/record_time.ts
@@ -37,7 +37,7 @@
   /**
    * Maximal recording time in milliseconds.
    */
-  private maxTimeMs: number = Infinity;
+  private maxTimeMs = Infinity;
 
   constructor(private readonly onMaxTimeout: () => void) {}
 
@@ -64,7 +64,7 @@
   /**
    * Starts to count and show the elapsed recording time.
    */
-  start(maxTimeMs: number = Infinity): void {
+  start(maxTimeMs = Infinity): void {
     this.totalDuration = 0;
     this.maxTimeMs = maxTimeMs;
     this.resume();
diff --git a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
index a28d1259..85355861 100644
--- a/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/mode/video.ts
@@ -498,7 +498,8 @@
     }
     const preference = encoderPreference.get(loadTimeData.getBoard()) ??
         {profile: h264.Profile.HIGH, multiplier: 2};
-    let {profile, multiplier} = preference;
+    const {profile} = preference;
+    let {multiplier} = preference;
     if (this.recordingType === RecordType.TIME_LAPSE) {
       multiplier = Math.max(multiplier, TIME_LAPSE_MIN_BITRATE_MULTIPLIER);
     }
diff --git a/ash/webui/camera_app_ui/resources/js/device/preview.ts b/ash/webui/camera_app_ui/resources/js/device/preview.ts
index 825be9d..c82a8c1 100644
--- a/ash/webui/camera_app_ui/resources/js/device/preview.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/preview.ts
@@ -55,11 +55,11 @@
 import {WaitableEvent} from '../waitable_event.js';
 
 import {
-  assertStrictPTZSettings,
-  DigitalZoomPTZController,
-  MediaStreamPTZController,
-  PTZController,
-  StrictPTZSettings,
+  assertStrictPtzSettings,
+  DigitalZoomPtzController,
+  MediaStreamPtzController,
+  PtzController,
+  StrictPtzSettings,
 } from './ptz_controller.js';
 import {
   StreamConstraints,
@@ -121,7 +121,7 @@
   /**
    * Map from device id to constraints to reset default PTZ setting.
    */
-  private readonly deviceDefaultPTZ =
+  private readonly deviceDefaultPtz =
       new Map<string, MediaTrackConstraintSet>();
 
   private constraints: StreamConstraints|null = null;
@@ -133,7 +133,7 @@
   private readonly digitalZoomFlag =
       loadTimeData.getChromeFlag(Flag.DIGITAL_ZOOM);
 
-  private static ptzControllerForTest: PTZController|null = null;
+  private static ptzControllerForTest: PtzController|null = null;
 
   /**
    * Triggered when the screen orientation is updated.
@@ -150,7 +150,7 @@
    * PTZController for the current stream constraint. Null if PTZ is not
    * supported.
    */
-  private ptzController: PTZController|null = null;
+  private ptzController: PtzController|null = null;
 
   /**
    * @param onNewStreamNeeded Callback to request new stream.
@@ -227,7 +227,7 @@
     }
   }
 
-  private async updatePTZ() {
+  private async updatePtz() {
     const deviceOperator = DeviceOperator.getInstance();
     const {pan, tilt, zoom} = this.getVideoTrack().getCapabilities();
     const {deviceId} = getVideoTrackSettings(this.getVideoTrack());
@@ -241,7 +241,7 @@
       const isSquare = this.isSquareResolution();
       const aspectRatio = isSquare ? 1 : this.getResolution().aspectRatio;
       this.ptzController =
-          await DigitalZoomPTZController.create(deviceId, aspectRatio);
+          await DigitalZoomPtzController.create(deviceId, aspectRatio);
       return;
     }
 
@@ -269,15 +269,15 @@
       return;
     }
 
-    const deviceDefaultPTZ = await this.getDeviceDefaultPTZ(deviceId);
-    this.ptzController = new MediaStreamPTZController(
-        this.getVideoTrack(), deviceDefaultPTZ, this.vidPid);
+    const deviceDefaultPtz = await this.getDeviceDefaultPtz(deviceId);
+    this.ptzController = new MediaStreamPtzController(
+        this.getVideoTrack(), deviceDefaultPtz, this.vidPid);
   }
 
-  private async getDeviceDefaultPTZ(deviceId: string):
+  private async getDeviceDefaultPtz(deviceId: string):
       Promise<MediaTrackConstraintSet> {
-    if (this.deviceDefaultPTZ.has(deviceId)) {
-      return assertExists(this.deviceDefaultPTZ.get(deviceId));
+    if (this.deviceDefaultPtz.has(deviceId)) {
+      return assertExists(this.deviceDefaultPtz.get(deviceId));
     }
 
     const deviceOperator = DeviceOperator.getInstance();
@@ -307,31 +307,31 @@
         defaultConstraints.zoom = await deviceOperator.getZoomDefault(deviceId);
       }
     }
-    this.deviceDefaultPTZ.set(deviceId, defaultConstraints);
+    this.deviceDefaultPtz.set(deviceId, defaultConstraints);
     return defaultConstraints;
   }
 
   /**
    * If the preview camera support PTZ controls.
    */
-  isSupportPTZ(): boolean {
+  isSupportPtz(): boolean {
     return this.isSupportPTZInternal;
   }
 
-  getPTZController(): PTZController {
+  getPtzController(): PtzController {
     return assertExists(this.ptzController);
   }
 
-  async resetPTZ(): Promise<void> {
+  async resetPtz(): Promise<void> {
     if (this.streamInternal === null || !this.isSupportPTZInternal) {
       return;
     }
     assert(this.ptzController !== null);
-    await this.ptzController.resetPTZ();
+    await this.ptzController.resetPtz();
   }
 
   getZoomRatio(): number {
-    if (this.ptzController instanceof DigitalZoomPTZController) {
+    if (this.ptzController instanceof DigitalZoomPtzController) {
       return assertExists(this.ptzController.getSettings().zoom);
     }
     return 1;
@@ -420,7 +420,7 @@
       }, 100);
       this.updateFacing();
       this.deviceId = getVideoTrackSettings(this.getVideoTrack()).deviceId;
-      await this.updatePTZ();
+      await this.updatePtz();
       Preview.ptzControllerForTest = this.ptzController;
       window.screen.orientation.addEventListener(
           'change', this.orientationListener);
@@ -684,7 +684,7 @@
           this.faceOverlay?.show(rects);
         };
 
-    const updatePTZ = () => {
+    const updatePtz = () => {
       const ptz = this.ptzController?.getSettings();
       showValue('#preview-ptz-pan', `Pan ${ptz?.pan?.toFixed(1) ?? '-'}`);
       showValue('#preview-ptz-tilt', `Tilt ${ptz?.tilt?.toFixed(1) ?? '-'}`);
@@ -751,7 +751,7 @@
       // in the metadata, which may happen if there is no face detected.
       updateFace(faceMode, faceRects);
 
-      updatePTZ();
+      updatePtz();
     };
 
     this.metadataObserver = await deviceOperator.addMetadataObserver(
@@ -797,7 +797,7 @@
    *     |x| and |y| are in range [0, 1).
    */
   setPointOfInterest(point: Point): Promise<void> {
-    if (this.ptzController instanceof DigitalZoomPTZController) {
+    if (this.ptzController instanceof DigitalZoomPtzController) {
       point = this.ptzController.calculatePointOnCameraFrame(point);
     }
     const constraints = {
@@ -862,9 +862,9 @@
   /**
    * Returns current PTZ settings for testing.
    */
-  static getPTZSettingsForTest(): StrictPTZSettings {
+  static getPtzSettingsForTest(): StrictPtzSettings {
     assert(Preview.ptzControllerForTest !== null, 'PTZ is not enabled');
     const settings = Preview.ptzControllerForTest.getSettings();
-    return assertStrictPTZSettings(settings);
+    return assertStrictPtzSettings(settings);
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts b/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts
index e178ac9..5d578b2 100644
--- a/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/ptz_controller.ts
@@ -10,19 +10,19 @@
 import * as state from '../state.js';
 import {CropRegionRect, Mode, Resolution} from '../type.js';
 
-enum PTZAttr {
+enum PtzAttr {
   PAN = 'pan',
   TILT = 'tilt',
   ZOOM = 'zoom',
 }
 
-export interface PTZCapabilities {
+export interface PtzCapabilities {
   pan: MediaSettingsRange;
   tilt: MediaSettingsRange;
   zoom: MediaSettingsRange;
 }
 
-interface PTZSettings {
+interface PtzSettings {
   pan?: number;
   tilt?: number;
   zoom?: number;
@@ -31,9 +31,9 @@
 /**
  * All pan, tilt, and zoom values must be non-empty.
  */
-export type StrictPTZSettings = Required<PTZSettings>;
+export type StrictPtzSettings = Required<PtzSettings>;
 
-export interface PTZController {
+export interface PtzController {
   /**
    * Returns whether pan control is supported.
    */
@@ -52,12 +52,12 @@
   /**
    * Returns min, max, and step values for pan, tilt, and zoom controls.
    */
-  getCapabilities(): PTZCapabilities;
+  getCapabilities(): PtzCapabilities;
 
   /**
    * Returns current pan, tilt, and zoom settings.
    */
-  getSettings(): PTZSettings;
+  getSettings(): PtzSettings;
 
   /**
    * Updates PTZ settings when the screen is rotated.
@@ -73,7 +73,7 @@
   /**
    * Resets to the default PTZ value.
    */
-  resetPTZ(): Promise<void>;
+  resetPtz(): Promise<void>;
 
   /**
    * Applies a new pan value.
@@ -106,10 +106,10 @@
   '046d:0893',
 ]);
 
-export class MediaStreamPTZController implements PTZController {
+export class MediaStreamPtzController implements PtzController {
   constructor(
       readonly track: MediaStreamTrack,
-      readonly defaultPTZ: MediaTrackConstraintSet,
+      readonly defaultPtz: MediaTrackConstraintSet,
       readonly vidPid: string|null) {}
 
   canPan(): boolean {
@@ -124,11 +124,11 @@
     return this.track.getCapabilities().zoom !== undefined;
   }
 
-  getCapabilities(): PTZCapabilities {
+  getCapabilities(): PtzCapabilities {
     return this.track.getCapabilities();
   }
 
-  getSettings(): PTZSettings {
+  getSettings(): PtzSettings {
     return this.track.getSettings();
   }
 
@@ -141,23 +141,23 @@
         (this.vidPid !== null && panTiltRestrictedCameras.has(this.vidPid));
   }
 
-  async resetPTZ(): Promise<void> {
-    await this.track.applyConstraints({advanced: [this.defaultPTZ]});
+  async resetPtz(): Promise<void> {
+    await this.track.applyConstraints({advanced: [this.defaultPtz]});
   }
 
   async pan(value: number): Promise<void> {
-    await this.applyPTZ(PTZAttr.PAN, value);
+    await this.applyPtz(PtzAttr.PAN, value);
   }
 
   async tilt(value: number): Promise<void> {
-    await this.applyPTZ(PTZAttr.TILT, value);
+    await this.applyPtz(PtzAttr.TILT, value);
   }
 
   async zoom(value: number): Promise<void> {
-    await this.applyPTZ(PTZAttr.ZOOM, value);
+    await this.applyPtz(PtzAttr.ZOOM, value);
   }
 
-  private async applyPTZ(attr: PTZAttr, value: number): Promise<void> {
+  private async applyPtz(attr: PtzAttr, value: number): Promise<void> {
     if (!this.track.enabled) {
       return;
     }
@@ -168,12 +168,12 @@
 const DIGITAL_ZOOM_MAX_PAN = 1;
 const DIGITAL_ZOOM_MAX_TILT = 1;
 const DIGITAL_ZOOM_DEFAULT_MAX_ZOOM = 6;
-export const DIGITAL_ZOOM_CAPABILITIES: PTZCapabilities = {
+export const DIGITAL_ZOOM_CAPABILITIES: PtzCapabilities = {
   pan: {min: -DIGITAL_ZOOM_MAX_PAN, max: DIGITAL_ZOOM_MAX_PAN, step: 0.1},
   tilt: {min: -DIGITAL_ZOOM_MAX_TILT, max: DIGITAL_ZOOM_MAX_TILT, step: 0.1},
   zoom: {min: 1, max: DIGITAL_ZOOM_DEFAULT_MAX_ZOOM, step: 0.1},
 };
-const DIGITAL_ZOOM_DEFAULT_SETTINGS: PTZSettings = {
+const DIGITAL_ZOOM_DEFAULT_SETTINGS: PtzSettings = {
   pan: 0,
   tilt: 0,
   zoom: 1,
@@ -212,8 +212,8 @@
 /**
  * Asserts that all pan, tilt, and zoom fields have values.
  */
-export function assertStrictPTZSettings({pan, tilt, zoom}: PTZSettings):
-    StrictPTZSettings {
+export function assertStrictPtzSettings({pan, tilt, zoom}: PtzSettings):
+    StrictPtzSettings {
   assert(pan !== undefined);
   assert(tilt !== undefined);
   assert(zoom !== undefined && zoom > 0, `Zoom value ${zoom} is invalid.`);
@@ -224,9 +224,9 @@
  * Calculate a crop region from given PTZ settings. The crop region result is
  * normalized given full width and full height equal to 1.
  */
-function calculateNormalizedCropRegion(ptzSettings: PTZSettings):
+function calculateNormalizedCropRegion(ptzSettings: PtzSettings):
     CropRegionRect {
-  const {pan, tilt, zoom} = assertStrictPTZSettings(ptzSettings);
+  const {pan, tilt, zoom} = assertStrictPtzSettings(ptzSettings);
 
   const width = 1 / zoom;
   const height = 1 / zoom;
@@ -254,7 +254,7 @@
  * Calculate a crop region from PTZ settings with respect to |fullCropRegion|.
  */
 function calculateCropRegion(
-    ptzSettings: PTZSettings, fullCropRegion: CropRegionRect): CropRegionRect {
+    ptzSettings: PtzSettings, fullCropRegion: CropRegionRect): CropRegionRect {
   const normCropRegion = calculateNormalizedCropRegion(ptzSettings);
   const {width: fullWidth, height: fullHeight} = fullCropRegion;
 
@@ -270,7 +270,7 @@
  * Asserts that pan, tilt, or zoom value is within the range defined in
  * |DIGITAL_ZOOM_CAPABILITIES|.
  */
-function assertPTZRange(attr: PTZAttr, value: number) {
+function assertPtzRange(attr: PtzAttr, value: number) {
   const {max: maxValue, min: minValue} = DIGITAL_ZOOM_CAPABILITIES[attr];
   const tolerance = 1e-3;
   assert(
@@ -301,23 +301,23 @@
 /**
  * Rotates PTZ settings clockwise by |rotation| degree.
  */
-function rotatePTZ(ptzSettings: PTZSettings, rotation: number): PTZSettings {
-  const {pan, tilt, zoom} = assertStrictPTZSettings(ptzSettings);
+function rotatePtz(ptzSettings: PtzSettings, rotation: number): PtzSettings {
+  const {pan, tilt, zoom} = assertStrictPtzSettings(ptzSettings);
   const [rotatedPan, rotatedTilt] = rotateClockwise(pan, tilt, rotation);
   return {pan: rotatedPan, tilt: rotatedTilt, zoom};
 }
 
-export class DigitalZoomPTZController implements PTZController {
+export class DigitalZoomPtzController implements PtzController {
   /**
    * Current PTZ settings based on the camera frame with rotation = 0. This
    * value remains the same regardless of the camera rotation.
    */
-  private ptzSettings: PTZSettings = DIGITAL_ZOOM_DEFAULT_SETTINGS;
+  private ptzSettings: PtzSettings = DIGITAL_ZOOM_DEFAULT_SETTINGS;
 
   /**
    * Current camera frame rotation.
    */
-  private cameraRotation: number = 0;
+  private cameraRotation = 0;
 
   private constructor(
       private readonly deviceId: string,
@@ -335,14 +335,14 @@
     return true;
   }
 
-  getCapabilities(): PTZCapabilities {
+  getCapabilities(): PtzCapabilities {
     return DIGITAL_ZOOM_CAPABILITIES;
   }
 
-  getSettings(): PTZSettings {
+  getSettings(): PtzSettings {
     // Rotates current PTZ settings because pan and tilt values are different in
     // different camera frame rotations.
-    return rotatePTZ(this.ptzSettings, this.cameraRotation);
+    return rotatePtz(this.ptzSettings, this.cameraRotation);
   }
 
   async handleScreenRotationUpdated(): Promise<void> {
@@ -371,7 +371,7 @@
     return new Point(x, y);
   }
 
-  async resetPTZ(): Promise<void> {
+  async resetPtz(): Promise<void> {
     const deviceOperator = assertExists(DeviceOperator.getInstance());
     await deviceOperator.resetCropRegion(this.deviceId);
     this.ptzSettings = DIGITAL_ZOOM_DEFAULT_SETTINGS;
@@ -379,26 +379,26 @@
   }
 
   async pan(value: number): Promise<void> {
-    assertPTZRange(PTZAttr.PAN, value);
+    assertPtzRange(PtzAttr.PAN, value);
     const newSettings = {...this.getSettings(), pan: value};
-    await this.applyPTZ(newSettings);
+    await this.applyPtz(newSettings);
   }
 
   async tilt(value: number): Promise<void> {
-    assertPTZRange(PTZAttr.TILT, value);
+    assertPtzRange(PtzAttr.TILT, value);
     const newSettings = {...this.getSettings(), tilt: value};
-    await this.applyPTZ(newSettings);
+    await this.applyPtz(newSettings);
   }
 
   async zoom(value: number): Promise<void> {
-    assertPTZRange(PTZAttr.ZOOM, value);
+    assertPtzRange(PtzAttr.ZOOM, value);
     const newSettings = {...this.getSettings(), zoom: value};
-    await this.applyPTZ(newSettings);
+    await this.applyPtz(newSettings);
   }
 
-  private async applyPTZ(settings: PTZSettings): Promise<void> {
+  private async applyPtz(settings: PtzSettings): Promise<void> {
     if (this.isFullFrame(settings)) {
-      return this.resetPTZ();
+      return this.resetPtz();
     }
 
     const deviceOperator = assertExists(DeviceOperator.getInstance());
@@ -407,7 +407,7 @@
     // degree camera rotation.
     this.cameraRotation =
         await deviceOperator.getCameraFrameRotation(this.deviceId);
-    const baseSettings = rotatePTZ(settings, 360 - this.cameraRotation);
+    const baseSettings = rotatePtz(settings, 360 - this.cameraRotation);
 
     const cropRegion = calculateCropRegion(baseSettings, this.fullCropRegion);
     await deviceOperator.setCropRegion(this.deviceId, cropRegion);
@@ -420,7 +420,7 @@
     return state.get(Mode.PHOTO) && loadTimeData.getChromeFlag(Flag.SUPER_RES);
   }
 
-  private isFullFrame({zoom}: PTZSettings): boolean {
+  private isFullFrame({zoom}: PtzSettings): boolean {
     assert(zoom !== undefined);
     const minZoom = assertExists(DIGITAL_ZOOM_CAPABILITIES.zoom.min);
     const zoomStep = assertExists(DIGITAL_ZOOM_CAPABILITIES.zoom.step);
@@ -428,11 +428,11 @@
   }
 
   static async create(deviceId: string, aspectRatio: number):
-      Promise<DigitalZoomPTZController> {
+      Promise<DigitalZoomPtzController> {
     const deviceOperator = assertExists(DeviceOperator.getInstance());
     const activeArray = await deviceOperator.getActiveArraySize(deviceId);
     const fullCropRegion =
         getFullCropRegionForAspectRatio(activeArray, aspectRatio);
-    return new DigitalZoomPTZController(deviceId, fullCropRegion);
+    return new DigitalZoomPtzController(deviceId, fullCropRegion);
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/device/type.ts b/ash/webui/camera_app_ui/resources/js/device/type.ts
index 027c9f589..498acf0 100644
--- a/ash/webui/camera_app_ui/resources/js/device/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/device/type.ts
@@ -29,7 +29,7 @@
   mode: Mode;
 }
 
-export type CameraViewUI = CaptureHandler;
+export type CameraViewUi = CaptureHandler;
 
 export class CameraInfo {
   readonly devicesInfo: MediaDeviceInfo[];
@@ -65,9 +65,9 @@
     return assertInstanceof(info, Camera3DeviceInfo);
   }
 
-  hasBuiltinPTZSupport(deviceId: string): boolean {
+  hasBuiltinPtzSupport(deviceId: string): boolean {
     const info = this.getCamera3DeviceInfo(deviceId);
-    return info === null ? false : info.builtinPTZSupport;
+    return info === null ? false : info.builtinPtzSupport;
   }
 }
 
@@ -100,7 +100,7 @@
   captureCandidate: CaptureCandidate;
 }
 
-export interface CameraUI {
+export interface CameraUi {
   onUpdateCapability?(cameraInfo: CameraInfo): void;
   onTryingNewConfig?(config: CameraConfigCandidate): void;
   onUpdateConfig?(config: CameraConfig): Promise<void>|void;
diff --git a/ash/webui/camera_app_ui/resources/js/error.ts b/ash/webui/camera_app_ui/resources/js/error.ts
index f2faf12..d3587516 100644
--- a/ash/webui/camera_app_ui/resources/js/error.ts
+++ b/ash/webui/camera_app_ui/resources/js/error.ts
@@ -24,7 +24,7 @@
 
 function parseTopFrameInfo(stackTrace: string): StackFrame {
   const regex = /at (\[?\w+\]? |)\(?(.+):(\d+):(\d+)/;
-  const match = stackTrace.match(regex) ?? ['', '', '', '-1', '-1'] as const;
+  const match = regex.exec(stackTrace) ?? ['', '', '', '-1', '-1'] as const;
   return {
     funcName: match[1].trim(),
     fileName: match[2],
@@ -114,7 +114,6 @@
   };
 
   if (isLocalDev()) {
-    // eslint-disable-next-line no-console
     console.info('crashReportPrivate called with:', params);
   } else {
     chrome.crashReportPrivate.reportError(
diff --git a/ash/webui/camera_app_ui/resources/js/externs/types.d.ts b/ash/webui/camera_app_ui/resources/js/externs/types.d.ts
index 00f1274..ec14479 100644
--- a/ash/webui/camera_app_ui/resources/js/externs/types.d.ts
+++ b/ash/webui/camera_app_ui/resources/js/externs/types.d.ts
@@ -5,9 +5,6 @@
 // TODO(pihsun): Remove this once we fully specify all the types.
 /* eslint-disable @typescript-eslint/no-explicit-any */
 
-// ESLint doesn't like "declare class" without jsdoc.
-/* eslint-disable require-jsdoc */
-
 // File System Access API: This is currently a Chrome only API, and the spec is
 // still in working draft stage.
 // https://wicg.github.io/file-system-access/
@@ -60,9 +57,7 @@
   readonly time: number;
 }
 
-interface PressureObserverCallback {
-  (records: PressureRecord[]): void;
-}
+type PressureObserverCallback = (records: PressureRecord[]) => void;
 
 declare class PressureObserver {
   constructor(
@@ -145,6 +140,8 @@
   rtpTimestamp?: number;
 }
 
+// This is a builtin name.
+// eslint-disable-next-line @typescript-eslint/naming-convention
 interface HTMLVideoElement {
   requestVideoFrameCallback(callback: VideoFrameRequestCallback): number;
   cancelVideoFrameCallback(handle: number): undefined;
diff --git a/ash/webui/camera_app_ui/resources/js/geometry.ts b/ash/webui/camera_app_ui/resources/js/geometry.ts
index 5611fa78..c3865da1 100644
--- a/ash/webui/camera_app_ui/resources/js/geometry.ts
+++ b/ash/webui/camera_app_ui/resources/js/geometry.ts
@@ -255,15 +255,15 @@
       return null;
     }
 
-    const cornRD = new Point(this.size.width, this.size.height);
-    const cornLD = new Point(0, this.size.height);
-    const cornLU = new Point(0, 0);
-    const cornRU = new Point(this.size.width, 0);
+    const cornRd = new Point(this.size.width, this.size.height);
+    const cornLd = new Point(0, this.size.height);
+    const cornLu = new Point(0, 0);
+    const cornRu = new Point(this.size.width, 0);
     const segs: Array<[Point, Point]> = [
-      [cornRU, cornLU],
-      [cornRD, cornRU],
-      [cornLU, cornLD],
-      [cornLD, cornRD],
+      [cornRu, cornLu],
+      [cornRd, cornRu],
+      [cornLu, cornLd],
+      [cornLd, cornRd],
     ];
 
     const intersectPts = [];
diff --git a/ash/webui/camera_app_ui/resources/js/h264.ts b/ash/webui/camera_app_ui/resources/js/h264.ts
index 6769a9b..b93034a9 100644
--- a/ash/webui/camera_app_ui/resources/js/h264.ts
+++ b/ash/webui/camera_app_ui/resources/js/h264.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 /**
- * @file
+ * @fileoverview
  * H264 related utility functions referenced from
  * media/video/h264_level_limits.cc.
  */
diff --git a/ash/webui/camera_app_ui/resources/js/init.ts b/ash/webui/camera_app_ui/resources/js/init.ts
index e023b32b..3503327 100644
--- a/ash/webui/camera_app_ui/resources/js/init.ts
+++ b/ash/webui/camera_app_ui/resources/js/init.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {AppWindow} from './app_window.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 import {TestBridge} from './test_bridge.js';
 import {getSanitizedScriptUrl} from './trusted_script_url_policy_util.js';
 import {
@@ -19,7 +19,7 @@
   interface Window {
     // TODO(crbug.com/980846): Refactor to use a better way rather than window
     // properties to pass data to other modules.
-    appWindow: Comlink.Remote<AppWindow>|null;
+    appWindow: comlink.Remote<AppWindow>|null;
     isInTestSession: boolean;
     windowCreationTime: number;
   }
@@ -29,7 +29,7 @@
 document.addEventListener('DOMContentLoaded', async () => {
   const sharedWorker = new SharedWorker(
       getSanitizedScriptUrl('/js/test_bridge.js'), {type: 'module'});
-  const testBridge = Comlink.wrap<TestBridge>(sharedWorker.port);
+  const testBridge = comlink.wrap<TestBridge>(sharedWorker.port);
 
   // To support code coverage collection and communication with tast, the
   // initialization is split into several steps:
@@ -51,8 +51,8 @@
   // waitForDebuggerOnStart in CDP to achieve this without separating the steps
   // here, but those are currently limited to browser target and not usable by
   // tast now.
-  const gaHelperIFrame = createUntrustedIframe();
-  const videoProcessorHelperIFrame = createUntrustedIframe();
+  const gaHelperIframe = createUntrustedIframe();
+  const videoProcessorHelperIframe = createUntrustedIframe();
 
   const appWindow = await testBridge.bindWindow(window.location.href);
   window.appWindow = appWindow;
@@ -63,9 +63,9 @@
   }
 
   setGaHelper(injectUntrustedJSModule(
-      gaHelperIFrame, expandPath('/js/untrusted_ga_helper.js')));
+      gaHelperIframe, expandPath('/js/untrusted_ga_helper.js')));
   setVideoProcessorHelper(injectUntrustedJSModule(
-      videoProcessorHelperIFrame,
+      videoProcessorHelperIframe,
       expandPath('/js/untrusted_video_processor_helper.js')));
 
   // Dynamically import the error module here so that the codes can be counted
diff --git a/ash/webui/camera_app_ui/resources/js/lib/ffmpeg.d.ts b/ash/webui/camera_app_ui/resources/js/lib/ffmpeg.d.ts
index fc3da3d3..930aaa0 100644
--- a/ash/webui/camera_app_ui/resources/js/lib/ffmpeg.d.ts
+++ b/ash/webui/camera_app_ui/resources/js/lib/ffmpeg.d.ts
@@ -2,5 +2,5 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-declare const runFFmpeg: EmscriptenModuleFactory;
-export default runFFmpeg;
+declare const runFfmpeg: EmscriptenModuleFactory;
+export default runFfmpeg;
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts b/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts
index 1a049ef..349dcae9 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/gallery-button.ts
@@ -81,7 +81,7 @@
 
   cover: CoverPhoto|null = null;
 
-  getCoverURLForTesting(): string {
+  getCoverUrlForTesting(): string {
     return this.shadowRoot?.querySelector('img')?.getAttribute('src') ?? '';
   }
 
@@ -134,7 +134,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'gallery-button': GalleryButton;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/mode-selector.ts b/ash/webui/camera_app_ui/resources/js/lit/components/mode-selector.ts
index 8175062..ce38304 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/mode-selector.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/mode-selector.ts
@@ -260,7 +260,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'mode-selector': ModeSelector;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/record-time-chip.ts b/ash/webui/camera_app_ui/resources/js/lit/components/record-time-chip.ts
index bd5b75f..ec5f9c7 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/record-time-chip.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/record-time-chip.ts
@@ -69,7 +69,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'record-time-chip': RecordTimeChip;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts b/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts
index 454dd270..debf4cf 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/super-res-loading-indicator.ts
@@ -88,7 +88,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'super-res-loading-indicator': SuperResLoadingIndicator;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/svg-wrapper.ts b/ash/webui/camera_app_ui/resources/js/lit/components/svg-wrapper.ts
index b23973d..0094b05 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/svg-wrapper.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/svg-wrapper.ts
@@ -56,7 +56,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'svg-wrapper': SvgWrapper;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/switch-device-button.ts b/ash/webui/camera_app_ui/resources/js/lit/components/switch-device-button.ts
index 1b11995..0ab9e9a 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/switch-device-button.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/switch-device-button.ts
@@ -66,7 +66,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'switch-device-button': SwitchDeviceButton;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/lit/components/text-tooltip.ts b/ash/webui/camera_app_ui/resources/js/lit/components/text-tooltip.ts
index dd6dcdc..cca268b 100644
--- a/ash/webui/camera_app_ui/resources/js/lit/components/text-tooltip.ts
+++ b/ash/webui/camera_app_ui/resources/js/lit/components/text-tooltip.ts
@@ -119,7 +119,6 @@
 
 declare global {
   interface HTMLElementTagNameMap {
-    /* eslint-disable-next-line @typescript-eslint/naming-convention */
     'text-tooltip': TextTooltip;
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/local_dev_overrides.ts b/ash/webui/camera_app_ui/resources/js/local_dev_overrides.ts
index 6bda974b..9ed2cf1 100644
--- a/ash/webui/camera_app_ui/resources/js/local_dev_overrides.ts
+++ b/ash/webui/camera_app_ui/resources/js/local_dev_overrides.ts
@@ -68,14 +68,14 @@
     if (file === null) {
       return;
     }
-    const objectURL = await getObjectURL(file);
-    const newTabWindow = window.open(objectURL, '_blank');
+    const objectUrl = await getObjectURL(file);
+    const newTabWindow = window.open(objectUrl, '_blank');
     newTabWindow?.addEventListener('load', () => {
       // The unload handler is fired immediately since the window.open
       // triggered unload event on the initial empty page. See
       // https://stackoverflow.com/q/7476660
       newTabWindow?.addEventListener('unload', () => {
-        URL.revokeObjectURL(objectURL);
+        URL.revokeObjectURL(objectUrl);
       });
     });
   }
@@ -160,7 +160,7 @@
     return LidState.kNotPresent;
   }
 
-  override async initSWPrivacySwitchMonitor(
+  override async initSwPrivacySwitchMonitor(
       _onChange: (is_sw_privacy_switch_on: boolean) => void): Promise<boolean> {
     return false;
   }
diff --git a/ash/webui/camera_app_ui/resources/js/main.ts b/ash/webui/camera_app_ui/resources/js/main.ts
index f5fb3d3a..addaa05 100644
--- a/ash/webui/camera_app_ui/resources/js/main.ts
+++ b/ash/webui/camera_app_ui/resources/js/main.ts
@@ -27,7 +27,7 @@
 import {reportError} from './error.js';
 import {Flag} from './flag.js';
 import {Intent} from './intent.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 import {startMeasuringMemoryUsage} from './memory_usage.js';
 import * as metrics from './metrics.js';
 import * as filesystem from './models/file_system.js';
@@ -319,7 +319,7 @@
   const multiWindowManagerWorker = new SharedWorker(
       getSanitizedScriptUrl('/js/multi_window_manager.js'), {type: 'module'});
   const windowInstance =
-      Comlink.wrap<WindowInstance>(multiWindowManagerWorker.port);
+      comlink.wrap<WindowInstance>(multiWindowManagerWorker.port);
   addUnloadCallback(() => {
     windowInstance.onWindowClosed().catch((e) => {
       reportError(
@@ -328,7 +328,7 @@
     });
   });
   await windowInstance.init(
-      Comlink.proxy(handleSuspend), Comlink.proxy(handleResume));
+      comlink.proxy(handleSuspend), comlink.proxy(handleResume));
   await ChromeHelper.getInstance().initCameraWindowController();
   windowController.addWindowStateListener((states) => {
     const isMinimizing = states.includes(WindowStateType.kMinimized);
diff --git a/ash/webui/camera_app_ui/resources/js/memory_usage.ts b/ash/webui/camera_app_ui/resources/js/memory_usage.ts
index d26acd48..f365858 100644
--- a/ash/webui/camera_app_ui/resources/js/memory_usage.ts
+++ b/ash/webui/camera_app_ui/resources/js/memory_usage.ts
@@ -9,7 +9,7 @@
 import {Mode} from './type.js';
 import {measureUntrustedScriptsMemory} from './untrusted_scripts.js';
 
-export interface CCAMemoryMeasurement {
+export interface CcaMemoryMeasurement {
   main: MemoryMeasurement;
   untrusted: MemoryMeasurement;
 }
@@ -17,7 +17,7 @@
 /**
  * Measures memory usage from trusted and untrusted frames.
  */
-export async function measureAppMemoryUsage(): Promise<CCAMemoryMeasurement> {
+export async function measureAppMemoryUsage(): Promise<CcaMemoryMeasurement> {
   assert(self.crossOriginIsolated);
   const usages = await Promise.all([
     performance.measureUserAgentSpecificMemory(),
diff --git a/ash/webui/camera_app_ui/resources/js/metrics.ts b/ash/webui/camera_app_ui/resources/js/metrics.ts
index 99de23b5..c48435a 100644
--- a/ash/webui/camera_app_ui/resources/js/metrics.ts
+++ b/ash/webui/camera_app_ui/resources/js/metrics.ts
@@ -4,7 +4,7 @@
 
 import {assert, assertExists} from './assert.js';
 import {Intent} from './intent.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 import * as loadTimeData from './models/load_time_data.js';
 import * as localStorage from './models/local_storage.js';
 import {ChromeHelper} from './mojo/chrome_helper.js';
@@ -115,7 +115,7 @@
           clientId,
           measurementId: GA4_ID,
         },
-        Comlink.proxy(setClientId));
+        comlink.proxy(setClientId));
   }
 
   // GA_IDs are refreshed every 90 days cycle according to GA_ID_REFRESH_TIME.
@@ -542,8 +542,7 @@
  * Sends the barcode detected event.
  */
 export function sendBarcodeDetectedEvent(
-    {contentType}: BarcodeDetectedEventParam,
-    wifiSecurityType: string = ''): void {
+    {contentType}: BarcodeDetectedEventParam, wifiSecurityType = ''): void {
   sendEvent('detect', {
     [Ga4MetricDimension.EVENT_CATEGORY]: 'barcode',
     [Ga4MetricDimension.EVENT_LABEL]: contentType,
@@ -717,7 +716,7 @@
   }
 }
 
-const moduleIDSet = new PopularCamPeripheralSet();
+const moduleIdSet = new PopularCamPeripheralSet();
 
 /**
  * Sends camera opening event.
@@ -727,7 +726,7 @@
  */
 export function sendOpenCameraEvent(moduleId: string|null): void {
   const newModuleId =
-      moduleId === null ? 'MIPI' : moduleIDSet.getMaskedId(moduleId);
+      moduleId === null ? 'MIPI' : moduleIdSet.getMaskedId(moduleId);
 
   sendEvent('open-camera', {
     [Ga4MetricDimension.EVENT_CATEGORY]: 'open-camera',
@@ -741,7 +740,7 @@
     };
   } else {
     params.cameraModule = {
-      usbCamera: {id: moduleIDSet.has(moduleId) ? moduleId : null},
+      usbCamera: {id: moduleIdSet.has(moduleId) ? moduleId : null},
     };
   }
   void (async () => {
diff --git a/ash/webui/camera_app_ui/resources/js/models/barcode.ts b/ash/webui/camera_app_ui/resources/js/models/barcode.ts
index 28f8db4..67b0e25 100644
--- a/ash/webui/camera_app_ui/resources/js/models/barcode.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/barcode.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert, assertInstanceof} from '../assert.js';
-import * as Comlink from '../lib/comlink.js';
+import * as comlink from '../lib/comlink.js';
 import {BARCODE_SCAN_INTERVAL} from '../photo_mode_auto_scanner.js';
 import * as state from '../state.js';
 import {getSanitizedScriptUrl} from '../trusted_script_url_policy_util.js';
@@ -29,7 +29,7 @@
 const ACTIVE_SCAN_RATIO = 1.0;
 
 const getBarcodeWorker = lazySingleton(
-    () => Comlink.wrap<BarcodeWorker>(new Worker(
+    () => comlink.wrap<BarcodeWorker>(new Worker(
         getSanitizedScriptUrl('/js/models/barcode_worker.js'),
         {type: 'module'})));
 
@@ -117,7 +117,7 @@
     const frame = await this.grabFrameForScan();
     const {width, height} = frame;
     const codes =
-        await getBarcodeWorker().detect(Comlink.transfer(frame, [frame]));
+        await getBarcodeWorker().detect(comlink.transfer(frame, [frame]));
     if (codes.length === 0) {
       return null;
     }
diff --git a/ash/webui/camera_app_ui/resources/js/models/barcode_worker.ts b/ash/webui/camera_app_ui/resources/js/models/barcode_worker.ts
index 143e12e..701044b49 100644
--- a/ash/webui/camera_app_ui/resources/js/models/barcode_worker.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/barcode_worker.ts
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import * as Comlink from '../lib/comlink.js';
+import * as comlink from '../lib/comlink.js';
 
 /**
  * A barcode worker to detect barcode from images.
@@ -34,4 +34,4 @@
 // runtime.
 export type BarcodeWorker = BarcodeWorkerImpl;
 
-Comlink.expose(new BarcodeWorkerImpl());
+comlink.expose(new BarcodeWorkerImpl());
diff --git a/ash/webui/camera_app_ui/resources/js/models/ffmpeg/video_processor.ts b/ash/webui/camera_app_ui/resources/js/models/ffmpeg/video_processor.ts
index 0761aa9..7848b6c 100644
--- a/ash/webui/camera_app_ui/resources/js/models/ffmpeg/video_processor.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/ffmpeg/video_processor.ts
@@ -4,8 +4,8 @@
 
 import {assert, assertNotReached} from '../../assert.js';
 import {AsyncJobQueue} from '../../async_job_queue.js';
-import * as Comlink from '../../lib/comlink.js';
-import runFFmpeg from '../../lib/ffmpeg.js';
+import * as comlink from '../../lib/comlink.js';
+import runFfmpeg from '../../lib/ffmpeg.js';
 import {WaitableEvent} from '../../waitable_event.js';
 import {AsyncWriter} from '../async_writer.js';
 
@@ -42,15 +42,15 @@
  *
  * Ref: https://emscripten.org/docs/api_reference/Filesystem-API.html#devices
  */
-interface FSStream {
+interface FsStream {
   fd: number;
 }
-interface FS {
+interface Fs {
   makedev(major: number, minor: number): number;
   mkdev(path: string, mode?: number): void;
   registerDevice(dev: number, ops: FileOps): void;
   symlink(oldpath: string, newpath: string): void;
-  open(path: string, flags: string): FSStream;
+  open(path: string, flags: string): FsStream;
 }
 
 /**
@@ -289,7 +289,7 @@
  * A ffmpeg-based video processor that can process input and output data
  * incrementally.
  */
-class FFMpegVideoProcessor {
+class FfmpegVideoProcessor {
   private readonly inputDevice = new InputDevice();
 
   private readonly outputDevice: OutputDevice;
@@ -340,13 +340,15 @@
         // tsconfig.json, so this can be caught at compile time.
         return '../../../js/lib/ffmpeg.wasm';
       },
+      // This is from emscripten.
+      // eslint-disable-next-line @typescript-eslint/naming-convention
       noFSInit: true,  // It would be setup in preRun().
       preRun: [() => {
         // The FS property are injected by emscripten at runtime.
         /* eslint-disable-next-line
              @typescript-eslint/naming-convention,
              @typescript-eslint/consistent-type-assertions */
-        const fs = (config as unknown as {FS: FS}).FS;
+        const fs = (config as unknown as {FS: Fs}).FS;
         assert(fs !== null);
         // 80 is just a random major number that won't collide with other
         // default devices of the Emscripten runtime environment, which uses
@@ -374,17 +376,17 @@
       },
     };
 
-    function initFFmpeg() {
+    function initFfmpeg() {
       return new Promise<void>((resolve) => {
         // runFFmpeg() is a special function exposed by Emscripten that will
         // return an object with then(). The function passed into then() would
         // be called when the runtime is initialized. Note that because the
         // then() function will return the object itself again, using await here
         // would cause an infinite loop.
-        void runFFmpeg(config).then(() => resolve());
+        void runFfmpeg(config).then(() => resolve());
       });
     }
-    this.jobQueue.push(initFFmpeg);
+    this.jobQueue.push(initFfmpeg);
   }
 
   /**
@@ -436,14 +438,14 @@
 
 // Only export types to ensure that the file is not imported by other files at
 // runtime.
-export type VideoProcessorConstructor = typeof FFMpegVideoProcessor;
-export type VideoProcessor = FFMpegVideoProcessor;
+export type VideoProcessorConstructor = typeof FfmpegVideoProcessor;
+export type VideoProcessor = FfmpegVideoProcessor;
 
 /**
  * Expose the VideoProcessor constructor to given end point.
  */
 function exposeVideoProcessor(endPoint: MessagePort) {
-  Comlink.expose(FFMpegVideoProcessor, endPoint);
+  comlink.expose(FfmpegVideoProcessor, endPoint);
 }
 
-Comlink.expose({exposeVideoProcessor});
+comlink.expose({exposeVideoProcessor});
diff --git a/ash/webui/camera_app_ui/resources/js/models/file_namer.ts b/ash/webui/camera_app_ui/resources/js/models/file_namer.ts
index afae0cf..b2c8655a 100644
--- a/ash/webui/camera_app_ui/resources/js/models/file_namer.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/file_namer.ts
@@ -140,7 +140,7 @@
   /**
    * Returns true if given |fileName| matches the format that CCA generates.
    */
-  static isCCAFileFormat(fileName: string): boolean {
+  static isCcaFileFormat(fileName: string): boolean {
     return FILE_NAME_PATTERN.test(fileName);
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/models/file_system.ts b/ash/webui/camera_app_ui/resources/js/models/file_system.ts
index 8559d26..92350c2 100644
--- a/ash/webui/camera_app_ui/resources/js/models/file_system.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/file_system.ts
@@ -172,7 +172,7 @@
         !hasDocumentPrefix(entry)) {
       return false;
     }
-    return entry.name.match(/_(\d{8})_(\d{6})(?: \((\d+)\))?/);
+    return /_(\d{8})_(\d{6})(?: \((\d+)\))?/.exec(entry.name);
   });
 }
 
diff --git a/ash/webui/camera_app_ui/resources/js/models/result_saver.ts b/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
index 815667b..6424cf8e 100644
--- a/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/result_saver.ts
@@ -49,7 +49,7 @@
   /**
    * Saves captured video result.
    *
-   * @param file Contains the video file to be saved.
+   * @param video Contains the video file to be saved.
    */
   saveVideo(video: FileAccessEntry): Awaitable<void>;
 }
@@ -132,7 +132,7 @@
 
     // Rescan file system. Only select files following CCA naming styles.
     const files = (await filesystem.getEntries())
-                      .filter((file) => Filenamer.isCCAFileFormat(file.name));
+                      .filter((file) => Filenamer.isCcaFileFormat(file.name));
     if (files.length === 0) {
       await this.updateCover(null);
       return;
diff --git a/ash/webui/camera_app_ui/resources/js/models/video_saver.ts b/ash/webui/camera_app_ui/resources/js/models/video_saver.ts
index 499cc54..2db7f2f3 100644
--- a/ash/webui/camera_app_ui/resources/js/models/video_saver.ts
+++ b/ash/webui/camera_app_ui/resources/js/models/video_saver.ts
@@ -4,7 +4,7 @@
 
 import {assertExists, assertInstanceof} from '../assert.js';
 import {Intent} from '../intent.js';
-import * as Comlink from '../lib/comlink.js';
+import * as comlink from '../lib/comlink.js';
 import {
   MimeType,
   Resolution,
@@ -28,12 +28,12 @@
 
 // This is used like a class constructor.
 // We don't initialize this immediately to avoid side effect on module import.
-const getFFMpegVideoProcessorConstructor = lazySingleton(async () => {
+const getFfmpegVideoProcessorConstructor = lazySingleton(async () => {
   const workerChannel = new MessageChannel();
   const videoProcessorHelper = await getVideoProcessorHelper();
   await videoProcessorHelper.connectToWorker(
-      Comlink.transfer(workerChannel.port2, [workerChannel.port2]));
-  return Comlink.wrap<VideoProcessorConstructor>(workerChannel.port1);
+      comlink.transfer(workerChannel.port2, [workerChannel.port2]));
+  return comlink.wrap<VideoProcessorConstructor>(workerChannel.port1);
 });
 
 
@@ -41,9 +41,9 @@
  * Creates a VideoProcessor instance for recording video.
  */
 async function createVideoProcessor(output: AsyncWriter, videoRotation: number):
-    Promise<Comlink.Remote<VideoProcessor>> {
-  return new (await getFFMpegVideoProcessorConstructor())(
-      Comlink.proxy(output), createMp4Args(videoRotation, output.seekable()));
+    Promise<comlink.Remote<VideoProcessor>> {
+  return new (await getFfmpegVideoProcessorConstructor())(
+      comlink.proxy(output), createMp4Args(videoRotation, output.seekable()));
 }
 
 /**
@@ -51,9 +51,9 @@
  */
 async function createGifVideoProcessor(
     output: AsyncWriter,
-    resolution: Resolution): Promise<Comlink.Remote<VideoProcessor>> {
-  return new (await getFFMpegVideoProcessorConstructor())(
-      Comlink.proxy(output), createGifArgs(resolution));
+    resolution: Resolution): Promise<comlink.Remote<VideoProcessor>> {
+  return new (await getFfmpegVideoProcessorConstructor())(
+      comlink.proxy(output), createGifArgs(resolution));
 }
 
 /*
@@ -62,9 +62,9 @@
 async function createTimeLapseProcessor(
     output: AsyncWriter,
     {resolution, fps, videoRotation}: TimeLapseEncoderArgs):
-    Promise<Comlink.Remote<VideoProcessor>> {
-  return new (await getFFMpegVideoProcessorConstructor())(
-      Comlink.proxy(output),
+    Promise<comlink.Remote<VideoProcessor>> {
+  return new (await getFfmpegVideoProcessorConstructor())(
+      comlink.proxy(output),
       createTimeLapseArgs(resolution, fps, videoRotation));
 }
 
@@ -85,7 +85,7 @@
 export class VideoSaver {
   constructor(
       private readonly file: FileAccessEntry,
-      private readonly processor: Comlink.Remote<VideoProcessor>) {}
+      private readonly processor: comlink.Remote<VideoProcessor>) {}
 
   /**
    * Writes video data to result video.
@@ -143,7 +143,7 @@
 export class GifSaver {
   constructor(
       private readonly blobs: Blob[],
-      private readonly processor: Comlink.Remote<VideoProcessor>) {}
+      private readonly processor: comlink.Remote<VideoProcessor>) {}
 
   write(frame: Uint8ClampedArray): void {
     // processor.write does queuing internally.
@@ -190,7 +190,7 @@
 
   constructor(
       readonly speed: number, readonly file: FileAccessEntry,
-      private readonly processor: Comlink.Remote<VideoProcessor>) {}
+      private readonly processor: comlink.Remote<VideoProcessor>) {}
 
   write(blob: Blob, frameNo: number): void {
     // processor.write does queuing internally.
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
index d823a69..782a24d 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/chrome_helper.ts
@@ -291,7 +291,7 @@
   abstract initLidStateMonitor(onChange: (lidStatus: LidState) => void):
       Promise<LidState>;
 
-  abstract initSWPrivacySwitchMonitor(
+  abstract initSwPrivacySwitchMonitor(
       onChange: (is_sw_privacy_switch_on: boolean) => void): Promise<boolean>;
 
   abstract getEventsSender(): Promise<EventsSenderRemote>;
@@ -533,7 +533,7 @@
     return lidStatus;
   }
 
-  override async initSWPrivacySwitchMonitor(
+  override async initSwPrivacySwitchMonitor(
       onChange: (is_sw_privacy_switch_on: boolean) => void): Promise<boolean> {
     const monitorCallbackRouter =
         wrapEndpoint(new SWPrivacySwitchMonitorCallbackRouter());
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/type.ts b/ash/webui/camera_app_ui/resources/js/mojo/type.ts
index 17e72c6..a8892d0 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/type.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/type.ts
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file contains many long export lines that exceed the max-len limit */
-/* eslint-disable max-len */
+// This file contains many long export lines that exceed the max-len limit
+/* eslint-disable @stylistic/max-len */
 
 export type {
   BigBuffer,
diff --git a/ash/webui/camera_app_ui/resources/js/mojo/util.ts b/ash/webui/camera_app_ui/resources/js/mojo/util.ts
index aa5a3a7..db883a80 100644
--- a/ash/webui/camera_app_ui/resources/js/mojo/util.ts
+++ b/ash/webui/camera_app_ui/resources/js/mojo/util.ts
@@ -93,8 +93,10 @@
   // Disable type assertion since it is intended to make all function calls as
   // no-ops.
   const handler = {
-    apply: (): unknown => new Proxy(() => {}, handler),
-    get: (): unknown => new Proxy(() => {}, handler),
+    apply: (): unknown =>
+        new Proxy(() => {/* Doing nothing for fake */}, handler),
+    get: (): unknown =>
+        new Proxy(() => {/* Doing nothing for fake */}, handler),
   };
   // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
   return new Proxy({}, handler) as T;
diff --git a/ash/webui/camera_app_ui/resources/js/multi_window_manager.ts b/ash/webui/camera_app_ui/resources/js/multi_window_manager.ts
index 2c20c753..7959dd3 100644
--- a/ash/webui/camera_app_ui/resources/js/multi_window_manager.ts
+++ b/ash/webui/camera_app_ui/resources/js/multi_window_manager.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 /**
- * @file
+ * @fileoverview
  *
  * This is used to handle multiple windows of CCA.
  * An example is when using the following windows at the same time:
@@ -29,7 +29,7 @@
  */
 
 import {assert, assertNotReached} from './assert.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 
 // This is needed since we currently have the same tsconfig for files running
 // in SharedWorker and in CCA.
@@ -237,6 +237,6 @@
  */
 sharedWorkerScope.onconnect = (event: MessageEvent) => {
   const port = event.ports[0];
-  Comlink.expose(windowManager.createWindowInstance(), port);
+  comlink.expose(windowManager.createWindowInstance(), port);
   port.start();
 };
diff --git a/ash/webui/camera_app_ui/resources/js/photo_mode_auto_scanner.ts b/ash/webui/camera_app_ui/resources/js/photo_mode_auto_scanner.ts
index 19fe7a8..b17a75ae 100644
--- a/ash/webui/camera_app_ui/resources/js/photo_mode_auto_scanner.ts
+++ b/ash/webui/camera_app_ui/resources/js/photo_mode_auto_scanner.ts
@@ -136,7 +136,13 @@
   }
 
   private createBarcodeRunner(interval: number) {
-    const barcodeScanner = new BarcodeScanner(this.video, () => {});
+    const barcodeScanner = new BarcodeScanner(
+        this.video,
+        () => {
+            // We don't use the BarcodeScanner.start so callback does nothing.
+            // TODO(pihsun): callback should be directly passed to `start`
+            // instead of in constructor.
+        });
     return new AsyncIntervalRunner(async (stopped) => {
       const result = await barcodeScanner.scan();
       if (stopped.isSignaled()) {
diff --git a/ash/webui/camera_app_ui/resources/js/test/cca_test.ts b/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
index 27c6c8c..682edd87 100644
--- a/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
+++ b/ash/webui/camera_app_ui/resources/js/test/cca_test.ts
@@ -12,8 +12,8 @@
 import {Preview} from '../device/preview.js';
 import {
   DIGITAL_ZOOM_CAPABILITIES,
-  PTZCapabilities,
-  StrictPTZSettings,
+  PtzCapabilities,
+  StrictPtzSettings,
 } from '../device/ptz_controller.js';
 import * as dom from '../dom.js';
 import {GalleryButton} from '../lit/components/gallery-button.js';
@@ -42,7 +42,7 @@
   SETTING_OPTION_MAP,
   SettingMenu,
   SettingOption,
-  UIComponent,
+  UiComponent,
 } from './cca_type.js';
 
 interface Coordinate {
@@ -59,7 +59,7 @@
  * Get HTMLInputElement from the specified component and ensure that the type of
  * the input element is "range".
  */
-function getRangeInputComponent(component: UIComponent): HTMLInputElement {
+function getRangeInputComponent(component: UiComponent): HTMLInputElement {
   const element = resolveElement(component);
   const inputElement = assertInstanceof(
       element, HTMLInputElement,
@@ -97,7 +97,7 @@
  * Resolves selector of the component and returns a list of HTML elements with
  * that selector.
  */
-function getElementList(component: UIComponent): HTMLElement[] {
+function getElementList(component: UiComponent): HTMLElement[] {
   const selector = SELECTOR_MAP[component];
   // Value from Tast may not be UIComponent and results in undefined.
   assert(selector !== undefined, 'Invalid UIComponent value.');
@@ -110,7 +110,7 @@
 /**
  * Returns a list of HTML elements which are visible.
  */
-function getVisibleElementList(component: UIComponent): HTMLElement[] {
+function getVisibleElementList(component: UiComponent): HTMLElement[] {
   const elements = getElementList(component);
   const visibleElements =
       elements.filter((element) => isVisibleElement(element));
@@ -132,7 +132,7 @@
  * specified, returns the |index|'th element, else returns the first element
  * found. This will throw an error if it cannot be resolved.
  */
-function resolveElement(component: UIComponent, index = 0): HTMLElement {
+function resolveElement(component: UiComponent, index = 0): HTMLElement {
   const elements = getElementList(component);
   assert(
       index < elements.length,
@@ -143,7 +143,7 @@
 /**
  * Resolves the |index|'th visible HTMLElement of the specified ui |component|.
  */
-function resolveVisibleElement(component: UIComponent, index = 0): HTMLElement {
+function resolveVisibleElement(component: UiComponent, index = 0): HTMLElement {
   const elements = getVisibleElementList(component);
   assert(
       index < elements.length,
@@ -154,6 +154,11 @@
 /**
  * Return test functionalities to be used in Tast automation test.
  */
+// This is used by tast side and name needs to be keep as is for backward
+// compatibility.
+// TODO(b/371112908): Have alias of these names, update tast, then remove the
+// old names.
+// eslint-disable-next-line @typescript-eslint/naming-convention
 export class CCATest {
   /**
    * Checks if mojo connection could be constructed without error. In this check
@@ -228,7 +233,7 @@
   /**
    * Clicks on the UI component if it's visible.
    */
-  static click(component: UIComponent, index?: number): void {
+  static click(component: UiComponent, index?: number): void {
     const element = resolveVisibleElement(component, index);
     element.click();
   }
@@ -250,21 +255,27 @@
   /**
    * Returns the number of ui elements of the specified component.
    */
-  static countUI(component: UIComponent): number {
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  static countUI(component: UiComponent): number {
     return getElementList(component).length;
   }
 
   /**
    * Returns the number of visible ui elements of the specified component.
    */
-  static countVisibleUI(component: UIComponent): number {
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  static countVisibleUI(component: UiComponent): number {
     return getVisibleElementList(component).length;
   }
 
   /**
    * Returns whether the UI exists in the current DOM tree.
    */
-  static exists(component: UIComponent): boolean {
+  static exists(component: UiComponent): boolean {
     const elements = getElementList(component);
     return elements.length > 0;
   }
@@ -280,7 +291,7 @@
   /**
    * Returns the attribute |attr| of the |index|'th ui.
    */
-  static getAttribute(component: UIComponent, attr: string, index?: number):
+  static getAttribute(component: UiComponent, attr: string, index?: number):
       string|null {
     const element = resolveElement(component, index);
     return element.getAttribute(attr);
@@ -297,7 +308,7 @@
   /**
    * Gets the capabilities of digital zoom.
    */
-  static getDigitalZoomCapabilities(): PTZCapabilities {
+  static getDigitalZoomCapabilities(): PtzCapabilities {
     return DIGITAL_ZOOM_CAPABILITIES;
   }
 
@@ -331,7 +342,7 @@
    * Get [min, max] range of the component. Throws an error if the component is
    * not HTMLInputElement with type "range".
    */
-  static getInputRange(component: UIComponent): InputRange {
+  static getInputRange(component: UiComponent): InputRange {
     const element = getRangeInputComponent(component);
     const max = Number(element.max);
     const min = Number(element.min);
@@ -378,8 +389,11 @@
    * Returns current PTZ settings. Throws an error if PTZ is not enabled, or
    * any of the pan, tilt, or zoom values are missing.
    */
-  static getPTZSettings(): StrictPTZSettings {
-    return Preview.getPTZSettingsForTest();
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  static getPTZSettings(): StrictPtzSettings {
+    return Preview.getPtzSettingsForTest();
   }
 
   static getScreenOrientation(): OrientationType {
@@ -389,7 +403,10 @@
   /**
    * Gets screen x, y of the center of |index|'th ui component.
    */
-  static getScreenXY(component: UIComponent, index?: number): Coordinate {
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
+  static getScreenXY(component: UiComponent, index?: number): Coordinate {
     const element = resolveVisibleElement(component, index);
     const rect = element.getBoundingClientRect();
     const actionBarH = window.outerHeight - window.innerHeight;
@@ -402,7 +419,7 @@
   /**
    * Gets rounded numbers of width and height of the specified ui component.
    */
-  static getSize(component: UIComponent, index?: number): Resolution {
+  static getSize(component: UiComponent, index?: number): Resolution {
     const element = resolveVisibleElement(component, index);
     const {width, height} = element.getBoundingClientRect();
     return new Resolution(Math.round(width), Math.round(height));
@@ -433,16 +450,19 @@
   /**
    * Gets the cover image URL of the gallery button.
    */
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   static getGalleryButtonCoverURL(): string {
     const galleryButton =
         assertInstanceof(resolveElement('galleryButton'), GalleryButton);
-    return galleryButton.getCoverURLForTesting();
+    return galleryButton.getCoverUrlForTesting();
   }
 
   /**
    * Performs mouse hold by sending pointerdown and pointerup events.
    */
-  static async hold(component: UIComponent, ms: number, index?: number):
+  static async hold(component: UiComponent, ms: number, index?: number):
       Promise<void> {
     const element = resolveVisibleElement(component, index);
     element.dispatchEvent(new Event('pointerdown'));
@@ -454,7 +474,7 @@
    * Returns checked attribute of component. Throws an error if the component is
    * not HTMLInputElement.
    */
-  static isChecked(component: UIComponent, index?: number): boolean {
+  static isChecked(component: UiComponent, index?: number): boolean {
     const element = resolveElement(component, index);
     const inputElement = assertInstanceof(element, HTMLInputElement);
     return inputElement.checked;
@@ -464,7 +484,7 @@
    * Returns disabled attribute of the component. In case the element without
    * "disabled" attribute, always returns false.
    */
-  static isDisabled(component: UIComponent, index?: number): boolean {
+  static isDisabled(component: UiComponent, index?: number): boolean {
     const element = resolveElement(component, index);
     if ('disabled' in element && typeof element.disabled === 'boolean') {
       return element.disabled;
@@ -490,7 +510,7 @@
   /**
    * Returns whether the UI component is currently visible.
    */
-  static isVisible(component: UIComponent, index?: number): boolean {
+  static isVisible(component: UiComponent, index?: number): boolean {
     const element = resolveElement(component, index);
     return isVisibleElement(element);
   }
@@ -515,7 +535,7 @@
   /**
    * Selects the select component with the option with the provided value.
    */
-  static selectOption(component: UIComponent, value: string): void {
+  static selectOption(component: UiComponent, value: string): void {
     const element = resolveElement(component);
     const selectElement = assertInstanceof(element, HTMLSelectElement);
     const option =
@@ -531,6 +551,9 @@
   /**
    * Hides all toasts, nudges and tooltips.
    */
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   static hideFloatingUI(): void {
     state.set(state.State.HIDE_FLOATING_UI_FOR_TESTING, true);
   }
@@ -547,7 +570,7 @@
    * HTMLInputElement with type "range", or the value is not within [min, max]
    * range.
    */
-  static setRangeInputValue(component: UIComponent, value: number): void {
+  static setRangeInputValue(component: UiComponent, value: number): void {
     const {max, min} = CCATest.getInputRange(component);
     if (value < min || value > max) {
       throw new Error(`Invalid value ${value} within range ${min}-${max}`);
diff --git a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
index 7a6d9be..cfe6e46 100644
--- a/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
+++ b/ash/webui/camera_app_ui/resources/js/test/cca_type.ts
@@ -14,9 +14,15 @@
   backVideoResolutionOptions: `#view-video-resolution-settings ` +
       `.menu-item>input[data-facing="environment"]`,
   barcodeChipText: '.barcode-chip-text',
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   barcodeChipURL: '#barcode-chip-url',
   barcodeChipWifi: '#barcode-chip-wifi',
   barcodeCopyTextButton: '#barcode-chip-text-container .barcode-copy-button',
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   barcodeCopyURLButton: '#barcode-chip-url-container .barcode-copy-button',
   bitrateMultiplierRangeInput: '#bitrate-slider input[type=range]',
   cancelResultButton: 'button[i18n-label=cancel_review_button]',
@@ -61,6 +67,9 @@
   lowStorageDialog: '#view-low-storage-dialog',
   lowStorageDialogManageButton:
       '#view-low-storage-dialog button.dialog-negative-button',
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   lowStorageDialogOKButton:
       '#view-low-storage-dialog button.dialog-positive-button',
   lowStorageWarning: '#nudge',
@@ -69,6 +78,9 @@
   modeSelector: 'mode-selector',
   openGridPanelButton: '#open-grid-panel',
   openMirrorPanelButton: '#open-mirror-panel',
+  // This is used by tast side and name needs to be keep as is for backward
+  // compatibility.
+  // eslint-disable-next-line @typescript-eslint/naming-convention
   openPTZPanelButton: '#open-ptz-panel',
   openTimerPanelButton: '#open-timer-panel',
   panLeftButton: '#pan-left',
@@ -107,7 +119,7 @@
   zoomInButton: '#zoom-in',
   zoomOutButton: '#zoom-out',
 } as const;
-export type UIComponent = keyof typeof SELECTOR_MAP;
+export type UiComponent = keyof typeof SELECTOR_MAP;
 
 export const SETTING_OPTION_MAP = {
   customVideoParametersOption: {
@@ -130,7 +142,7 @@
     component: 'previewOcrOption',
     state: State.ENABLE_PREVIEW_OCR,
   },
-} satisfies Record<string, {component: UIComponent, state: StateUnion}>;
+} satisfies Record<string, {component: UiComponent, state: StateUnion}>;
 export type SettingOption = keyof typeof SETTING_OPTION_MAP;
 
 export const SETTING_MENU_MAP = {
@@ -154,5 +166,5 @@
     component: 'videoResolutionSettingButton',
     view: ViewName.VIDEO_RESOLUTION_SETTINGS,
   },
-} satisfies Record<string, {component: UIComponent, view: ViewName}>;
+} satisfies Record<string, {component: UiComponent, view: ViewName}>;
 export type SettingMenu = keyof typeof SETTING_MENU_MAP;
diff --git a/ash/webui/camera_app_ui/resources/js/test_bridge.ts b/ash/webui/camera_app_ui/resources/js/test_bridge.ts
index 58071a5..a2ed63a 100644
--- a/ash/webui/camera_app_ui/resources/js/test_bridge.ts
+++ b/ash/webui/camera_app_ui/resources/js/test_bridge.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 /**
- * @file
+ * @fileoverview
  * This scripts should only be loaded as a SharedWorker and the worker is only
  * used for communication between Tast tests and CCA instance. Generally, the
  * SharedWorker will first be created by Tast tests when constructing the test
@@ -14,7 +14,7 @@
 
 import {AppWindow} from './app_window.js';
 import {assert} from './assert.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 
 /**
  * Pending unbound AppWindow requested by tast waiting to be bound by next
@@ -38,11 +38,11 @@
  * later once the window is created. This method is expected to be called in
  * Tast tests.
  */
-export function registerUnboundWindow(): AppWindow&Comlink.ProxyMarked {
+export function registerUnboundWindow(): AppWindow&comlink.ProxyMarked {
   assert(pendingAppWindow === null);
   const appWindow = new AppWindow(fromColdStart);
   pendingAppWindow = appWindow;
-  return Comlink.proxy(appWindow);
+  return comlink.proxy(appWindow);
 }
 
 /**
@@ -50,13 +50,13 @@
  *
  * @param url The URL to bind.
  */
-function bindWindow(url: string): (AppWindow&Comlink.ProxyMarked)|null {
+function bindWindow(url: string): (AppWindow&comlink.ProxyMarked)|null {
   fromColdStart = false;
   if (pendingAppWindow !== null) {
     const appWindow = pendingAppWindow;
     pendingAppWindow = null;
     appWindow.bindUrl(url);
-    return Comlink.proxy(appWindow);
+    return comlink.proxy(appWindow);
   }
   return null;
 }
@@ -94,7 +94,7 @@
  */
 sharedWorkerScope.onconnect = (event: MessageEvent) => {
   const port = event.ports[0];
-  Comlink.expose(
+  comlink.expose(
       {
         bindWindow,
         isInTestSession,
diff --git a/ash/webui/camera_app_ui/resources/js/trusted_script_url_policy_util.ts b/ash/webui/camera_app_ui/resources/js/trusted_script_url_policy_util.ts
index 1a16e12..64db11f 100644
--- a/ash/webui/camera_app_ui/resources/js/trusted_script_url_policy_util.ts
+++ b/ash/webui/camera_app_ui/resources/js/trusted_script_url_policy_util.ts
@@ -18,6 +18,7 @@
 const trustedScriptUrlPolicy =
     assertExists(window.trustedTypes)
         .createPolicy('camera-app-trusted-script', {
+          // eslint-disable-next-line @typescript-eslint/naming-convention
           createScriptURL: (url: string) => {
             if (!ALLOWED_SCRIPT_URLS.has(url)) {
               throw new Error('Script URL not allowed: ' + url);
diff --git a/ash/webui/camera_app_ui/resources/js/untrusted_ga_helper.ts b/ash/webui/camera_app_ui/resources/js/untrusted_ga_helper.ts
index 06bcad72..29c824b3 100644
--- a/ash/webui/camera_app_ui/resources/js/untrusted_ga_helper.ts
+++ b/ash/webui/camera_app_ui/resources/js/untrusted_ga_helper.ts
@@ -77,7 +77,7 @@
 type Ga4MeasurementProtocolEventParams = Ga4EventParams&{
   ['engagement_time_msec']: string,
   ['session_id']: string,
-}
+};
 
 interface InitGa4Params {
   apiSecret: string;
diff --git a/ash/webui/camera_app_ui/resources/js/untrusted_script_loader.ts b/ash/webui/camera_app_ui/resources/js/untrusted_script_loader.ts
index b7e876b..37f5df0 100644
--- a/ash/webui/camera_app_ui/resources/js/untrusted_script_loader.ts
+++ b/ash/webui/camera_app_ui/resources/js/untrusted_script_loader.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert} from './assert.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 import {WaitableEvent} from './waitable_event.js';
 
 const domReady = new WaitableEvent();
@@ -31,4 +31,4 @@
   domReady.signal();
 });
 
-Comlink.expose(exposedObjects, Comlink.windowEndpoint(self.parent, self));
+comlink.expose(exposedObjects, comlink.windowEndpoint(self.parent, self));
diff --git a/ash/webui/camera_app_ui/resources/js/untrusted_scripts.ts b/ash/webui/camera_app_ui/resources/js/untrusted_scripts.ts
index 070836a..879d34a4 100644
--- a/ash/webui/camera_app_ui/resources/js/untrusted_scripts.ts
+++ b/ash/webui/camera_app_ui/resources/js/untrusted_scripts.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assert, assertExists} from './assert.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 import {isLocalDev} from './models/load_time_data.js';
 import {
   Ga4EventParams,
@@ -15,7 +15,7 @@
 import {expandPath} from './util.js';
 import {WaitableEvent} from './waitable_event.js';
 
-interface UntrustedIFrame {
+interface UntrustedIframe {
   iframe: HTMLIFrameElement;
   pageReadyEvent: WaitableEvent;
 }
@@ -24,7 +24,7 @@
  * Creates the iframe to host the untrusted scripts under
  * chrome-untrusted://camera-app and append to the document.
  */
-export function createUntrustedIframe(): UntrustedIFrame {
+export function createUntrustedIframe(): UntrustedIframe {
   const untrustedPageReady = new WaitableEvent();
   const iframe = document.createElement('iframe');
   iframe.addEventListener('load', () => untrustedPageReady.signal());
@@ -48,7 +48,7 @@
   measureMemoryUsage(): Promise<MemoryMeasurement>;
 }
 
-let memoryMeasurementHelper: Comlink.Remote<UntrustedScriptLoader>|null = null;
+let memoryMeasurementHelper: comlink.Remote<UntrustedScriptLoader>|null = null;
 
 /**
  * Creates JS module by given |scriptUrl| under untrusted context with given
@@ -58,13 +58,13 @@
  * @param scriptUrl The URL of the script to load.
  */
 export async function injectUntrustedJSModule<T>(
-    untrustedIframe: UntrustedIFrame,
-    scriptUrl: string): Promise<Comlink.Remote<T>> {
+    untrustedIframe: UntrustedIframe,
+    scriptUrl: string): Promise<comlink.Remote<T>> {
   const {iframe, pageReadyEvent} = untrustedIframe;
   await pageReadyEvent.wait();
   assert(iframe.contentWindow !== null);
-  const untrustedRemote = Comlink.wrap<UntrustedScriptLoader>(
-      Comlink.windowEndpoint(iframe.contentWindow, self));
+  const untrustedRemote = comlink.wrap<UntrustedScriptLoader>(
+      comlink.windowEndpoint(iframe.contentWindow, self));
 
   // Memory measurement for all untrusted scripts can be done on any single
   // untrusted frame.
@@ -77,11 +77,11 @@
   // loadScript adds the script exports to what's exported by the
   // untrustedRemote, so we manually cast it to the expected type.
   // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
-  return untrustedRemote as unknown as Comlink.Remote<T>;
+  return untrustedRemote as unknown as comlink.Remote<T>;
 }
 
-let gaHelper: Promise<Comlink.Remote<GaHelper>>|null = null;
-let videoProcessorHelper: Promise<Comlink.Remote<VideoProcessorHelper>>|null =
+let gaHelper: Promise<comlink.Remote<GaHelper>>|null = null;
+let videoProcessorHelper: Promise<comlink.Remote<VideoProcessorHelper>>|null =
     null;
 
 /**
@@ -96,7 +96,7 @@
 /**
  * Gets the singleton GaHelper instance that is located in an untrusted iframe.
  */
-export function getGaHelper(): Promise<Comlink.Remote<GaHelper>> {
+export function getGaHelper(): Promise<comlink.Remote<GaHelper>> {
   return assertExists(gaHelper);
 }
 
@@ -104,7 +104,7 @@
  * Sets the singleton GaHelper instance. This should only be called on
  * initialize by init.ts.
  */
-export function setGaHelper(newGaHelper: Promise<Comlink.Remote<GaHelper>>):
+export function setGaHelper(newGaHelper: Promise<comlink.Remote<GaHelper>>):
     void {
   assert(gaHelper === null, 'gaHelper should only be initialize once on init');
   gaHelper = newGaHelper;
@@ -121,7 +121,7 @@
  * untrusted iframe.
  */
 export function getVideoProcessorHelper():
-    Promise<Comlink.Remote<VideoProcessorHelper>> {
+    Promise<comlink.Remote<VideoProcessorHelper>> {
   return assertExists(videoProcessorHelper);
 }
 
@@ -130,7 +130,7 @@
  * on initialize by init.ts.
  */
 export function setVideoProcessorHelper(
-    newVideoProcessorHelper: Promise<Comlink.Remote<VideoProcessorHelper>>):
+    newVideoProcessorHelper: Promise<comlink.Remote<VideoProcessorHelper>>):
     void {
   assert(
       videoProcessorHelper === null,
diff --git a/ash/webui/camera_app_ui/resources/js/untrusted_video_processor_helper.ts b/ash/webui/camera_app_ui/resources/js/untrusted_video_processor_helper.ts
index 0af6f3ed..f8a6ba0 100644
--- a/ash/webui/camera_app_ui/resources/js/untrusted_video_processor_helper.ts
+++ b/ash/webui/camera_app_ui/resources/js/untrusted_video_processor_helper.ts
@@ -3,20 +3,22 @@
 // found in the LICENSE file.
 
 import {assertExists} from './assert.js';
-import * as Comlink from './lib/comlink.js';
+import * as comlink from './lib/comlink.js';
 
 /**
  * The MP4 video processor URL in trusted type.
  */
-const mp4VideoProcessorURL: TrustedScriptURL = (() => {
-  const staticUrlPolicy = assertExists(window.trustedTypes)
-                              .createPolicy('video-processor-js-static', {
-                                // util.expandPath is not used here since this
-                                // is in a different window, and local dev
-                                // doesn't override this.
-                                createScriptURL: (_url: string) =>
-                                    '../js/models/ffmpeg/video_processor.js',
-                              });
+const mp4VideoProcessorUrl: TrustedScriptURL = (() => {
+  const trustedTypes = assertExists(window.trustedTypes);
+  const staticUrlPolicy =
+      trustedTypes.createPolicy('video-processor-js-static', {
+        // util.expandPath is not used here since this
+        // is in a different window, and local dev
+        // doesn't override this.
+        // eslint-disable-next-line @typescript-eslint/naming-convention
+        createScriptURL: (_url: string) =>
+            '../js/models/ffmpeg/video_processor.js',
+      });
   // TODO(crbug.com/980846): Remove the empty string if
   // https://github.com/w3c/webappsec-trusted-types/issues/278 gets fixed.
   return staticUrlPolicy.createScriptURL('');
@@ -31,12 +33,12 @@
    * TrustedScriptURL as parameter to Worker.
    */
   // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
-  const trustedURL = mp4VideoProcessorURL as unknown as URL;
+  const trustedUrl = mp4VideoProcessorUrl as unknown as URL;
 
   // TODO(pihsun): actually get correct type from the function definition.
-  const worker = Comlink.wrap<{exposeVideoProcessor(port: MessagePort): void}>(
-      new Worker(trustedURL, {type: 'module'}));
-  await worker.exposeVideoProcessor(Comlink.transfer(port, [port]));
+  const worker = comlink.wrap<{exposeVideoProcessor(port: MessagePort): void}>(
+      new Worker(trustedUrl, {type: 'module'}));
+  await worker.exposeVideoProcessor(comlink.transfer(port, [port]));
 }
 
 export interface VideoProcessorHelper {
diff --git a/ash/webui/camera_app_ui/resources/js/util.ts b/ash/webui/camera_app_ui/resources/js/util.ts
index a3b82ff..e4c5290 100644
--- a/ash/webui/camera_app_ui/resources/js/util.ts
+++ b/ash/webui/camera_app_ui/resources/js/util.ts
@@ -405,7 +405,7 @@
   if (imageValue === null || imageValue === undefined) {
     return null;
   }
-  const match = imageValue.toString().match(/url\(['"](.*)['"]\)/);
+  const match = /url\(['"](.*)['"]\)/.exec(imageValue.toString());
   return match?.[1] ?? null;
 }
 
@@ -432,7 +432,7 @@
  * value and value to name, which most of the time isn't what we want.
  */
 export function getNumberEnumMapping<T extends number>(
-    enumType: {[key: string]: T|string}): {[key: string]: T} {
+    enumType: Record<string, T|string>): Record<string, T> {
   return Object.fromEntries(Object.entries(enumType).flatMap(([k, v]) => {
     if (typeof v === 'string') {
       return [];
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera.ts b/ash/webui/camera_app_ui/resources/js/views/camera.ts
index 529f8ad1..f47b951 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera.ts
@@ -14,7 +14,7 @@
 import {
   CameraConfig,
   CameraManager,
-  CameraViewUI,
+  CameraViewUi,
   getDefaultScanCorners,
   GifResult,
   PhotoResult,
@@ -75,7 +75,7 @@
 } from './document_review.js';
 import {Flash} from './flash.js';
 import {OptionPanel} from './option_panel.js';
-import {PTZPanel} from './ptz_panel.js';
+import {PtzPanel} from './ptz_panel.js';
 import * as review from './review.js';
 import {PrimarySettings} from './settings/primary.js';
 import {View} from './view.js';
@@ -84,7 +84,7 @@
 /**
  * Camera-view controller.
  */
-export class Camera extends View implements CameraViewUI {
+export class Camera extends View implements CameraViewUi {
   private readonly documentReview: DocumentReview;
 
   private currentLowStorageType: LowStorageDialogType|null = null;
@@ -165,7 +165,7 @@
     this.subViews = [
       new PrimarySettings(this.cameraManager),
       new OptionPanel(),
-      new PTZPanel(),
+      new PtzPanel(),
       this.review,
       this.documentReview,
       this.lowStorageDialogView,
@@ -254,7 +254,7 @@
       offLabel: I18nString.RECORD_VIDEO_PAUSE_BUTTON,
     });
 
-    this.cameraManager.registerCameraUI({
+    this.cameraManager.registerCameraUi({
       onTryingNewConfig: (config: CameraConfig) => {
         this.updateMode(config.mode);
       },
@@ -353,7 +353,7 @@
 
   private initVideoEncoderOptions() {
     const options = this.videoEncoderOptions;
-    this.cameraManager.registerCameraUI({
+    this.cameraManager.registerCameraUi({
       onUpdateConfig: () => {
         if (state.get(Mode.VIDEO)) {
           const {width, height, frameRate} =
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera/document_corner_overlay.ts b/ash/webui/camera_app_ui/resources/js/views/camera/document_corner_overlay.ts
index 999708c..7b5d364 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera/document_corner_overlay.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera/document_corner_overlay.ts
@@ -284,8 +284,8 @@
       let centerX = 0;
       let centerY = 0;
       let maxEdgeLength = 0;
-      const shouldUpdatePOI = (() => {
-        let isPreviousPOIOutsideNewDoc = this.prevDocArea === null;
+      const shouldUpdatePoi = (() => {
+        let isPreviousPoiOutsideNewDoc = this.prevDocArea === null;
         const {x: xp, y: yp} = this.prevDocArea?.center ?? {x: 0, y: 0};
         for (let i = 0; i < corners.length; ++i) {
           const {x: x1, y: y1} = corners[i];
@@ -299,16 +299,16 @@
 
           const d = (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1);
           if (d >= 0) {
-            isPreviousPOIOutsideNewDoc = true;
+            isPreviousPoiOutsideNewDoc = true;
           }
         }
         const isDocScaleChanges = this.prevDocArea === null ||
             Math.abs(maxEdgeLength - this.prevDocArea.scale) /
                     this.prevDocArea.scale >
                 THRESHOLD_SCALE_DIFF;
-        return isPreviousPOIOutsideNewDoc || isDocScaleChanges;
+        return isPreviousPoiOutsideNewDoc || isDocScaleChanges;
       })();
-      if (!shouldUpdatePOI) {
+      if (!shouldUpdatePoi) {
         return null;
       }
       return {center: new Point(centerX, centerY), scale: maxEdgeLength};
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera/options.ts b/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
index aa55369..0a43e36 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera/options.ts
@@ -8,7 +8,7 @@
   CameraConfig,
   CameraInfo,
   CameraManager,
-  CameraUI,
+  CameraUi,
 } from '../../device/index.js';
 import * as dom from '../../dom.js';
 import {I18nString} from '../../i18n_string.js';
@@ -17,12 +17,12 @@
 import * as state from '../../state.js';
 import {Facing, LocalStorageKey, Mode, ViewName} from '../../type.js';
 import * as util from '../../util.js';
-import {OptionPanelOptions, PTZPanelOptions, StateOption} from '../view.js';
+import {OptionPanelOptions, PtzPanelOptions, StateOption} from '../view.js';
 
 /**
  * Creates a controller for the options of Camera view.
  */
-export class Options implements CameraUI {
+export class Options implements CameraUi {
   private readonly toggleMic = dom.get('#toggle-mic', HTMLButtonElement);
 
   private readonly openMirrorPanel =
@@ -55,7 +55,7 @@
   private audioTrack: MediaStreamTrack|null = null;
 
   constructor(private readonly cameraManager: CameraManager) {
-    this.cameraManager.registerCameraUI(this);
+    this.cameraManager.registerCameraUi(this);
     this.switchDeviceButton.addEventListener('click', () => {
       if (state.get(state.State.TAKING)) {
         return;
@@ -71,7 +71,7 @@
     this.initOpenMirrorPanel();
     this.initOpenGridPanel();
     this.initOpenTimerPanel();
-    this.initOpenPTZPanel();
+    this.initOpenPtzPanel();
     this.initToggleMic();
 
     // Restore saved mirroring states per video device.
@@ -219,12 +219,12 @@
     });
   }
 
-  private initOpenPTZPanel() {
+  private initOpenPtzPanel() {
     this.openPTZPanel.addEventListener('click', () => {
       toggleIndicatorOnOpenPTZButton(false);
       nav.open(
           ViewName.PTZ_PANEL,
-          new PTZPanelOptions(this.cameraManager.getPTZController()));
+          new PtzPanelOptions(this.cameraManager.getPtzController()));
     });
   }
 
@@ -341,6 +341,6 @@
  * the new super-resolution feature.
  */
 export function toggleIndicatorOnOpenPTZButton(display: boolean): void {
-  const openPTZPanel = dom.get('#open-ptz-panel', HTMLButtonElement);
-  openPTZPanel.classList.toggle('notify-new-feature', display);
+  const openPtzPanel = dom.get('#open-ptz-panel', HTMLButtonElement);
+  openPtzPanel.classList.toggle('notify-new-feature', display);
 }
diff --git a/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts b/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts
index 4c754f8..369837e 100644
--- a/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/camera/scan_options.ts
@@ -4,7 +4,7 @@
 
 import {assert, assertEnumVariant} from '../../assert.js';
 import {queuedAsyncCallback} from '../../async_job_queue.js';
-import {CameraManager, CameraUI} from '../../device/index.js';
+import {CameraManager, CameraUi} from '../../device/index.js';
 import * as dom from '../../dom.js';
 import {sendBarcodeEnabledEvent} from '../../metrics.js';
 import {BarcodeScanner} from '../../models/barcode.js';
@@ -39,7 +39,7 @@
 /**
  * Controller for the scan options of Camera view.
  */
-export class ScanOptions implements CameraUI {
+export class ScanOptions implements CameraUi {
   private readonly scanOptions =
       [...dom.getAll('#scan-modes-group [data-scantype]', HTMLInputElement)];
 
@@ -63,7 +63,7 @@
       dom.get('#scan-document-option', HTMLDivElement);
 
   constructor(private readonly cameraManager: CameraManager) {
-    this.cameraManager.registerCameraUI(this);
+    this.cameraManager.registerCameraUi(this);
 
     this.documentCornerOverlay = new DocumentCornerOverlay(
         (p) => this.cameraManager.setPointOfInterest(p));
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts b/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
index 6a7fc4c0..452d167 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_fix_mode.ts
@@ -305,15 +305,15 @@
           let moveX = 0;
           let moveY = 0;
           for (const keyIdx of pressedKeyIndices) {
-            const announceMoveXY = KEY_MOVEMENTS[keyIdx];
-            announceMoveX += announceMoveXY.x;
-            announceMoveY += announceMoveXY.y;
+            const announceMoveXy = KEY_MOVEMENTS[keyIdx];
+            announceMoveX += announceMoveXy.x;
+            announceMoveY += announceMoveXy.y;
             const movementIndex =
                 (keyIdx + this.getRotationIndex(this.rotation)) %
                 KEY_MOVEMENTS.length;
-            const moveXY = KEY_MOVEMENTS[movementIndex];
-            moveX += moveXY.x;
-            moveY += moveXY.y;
+            const moveXy = KEY_MOVEMENTS[movementIndex];
+            moveX += moveXy.x;
+            moveY += moveXy.y;
           }
           announcer.updateMovement(announceMoveX, announceMoveY);
           const {x: curX, y: curY} = corner.pt;
diff --git a/ash/webui/camera_app_ui/resources/js/views/document_review.ts b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
index 5a52aa7..43d5b4e 100644
--- a/ash/webui/camera_app_ui/resources/js/views/document_review.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/document_review.ts
@@ -500,8 +500,7 @@
    * Changes active page and updates related elements.
    */
   private selectPageView(index: number): void {
-    for (let i = 0; i < this.pagesElement.children.length; i++) {
-      const pageElement = this.pagesElement.children[i];
+    for (const pageElement of this.pagesElement.children) {
       pageElement.classList.remove(ACTIVE_PAGE_CLASS);
       pageElement.setAttribute('aria-selected', 'false');
       pageElement.setAttribute('tabindex', '-1');
diff --git a/ash/webui/camera_app_ui/resources/js/views/ptz_panel.ts b/ash/webui/camera_app_ui/resources/js/views/ptz_panel.ts
index f295d33..cac4cf3 100644
--- a/ash/webui/camera_app_ui/resources/js/views/ptz_panel.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/ptz_panel.ts
@@ -4,14 +4,14 @@
 
 import {assert, assertExists, assertInstanceof} from '../assert.js';
 import {AsyncJobQueue} from '../async_job_queue.js';
-import {PTZController} from '../device/ptz_controller.js';
+import {PtzController} from '../device/ptz_controller.js';
 import * as dom from '../dom.js';
 import * as metrics from '../metrics.js';
 import * as state from '../state.js';
 import {ViewName} from '../type.js';
 import {DelayInterval} from '../util.js';
 
-import {EnterOptions, PTZPanelOptions, View} from './view.js';
+import {EnterOptions, PtzPanelOptions, View} from './view.js';
 
 /**
  * Detects hold gesture on UI and triggers corresponding handler.
@@ -91,8 +91,8 @@
 /**
  * View controller for PTZ panel.
  */
-export class PTZPanel extends View {
-  private ptzController: PTZController|null = null;
+export class PtzPanel extends View {
+  private ptzController: PtzController|null = null;
 
   private readonly panel = dom.get('#ptz-panel', HTMLDivElement);
 
@@ -273,7 +273,7 @@
   }
 
   override entering(options: EnterOptions): void {
-    const {ptzController} = assertInstanceof(options, PTZPanelOptions);
+    const {ptzController} = assertInstanceof(options, PtzPanelOptions);
     const {bottom, right} =
         dom.get('#open-ptz-panel', HTMLButtonElement).getBoundingClientRect();
     this.panel.style.bottom = `${window.innerHeight - bottom}px`;
@@ -313,7 +313,7 @@
         this.tiltQueues.clear(),
         this.zoomQueues.clear(),
       ]);
-      await ptzController.resetPTZ();
+      await ptzController.resetPtz();
       this.checkDisabled();
     };
   }
diff --git a/ash/webui/camera_app_ui/resources/js/views/review.ts b/ash/webui/camera_app_ui/resources/js/views/review.ts
index 08d7845..b60247aa 100644
--- a/ash/webui/camera_app_ui/resources/js/views/review.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/review.ts
@@ -14,7 +14,7 @@
 
 import {View} from './view.js';
 
-interface UIArgs {
+interface UiArgs {
   text?: I18nString;
   label?: I18nString;
   icon?: string;
@@ -41,7 +41,7 @@
    *     selected.
    * @param params.hasPopup Sets aria-haspopup for the option.
    */
-  constructor(readonly uiArgs: UIArgs, {exitValue, callback, hasPopup}: {
+  constructor(readonly uiArgs: UiArgs, {exitValue, callback, hasPopup}: {
     exitValue?: T,
     callback?: (() => void),
     hasPopup?: boolean,
diff --git a/ash/webui/camera_app_ui/resources/js/views/settings/photo_aspect_ratio.ts b/ash/webui/camera_app_ui/resources/js/views/settings/photo_aspect_ratio.ts
index 944ba57..f119c6b 100644
--- a/ash/webui/camera_app_ui/resources/js/views/settings/photo_aspect_ratio.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/settings/photo_aspect_ratio.ts
@@ -29,7 +29,7 @@
     super(ViewName.PHOTO_ASPECT_RATIO_SETTINGS);
 
     this.menu = dom.getFrom(this.root, 'div.menu', HTMLDivElement);
-    cameraManager.registerCameraUI({
+    cameraManager.registerCameraUi({
       onCameraUnavailable: () => {
         for (const input of dom.getAllFrom(
                  this.menu, 'input', HTMLInputElement)) {
diff --git a/ash/webui/camera_app_ui/resources/js/views/settings/photo_resolution.ts b/ash/webui/camera_app_ui/resources/js/views/settings/photo_resolution.ts
index 101e7179..121642d5 100644
--- a/ash/webui/camera_app_ui/resources/js/views/settings/photo_resolution.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/settings/photo_resolution.ts
@@ -31,7 +31,7 @@
     super(ViewName.PHOTO_RESOLUTION_SETTINGS);
 
     this.menu = dom.getFrom(this.root, 'div.menu', HTMLDivElement);
-    cameraManager.registerCameraUI({
+    cameraManager.registerCameraUi({
       onCameraUnavailable: () => {
         for (const input of dom.getAllFrom(
                  this.menu, 'input', HTMLInputElement)) {
diff --git a/ash/webui/camera_app_ui/resources/js/views/settings/primary.ts b/ash/webui/camera_app_ui/resources/js/views/settings/primary.ts
index b94c8af..85df3a2 100644
--- a/ash/webui/camera_app_ui/resources/js/views/settings/primary.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/settings/primary.ts
@@ -108,7 +108,7 @@
       this.videoResolutionSettings,
     ];
 
-    cameraManager.registerCameraUI({
+    cameraManager.registerCameraUi({
       onCameraUnavailable: () => {
         for (const setting of cameraSettings) {
           setting.disabled = true;
diff --git a/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts b/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
index 1afeb648..c91a394 100644
--- a/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/settings/video_resolution.ts
@@ -33,7 +33,7 @@
     super(ViewName.VIDEO_RESOLUTION_SETTINGS);
 
     this.menu = dom.getFrom(this.root, 'div.menu', HTMLDivElement);
-    cameraManager.registerCameraUI({
+    cameraManager.registerCameraUi({
       onCameraUnavailable: () => {
         for (const input of dom.getAllFrom(
                  this.menu, 'input', HTMLInputElement)) {
@@ -53,7 +53,7 @@
 
     expert.addObserver(
         expert.ExpertOption.ENABLE_FPS_PICKER_FOR_BUILTIN,
-        () => this.toggleFPSPickerVisiblity);
+        () => this.toggleFpsPickerVisiblity);
   }
 
   private onOptionsUpdate(groups: VideoResolutionOptionGroup[]): void {
@@ -179,13 +179,13 @@
     }
   }
 
-  private toggleFPSPickerVisiblity(): void {
-    const isFPSEnabled =
+  private toggleFpsPickerVisiblity(): void {
+    const isFpsEnabled =
         expert.isEnabled(expert.ExpertOption.ENABLE_FPS_PICKER_FOR_BUILTIN);
     const fpsButtons =
         dom.getAllFrom(this.menu, '.fps-buttons button', HTMLButtonElement);
     for (const fpsButton of fpsButtons) {
-      fpsButton.hidden = !isFPSEnabled;
+      fpsButton.hidden = !isFpsEnabled;
     }
   }
 }
diff --git a/ash/webui/camera_app_ui/resources/js/views/view.ts b/ash/webui/camera_app_ui/resources/js/views/view.ts
index 13e7286..458cdc5 100644
--- a/ash/webui/camera_app_ui/resources/js/views/view.ts
+++ b/ash/webui/camera_app_ui/resources/js/views/view.ts
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 import {assertExists, assertInstanceof} from '../assert.js';
-import {PTZController} from '../device/ptz_controller.js';
+import {PtzController} from '../device/ptz_controller.js';
 import * as dom from '../dom.js';
 import {I18nString} from '../i18n_string.js';
 import * as state from '../state.js';
@@ -43,10 +43,10 @@
 /**
  * Options for open PTZ panel.
  */
-export class PTZPanelOptions {
-  readonly ptzController: PTZController;
+export class PtzPanelOptions {
+  readonly ptzController: PtzController;
 
-  constructor(ptzController: PTZController) {
+  constructor(ptzController: PtzController) {
     this.ptzController = ptzController;
   }
 }
@@ -100,14 +100,14 @@
 // sort of "global" view registration, so we can enforce the enter / leave type
 // at compile time.
 export type EnterOptions = DialogEnterOptions|FlashEnterOptions|
-    OptionPanelOptions|PTZPanelOptions|WarningEnterOptions;
+    OptionPanelOptions|PtzPanelOptions|WarningEnterOptions;
 
 export type LeaveCondition = {
   kind: 'BACKGROUND_CLICKED'|'ESC_KEY_PRESSED'|'STREAMING_STOPPED',
 }|{
   kind: 'CLOSED',
   val?: unknown,
-}
+};
 
 interface ViewOptions {
   /**
diff --git a/ash/webui/camera_app_ui/resources/utils/cca/commands/lint.py b/ash/webui/camera_app_ui/resources/utils/cca/commands/lint.py
index 7d334911..3990e08b 100644
--- a/ash/webui/camera_app_ui/resources/utils/cca/commands/lint.py
+++ b/ash/webui/camera_app_ui/resources/utils/cca/commands/lint.py
@@ -21,9 +21,7 @@
         "eslint/bin/eslint.js",
         "js",
         "eslint_plugin",
-        ".eslintrc.js",
-        "--resolve-plugins-relative-to",
-        os.path.join(util.get_chromium_root(), "third_party/node"),
+        "eslint.config.mjs",
     ]
     if fix:
         cmd.append("--fix")