This is an automated email from the ASF dual-hosted git repository.

msciabarra pushed a commit to branch main
in repository 
https://gitbox.apache.org/repos/asf/openserverless-vscode-extension.git

commit 1adcf3a40b66893f01424b7a07a210b8e69b670e
Author: AntonioPiga <[email protected]>
AuthorDate: Tue Sep 10 11:14:33 2024 +0200

    refactor: clean code methods validate and delete polling login
---
 src/extension.ts          | 169 ++++++++++++++++++++++++----------------------
 src/login/LoginPanel.ts   |  60 ++++++++--------
 src/login/login.ts        |  69 ++++++++++---------
 src/utilities/validate.ts | 166 ++++++++++++++++++++++-----------------------
 4 files changed, 239 insertions(+), 225 deletions(-)

diff --git a/src/extension.ts b/src/extension.ts
index 3db737a..8d770ec 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,106 +1,115 @@
-import * as vscode from 'vscode';
-import { NuvolarisTerminalName } from './constants';
-import { LoginPanel } from './login/LoginPanel';
-import { CliCommands } from './enumerators';
-import * as fs from "fs";
-import * as os from "os";
-import { exec, execSync } from 'child_process';
-import { stderr } from 'process';
+import * as vscode from "vscode";
+import { NuvolarisTerminalName } from "./constants";
+import { LoginPanel } from "./login/LoginPanel";
+import { CliCommands } from "./enumerators";
+import { execSync } from "child_process";
 
 let context: vscode.ExtensionContext;
 
 export async function activate(ctx: vscode.ExtensionContext) {
-       try {
-
-               // Necessary for Theia compatibility of welcome screen. See 
https://github.com/eclipse-theia/theia/issues/9361
-               vscode.window.registerTreeDataProvider(
-                       "command-palette",
-                       new EmptyTreeDataProvider()
-               );
-               // 
-
-               context = ctx;
-               if (!isLoggedIn()) {
-                       LoginPanel.render(handleLogin, context.extensionUri);
-               } 
-
-               Object.entries(CliCommands).forEach(([name, command]) =>
-                       
context.subscriptions.push(vscode.commands.registerCommand(`nuvolaris.${name.toLowerCase()}`,
 () => {
-                                       if (!isLoggedIn()) {
-                                               LoginPanel.render(handleLogin, 
context.extensionUri);
-                                               return;
-                                       }
-                               launchTerminal(command);
-                       }
-                       )));
-
-               
context.subscriptions.push(vscode.commands.registerCommand('nuvolaris.login', 
() => {
-                                               LoginPanel.render(handleLogin, 
context.extensionUri);
-               }));
-       } catch (error: any) {
-               printError(error);
-               throw error;
-       }
+  try {
+    // Necessary for Theia compatibility of welcome screen. See 
https://github.com/eclipse-theia/theia/issues/9361
+    vscode.window.registerTreeDataProvider(
+      "command-palette",
+      new EmptyTreeDataProvider()
+    );
+    //
+
+    context = ctx;
+    if (!isLoggedIn()) {
+      LoginPanel.render(handleLogin, context.extensionUri);
+    }
+
+    Object.entries(CliCommands).forEach(([name, command]) =>
+      context.subscriptions.push(
+        vscode.commands.registerCommand(
+          `nuvolaris.${name.toLowerCase()}`,
+          () => {
+            if (!isLoggedIn()) {
+              LoginPanel.render(handleLogin, context.extensionUri);
+              return;
+            }
+            launchTerminal(command);
+          }
+        )
+      )
+    );
+
+    context.subscriptions.push(
+      vscode.commands.registerCommand("nuvolaris.login", () => {
+        LoginPanel.render(handleLogin, context.extensionUri);
+      })
+    );
+  } catch (error: any) {
+    printError(error);
+    throw error;
+  }
 }
 
 function isLoggedIn(): boolean {
-       try {
-               execSync('nuv -wsk namespace list');
-               return true;
-       } catch (error) {
-               return false;
-       }
-       
+  try {
+    execSync("nuv -wsk namespace list");
+    return true;
+  } catch (error) {
+    return false;
+  }
 }
 
 function handleLogin(username: string, password: string, apiHost: string) {
-       const loginOutput = vscode.window.createOutputChannel('Nuvolaris 
Login');
-       loginOutput.show();
-       try {
-               loginOutput.appendLine('Launching login script...');
-               const execLogin = execSync(`nuv ide login  "${username}" 
"${apiHost.endsWith('/') ? apiHost.slice(0, -1) : apiHost}"`, {
-                       env: {...process.env, NUV_PASSWORD: password}
-               });
-               loginOutput.appendLine(execLogin.toString());
-               printInfo("You successfully logged in. You can now use the 
Nuvolaris command palette.")
-       } catch (error: any) {
-               loginOutput.appendLine(error);
-               printError("An error occurred in the login process. Check the 
output window for further details.")
-               throw error;
-       }
+  const loginOutput = vscode.window.createOutputChannel("Nuvolaris Login");
+  loginOutput.show();
+  try {
+    loginOutput.appendLine("Launching login script...");
+    const execLogin = execSync(
+      `nuv ide login  "${username}" "${
+        apiHost.endsWith("/") ? apiHost.slice(0, -1) : apiHost
+      }"`,
+      {
+        env: { ...process.env, NUV_PASSWORD: password },
+      }
+    );
+    loginOutput.appendLine(execLogin.toString());
+    printInfo(
+      "You successfully logged in. You can now use the Nuvolaris command 
palette."
+    );
+  } catch (error: any) {
+    loginOutput.appendLine(error);
+    printError(
+      "An error occurred in the login process. Check the output window for 
further details."
+    );
+    throw error;
+  }
 }
 
-
 function launchTerminal(command: string): void {
-       try {
-               const terminal = 
vscode.window.createTerminal(NuvolarisTerminalName);
-               terminal.show();
-               terminal.sendText(command, true);
-       } catch (error) {
-               printError(error);
-               throw error;
-       }
+  try {
+    const terminal = vscode.window.createTerminal(NuvolarisTerminalName);
+    terminal.show();
+    terminal.sendText(command, true);
+  } catch (error) {
+    printError(error);
+    throw error;
+  }
 }
 
 function printError(error: any) {
-       return vscode.window.showErrorMessage(error.toString());
+  return vscode.window.showErrorMessage(error.toString());
 }
 function printInfo(info: string) {
-       return vscode.window.showInformationMessage(info);
-
+  return vscode.window.showInformationMessage(info);
 }
 
 export function deactivate() {}
 
 // Necessary for Theia compatibility of welcome screen. See 
https://github.com/eclipse-theia/theia/issues/9361
 export class EmptyTreeDataProvider implements vscode.TreeDataProvider<any> {
-       constructor() {}
+  constructor() {}
 
-       getTreeItem(element: any): vscode.TreeItem {
-               return {};
-       }
+  getTreeItem(element: any): vscode.TreeItem {
+    return {};
+  }
 
-       getChildren(element?: any): Thenable<any[]> {
-               return new Promise((resolve) => resolve([]));
-       }
-}
\ No newline at end of file
+  getChildren(element?: any): Thenable<any[]> {
+    return new Promise((resolve) => resolve([]));
+  }
+}
diff --git a/src/login/LoginPanel.ts b/src/login/LoginPanel.ts
index 225f267..27a444d 100644
--- a/src/login/LoginPanel.ts
+++ b/src/login/LoginPanel.ts
@@ -1,4 +1,3 @@
-
 import * as vscode from "vscode";
 import { getUri } from "../utilities/getUri";
 import { getNonce } from "../utilities/getNonce";
@@ -11,21 +10,11 @@ export class LoginPanel {
   private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
     this._panel = panel;
     this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
-    this._panel.webview.html = this._getWebviewContent(this._panel.webview, 
extensionUri);
+    this._panel.webview.html = this._getWebviewContent(
+      this._panel.webview,
+      extensionUri
+    );
     this._setWebviewMessageListener(this._panel.webview);
-    // this._panel.webview.onDidReceiveMessage(message => {
-    //   switch (message.command) {
-    //     case 'login':
-    //       // Handle login form submission
-    //       const { username, password, apiHost } = message;
-    //       console.log('Submitted login details:', username, password, 
apiHost);
-    //       // Pass the login details back to the extension
-    //       if (this._onLoginCallback) {
-    //         this._onLoginCallback(username, password, apiHost);
-    //       }
-    //       break;
-    //   }
-    // }, undefined, this._disposables);
   }
 
   private _setWebviewMessageListener(webview: vscode.Webview) {
@@ -48,7 +37,10 @@ export class LoginPanel {
       this._disposables
     );
   }
-  private _getWebviewContent(webview: vscode.Webview, extensionUri: 
vscode.Uri) {
+  private _getWebviewContent(
+    webview: vscode.Webview,
+    extensionUri: vscode.Uri
+  ) {
     const webviewUri = getUri(webview, extensionUri, ["out", "login.js"]);
     const nonce = getNonce();
     return /*html*/ `
@@ -57,7 +49,6 @@ export class LoginPanel {
       <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
-        <!--<meta http-equiv="Content-Security-Policy" content="default-src 
'none'; script-src 'nonce-${nonce}'; style-src 'self';">-->
         <title>Nuvolaris - Login!</title>
         <style>
             body {
@@ -116,27 +107,38 @@ export class LoginPanel {
         <img 
src="https://assets-global.website-files.com/64b64691257b91236b0e7482/64bfcab6bd343008e30e5d06_Nuvolaris%20logo%20white.png";
 class="logo-img"></img>
         <h2>Login</h2>
         <form class="login-form" id="login-form">
-          <input type="text" id="username-input" placeholder="Username">
-          <input type="password" id="password-input" placeholder="Password">
-          <input type="text" id="api-host-input" placeholder="API Host URL" 
value="https://nuvolaris.dev";>
-          <vscode-button id="login-button" type="submit" > L O G I N 
</vscode-button>
+          <input type="text" id="username-input" name="username" 
placeholder="Username" autocomplete="username">
+          <input type="password" id="password-input" name="password" 
placeholder="Password" autocomplete="current-password">
+          <input type="text" id="api-host-input" name="apiHost" 
placeholder="API Host URL" value="https://nuvolaris.dev";>
+          <vscode-button id="login-button" type="submit"> L O G I N 
</vscode-button>
         </form>
         </div>
         <script type="module" nonce="${nonce}" src="${webviewUri}"></script>
       </body>
     </html>
-  `;
+    `;
   }
-  private _onLoginCallback: ((username: string, password: string, apiHost: 
string) => void) | undefined;
-  public static render(onLogin: (username: string, password: string, apiHost: 
string) => void, extensionUri: vscode.Uri) {
+
+  private _onLoginCallback:
+    | ((username: string, password: string, apiHost: string) => void)
+    | undefined;
+  public static render(
+    onLogin: (username: string, password: string, apiHost: string) => void,
+    extensionUri: vscode.Uri
+  ) {
     if (LoginPanel.currentPanel) {
       LoginPanel.currentPanel._panel.reveal(vscode.ViewColumn.One);
     } else {
-      const panel = vscode.window.createWebviewPanel("login-panel", "Login", 
vscode.ViewColumn.One, {
-        enableScripts: true,
-        // Restrict the webview to only load resources from the `out` directory
-        localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'out')]
-      });
+      const panel = vscode.window.createWebviewPanel(
+        "login-panel",
+        "Login",
+        vscode.ViewColumn.One,
+        {
+          enableScripts: true,
+          // Restrict the webview to only load resources from the `out` 
directory
+          localResourceRoots: [vscode.Uri.joinPath(extensionUri, "out")],
+        }
+      );
       LoginPanel.currentPanel = new LoginPanel(panel, extensionUri);
     }
     LoginPanel.currentPanel._onLoginCallback = onLogin;
diff --git a/src/login/login.ts b/src/login/login.ts
index 667c66f..c2bd1e0 100644
--- a/src/login/login.ts
+++ b/src/login/login.ts
@@ -1,31 +1,33 @@
-import { provideVSCodeDesignSystem, vsCodeButton } from 
"@vscode/webview-ui-toolkit";
+import {
+  provideVSCodeDesignSystem,
+  vsCodeButton,
+} from "@vscode/webview-ui-toolkit";
 import { LoginPageIDs } from "../enumerators";
-import { validateApiHost, validatePassword, validateUsername } from 
"../utilities/validate";
+import { validateNotEmptyField } from "../utilities/validate";
 provideVSCodeDesignSystem().register(vsCodeButton());
 const vscode = acquireVsCodeApi();
 window.addEventListener("load", main);
 
 const LoginPage = {
-  getUsername: (): HTMLInputElement => { return 
document.getElementById(LoginPageIDs.Username) as HTMLInputElement },
-  getPassword: (): HTMLInputElement => { return 
document.getElementById(LoginPageIDs.Password) as HTMLInputElement },
-  getApiHost: (): HTMLInputElement => { return 
document.getElementById(LoginPageIDs.ApiHost) as HTMLInputElement },
-  getLoginButton: (): HTMLButtonElement => { return 
document.getElementById(LoginPageIDs.LoginButton) as HTMLButtonElement }
-}
+  getUsername: (): HTMLInputElement => {
+    return document.getElementById(LoginPageIDs.Username) as HTMLInputElement;
+  },
+  getPassword: (): HTMLInputElement => {
+    return document.getElementById(LoginPageIDs.Password) as HTMLInputElement;
+  },
+  getApiHost: (): HTMLInputElement => {
+    return document.getElementById(LoginPageIDs.ApiHost) as HTMLInputElement;
+  },
+  getLoginButton: (): HTMLButtonElement => {
+    return document.getElementById(
+      LoginPageIDs.LoginButton
+    ) as HTMLButtonElement;
+  },
+};
 
 function main() {
   try {
-    LoginPage.getLoginButton()
-      .addEventListener("click", handleLoginSubmit);
-
-    LoginPage.getUsername()
-      .addEventListener("input", validateLogin);
-
-    LoginPage.getPassword()
-      .addEventListener("input", validateLogin)
-      
-    LoginPage.getApiHost()
-      .addEventListener("input", validateLogin);
-
+    LoginPage.getLoginButton().addEventListener("click", handleLoginSubmit);
   } catch (error: any) {
     sendError(error);
     throw error;
@@ -38,7 +40,6 @@ function handleLoginSubmit() {
     const password = LoginPage.getPassword();
     const apiHost = LoginPage.getApiHost();
 
-    validateLogin();
     if (validateLogin()) {
       vscode.postMessage({
         command: "login",
@@ -47,8 +48,7 @@ function handleLoginSubmit() {
         apiHost: `${apiHost.value}`,
         text: `${username.value} ${password.value} ${apiHost.value} PASS`,
       });
-    }
-    else {
+    } else {
       vscode.postMessage({
         command: "login",
         text: `${username.value} ${password.value} ${apiHost.value} NOT PASS`,
@@ -60,21 +60,26 @@ function handleLoginSubmit() {
   }
 }
 
-
 function validateLogin() {
   try {
-    const loginSubmitButton = LoginPage.getLoginButton();
-    let isUsernameValid = validateUsername(LoginPage.getUsername());
-    let isPasswordValid = validatePassword(LoginPage.getPassword());
-    let isApiHostValid = validateApiHost(LoginPage.getApiHost());
-    let isValid = isUsernameValid && isPasswordValid && isApiHostValid;
-    loginSubmitButton.disabled = !isValid;
-    return isValid;
+    const isUsernameValid = validateNotEmptyField(
+      "username",
+      LoginPage.getUsername()
+    );
+    const isPasswordValid = validateNotEmptyField(
+      "password",
+      LoginPage.getPassword()
+    );
+    const isApiHostValid = validateNotEmptyField(
+      "Api Host",
+      LoginPage.getApiHost()
+    );
+
+    return isUsernameValid && isPasswordValid && isApiHostValid;
   } catch (error: any) {
     sendError(error);
     throw error;
   }
-
 }
 
 function sendError(error: any) {
@@ -82,4 +87,4 @@ function sendError(error: any) {
     type: "error",
     text: `Error occurred: ${error.toString()}`,
   });
-}
\ No newline at end of file
+}
diff --git a/src/utilities/validate.ts b/src/utilities/validate.ts
index 3855527..1e5df74 100644
--- a/src/utilities/validate.ts
+++ b/src/utilities/validate.ts
@@ -1,90 +1,83 @@
 import { ValidatorAssertion } from "../interfaces";
 
 export const Validators = {
-  minChars: (htmlElement: HTMLInputElement, min: number, fieldName: string | 
null = null): ValidatorAssertion => {
-    let message = `Field '${fieldName || htmlElement.id}' should contain 
minimum ${min} chars.`
+  minChars: (
+    htmlElement: HTMLInputElement,
+    min: number,
+    fieldName: string | null = null
+  ): ValidatorAssertion => {
+    const message = `Field '${
+      fieldName || htmlElement.id
+    }' should contain minimum ${min} chars.`;
     let isValid = true;
     isValid = htmlElement.value.length >= min;
     return { isValid, message, htmlElement };
   },
-  maxChars: (htmlElement: HTMLInputElement, max: number, fieldName: string | 
null = null): ValidatorAssertion => {
-    let message = `Field '${fieldName || htmlElement.id}' should contain 
maximum ${max} chars.`
+  maxChars: (
+    htmlElement: HTMLInputElement,
+    max: number,
+    fieldName: string | null = null
+  ): ValidatorAssertion => {
+    const message = `Field '${
+      fieldName || htmlElement.id
+    }' should contain maximum ${max} chars.`;
     let isValid = true;
     isValid = htmlElement.value.length <= max;
     return { isValid, message, htmlElement };
   },
-  validUrl: (htmlElement: HTMLInputElement, fieldName: string | null = null): 
ValidatorAssertion => {
-    let message = `Field '${fieldName || htmlElement.id}' should be a valid 
URL.`
-    let pattern = new RegExp('^(https?:\\/\\/)?' + // protocol (optional)
-      '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain
-      '((\\d{1,3}\\.){3}\\d{1,3}))' + // or IP address
-      '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*' + // port and path (optional)
-      '(\\?[;&a-z\\d%_.~+=-]*)?' + // query string
-      '(\\#[-a-z\\d_]*)?$', 'i'); // anchor (optional)
-    let isValid = pattern.test(htmlElement.value);
+  validUrl: (
+    htmlElement: HTMLInputElement,
+    fieldName: string | null = null
+  ): ValidatorAssertion => {
+    const message = `Field '${
+      fieldName || htmlElement.id
+    }' should be a valid URL.`;
+    const pattern = new RegExp(
+      "^(https?:\\/\\/)?" + // protocol (optional)
+        "((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|" + // domain
+        "((\\d{1,3}\\.){3}\\d{1,3}))" + // or IP address
+        "(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*" + // port and path (optional)
+        "(\\?[;&a-z\\d%_.~+=-]*)?" + // query string
+        "(\\#[-a-z\\d_]*)?$",
+      "i"
+    ); // anchor (optional)
+    const isValid = pattern.test(htmlElement.value);
     return { isValid, message, htmlElement };
   },
-  isNotNullOrUndefined: (htmlElement: HTMLInputElement, fieldName: string | 
null = null): ValidatorAssertion => {
-    let message = `Field '${fieldName || htmlElement.id}' should not be null 
or undefined.`;
-    let isValid = htmlElement.value !== null && htmlElement.value !== 
undefined;
-    return { isValid, message, htmlElement }
+  isNotNullOrUndefined: (
+    htmlElement: HTMLInputElement,
+    fieldName: string | null = null
+  ): ValidatorAssertion => {
+    const message = `Field '${
+      fieldName || htmlElement.id
+    }' should not be null or undefined.`;
+    const isValid =
+      htmlElement.value !== null && htmlElement.value !== undefined;
+    return { isValid, message, htmlElement };
   },
-  isNot: (htmlElement: HTMLInputElement, value: any, fieldName: string | null 
= null): ValidatorAssertion => {
-    let message = `Field '${fieldName || htmlElement.id}' should not be 
${value}.`;
-    let isValid = htmlElement.value !== value;
-    return { isValid, message, htmlElement }
-  }
-
-}
-
-export function validateUsername(input: HTMLInputElement) {
-  try {
-    let fieldName = "Username";
-    let assertions = [];
-    let isNotEmpty = Validators.minChars(input, 1, fieldName);
-    // let shouldBeMax12 = Validators.maxChars(input, 12, fieldName);
-    assertions.push(isNotEmpty);
-    // assertions.push(shouldBeMax12);
-    createErrorMessages(assertions);
-    return assertions.filter(a => !a.isValid).length === 0;
-  } catch (error: any) {
-    throw error;
-  }
-
-}
-
-export function validatePassword(input: HTMLInputElement) {
-  try {
-    let fieldName = "Password";
-    let assertions = [];
-    let isNotEmpty = Validators.minChars(input, 1, fieldName);
-    // let shouldBeMax30 = Validators.maxChars(input, 30, fieldName);
-    assertions.push(isNotEmpty);
-    // assertions.push(shouldBeMax30);
-    createErrorMessages(assertions);
-    return assertions.filter(a => !a.isValid).length === 0;
-  } catch (error: any) {
-    throw error;
-  }
-}
+  isNot: (
+    htmlElement: HTMLInputElement,
+    value: any,
+    fieldName: string | null = null
+  ): ValidatorAssertion => {
+    const message = `Field '${
+      fieldName || htmlElement.id
+    }' should not be ${value}.`;
+    const isValid = htmlElement.value !== value;
+    return { isValid, message, htmlElement };
+  },
+};
 
-export function validateApiHost(input: HTMLInputElement) {
-  try {
-    let fieldName = "Api Host";
-    let assertions = [];
-    let isNotEmpty = Validators.minChars(input, 1, fieldName);
-    /*if(shouldBeUrl.isValid && !/^https?:\/\//i.test(input.value)){
-        input.value = "https://"; + input.value;
-    }*/
-    assertions.push(isNotEmpty);
-    createErrorMessages(assertions);
-    return assertions.filter(a => !a.isValid).length === 0;
-  } catch (error: any) {
-    throw error;
-  }
+export function validateNotEmptyField(
+  fieldName: string,
+  input: HTMLInputElement
+) {
+  const assertions = [];
+  assertions.push(Validators.minChars(input, 1, fieldName));
+  createErrorMessages(assertions);
+  return assertions.filter((a) => !a.isValid).length === 0;
 }
 
-
 export function createErrorMessages(assertions: ValidatorAssertion[]) {
   try {
     assertions.forEach((assertion: ValidatorAssertion, i: number) => {
@@ -92,25 +85,30 @@ export function createErrorMessages(assertions: 
ValidatorAssertion[]) {
       htmlElement.classList.remove("input-error");
       htmlElement.classList.add("input-success");
 
-      let oldErrorMessageElements = 
Array.from(document.getElementsByClassName("error-message"));
+      let oldErrorMessageElements = Array.from(
+        document.getElementsByClassName("error-message")
+      );
       oldErrorMessageElements.forEach((errorMessageElement) => {
-        if (errorMessageElement.id === `${htmlElement.id}-error-${i + 1}`) 
errorMessageElement.remove();
-      })
+        if (errorMessageElement.id === `${htmlElement.id}-error-${i + 1}`)
+          errorMessageElement.remove();
+      });
     });
 
-    assertions.filter(a => !a.isValid).forEach((assertion: ValidatorAssertion, 
i: number) => {
-      let { htmlElement, message } = assertion;
-      htmlElement.classList.add("input-error");
-      htmlElement.classList.remove("input-success");
+    assertions
+      .filter((a) => !a.isValid)
+      .forEach((assertion: ValidatorAssertion, i: number) => {
+        let { htmlElement, message } = assertion;
+        htmlElement.classList.add("input-error");
+        htmlElement.classList.remove("input-success");
 
-      let errorMessageElement = document.createElement("small");
-      errorMessageElement.id = `${htmlElement.id}-error-${i + 1}`;
-      errorMessageElement.classList.add("error-message");
+        let errorMessageElement = document.createElement("small");
+        errorMessageElement.id = `${htmlElement.id}-error-${i + 1}`;
+        errorMessageElement.classList.add("error-message");
 
-      errorMessageElement.textContent = message;
-      htmlElement.parentNode?.insertBefore(errorMessageElement, htmlElement);
-    })
+        errorMessageElement.textContent = message;
+        htmlElement.parentNode?.insertBefore(errorMessageElement, htmlElement);
+      });
   } catch (error: any) {
     throw error;
   }
-}
\ No newline at end of file
+}

Reply via email to