// src/compiler/buffer.ts
var CompilerBuffer = class _CompilerBuffer {
  #content = "";
  /**
   * The character used to create a new line
   */
  newLine = "\n";
  /**
   * Write statement ot the output
   */
  writeStatement(statement) {
    this.#content = `${this.#content}${this.newLine}${statement}`;
  }
  /**
   * Creates a child buffer
   */
  child() {
    return new _CompilerBuffer();
  }
  /**
   * Returns the buffer contents as string
   */
  toString() {
    return this.#content;
  }
  /**
   * Flush in-memory string
   */
  flush() {
    this.#content = "";
  }
};

// src/scripts/field/variables.ts
function defineFieldVariables({
  parseFnRefId,
  variableName,
  wildCardPath,
  isArrayMember,
  valueExpression,
  parentExpression,
  fieldNameExpression,
  parentValueExpression
}) {
  const inValueExpression = parseFnRefId ? `refs['${parseFnRefId}'](${valueExpression}, {
      data: root,
      meta: meta,
      parent: ${parentValueExpression}
    })` : valueExpression;
  let fieldPathOutputExpression = "";
  if (parentExpression === "root" || parentExpression === "root_item") {
    fieldPathOutputExpression = fieldNameExpression;
  } else if (fieldNameExpression !== "''") {
    fieldPathOutputExpression = `${parentExpression}.getFieldPath() + '.' + ${fieldNameExpression}`;
  }
  return `const ${variableName} = defineValue(${inValueExpression}, {
  data: root,
  meta: meta,
  name: ${fieldNameExpression},
  wildCardPath: '${wildCardPath}',
  getFieldPath() {
    return ${fieldPathOutputExpression};
  },
  mutate: defineValue,
  report: report,
  isValid: true,
  parent: ${parentValueExpression},
  isArrayMember: ${isArrayMember},
});`;
}

// src/compiler/nodes/base.ts
var BaseNode = class {
  #node;
  #parentField;
  field;
  constructor(node, compiler, parent, parentField) {
    this.#parentField = parentField;
    this.#node = node;
    if (this.#parentField) {
      this.field = this.#parentField;
    } else {
      compiler.variablesCounter++;
      this.field = compiler.createFieldFor(node, parent);
    }
  }
  defineField(buffer) {
    if (!this.#parentField) {
      buffer.writeStatement(
        defineFieldVariables({
          fieldNameExpression: this.field.fieldNameExpression,
          isArrayMember: this.field.isArrayMember,
          parentExpression: this.field.parentExpression,
          parentValueExpression: this.field.parentValueExpression,
          valueExpression: this.field.valueExpression,
          variableName: this.field.variableName,
          wildCardPath: this.field.wildCardPath,
          parseFnRefId: "parseFnId" in this.#node ? this.#node.parseFnId : void 0
        })
      );
    }
  }
};

// src/scripts/array/guard.ts
function defineArrayGuard({ variableName, guardedCodeSnippet }) {
  return `if (${variableName}_is_array) {
${guardedCodeSnippet}
}`;
}

// src/scripts/field/is_valid_guard.ts
function defineIsValidGuard({ variableName, bail, guardedCodeSnippet }) {
  if (!bail) {
    return guardedCodeSnippet;
  }
  return `if (${variableName}.isValid) {
${guardedCodeSnippet}
}`;
}

// src/scripts/field/null_output.ts
function defineFieldNullOutput({
  allowNull,
  conditional,
  variableName,
  outputExpression,
  transformFnRefId
}) {
  if (!allowNull) {
    return "";
  }
  return `${conditional || "if"}(${variableName}.value === null) {
  ${outputExpression} = ${transformFnRefId ? `refs['${transformFnRefId}'](null, ${variableName});` : "null;"}
}`;
}

