<commit_before>import { Base, SurveyError, ITextProcessor } from "./base";
import { ItemValue } from "./itemvalue";
import { JsonObject, JsonObjectProperty } from "./jsonobject";
import { surveyLocalization } from "./surveyStrings";
import { CustomError } from "./error";

class XmlParser {
  private parser = new DOMParser();
  public assignValue(target: any, name: string, value: any) {
    if (Array.isArray(target[name])) {
      target[name].push(value);
    } else if (target[name] !== undefined) {
      target[name] = [target[name]].concat(value);
    } else if (
      typeof value === "object" &&
      Object.keys(value).length === 1 &&
      Object.keys(value)[0] === name
    ) {
      target[name] = value[name];
    } else {
      target[name] = value;
    }
  }
  public xml2Json(xmlNode: any, result: any) {
    if (xmlNode.children && xmlNode.children.length > 0) {
      for (let i = 0; i < xmlNode.children.length; i++) {
        let childNode = xmlNode.children[i];
        let childObject = {};
        this.xml2Json(childNode, childObject);
        this.assignValue(result, childNode.nodeName, childObject);
      }
    } else {
      this.assignValue(result, xmlNode.nodeName, xmlNode.textContent);
    }
  }
  public parseXmlString(xmlString: string) {
    let xmlRoot = this.parser.parseFromString(xmlString, "text/xml");
    let json = {};
    this.xml2Json(xmlRoot, json);
    return json;
  }
}

/**
 * A definition for filling choices for checkbox, dropdown and radiogroup questions from resfull services.
 * The run method call a restfull service and results can be get on getResultCallback.
 */
