lib:strict

none

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==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,
  })
})()