// src/scripts/field/validations.ts
function wrapInConditional(conditions, wrappingCode) {
  const [first, second] = conditions;
  if (first && second) {
    return `if (${first} && ${second}) {
  ${wrappingCode}
}`;
  }
  if (first) {
    return `if (${first}) {
  ${wrappingCode}
}`;
  }
  if (second) {
    return `if (${second}) {
  ${wrappingCode}
}`;
  }
  return wrappingCode;
}
function emitValidationSnippet({ isAsync, implicit, ruleFnId }, variableName, bail, dropMissingCheck, existenceCheckExpression) {
  const rule = `refs['${ruleFnId}']`;
  const callable = `${rule}.validator(${variableName}.value, ${rule}.options, ${variableName});`;
  existenceCheckExpression = existenceCheckExpression || `${variableName}.isDefined`;
  const bailCondition = bail ? `${variableName}.isValid` : "";
  const implicitCondition = implicit || dropMissingCheck ? "" : existenceCheckExpression;
  return wrapInConditional(
    [bailCondition, implicitCondition],
    isAsync ? `await ${callable}` : `${callable}`
  );
}
function defineFieldValidations({
  bail,
  validations,
  variableName,
  dropMissingCheck,
  existenceCheckExpression
}) {
  return `${validations.map(
    (one) => emitValidationSnippet(one, variableName, bail, dropMissingCheck, existenceCheckExpression)
  ).join("\n")}`;
}

// src/scripts/array/initial_output.ts
function defineArrayInitialOutput({
  variableName,
  outputExpression,
  outputValueExpression
}) {
  return `const ${variableName}_out = ${outputValueExpression};
${outputExpression} = ${variableName}_out;`;
}

// src/scripts/field/existence_validations.ts
function defineFieldExistenceValidations({
  allowNull,
  isOptional,
  variableName
}) {
  if (isOptional === false) {
    if (allowNull === false) {
      return `ensureExists(${variableName});`;
    } else {
      return `ensureIsDefined(${variableName});`;
    }
  }
  return "";
}

// src/scripts/array/variables.ts
function defineArrayVariables({ variableName }) {
  return `const ${variableName}_is_array = ensureIsArray(${variableName});`;
}

