{"id":13483325,"url":"https://github.com/sablejs/sablejs","last_synced_at":"2025-05-15T20:05:02.708Z","repository":{"id":37742412,"uuid":"298495592","full_name":"sablejs/sablejs","owner":"sablejs","description":"🏖️ The safer and faster ECMA5.1 interpreter written by JavaScript","archived":false,"fork":false,"pushed_at":"2022-09-12T08:52:25.000Z","size":4785,"stargazers_count":1115,"open_issues_count":4,"forks_count":55,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-13T20:05:25.249Z","etag":null,"topics":["compiler","ecma5","interpreter","javascript","opcode","sandbox"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sablejs.png","metadata":{"files":{"readme":"README-zh_CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-25T07:07:42.000Z","updated_at":"2025-05-08T21:37:32.000Z","dependencies_parsed_at":"2022-08-08T21:30:55.151Z","dependency_job_id":null,"html_url":"https://github.com/sablejs/sablejs","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sablejs%2Fsablejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sablejs%2Fsablejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sablejs%2Fsablejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sablejs%2Fsablejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sablejs","download_url":"https://codeload.github.com/sablejs/sablejs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414499,"owners_count":22067272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","ecma5","interpreter","javascript","opcode","sandbox"],"created_at":"2024-07-31T17:01:10.116Z","updated_at":"2025-05-15T20:04:55.649Z","avatar_url":"https://github.com/sablejs.png","language":"JavaScript","readme":"![LOGO](./logo.jpg)\n\n![linux ci](https://github.com/sablejs/sablejs/actions/workflows/linux.yml/badge.svg)\n![osx ci](https://github.com/sablejs/sablejs/actions/workflows/osx.yml/badge.svg)\n![windows ci](https://github.com/sablejs/sablejs/actions/workflows/win.yml/badge.svg)\n\u003ca href=\"https://www.npmjs.com/package/sablejs\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/sablejs.svg?sanitize=true\" alt=\"Version\"\u003e\u003c/a\u003e\n\n\u003e 🎉 sablejs 2.0 计划开源所有代码，请[点击此处](https://github.com/sablejs/sablejs/issues/19)了解我们的规划.\n\n[English](./README.md) | 简体中文\n\n使用JavaScript编写的更快更安全的JavaScript解释器，其可以用来：\n\n1. 执行沙盒(类似于Figma的插件沙盒，但是更易于使用)；\n2. 通过将JavaScript编译为opcode进行代码保护；\n\nsablejs已经覆盖了约95%的 [test262 es5-tests cases](https://github.com/tc39/test262/tree/es5-tests)，其可以很安全可靠的用于你的生产之中。\n\n* [快速开始](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#快速开始)\n* [APIs](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#apis)\n* [性能测试](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#性能测试)\n* [限制](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#限制)\n* [使用协议](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#使用协议)\n\n### 快速开始\n\n**sablejs分离出了编译器和解释器**，因此我们移除了规范之中一些需要动态执行的相关API(详情见 [限制](https://github.com/sablejs/sablejs/blob/master/README-zh_CN.md#限制))。简而言之, 你需要先使用sablejs cli编译你的JavaScript代码，然后才能使用解释器进行执行。\n\n#### 示例代码\n\n假设我们编写了 `fib.js` 中的代码:\n\n```javascript\nfunction fib(n) {\n  return n \u003c 2 ? n : fib(n - 1) + fib(n - 2);\n}\n\nvar start = Date.now();\nconsole.log(\"[INFO] fib: \" + fib(30));\nconsole.log(\"[INFO] time consuming: \" + (Date.now() - start) + \"ms\");\n```\n\n#### 编译代码\n\n```shell\n\u003e npm i sablejs -g\n\u003e sablejs -i fib.js -o output # 你将获得一个base64字符串的生成文件\n```\n\nsablejs cli包含了如下的命令:\n\n```shell\nUsage: sablejs [options]\n\nOptions:\n  -v, --vers           输出当前版本号\n  -i, --input \u003cpath\u003e   指定编译的文件路径\n  -o, --output \u003cpath\u003e  指定输出的文件路径\n  -j, --json           直接输出JSON产物，不进行Base64编码\n  -s, --slient         静默模式，不输出日志\n  -h, --help\n```\n\n#### 执行代码\n\n```shell\n\u003e npm install sablejs --save\n```\n\n你也可以直接通过script标签进行运行时的引入：\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/sablejs@1.0.8/runtime.js\"\u003e\u003c/script\u003e\n```\n\n##### 浏览器环境\n\n```javascript\nconst VM = require(\"sablejs/runtime\")();\n\n// import console.log function to vm call\nconst vm = new VM();\nconst vGlobal = vm.getGlobal();\nconst vConsole = vm.createObject();\nconst vLog = vm.createFunction(\"log\", function () {\n  const temp = [];\n  for (let i = 0; i \u003c arguments.length; i++) {\n    temp.push(vm.asString(arguments[i]));\n  }\n\n  console.log(...temp);\n  return vm.createUndefined();\n});\n\nvm.setProperty(vConsole, \"log\", vLog);\nvm.setProperty(vGlobal, \"console\", vConsole);\n\n(async () =\u003e {\n  const resp = await fetch(\"\u003coutput url\u003e\");\n  const data = await resp.text();\n  vm.run(data);\n  vm.destroy();\n})();\n```\n\n##### Node.js环境\n\n```javascript\nconst VM = require(\"sablejs/runtime\")();\nconst fs = require(\"fs\");\n\n// import console.log function to vm call\nconst vm = new VM();\nconst vGlobal = vm.getGlobal();\nconst vConsole = vm.createObject();\nconst vLog = vm.createFunction(\"log\", function () {\n  const temp = [];\n  for (let i = 0; i \u003c arguments.length; i++) {\n    temp.push(vm.asString(arguments[i]));\n  }\n\n  console.log(...temp);\n  return vm.createUndefined();\n});\n\nvm.setProperty(vConsole, \"log\", vLog);\nvm.setProperty(vGlobal, \"console\", vConsole);\n\n// please run: sablejs -i fib.js -o output\nvm.run(fs.readFileSync(\"./output\").toString());\nvm.destroy();\n```\n\n### APIs\n\n- VM.prototype.run(source, isSimpleJSON)\n  - source: String - 通过sablejs编译器编译出的产物\n  - isSimpleJSON: Boolean - 如果设置为true，那么对应的编译产物应该是sablejs -j产生的JSON数据（而不是base64字符串），默认为false\n  - `return:` undefined\n\n初始化VM并执行编译的代码。  \n\n```javascript\nconst VM = require('sablejs/runtime')();\nconst vm = new VM();\n\n// source should be base64 string via sablejs compiling\nvm.run(`\u003ccompile source string\u003e`);\n```\n\n- VM.prototype.getGlobal()\n  - `return:` Value\n\n返回VM的 `global` 对象，其类似于浏览器环境中的 `window` 对象呢及Node.js环境的 `global` 对象。\n\n```javascript\nconst global = vm.getGlobal();\n```\n\n- VM.prototype.createUndefined()\n  - `return` Value\n\n创建 `undefined` 的包装类型。\n\n```javascript\nconst vUndefined = vm.createUndefined();\n```\n\n- VM.prototype.createNull()\n  - `return:` Value\n\n创建 `null` 的包装类型。\n\n```javascript\nconst vNull = vm.createNull();\n```\n\n- VM.prototype.createBoolean(bool)\n  - bool: Boolean\n  - `return` Value\n\n创建 `bool` 的包装类型。\n\n```javascript\nconst vBoolean = vm.createBoolean(true);\n```\n\n- VM.prototype.createNumber(num)\n  - num: Number\n  - `return` Value\n\n创建 `number` 的包装类型。\n\n```javascript\nconst vNumber = vm.createNumber(1024);\n```\n\n- VM.prototype.createString(str)\n  - str: String\n  - `return` Value\n\n创建 `string` 的包装类型。\n\n```javascript\nconst vString = vm.createString('Hello World!');\n```\n\n\n- VM.prototype.createObject()\n  - `return` Value\n\n创建 `object` 的包装类型。\n\n```javascript\nconst vObject = vm.createObject();\n```\n\n- VM.prototype.createArray(length)\n  - length: Number | undefined\n  - `return` Value\n\n创建 `array` 的包装类型。\n\n```javascript\nconst vArray1 = vm.createArray();\n// or\nconst vArray2 = vm.createArray(128);\n```\n\n- VM.prototype.createFunction(name, func)\n  - name: String\n  - func: Function\n  - `return` Value\n\n创建 `function` 的包装类型。其接收函数名 `name` 及具体函数实现 `func` 两个参数。但需要注意的是，其函数入参及 `this` 均为包装类型。\n\n```javascript\nconst vFuncntion = vm.createFunction(\"trim\", function(str) {\n  // this is the undefined or new's instannce boxed type\n  // str maybe the string boxed type, we need to check it\n});\n```\n\n- VM.prototype.createError(message)\n  - message: String | undefined\n  - `return` Value\n\n创建 `error` 的包装类型。\n\n```javascript\nconst vError1 = vm.createError();\n// or\nconst vError2 = vm.createError(\"unknown error\");\n```\n\n- VM.prototype.createRegExp(pattern, flags)\n  - pattern: String\n  - flags: String | undefined\n  - `return` Value\n\n创建 `regexp` 的包装类型。\n\n```javascript\nconst vRegExp = vm.createRegExp(\"\\\\w+\", \"ig\");\n```\n\n- VM.prototype.createDate()\n  - `return` Value\n\n创建 `date` 的包装类型。\n\n```javascript\nconst vDate = vm.createDate();\n```\n\n- VM.prototype.isUndefined(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `undefined`。\n\n```javascript\nconst vUndefined = vm.createUndefined();\nif(vm.isUndefined(vUndefined)) {\n  // ...\n}\n```\n\n- VM.prototype.isNull(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `null`。\n\n```javascript\nconst vNull = vm.createNull();\nif(vm.isNull(vNull)) {\n  // ...\n}\n```\n\n- VM.prototype.isBoolean(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `bool`。\n\n```javascript\nconst vBoolean = vm.createBoolean(true);\nif(vm.isBoolean(vBoolean)) {\n  // ...\n}\n```\n\n- VM.prototype.isNumber(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `number`。\n\n```javascript\nconst vNumber = vm.createNumber(1024);\nif(vm.isNumber(vNumber)) {\n  // ...\n}\n```\n\n- VM.prototype.isString(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `string`。\n\n```javascript\nconst vString = vm.createString(\"Hello World!\");\nif(vm.isString(vString)) {\n  // ...\n}\n```\n\n- VM.prototype.isObject(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `object`。\n\n```javascript\nconst vObject = vm.createObject();\nconst vArray = vm.createArray();\nif(vm.isObject(vObject) \u0026\u0026 vm.isObject(vArray)) {\n  // ...\n}\n```\n\n- VM.prototype.isArray(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `array`。\n\n```javascript\nconst vArray = vm.createArray();\nif(vm.isArray(vArray)) {\n  // ...\n}\n```\n\n- VM.prototype.isFunction(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `function`。\n\n```javascript\nconst vFunction = vm.createFunction(\"log\", function(){});\nif(vm.isFunction(vFunction)){\n  // ...\n}\n```\n\n- VM.prototype.isError(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `error`。\n\n```javascript\nconst vError = vm.createError('unknown error');\nif(vm.isError(vError)){\n  // ...\n}\n```\n\n- VM.prototype.isRegExp(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `regexp`。\n\n```javascript\nconst vRegExp = vm.createRegExp(\"\\\\w+\", \"ig\");\nif(vm.isRegExp(vRegExp)){\n  // ...\n}\n```\n\n- VM.prototype.isDate(value)\n  - value: Value\n  - `return` Boolean\n\n判断包装类型是否为 `date`。\n\n```javascript\nconst vDate = vm.createDate();\nif(vm.isDate(vDate)){\n  // ...\n}\n```\n\n- VM.prototype.asUndefined(value)\n- value: Value\n- `return` undefined\n\n将 `undefined` 包装类型转换为普通的 `undefined` 值。\n\n```javascript\nconst vUndefined = vm.createUndefined();\nvm.asUndefined(vUndefined) === undefined;\n```\n\n- VM.prototype.asNull(value)\n- value: Value\n- `return` null\n\n将 `null` 包装类型转换为普通的 `null` 值。\n\n```javascript\nconst vNull = vm.createNull();\nvm.asNull(vNull) === null;\n```\n\n- VM.prototype.asBoolean(value)\n  - value: Value\n  - `return` Boolean\n\n将 `bool` 包装类型转换为普通的 `bool` 值。\n\n```javascript\nconst vBoolean = vm.createBoolean(true);\nconst boolean = vm.asBoolean(vBoolean);\nif(boolean === true) {\n  // ...\n}\n```\n\n- VM.prototype.asNumber(value)\n  - value: Value\n  - `return` Number\n\n将 `number` 包装类型转换为普通的 `number` 值。\n\n```javascript\nconst vNumber = vm.createNumber(1024);\nconst number = vm.asNumber(vNumber);\nif(number === 1024) {\n  // ...\n}\n```\n\n- VM.prototype.asString(value)\n  - value: Value\n  - `return` String\n\n将 `string` 包装类型转换为普通的 `string` 值。\n\n```javascript\nconst vString = vm.createString('Hello World!');\nconst string = vm.asString(vString);\nif(string === 'Hello World!') {\n  // ...\n}\n```\n\n- VM.prototype.asObject(value)\n  - value: Value\n  - `return` Object\n\n将 `object` 包装类型转换为内部的 `object` 类型。\n\n```javascript\nconst vObject = vm.createFunction(\"asObject\", function(){});\nconst object = vm.asObject(vObject);\nif(object.type === 12) {\n  // ...\n}\n```\n\n- VM.prototype.instanceof(lval, rval)\n  - lval: Value\n  - rval: Value\n  - `return` Boolean\n\n等价于 `instanceof` 关键字用法。\n\n```javascript\nconst global = vm.getGlobal();\nconst vDateFunc = vm.getProperty(global, \"Date\");\nconst vDate = vm.createDate();\nif(vm.instanceof(vDate, vDateFunc)) {\n  // ...\n}\n```\n\n- VM.prototype.typeof(value)\n  - value: Value\n  - `return` String\n\n等价于 `typeof` 关键字用法。\n\n```javascript\nconst vString = vm.createString('Hello World!');\nif(vm.typeof(vString) === \"string\") {\n  // ...\n}\n```\n\n- VM.prototype.getProperty(value, name)\n  - value: Value\n  - name: String\n  - `return` Value\n\n获取一个对象的对应属性，其返回值是一个包装类型。\n\n```javascript\nconst global = vm.getGlobal();\nconst vPrint = vm.getProperty(global, \"print\");\nif(vm.isFunction(vPrint)) {\n  // ...\n}\n```\n\n- VM.prototype.setProperty(value, name, property)\n  - value: Value\n  - name: String\n  - property: Value\n  - `return` Value\n\n设置一个对象的对应属性，其返回值是一个包装那类型。\n\n```javascript\nconst global = vm.getGlobal();\nconst console = vm.createObject();\nconst log = vm.createFunction(\"log\", function() {\n  // console.log impl\n});\n\nvm.setProperty(console, \"log\", log);\nvm.setProperty(global, \"console\", console);\n```\n\n- VM.prototype.deleteProperty(value, name)\n  - value: Value\n  - name: String\n  - `return` Boolean\n\n删除对象的对应属性。\n\n```javascript\nconst global = vm.getGlobal();\nvm.deleteProperty(global, \"print\");\n\nconst vPrint = vm.getProperty(global, \"print\");\nif(vm.isUndefined(vPrint)) {\n  // ...\n} \n```\n\n- VM.prototype.defineProperty(value, name, desc)\n  - value: Value\n  - name: String\n  - desc: Object\n  - `return` Value\n\n等价于 `Object.defineProperty` 函数的用法。\n\n```javascript\nconst vObject = vm.createObject();\nvm.defineProperty(vObject, \"name\", { \n  value: vm.createString(\"sablejs\"),\n});\n\nconst getter = vm.createFunction(\"getter\", functionn() {\n  return vm.createNumber(\"101\");\n});\n\nconst setter = vm.createFunction(\"setter\", function(age) {\n  vm.setProperty(this, \"__age__\", age);\n});\n\nvm.defineProperty(vObject, \"age\", {\n  enumerable: false,\n  get: getter,\n  set: setter,\n});\n\n```\n\n- VM.prototype.getPrototype(value)\n  - value: Value\n  - `return` Value\n\n获取一个对象的原型。\n\n```javascript\nconst global = vm.getGlobal();\nconst vStringFunc = vm.getProperty(global, \"String\");\nif(!vm.isUndefined(vStringFunc)) {\n  const vTrimStart = vm.createFunction(\"trimStart\", function() {\n    const str = vm.asString(this);\n    return vm.createString(str);\n  });\n\n  const vStringFuncProto = vm.getPrototype(vStringFunc);\n  vm.setProperty(vStringFuncProto, \"trimStart\", vTrimStart);\n}\n```\n\n- VM.prototype.setPrototype(value, prototype)\n  - value: Value\n  - prototype: Value\n  - `return` Value\n\n设置一个对象的原型。\n\n```javascript\nconst vA = vm.createFunction(\"A\", function() {});\nconst vObject = vm.createObject();\n\nvm.setProperty(vObject, 'name', vm.createString('Hello World!'));\nvm.setPrototype(vA, vObject);\n```\n\n- VM.prototype.throw(value)\n  - value: Value\n  - `return` undefined\n\n等价于 `throw` 关键字。\n\n```javascript\nconst vError = vm.createError('unknown error');\nvm.throw(vError);\n```\n\n- VM.prototype.new(func[, arg1, arg2, arg3...])\n  - func: Value\n  - arg: Value\n  - `return` Value\n\n等价于 `new` 关键字。\n\n```javascript\nconst vA = vm.createFunction('A', function(name) {\n  vm.setProperty(this, 'name', name);\n});\n\nvm.new(vA, vm.createString(\"A\"));\n```\n\n- VM.prototype.call(func, thisPtr[, arg1, arg2, arg3...])\n  - func: Value\n  - thisPtr: Value | undefined\n  - arg: Value\n  - `return` Value\n\n等价于 `Function.prototype.call` 函数。\n\n```javascript\nconst vLog = vm.createFunction('log', function() {\n  const temp = [];\n  for(let i = 0; i \u003c arguments.length; i++){\n    temp.push(vm.asString(arguments[i]));\n  }\n  console.log(...temp); // '1', 1, false\n});\n\nvm.call(\n  vLog, \n  vm.createUndefined(), \n  vm.createString('1'), \n  vm.createNumber(1), \n  vm.createBoolean(false)\n);\n```\n\n- VM.prototype.destroy\n  - `return` undefined\n\n销毁VM实例，释放内存。\n\n```javascript\nvm.destroy();\n```\n\n### 性能测试\n\nsablejs也许是使用JavaScript编写的JavaScript引擎中最快的实现 ([测试用例使用 v8 benchmark suites](https://github.com/mozilla/arewefastyet/tree/master/benchmarks/v8-v7)):\n\n\u003e 性能测试环境:\n\u003e\n\u003e - Node.js v12.19.0\n\u003e - Golang 1.15.6\n\u003e - GCC 5.4.0 -O3\n\u003e - 2.4 GHz Intel Core i9\n\u003e - MacOS Mojave 10.14.6 (18G6032)\n\n|               | sablejs    | sval       | eval5      | quickjs-wasm    | goja   |\n| ------------- | ---------- | ---------- | ---------- | --------------- | ------ |\n| Language      | JavaScript | JavaScript | JavaScript | C + WebAssembly | Golang |\n| Richards      | 110        | 24.9       | 24.7       | 376             | 208    |\n| Crypto        | 114        | 24.6       | 20.2       | 400             | 104    |\n| RayTrace      | 258        | 92.2       | 98.5       | 471             | 294    |\n| NavierStokes  | 183        | 35.9       | 49.8       | 665             | 191    |\n| DeltaBlue     | 120        | 35.3       | 29.5       | 402             | 276    |\n| Total score   | 148        | 37.3       | 37.3       | 452             | 202    |\n| Baseline      | 1          | ▼ 2.96     | ▼ 2.96     | ▲ 2.05          | ▲ 0.36 |\n| File Size(KB) | 216        | 152        | 134        | 434             | -      |\n| Gzip Size(KB) | 29         | 40         | 34         | 245             | -      |\n\n### 限制\n\n1. eval及Function的动态执行部分在sablejs是被禁止的，但是如果你参数仅传递string/number/null及undefined的话，其是可以被正常执行的（因为解释器中不包含编译器，因此仅支持字面量的分析和传入）。\n\n```javascript\neval(\"print('Hello World!')\"); // it's ok\neval(\"var \" + \"a=1\"); // it's ok\n\nvar str = \"Hello World!\";\neval(\"print('\" + str + \"')\"); // throw SyntaxError\n\nFunction(\"a\", \"b\", \"return a+b\"); // it's ok\nnew Function(\"a\", \"b\", \"return a+b\"); // it's ok\n\nvar str = \"return a+b\";\nFunction(\"a\", \"b\", str); // throw SyntaxError\nnew Function(\"a\", \"b\", str); // throw SyntaxError\n```\n\n2. 浏览器环境中需要支持`btoa`、`unescape`、`decodeURIComponent`等原生函数，若果你想在IE9及以下使用，请自行添加相关的shims。\n\n### 使用协议\n\nsablejs JavaScript Engine\n\nCopyright (c) 2020-Now ErosZhao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nNon-profit projects of individuals or organizations and commercial projects with\ncommercial authorization of the author.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n","funding_links":[],"categories":["javascript interpreters","JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsablejs%2Fsablejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsablejs%2Fsablejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsablejs%2Fsablejs/lists"}