Fix building plugin

Convert javascript files to typescript.

This is adapted for gerrit 3.14/3.13.

Change-Id: Id16ae2c508603a6a4a2a34e8c7c75c4c602dd59c
diff --git a/.gitignore b/.gitignore
index ebbbd5f..43617c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+.DS_Store
 /.classpath
 /.project
 /.settings
diff --git a/BUILD b/BUILD
index d870fbe..202c3e1 100644
--- a/BUILD
+++ b/BUILD
@@ -1,5 +1,4 @@
 load("//tools/bzl:plugin.bzl", "gerrit_plugin")
-load("//tools/bzl:js.bzl", "gerrit_js_bundle")
 
 gerrit_plugin(
     name = "ref-copy",
@@ -10,11 +9,5 @@
         "Implementation-Title: Ref Copy Plugin",
     ],
     resources = glob(["src/main/**/*"]),
-    resource_jars = [":ref-copy-ui"],
-)
-
-gerrit_js_bundle(
-    name = "ref-copy-ui",
-    srcs = glob(["ref-copy/*.js"]),
-    entry_point = "ref-copy/plugin.js",
+    resource_jars = ["//plugins/ref-copy/ref-copy:ref-copy-ui"],
 )
diff --git a/ref-copy/BUILD b/ref-copy/BUILD
new file mode 100644
index 0000000..8f7343f
--- /dev/null
+++ b/ref-copy/BUILD
@@ -0,0 +1,42 @@
+load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
+load("//tools/bzl:js.bzl", "gerrit_js_bundle")
+load("//tools/js:eslint.bzl", "plugin_eslint")
+
+package_group(
+    name = "visibility",
+    packages = ["//plugins/ref-copy/..."],
+)
+
+package(default_visibility = [":visibility"])
+
+ts_config(
+    name = "tsconfig",
+    src = "tsconfig.json",
+    deps = [
+        "//plugins:tsconfig-plugins-base.json",
+    ],
+)
+
+ts_project(
+    name = "ref-copy-ts",
+    srcs = glob(
+        ["**/*.ts"],
+        exclude = ["**/*test*"],
+    ),
+    incremental = True,
+    out_dir = "_bazel_ts_out",
+    tsc = "//tools/node_tools:tsc-bin",
+    tsconfig = ":tsconfig",
+    deps = [
+        "@plugins_npm//@gerritcodereview/typescript-api",
+        "@plugins_npm//lit",
+    ],
+)
+
+gerrit_js_bundle(
+    name = "ref-copy-ui",
+    srcs = [":ref-copy-ts"],
+    entry_point = "_bazel_ts_out/plugin.js",
+)
+
+plugin_eslint()
\ No newline at end of file
diff --git a/ref-copy/eslint.config.js b/ref-copy/eslint.config.js
new file mode 100644
index 0000000..770ccff
--- /dev/null
+++ b/ref-copy/eslint.config.js
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright (C) 2026 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+const {defineConfig} = require('eslint/config');
+
+// eslint-disable-next-line no-undef
+__plugindir = 'ref-copy/ref-copy';
+
+const gerritEslint = require('../../eslint.config.js');
+
+module.exports = defineConfig([
+  {
+    extends: [gerritEslint],
+  },
+]);
diff --git a/ref-copy/plugin.js b/ref-copy/plugin.js
deleted file mode 100644
index d406da0..0000000
--- a/ref-copy/plugin.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {REF_COPY} from './ref-copy';
-
-Gerrit.install(plugin => {
-  plugin.registerCustomComponent(
-      'change-metadata-item', REF_COPY);
-});
diff --git a/ref-copy/plugin.ts b/ref-copy/plugin.ts
new file mode 100644
index 0000000..add46e4
--- /dev/null
+++ b/ref-copy/plugin.ts
@@ -0,0 +1,22 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '@gerritcodereview/typescript-api/gerrit';
+import './ref-copy';
+
+window.Gerrit?.install(plugin => {
+  plugin.registerCustomComponent('change-metadata-item', 'ref-copy');
+});
diff --git a/ref-copy/ref-copy.js b/ref-copy/ref-copy.js
deleted file mode 100644
index efb3a35..0000000
--- a/ref-copy/ref-copy.js
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-import {css, html, LitElement} from 'lit';
-
-const COPY_TIMEOUT_MS = 1000;
-
-export const REF_COPY = 'ref-copy';
-class RefCopy extends LitElement {
-  static get properties() {
-    return {
-      revision: {type: Object}
-    };
-  }
-
-  static get styles() {
-    return css`
-    .text {
-      min-width: 8em;
-      padding: var(--spacing-l);
-      text-transform: none;
-    }
-    `;
-  }
-
-  render() {
-    return html`
-    <div class="text">
-      <input
-          id="input"
-          type="text"
-          .value="${this.revision.ref}"
-          @click="${this._handleInputTap}"
-          readonly/>
-      <gr-button
-        id="button"
-        link
-        class="copyToClipboard"
-        @click="${this._copyToClipboard}">
-        copy
-      </gr-button>
-    </div>`;
-  }
-
-  _handleInputTap(e) {
-    e.preventDefault();
-    const rootTarget = e.composedPath()[0];
-    rootTarget.select();
-  }
-
-  _copyToClipboard(e) {
-    const ref = this.revision.ref;
-    const copyBtn = e.target;
-    if (ref) {
-      navigator.clipboard.writeText(ref).then(() => {
-        copyBtn.innerText = 'done';
-        setTimeout(() => {
-          copyBtn.innerText = 'copy'
-        }, COPY_TIMEOUT_MS);
-      }).catch(err => {
-        console.log('Failed to copy ref to clipboard', err);
-      })
-    }
-  }
-}
-
-customElements.define(REF_COPY, RefCopy);
diff --git a/ref-copy/ref-copy.ts b/ref-copy/ref-copy.ts
new file mode 100644
index 0000000..440d756
--- /dev/null
+++ b/ref-copy/ref-copy.ts
@@ -0,0 +1,78 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import {css, html, LitElement} from 'lit';
+import {customElement, property} from 'lit/decorators.js';
+import {RevisionInfo} from '@gerritcodereview/typescript-api/rest-api';
+
+const COPY_TIMEOUT_MS = 1000;
+
+@customElement('ref-copy')
+export class RefCopy extends LitElement {
+  @property({type: Object})
+  revision!: RevisionInfo;
+
+  static override get styles() {
+    return [
+      css`
+        .text {
+          min-width: 8em;
+          padding: var(--spacing-l);
+          text-transform: none;
+        }
+      `
+    ];
+  }
+
+  override render() {
+    return html`
+      <div class="text">
+        <input
+          id="input"
+          type="text"
+          .value="${this.revision.ref}"
+          @click=${(e: InputEvent) => this.handleInputTap(e)}
+          readonly
+        />
+        <gr-button
+          id="button"
+          link
+          class="copyToClipboard"
+          @click=${(e: Event) => this.copyToClipboard(e)}>
+          copy
+        </gr-button>
+      </div>`;
+  }
+
+  private handleInputTap(e: InputEvent) {
+    e.preventDefault();
+    const rootTarget = e.composedPath()[0] as HTMLInputElement;
+    rootTarget.select();
+  }
+
+  private copyToClipboard(e: Event) {
+    const ref = this.revision.ref;
+    const copyBtn = e.target as HTMLButtonElement;
+    if (ref) {
+      navigator.clipboard.writeText(ref).then(() => {
+        copyBtn!.innerText = 'done';
+        setTimeout(() => {
+          copyBtn!.innerText = 'copy'
+        }, COPY_TIMEOUT_MS);
+      }).catch(err => {
+        console.log('Failed to copy ref to clipboard', err);
+      })
+    }
+  }
+}
diff --git a/ref-copy/tsconfig.json b/ref-copy/tsconfig.json
new file mode 100644
index 0000000..2fa9e29
--- /dev/null
+++ b/ref-copy/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig-plugins-base.json",
+  "compilerOptions": {
+    "rootDir": "."
+  },
+  "include": [
+    "**/*.ts"
+  ]
+}
\ No newline at end of file