// src/compiler/nodes/tuple.ts
var TupleNodeCompiler = class extends BaseNode {
  #node;
  #buffer;
  #compiler;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
    this.#compiler = compiler;
  }
  /**
   * Compiles the tuple children to a JS fragment
   */
  #compileTupleChildren() {
    const buffer = this.#buffer.child();
    const parent = {
      type: "tuple",
      fieldPathExpression: this.field.fieldPathExpression,
      outputExpression: this.field.outputExpression,
      variableName: this.field.variableName,
      wildCardPath: this.field.wildCardPath
    };
    this.#node.properties.forEach((child) => {
      this.#compiler.compileNode(child, buffer, parent);
    });
    return buffer.toString();
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(
      defineFieldExistenceValidations({
        allowNull: this.#node.allowNull,
        isOptional: this.#node.isOptional,
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineArrayVariables({
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineFieldValidations({
        variableName: this.field.variableName,
        validations: this.#node.validations,
        bail: this.#node.bail,
        dropMissingCheck: false,
        existenceCheckExpression: `${this.field.variableName}_is_array`
      })
    );
    const isArrayValidBlock = defineArrayGuard({
      variableName: this.field.variableName,
      guardedCodeSnippet: `${this.#buffer.newLine}${defineIsValidGuard({
        variableName: this.field.variableName,
        bail: this.#node.bail,
        guardedCodeSnippet: `${defineArrayInitialOutput({
          variableName: this.field.variableName,
          outputExpression: this.field.outputExpression,
          outputValueExpression: this.#node.allowUnknownProperties ? `copyProperties(${this.field.variableName}.value)` : `[]`
        })}${this.#buffer.newLine}${this.#compileTupleChildren()}`
      })}`
    });
    this.#buffer.writeStatement(
      `${isArrayValidBlock}${this.#buffer.newLine}${defineFieldNullOutput({
        allowNull: this.#node.allowNull,
        outputExpression: this.field.outputExpression,
        variableName: this.field.variableName,
        conditional: "else if"
      })}`
    );
  }
};

// src/scripts/array/loop.ts
function defineArrayLoop({
  variableName,
  loopCodeSnippet,
  startingIndex
}) {
  startingIndex = startingIndex || 0;
  return `const ${variableName}_items_size = ${variableName}.value.length;
for (let ${variableName}_i = ${startingIndex}; ${variableName}_i < ${variableName}_items_size; ${variableName}_i++) {
${loopCodeSnippet}
}`;
}

// src/compiler/nodes/array.ts
var ArrayNodeCompiler = class extends BaseNode {
  #node;
  #buffer;
  #compiler;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
    this.#compiler = compiler;
  }
  /**
   * Compiles the array elements to a JS fragment
   */
  #compileArrayElements() {
    const arrayElementsBuffer = this.#buffer.child();
    this.#compiler.compileNode(this.#node.each, arrayElementsBuffer, {
      type: "array",
      fieldPathExpression: this.field.fieldPathExpression,
      outputExpression: this.field.outputExpression,
      variableName: this.field.variableName,
      wildCardPath: this.field.wildCardPath
    });
    const buffer = this.#buffer.child();
    buffer.writeStatement(
      defineArrayLoop({
        variableName: this.field.variableName,
        startingIndex: 0,
        loopCodeSnippet: arrayElementsBuffer.toString()
      })
    );
    arrayElementsBuffer.flush();
    return buffer.toString();
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(
      defineFieldExistenceValidations({
        allowNull: this.#node.allowNull,
        isOptional: this.#node.isOptional,
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineArrayVariables({
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineFieldValidations({
        variableName: this.field.variableName,
        validations: this.#node.validations,
        bail: this.#node.bail,
        dropMissingCheck: false,
        existenceCheckExpression: `${this.field.variableName}_is_array`
      })
    );
    const isArrayValidBlock = defineArrayGuard({
      variableName: this.field.variableName,
      guardedCodeSnippet: `${this.#buffer.newLine}${defineIsValidGuard({
        variableName: this.field.variableName,
        bail: this.#node.bail,
        guardedCodeSnippet: `${defineArrayInitialOutput({
          variableName: this.field.variableName,
          outputExpression: this.field.outputExpression,
          outputValueExpression: `[]`
        })}${this.#buffer.newLine}${this.#compileArrayElements()}`
      })}`
    });
    this.#buffer.writeStatement(
      `${isArrayValidBlock}${this.#buffer.newLine}${defineFieldNullOutput({
        allowNull: this.#node.allowNull,
        outputExpression: this.field.outputExpression,
        variableName: this.field.variableName,
        conditional: "else if"
      })}`
    );
  }
};

// src/scripts/union/parse.ts
function callParseFunction({ parseFnRefId, variableName }) {
  if (parseFnRefId) {
    return `${variableName}.value = refs['${parseFnRefId}'](${variableName}.value);`;
  }
  return "";
}

// src/scripts/define_else_conditon.ts
function defineElseCondition({ variableName, conditionalFnRefId }) {
  return `else {
refs['${conditionalFnRefId}'](${variableName}.value, ${variableName});
}`;
}

// src/scripts/define_conditional_guard.ts
function defineConditionalGuard({
  conditional,
  variableName,
  conditionalFnRefId,
  guardedCodeSnippet
}) {
  return `${conditional}(refs['${conditionalFnRefId}'](${variableName}.value, ${variableName})) {
${guardedCodeSnippet}
}`;
}

// src/compiler/nodes/union.ts
var UnionNodeCompiler = class extends BaseNode {
  #compiler;
  #node;
  #buffer;
  #parent;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
    this.#parent = parent;
    this.#compiler = compiler;
  }
  /**
   * Compiles union children by wrapping each conditon inside a conditional
   * guard block
   */
  #compileUnionChildren() {
    const childrenBuffer = this.#buffer.child();
    this.#node.conditions.forEach((child, index) => {
      const conditionalBuffer = this.#buffer.child();
      if ("parseFnId" in child.schema) {
        conditionalBuffer.writeStatement(
          callParseFunction({
            parseFnRefId: child.schema.parseFnId,
            variableName: this.field.variableName
          })
        );
      }
      this.#compiler.compileNode(child.schema, conditionalBuffer, this.#parent, this.field);
      childrenBuffer.writeStatement(
        defineConditionalGuard({
          conditional: index === 0 ? "if" : "else if",
          variableName: this.field.variableName,
          conditionalFnRefId: child.conditionalFnRefId,
          guardedCodeSnippet: conditionalBuffer.toString()
        })
      );
      conditionalBuffer.flush();
    });
    if (this.#node.elseConditionalFnRefId && this.#node.conditions.length) {
      childrenBuffer.writeStatement(
        defineElseCondition({
          variableName: this.field.variableName,
          conditionalFnRefId: this.#node.elseConditionalFnRefId
        })
      );
    }
    return childrenBuffer.toString();
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(this.#compileUnionChildren());
  }
};

// src/scripts/record/loop.ts
function defineRecordLoop({ variableName, loopCodeSnippet }) {
  return `const ${variableName}_keys = Object.keys(${variableName}.value);
