lib:strict

none

当前为 2024-04-10 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         lib:strict
// @version      0.2
// @description  none
// @run-at       document-start
// @author       You
// @license      GPLv3
// @match        *://*/*
// @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(options.extrastype).gettype("string").val) {
        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(type).gettype("string").val) {
          type = type.split("|")
        }
        if (options.allowunset) type.push("none")
        if (!a(realvalue).gettype(type).val) {
          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(
                    obj[prop]
                  ).gettype()}" 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(obj[prop]).gettype(options.extrastype).val) {
          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 entireobject
  function newtestformat(
    obj,
    format,
    tempoptions = {
      allowextras: false,
      extrasformat: {},
      // allowconversions: false,
    }
  ) {
    entireobject ??= 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", {
              extrakey: objkey,
            })
          )
    }
    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, entireobject)
      if (!a(obj).gettype(["object", "array"]).val)
        throw new Error(
          error(`obj is not an object`, {
            objectisinstead: obj,
            tryingtoreadproperty: formatkey,
          })
        )
      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`, {
              formatkey,
              obj,
              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(currentcomparevalue).gettype(currentcheck).val ||
                currentcheck == "any" ||
                currentcheck?.includes?.("any")
              )
                break
              else
                throw new Error(
                  error("type missmatch", {
                    property: formatkey,
                    obj,
                    currentvalue: currentcomparevalue,
                    typeofcurrentvalue: a(currentcomparevalue).gettype().val,
                    typeshouldbe: currentcheck,
                  })
                )
            case "value":
              if (currentcheck.includes(currentcomparevalue)) break
              else
                throw new Error(
                  error("value missmatch", {
                    formatkey,
                    currentcomparevalue,
                    typeofcurrentcomparevalue:
                      a(currentcomparevalue).gettype().val,
                    currentcheck,
                  })
                )
            default:
              throw new Error(
                "invalid key in format",
                error({
                  typekey,
                  formatval,
                })
              )
          }
        }
      }
    }
    for (var key of extrakeys) {
      if (!options.extrasformat)
        throw new Error(
          `options has allowextras options must also have extrasformat`
        )
      // log(options.extrasformat, options)
      checkformat(key, setformat(options.extrasformat), 1)
    }
    entireobject = 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,
  })
})()