lib:strict

none

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         lib:strict
// @version      7
// @description  none
// @run-at       document-start
// @author       rssaromeo
// @license      GPLv3
// @tag          lib
// @match        *://*/*
// @include      *
// @exclude      /livereload.net\/files\/ffopen\/index.html$/
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII=
// @grant        none
// @namespace https://greasyfork.org/users/1184528
// ==/UserScript==

;(() => {
  const a = loadlib("allfuncs")
  function testformat(
    obj,
    format,
    options = {
      allowextras: false,
      extrastype: undefined,
      allowconversions: false,
      logerror: true,
      allowunset: false,
      throwerror: true,
      insideextras: undefined,
    },
    insideextras
  ) {
    if (options.extrastype) {
      if (a.gettype(options.extrastype, "string")) {
        options.extrastype = options.extrastype.split("|")
      }
    }
    if (options.allowunset) options.extrastype.push("none")
    var isvalid = true
    var unsets = []
    if (insideextras) {
      for (var i = 0; i < Object.keys(obj).length; i++) {
        format.push(insideextras)
      }
    }
    format.find(
      (
        {
          name,
          prop = name,
          type,
          inside,
          insideoptions = {},
          value = [],
          insideextras,
        },
        i
      ) => {
        prop ??= String(i)
        if (insideextras) inside ??= []
        insideoptions = { ...options, ...insideoptions }
        var realvalue = obj[prop]
        if (a.gettype(type, "string")) {
          type = type.split("|")
        }
        if (options.allowunset) type.push("none")
        if (!a.gettype(realvalue, type)) {
          if (options.allowconversions) {
            if (
              type.find((type) => {
                if (settype.test(realvalue, type)) {
                  obj[prop] = settype(realvalue, type)
                  return true
                }
              })
            ) {
              return false
            }
            if (type.includes("any")) return false
          }

          if (!type.includes(obj[prop]))
            if (options.logerror) {
              if (!(prop in obj))
                error(
                  `the object is missing the property "${prop}". the property "${prop}" should have a type of "${type.join(
                    "|"
                  )}"`
                )
              else
                error(
                  `the value "${prop}" is of type "${a.gettype(
                    obj[prop]
                  )}" when it should be a type of "${type.join("|")}"`
                )
              error("missing or invalid peram type", {
                prop,
                obj,
                type,
              })
            }
          if (options.throwerror)
            throw new Error("missing or invalid peram type")
          isvalid = false
          return true
        }
        if (!(prop in obj)) unsets.push(prop)
        if (inside) {
          if (
            !testformat(
              realvalue,
              inside,
              insideoptions,
              insideextras
            )
          ) {
            if (options.logerror) error("invalid inside", { obj })
            if (options.throwerror) throw new Error("invalid inside")
            isvalid = false
            return true
          }
        }
      }
    )
    var objnames = [...Object.keys(obj), ...unsets]
    var formatnames = Object.values(format).map(
      (e, i) => e.name ?? String(i)
    )
    var extras = objnames.filter(
      (prop) => !formatnames.includes(prop)
    )
    if (!options.allowextras) {
      if (extras.length) {
        if (options.logerror) {
          error(
            `the object has the following extra properties: ${JSON.stringify(
              extras
            )}`
          )
          error("extras found when allowextras is false", {
            obj,
            objnames,
            formatnames,
          })
        }
        if (options.throwerror)
          throw new Error("extras found when allowextras is false")

        isvalid = false
      }
    }
    if (extras?.[0]?.name == "__extras") {
      var extras = extras[0]
      extras.shift()
      if (!testformat(obj.inside, obj.__extras, options)) {
        isvalid = false
        return true
      }
    }

    if (options.extrastype) {
      extras.find((prop) => {
        if (!a.gettype(obj[prop], options.extrastype)) {
          if (options.allowconversions) {
            if (
              options.extrastype.find((type) => {
                if (settype.test(obj[prop], type)) {
                  obj[prop] = settype(obj[prop], type)
                  return true
                }
              })
            ) {
              return false
            }
            if (options.extrastype.includes("any")) return false
          }
          isvalid = false
          return true
        }
      })
    }
    return isvalid
  }
  function strictfunction(func, types, options = {}) {
    if (!!options === options) options = { allowconversions: options }
    return function (...args) {
      if (
        !testformat((args = [...args]), types, {
          ...options,
          throwerror: true,
          logerror: true,
        })
      )
        throw new Error("error when calling function")
      return func.call(this, ...args)
    }
  }

  function setformat(obj, options = {}) {
    if (obj[Symbol.for("setformat")]) obj = { ...obj }
    return new Proxy(obj, {
      get(_obj, prop) {
        if (prop == Symbol.for("setformat")) return true
        if (prop == Symbol.for("options")) return options
        return Reflect.get(_obj, prop)
      },
    })
  }
  var entire_object
  function newtestformat(
    obj,
    format,
    tempoptions = {
      allowextras: false,
      extrasformat: {},
      functionname: "no name given",
      // allowconversions: false,
    }
  ) {
    entire_object ??= obj
    var extrakeys = []
    var options = { ...tempoptions, ...format[Symbol.for("options")] }
    for (var objkey of Object.keys(obj)) {
      if (!(objkey in format))
        if (options.allowextras) extrakeys.push(objkey)
        else
          throw new Error(
            error("object has extra key", {
              function_name: options.functionname,
              extra_key: objkey,
              format,
              obj,
              entire_object,
            })
          )
    }
    for (var [formatkey, formatval] of Object.entries(format)) {
      checkformat(formatkey, formatval)
    }
    function checkformat(formatkey, formatval) {
      let currentcomparevalue = obj[formatkey]
      if (formatval[Symbol.for("condfunc")])
        formatval = formatval(obj, entire_object)
      if (!a.gettype(obj, ["object", "array"]))
        throw new Error(
          error(`obj is not an object`, {
            function_name: options.functionname,
            object_is_instead: obj,
            trying_to_read_property: formatkey,
            entire_object,
          })
        )
      if (!(formatkey in obj))
        if (
          (formatval && formatval[Symbol.for("optional")]) ||
          (formatval.type && formatval.type.includes("none")) ||
          (formatval.type && formatval.type.includes("undefined")) ||
          (formatval.value && formatval.value.includes(undefined))
        )
          return
        else {
          throw new Error(
            error(`obj is missing property`, {
              function_name: options.functionname,
              missing_property: formatkey,
              object: obj,
              entire_object,
              format: { ...format[formatkey] },
            })
          )
        }
      if (!formatval[Symbol.for("setformat")]) {
        newtestformat(currentcomparevalue, formatval, tempoptions)
      } else {
        for (var [typekey, currentcheck] of Object.entries(
          formatval
        )) {
          // log({ obj, currentcomparevalue, typekey, currentcheck, formatval })
          switch (typekey) {
            case "type":
              if (
                a.gettype(currentcomparevalue, currentcheck) ||
                currentcheck == "any" ||
                currentcheck?.includes?.("any")
              )
                break
              else
                throw new Error(
                  error("type missmatch", {
                    function_name: options.functionname,
                    property: formatkey,
                    object: obj,
                    entire_object,
                    current_value: currentcomparevalue,
                    type_of_current_value: a.gettype(currentcomparevalue),
                    type_should_be: currentcheck,
                  })
                )
            case "value":
              if (currentcheck.includes(currentcomparevalue)) break
              else
                throw new Error(
                  error("value missmatch", {
                    format_key: formatkey,
                    object: obj,
                    entire_object,
                    function_name: options.functionname,

                    current_compare_value: currentcomparevalue,
                    type_of_current_compare_value: a.gettype(currentcomparevalue),
                    current_check: currentcheck,
                  })
                )
            default:
              throw new Error(
                "invalid key in format",
                error({
                  function_name: options.functionname,
                  object: obj,
                  entire_object,
                  type_key: typekey,
                  format_val: formatval,
                })
              )
          }
        }
      }
    }
    for (var key of extrakeys) {
      if (!options.extrasformat)
        throw new Error(
          `options has allowextras options must also have extrasformat in function [${options.functionname}]`
        )
      // log(options.extrasformat, options)
      checkformat(key, setformat(options.extrasformat), 1)
    }
    entire_object = undefined
    return true
  }
  loadlib("libloader").savelib("strict", {
    strictfunction,
    oldtestformat: testformat,
    setformat,
    optional: function (obj) {
      return new Proxy(obj, {
        get(_obj, prop) {
          if (prop == Symbol.for("optional")) return true
          return Reflect.get(_obj, prop)
        },
      })
    },
    condfunc: function (func) {
      return new Proxy(func, {
        get(_obj, prop) {
          if (prop == Symbol.for("condfunc")) return true
          return Reflect.get(_obj, prop)
        },
      })
    },
    testformat: newtestformat,
  })
})()