const ${variableName}_keys_size = ${variableName}_keys.length;
for (let ${variableName}_key_i = 0; ${variableName}_key_i < ${variableName}_keys_size; ${variableName}_key_i++) {
const ${variableName}_i = ${variableName}_keys[${variableName}_key_i];
${loopCodeSnippet}
}`;
}

// src/scripts/object/guard.ts
function defineObjectGuard({ variableName, guardedCodeSnippet }) {
  return `if (${variableName}_is_object) {
${guardedCodeSnippet}
}`;
}

// src/scripts/object/initial_output.ts
function defineObjectInitialOutput({
  variableName,
  outputExpression,
  outputValueExpression
}) {
  return `const ${variableName}_out = ${outputValueExpression};
${outputExpression} = ${variableName}_out;`;
}

// src/scripts/object/variables.ts
function defineObjectVariables({ variableName }) {
  return `const ${variableName}_is_object = ensureIsObject(${variableName});`;
}

// src/compiler/nodes/record.ts
var RecordNodeCompiler = class extends BaseNode {
  #node;
  #buffer;
  #compiler;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
    this.#compiler = compiler;
  }
  /**
   * Compiles the record elements to a JS fragment
   */
  #compileRecordElements() {
    const buffer = this.#buffer.child();
    const recordElementsBuffer = this.#buffer.child();
    this.#compiler.compileNode(this.#node.each, recordElementsBuffer, {
      type: "record",
      fieldPathExpression: this.field.fieldPathExpression,
      outputExpression: this.field.outputExpression,
      variableName: this.field.variableName,
      wildCardPath: this.field.wildCardPath
    });
    buffer.writeStatement(
      defineRecordLoop({
        variableName: this.field.variableName,
        loopCodeSnippet: recordElementsBuffer.toString()
      })
    );
    recordElementsBuffer.flush();
    return buffer.toString();
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(
      defineFieldExistenceValidations({
        allowNull: this.#node.allowNull,
        isOptional: this.#node.isOptional,
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineObjectVariables({
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineFieldValidations({
        variableName: this.field.variableName,
        validations: this.#node.validations,
        bail: this.#node.bail,
        dropMissingCheck: false,
        existenceCheckExpression: `${this.field.variableName}_is_object`
      })
    );
    const isObjectValidBlock = defineIsValidGuard({
      variableName: this.field.variableName,
      bail: this.#node.bail,
      guardedCodeSnippet: `${defineObjectInitialOutput({
        variableName: this.field.variableName,
        outputExpression: this.field.outputExpression,
        outputValueExpression: `{}`
      })}${this.#compileRecordElements()}`
    });
    const isValueAnObjectBlock = defineObjectGuard({
      variableName: this.field.variableName,
      guardedCodeSnippet: `${this.#buffer.newLine}${isObjectValidBlock}`
    });
    this.#buffer.writeStatement(
      `${isValueAnObjectBlock}${this.#buffer.newLine}${defineFieldNullOutput({
        allowNull: this.#node.allowNull,
        outputExpression: this.field.outputExpression,
        variableName: this.field.variableName,
        conditional: "else if"
      })}`
    );
  }
};

// src/scripts/object/move_unknown_properties.ts
function arrayToString(arr) {
  return `[${arr.map((str) => `"${str}"`).join(", ")}]`;
}
function defineMoveProperties({
  variableName,
  fieldsToIgnore,
  allowUnknownProperties
}) {
  if (!allowUnknownProperties) {
    return "";
  }
  const serializedFieldsToIgnore = arrayToString(fieldsToIgnore);
  return `moveProperties(${variableName}.value, ${variableName}_out, ${serializedFieldsToIgnore});`;
}