export class ChoicesRestfull extends Base {
  private static itemsResult:{ [index: string]: any } = {};
  public static onBeforeSendRequest: (
    sender: ChoicesRestfull,
    options: { request: XMLHttpRequest }
  ) => void;
  private static getCachedItemsResult(obj: ChoicesRestfull): boolean {
    var hash = obj.objHash;
    var res = ChoicesRestfull.itemsResult[hash];
    if (!res) return false;
    if (obj.getResultCallback) {
      obj.getResultCallback(res);
    }
    return true;
  }
  private lastObjHash: string = "";
  private isRunningValue: boolean = false;
  protected processedUrl: string = "";
  protected processedPath: string = "";
  public getResultCallback: (items: Array<ItemValue>) => void;
  public updateResultCallback: (
    items: Array<ItemValue>,
    serverResult: any
  ) => Array<ItemValue>;
  public error: SurveyError = null;
  public owner: Base;
  constructor() {
    super();
  }
  public run(textProcessor: ITextProcessor = null) {
    if (!this.url || !this.getResultCallback) return;
    this.processedText(textProcessor);
    if (!this.processedUrl) {
      this.doEmptyResultCallback({});
      return;
    }
    if (this.lastObjHash == this.objHash) return;
    this.lastObjHash = this.objHash;
    if (this.useChangedItemsResults()) return;
    this.error = null;
    this.sendRequest();
  }
  public get isRunning() {
    return this.isRunningValue;
  }
  public get isWaitingForParameters() {
    return this.url && !this.processedUrl;
  }
  protected useChangedItemsResults(): boolean {
    return ChoicesRestfull.getCachedItemsResult(this);
  }
  private doEmptyResultCallback(serverResult: any) {
    var items: Array<any> = [];
    if (this.updateResultCallback) {
      items = this.updateResultCallback(items, serverResult);
    }
    this.getResultCallback(items);
  }
  private processedText(textProcessor: ITextProcessor) {
    if (textProcessor) {
      var pUrl = textProcessor.processTextEx(this.url, false);
      var pPath = textProcessor.processTextEx(this.path, false);
      if (!pUrl.hasAllValuesOnLastRun || !pPath.hasAllValuesOnLastRun) {
        this.processedUrl = "";
        this.processedPath = "";
      } else {
        this.processedUrl = pUrl.text;
        this.processedPath = pPath.text;
      }
    } else {
      this.processedUrl = this.url;
      this.processedPath = this.path;
    }
  }
  protected parseResponse(response:any) {
    let parsedResponse;
    if (
      !!response &&
      typeof response.indexOf === "function" &&
      response.indexOf("<") === 0
    ) {
      var parser = new XmlParser();
      parsedResponse = parser.parseXmlString(response);
    } else {
      try {
        parsedResponse = JSON.parse(response);
      } catch {
        parsedResponse = (response || "")
          .split("\n")
          .map((s:any) => s.trim(" "))
          .filter((s:any) => !!s);
      }
    }
    return parsedResponse;
  }
  protected sendRequest() {
    this.isRunningValue = true;
    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.processedUrl);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    var self = this;
    xhr.onload = function() {
      self.isRunningValue = false;
      if (xhr.status === 200) {
        self.onLoad(self.parseResponse(xhr.response));
      } else {
        self.onError(xhr.statusText, xhr.responseText);
      }
    };
    var options = { request: xhr };
    if (!!ChoicesRestfull.onBeforeSendRequest) {
      ChoicesRestfull.onBeforeSendRequest(this, options);
    }
    options.request.send();
  }
  public getType(): string {
    return "choicesByUrl";
  }
  public get isEmpty(): boolean {
    return !this.url && !this.path && !this.valueName && !this.titleName;
  }
  public getCustomPropertiesNames(): Array<string> {
    var properties = this.getCustomProperties();
    var res = new Array<string>();
    for (var i = 0; i < properties.length; i++) {
      res.push(this.getCustomPropertyName(properties[i].name));
    }
    return res;
  }
  private getCustomPropertyName(propertyName: string): string {
    return propertyName + "Name";
  }
  private getCustomProperties(): Array<JsonObjectProperty> {
    var properties = JsonObject.metaData.getProperties(this.itemValueType);
    var res = [];
    for (var i = 0; i < properties.length; i++) {
      if (
        properties[i].name === "value" ||
        properties[i].name === "text" ||
        properties[i].name === "visibleIf"
      )
        continue;<commit_msg>Removed extra property from choices restfull<commit_after>import { Base, SurveyError, ITextProcessor } from "./base";
import { ItemValue } from "./itemvalue";
import { JsonObject, JsonObjectProperty } from "./jsonobject";
import { surveyLocalization } from "./surveyStrings";
import { CustomError } from "./error";

class XmlParser {
  private parser = new DOMParser();
  public assignValue(target: any, name: string, value: any) {
    if (Array.isArray(target[name])) {
      target[name].push(value);
    } else if (target[name] !== undefined) {
      target[name] = [target[name]].concat(value);
    } else if (
      typeof value === "object" &&
      Object.keys(value).length === 1 &&
      Object.keys(value)[0] === name
    ) {
      target[name] = value[name];
    } else {
      target[name] = value;
    }
  }
  public xml2Json(xmlNode: any, result: any) {
    if (xmlNode.children && xmlNode.children.length > 0) {
      for (let i = 0; i < xmlNode.children.length; i++) {
        let childNode = xmlNode.children[i];
        let childObject = {};
        this.xml2Json(childNode, childObject);
        this.assignValue(result, childNode.nodeName, childObject);
      }
    } else {
      this.assignValue(result, xmlNode.nodeName, xmlNode.textContent);
    }
  }
  public parseXmlString(xmlString: string) {
    let xmlRoot = this.parser.parseFromString(xmlString, "text/xml");
    let json = {};
    this.xml2Json(xmlRoot, json);
    return json;
  }
}

/**
 * A definition for filling choices for checkbox, dropdown and radiogroup questions from resfull services.
 * The run method call a restfull service and results can be get on getResultCallback.
 */
export class ChoicesRestfull extends Base {
  private static itemsResult:{ [index: string]: any } = {};
  public static onBeforeSendRequest: (
    sender: ChoicesRestfull,
    options: { request: XMLHttpRequest }
  ) => void;
  private static getCachedItemsResult(obj: ChoicesRestfull): boolean {
    var hash = obj.objHash;
    var res = ChoicesRestfull.itemsResult[hash];
    if (!res) return false;
    if (obj.getResultCallback) {
      obj.getResultCallback(res);
    }
    return true;
  }
  private lastObjHash: string = "";
  private isRunningValue: boolean = false;
  protected processedUrl: string = "";
  protected processedPath: string = "";
  public getResultCallback: (items: Array<ItemValue>) => void;
  public updateResultCallback: (
    items: Array<ItemValue>,
    serverResult: any
  ) => Array<ItemValue>;
  public error: SurveyError = null;
  public owner: Base;
  constructor() {
    super();
  }
  public run(textProcessor: ITextProcessor = null) {
    if (!this.url || !this.getResultCallback) return;
    this.processedText(textProcessor);
    if (!this.processedUrl) {
      this.doEmptyResultCallback({});
      return;
    }
    if (this.lastObjHash == this.objHash) return;
    this.lastObjHash = this.objHash;
    if (this.useChangedItemsResults()) return;
    this.error = null;
    this.sendRequest();
  }
  public get isRunning() {
    return this.isRunningValue;
  }
  public get isWaitingForParameters() {
    return this.url && !this.processedUrl;
  }
  protected useChangedItemsResults(): boolean {
    return ChoicesRestfull.getCachedItemsResult(this);
  }
  private doEmptyResultCallback(serverResult: any) {
    var items: Array<any> = [];
    if (this.updateResultCallback) {
      items = this.updateResultCallback(items, serverResult);
    }
    this.getResultCallback(items);
  }
  private processedText(textProcessor: ITextProcessor) {
    if (textProcessor) {
      var pUrl = textProcessor.processTextEx(this.url, false);
      var pPath = textProcessor.processTextEx(this.path, false);
      if (!pUrl.hasAllValuesOnLastRun || !pPath.hasAllValuesOnLastRun) {
        this.processedUrl = "";
        this.processedPath = "";
      } else {
        this.processedUrl = pUrl.text;
        this.processedPath = pPath.text;
      }
    } else {
      this.processedUrl = this.url;
      this.processedPath = this.path;
    }
  }
  protected parseResponse(response:any) {
    let parsedResponse;
    if (
      !!response &&
      typeof response.indexOf === "function" &&
      response.indexOf("<") === 0
    ) {
      var parser = new XmlParser();
      parsedResponse = parser.parseXmlString(response);
    } else {
      try {
        parsedResponse = JSON.parse(response);
      } catch {
        parsedResponse = (response || "")
          .split("\n")
          .map((s:any) => s.trim(" "))
          .filter((s:any) => !!s);
      }
    }
    return parsedResponse;
  }
  protected sendRequest() {
    this.isRunningValue = true;
    var xhr = new XMLHttpRequest();
    xhr.open("GET", this.processedUrl);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    var self = this;
    xhr.onload = function() {
      self.isRunningValue = false;
      if (xhr.status === 200) {
        self.onLoad(self.parseResponse(xhr.response));
      } else {
        self.onError(xhr.statusText, xhr.responseText);
      }
    };
    var options = { request: xhr };
    if (!!ChoicesRestfull.onBeforeSendRequest) {
      ChoicesRestfull.onBeforeSendRequest(this, options);
    }
    options.request.send();
  }
  public getType(): string {
    return "choicesByUrl";
  }
  public get isEmpty(): boolean {
    return !this.url && !this.path && !this.valueName && !this.titleName;
  }
  public getCustomPropertiesNames(): Array<string> {
    var properties = this.getCustomProperties();
    var res = new Array<string>();
    for (var i = 0; i < properties.length; i++) {
      res.push(this.getCustomPropertyName(properties[i].name));
    }
    return res;
  }
  private getCustomPropertyName(propertyName: string): string {
    return propertyName + "Name";
  }
  private getCustomProperties(): Array<JsonObjectProperty> {
    var properties = JsonObject.metaData.getProperties(this.itemValueType);
    var res = [];
    for (var i = 0; i < properties.length; i++) {
      if (
        properties[i].name === "value" ||
        properties[i].name === "text" ||
        properties[i].name === "visibleIf" ||
        properties[i].name === "enableIf"
      )
        continue;
{'fraction_non_alphanumeric': 0.13336574299141143, 'fraction_numerical': 0.002106627775076973, 'mean_word_length': 3.066886326194399, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 30}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4190207', 'n_tokens_mistral': 3735, 'n_tokens_neox': 3689, 'n_words': 836}