// src/compiler/nodes/object.ts
var ObjectNodeCompiler = class extends BaseNode {
  #node;
  #buffer;
  #compiler;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
    this.#compiler = compiler;
  }
  /**
   * Returns known field names for the object
   */
  #getFieldNames(node) {
    let fieldNames = node.properties.map((child) => child.fieldName);
    const groupsFieldNames = node.groups.flatMap((group) => this.#getGroupFieldNames(group));
    return fieldNames.concat(groupsFieldNames);
  }
  /**
   * Returns field names of a group.
   */
  #getGroupFieldNames(group) {
    return group.conditions.flatMap((condition) => {
      return this.#getFieldNames(condition.schema);
    });
  }
  /**
   * Compiles object children to JS output
   */
  #compileObjectChildren() {
    const buffer = this.#buffer.child();
    const parent = {
      type: "object",
      fieldPathExpression: this.field.fieldPathExpression,
      outputExpression: this.field.outputExpression,
      variableName: this.field.variableName,
      wildCardPath: this.field.wildCardPath
    };
    this.#node.properties.forEach((child) => this.#compiler.compileNode(child, buffer, parent));
    return buffer.toString();
  }
  /**
   * Compiles object groups with conditions to JS output.
   */
  #compileObjectGroups() {
    const buffer = this.#buffer.child();
    const parent = {
      type: "object",
      fieldPathExpression: this.field.fieldPathExpression,
      outputExpression: this.field.outputExpression,
      variableName: this.field.variableName,
      wildCardPath: this.field.wildCardPath
    };
    this.#node.groups.forEach((group) => this.#compileObjectGroup(group, buffer, parent));
    return buffer.toString();
  }
  /**
   * Compiles an object groups recursively
   */
  #compileObjectGroup(group, buffer, parent) {
    group.conditions.forEach((condition, index) => {
      const guardBuffer = buffer.child();
      condition.schema.properties.forEach((child) => {
        this.#compiler.compileNode(child, guardBuffer, parent);
      });
      condition.schema.groups.forEach((child) => {
        this.#compileObjectGroup(child, guardBuffer, parent);
      });
      buffer.writeStatement(
        defineConditionalGuard({
          variableName: this.field.variableName,
          conditional: index === 0 ? "if" : "else if",
          conditionalFnRefId: condition.conditionalFnRefId,
          guardedCodeSnippet: guardBuffer.toString()
        })
      );
    });
    if (group.elseConditionalFnRefId && group.conditions.length) {
      buffer.writeStatement(
        defineElseCondition({
          variableName: this.field.variableName,
          conditionalFnRefId: group.elseConditionalFnRefId
        })
      );
    }
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(
      defineFieldExistenceValidations({
        allowNull: this.#node.allowNull,
        isOptional: this.#node.isOptional,
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineObjectVariables({
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineFieldValidations({
        variableName: this.field.variableName,
        validations: this.#node.validations,
        bail: this.#node.bail,
        dropMissingCheck: false,
        existenceCheckExpression: `${this.field.variableName}_is_object`
      })
    );
    const isObjectValidBlock = defineIsValidGuard({
      variableName: this.field.variableName,
      bail: this.#node.bail,
      guardedCodeSnippet: `${defineObjectInitialOutput({
        variableName: this.field.variableName,
        outputExpression: this.field.outputExpression,
        outputValueExpression: "{}"
      })}${this.#buffer.newLine}${this.#compileObjectChildren()}${this.#buffer.newLine}${this.#compileObjectGroups()}${this.#buffer.newLine}${defineMoveProperties({
        variableName: this.field.variableName,
        allowUnknownProperties: this.#node.allowUnknownProperties,
        fieldsToIgnore: this.#node.allowUnknownProperties ? this.#getFieldNames(this.#node) : []
      })}`
    });
    const isValueAnObject = defineObjectGuard({
      variableName: this.field.variableName,
      guardedCodeSnippet: `${isObjectValidBlock}`
    });
    this.#buffer.writeStatement(
      `${isValueAnObject}${this.#buffer.newLine}${defineFieldNullOutput({
        variableName: this.field.variableName,
        allowNull: this.#node.allowNull,
        outputExpression: this.field.outputExpression,
        conditional: "else if"
      })}`
    );
  }
};

// src/compiler/fields/root_field.ts
function createRootField(parent) {
  return {
    parentExpression: parent.variableName,
    parentValueExpression: parent.variableName,
    fieldNameExpression: `''`,
    fieldPathExpression: `''`,
    wildCardPath: "",
    variableName: `${parent.variableName}_item`,
    valueExpression: "root",
    outputExpression: parent.outputExpression,
    isArrayMember: false
  };
}

// src/scripts/field/value_output.ts
function defineFieldValueOutput({
  variableName,
  outputExpression,
  transformFnRefId
}) {
  const outputValueExpression = transformFnRefId ? `refs['${transformFnRefId}'](${variableName}.value, ${variableName})` : `${variableName}.value`;
  return `if (${variableName}.isDefined && ${variableName}.isValid) {
  ${outputExpression} = ${outputValueExpression};
}`;
}

// src/compiler/nodes/literal.ts
var LiteralNodeCompiler = class extends BaseNode {
  #node;
  #buffer;
  constructor(node, buffer, compiler, parent, parentField) {
    super(node, compiler, parent, parentField);
    this.#node = node;
    this.#buffer = buffer;
  }
  compile() {
    this.defineField(this.#buffer);
    this.#buffer.writeStatement(
      defineFieldExistenceValidations({
        allowNull: this.#node.allowNull,
        isOptional: this.#node.isOptional,
        variableName: this.field.variableName
      })
    );
    this.#buffer.writeStatement(
      defineFieldValidations({
        variableName: this.field.variableName,
        validations: this.#node.validations,
        bail: this.#node.bail,
        dropMissingCheck: false
      })
    );
    this.#buffer.writeStatement(
      `${defineFieldValueOutput({
        variableName: this.field.variableName,
        outputExpression: this.field.outputExpression,
        transformFnRefId: this.#node.transformFnId
      })}${this.#buffer.newLine}${defineFieldNullOutput({
        variableName: this.field.variableName,
        allowNull: this.#node.allowNull,
        outputExpression: this.field.outputExpression,
        transformFnRefId: this.#node.transformFnId,
        conditional: "else if"
      })}`
    );
  }
};

// src/compiler/fields/array_field.ts
function createArrayField(parent) {
  const wildCardPath = parent.wildCardPath !== "" ? `${parent.wildCardPath}.*` : `*`;
  return {
    parentExpression: parent.variableName,
    parentValueExpression: `${parent.variableName}.value`,
    fieldNameExpression: `${parent.variableName}_i`,
    fieldPathExpression: wildCardPath,
    wildCardPath,
    variableName: `${parent.variableName}_item`,
    valueExpression: `${parent.variableName}.value[${parent.variableName}_i]`,
    outputExpression: `${parent.variableName}_out[${parent.variableName}_i]`,
    isArrayMember: true
  };
}

// src/compiler/fields/tuple_field.ts
function createTupleField(node, parent) {
  const wildCardPath = parent.wildCardPath !== "" ? `${parent.wildCardPath}.${node.fieldName}` : node.fieldName;
  return {
    parentExpression: parent.variableName,
    parentValueExpression: `${parent.variableName}.value`,
    fieldNameExpression: `${node.fieldName}`,
    fieldPathExpression: wildCardPath,
    wildCardPath,
    variableName: `${parent.variableName}_item_${node.fieldName}`,
    valueExpression: `${parent.variableName}.value[${node.fieldName}]`,
    outputExpression: `${parent.variableName}_out[${node.propertyName}]`,
    isArrayMember: true
  };
}

// src/scripts/report_errors.ts
function reportErrors() {
  return `if(errorReporter.hasErrors) {
  throw errorReporter.createError();
}`;
}

// src/helpers.ts
var NUMBER_CHAR_RE = /\d/;
var VALID_CHARS = /[A-Za-z0-9]+/;
function isUppercase(char = "") {
  if (NUMBER_CHAR_RE.test(char)) {
    return void 0;
  }
  return char !== char.toLowerCase();
}
function upperFirst(value) {
  return value ? value[0].toUpperCase() + value.slice(1) : "";
}
function lowerFirst(value) {
  return value ? value[0].toLowerCase() + value.slice(1) : "";
}
function splitByCase(value) {
  const parts = [];
  if (!value || typeof value !== "string") {
    return parts;
  }
  let buff = "";
  let previousUpper;
  let previousSplitter;
  for (const char of value) {
    const isSplitter = !VALID_CHARS.test(char);
    if (isSplitter === true) {
      parts.push(buff);
      buff = "";
      previousUpper = void 0;
      continue;
    }
    const isUpper = isUppercase(char);
    if (previousSplitter === false) {
      if (previousUpper === false && isUpper === true) {
        parts.push(buff);
        buff = char;
        previousUpper = isUpper;
        continue;
      }
      if (previousUpper === true && isUpper === false && buff.length > 1) {
        const lastChar = buff.at(-1);
        parts.push(buff.slice(0, Math.max(0, buff.length - 1)));
        buff = lastChar + char;
        previousUpper = isUpper;
        continue;
      }
    }
    buff += char;
    previousUpper = isUpper;
    previousSplitter = isSplitter;
  }
  parts.push(buff);
  return parts;
}
function toVariableName(value) {
  const pascalCase = splitByCase(value).map((p) => upperFirst(p.toLowerCase())).join("");
  return /^[0-9]+/.test(pascalCase) ? `var_${pascalCase}` : lowerFirst(pascalCase);
}

// src/compiler/fields/object_field.ts
function createObjectField(node, variablesCounter, parent) {
  const wildCardPath = parent.wildCardPath !== "" ? `${parent.wildCardPath}.${node.fieldName}` : node.fieldName;
  return {
    parentExpression: parent.variableName,
    parentValueExpression: `${parent.variableName}.value`,
    fieldNameExpression: `'${node.fieldName}'`,
    fieldPathExpression: wildCardPath,
    wildCardPath,
    variableName: `${toVariableName(node.propertyName)}_${variablesCounter}`,
    valueExpression: `${parent.variableName}.value['${node.fieldName}']`,
    outputExpression: `${parent.variableName}_out['${node.propertyName}']`,
    isArrayMember: false
  };
}

// src/compiler/fields/record_field.ts
function createRecordField(parent) {
  const wildCardPath = parent.wildCardPath !== "" ? `${parent.wildCardPath}.*` : `*`;
  return {
    parentExpression: parent.variableName,
    parentValueExpression: `${parent.variableName}.value`,
    fieldNameExpression: `${parent.variableName}_i`,
    fieldPathExpression: wildCardPath,
    wildCardPath,
    variableName: `${parent.variableName}_item`,
    valueExpression: `${parent.variableName}.value[${parent.variableName}_i]`,
    outputExpression: `${parent.variableName}_out[${parent.variableName}_i]`,
    isArrayMember: false
  };
}

// src/scripts/define_inline_functions.ts
function defineInlineFunctions(options) {
  return `function report(message, rule, field, args) {
  field.isValid = false;
  errorReporter.report(messagesProvider.getMessage(message, rule, field, args), rule, field, args);
};
function defineValue(value, field) {
  ${options.convertEmptyStringsToNull ? `if (value === '') { value = null; }` : ""}
  field.value = value;
  field.isDefined = value !== undefined && value !== null;
  return field;
};
function ensureExists(field) {
  if (field.value === undefined || field.value === null) {
    field.report(REQUIRED, 'required', field);
    return false;
  }
  return true;
};
function ensureIsDefined(field) {
  if (field.value === undefined) {
    field.report(REQUIRED, 'required', field);
    return false;
  }
  return true;
};
function ensureIsObject(field) {
  if (!field.isDefined) {
    return false;
  }
  if (typeof field.value == 'object' && !Array.isArray(field.value)) {
    return true;
  }
  field.report(NOT_AN_OBJECT, 'object', field);
  return false;
};
function ensureIsArray(field) {
  if (!field.isDefined) {
    return false;
  }
  if (Array.isArray(field.value)) {
    return true;
  }
  field.report(NOT_AN_ARRAY, 'array', field);
  return false;
};
function copyProperties(val) {
  let k, out, tmp;

  if (Array.isArray(val)) {
    out = Array((k = val.length))
    while (k--) out[k] = (tmp = val[k]) && typeof tmp == 'object' ? copyProperties(tmp) : tmp
    return out
  }

  if (Object.prototype.toString.call(val) === '[object Object]') {
    out = {} // null
    for (k in val) {
      out[k] = (tmp = val[k]) && typeof tmp == 'object' ? copyProperties(tmp) : tmp
    }
    return out
  }
  return val
};
function moveProperties(source, destination, ignoreKeys) {
  for (let key in source) {
    if (!ignoreKeys.includes(key)) {
      const value = source[key]
      destination[key] = copyProperties(value)
    }
  }
};`;
}

// src/scripts/define_error_messages.ts
function defineInlineErrorMessages(messages) {
  return `const REQUIRED = '${messages.required}';
const NOT_AN_OBJECT = '${messages.object}';
const NOT_AN_ARRAY = '${messages.array}';`;
}

// src/compiler/main.ts
var AsyncFunction = Object.getPrototypeOf(async function() {
}).constructor;
var Compiler = class {
  /**
   * Variables counter is used to generate unique variable
   * names with a counter suffix.
   */
  variablesCounter = 0;
  /**
   * An array of nodes to process
   */
  #rootNode;
  /**
   * Options to configure the compiler behavior
   */
  #options;
  /**
   * Buffer for collection the JS output string
   */
  #buffer = new CompilerBuffer();
  constructor(rootNode, options) {
    this.#rootNode = rootNode;
    this.#options = options || { convertEmptyStringsToNull: false };
  }
  /**
   * Initiates the JS output
   */
  #initiateJSOutput() {
    this.#buffer.writeStatement(
      defineInlineErrorMessages({
        required: "value is required",
        object: "value is not a valid object",
        array: "value is not a valid array",
        ...this.#options.messages
      })
    );
    this.#buffer.writeStatement(defineInlineFunctions(this.#options));
    this.#buffer.writeStatement("let out;");
  }
  /**
   * Finished the JS output
   */
  #finishJSOutput() {
    this.#buffer.writeStatement(reportErrors());
    this.#buffer.writeStatement("return out;");
  }
  /**
   * Compiles all the nodes
   */
  #compileNodes() {
    this.compileNode(this.#rootNode.schema, this.#buffer, {
      type: "root",
      variableName: "root",
      outputExpression: "out",
      fieldPathExpression: "out",
      wildCardPath: ""
    });
  }
  /**
   * Returns compiled output as a function
   */
  #toAsyncFunction() {
    return new AsyncFunction(
      "root",
      "meta",
      "refs",
      "messagesProvider",
      "errorReporter",
      this.#buffer.toString()
    );
  }
  /**
   * Converts a node to a field. Optionally accepts a parent node to create
   * a field for a specific parent type.
   */
  createFieldFor(node, parent) {
    switch (parent.type) {
      case "array":
        return createArrayField(parent);
      case "root":
        return createRootField(parent);
      case "object":
        return createObjectField(node, this.variablesCounter, parent);
      case "tuple":
        return createTupleField(node, parent);
      case "record":
        return createRecordField(parent);
    }
  }
  /**
   * Compiles a given compiler node
   */
  compileNode(node, buffer, parent, parentField) {
    switch (node.type) {
      case "literal":
        return new LiteralNodeCompiler(node, buffer, this, parent, parentField).compile();
      case "array":
        return new ArrayNodeCompiler(node, buffer, this, parent, parentField).compile();
      case "record":
        return new RecordNodeCompiler(node, buffer, this, parent, parentField).compile();
      case "object":
        return new ObjectNodeCompiler(node, buffer, this, parent, parentField).compile();
      case "tuple":
        return new TupleNodeCompiler(node, buffer, this, parent, parentField).compile();
      case "union":
        return new UnionNodeCompiler(node, buffer, this, parent, parentField).compile();
    }
  }
  /**
   * Compile schema nodes to an async function
   */
  compile() {
    this.#initiateJSOutput();
    this.#compileNodes();
    this.#finishJSOutput();
    const outputFunction = this.#toAsyncFunction();
    this.variablesCounter = 0;
    this.#buffer.flush();
    return outputFunction;
  }
};

export {
  Compiler
};
