forked from GustavLindberg99/NuclideChart
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypecheck-v1.min.js
1 lines (1 loc) · 16.4 KB
/
typecheck-v1.min.js
1
"use strict";const typechecked=function(p){let y={};const w=async function(){}.constructor;const $=function*(){}.constructor;const m=async function*(){}.constructor;const r=["arguments","await","break","case","catch","const","continue","debugger","default","delete","do","else","eval","export","extends","false","finally","for","if","import","in","instanceof","let","new","return","static","super","switch","this","throw","true","try","typeof","while","with","yield"];class E{#t;#i;#o;#l;#u;constructor(e){Object.seal(this);this.#t=e.trim();if(this.#t===""){throw new SyntaxError("Expected type name")}const t=this.#t.match(/[^a-zA-Z\u00aa-\uffdc0-9_$\.\s<>\[\],|*]/)?.[0];if(t!==undefined){throw new SyntaxError(`Invalid character '${t} in type declaration '${this}`)}if(/(?<!function|async)\*/.test(this.#t)){throw new SyntaxError(`Unexpected token '*' in type declaration '${this}'`)}this.#i=this.#h();this.#u=this.#p();this.#o=this.#$();this.#l=this.#m();const n=this.#o?.split(".").find(e=>r.includes(e));if(n!==undefined){throw new SyntaxError(`Unexpected reserved keyword '${n}' in type declaration ${this}`)}}toString(){return this.#t}#k(t,n){const r=[""];let i=0;let s=0;for(let e=0;e<t.length;e++){switch(t[e]){case"<":i++;break;case">":i--;if(i<0){throw new SyntaxError(`Unexpected token '>' in type declaration '${this}'`)}break;case"[":s++;break;case"]":s--;if(s<0){throw new SyntaxError(`Unexpected token ']' in type declaration '${this}'`)}break;case n:if(i===0&&s===0){r.push("");continue}break}r[r.length-1]+=t[e]}if(i>0){throw new SyntaxError(`Unclosed generic in type declaration '${this}'`)}if(s>0){throw new SyntaxError(`Unclosed tuple in type declaration '${this}'`)}return r}#h(){let e=0;let t=0;const n=this.#k(this.#t,"|");if(n[0]===""){throw new SyntaxError(`Expected type name before '|' token in type declaration '${this}'`)}else if(n.at(-1)===""){throw new SyntaxError(`Expected type name after '|' token in type declaration '${this}'`)}else if(n.some(e=>e==="")){throw new SyntaxError(`Unexpected token '|' in type declaration '${this}'`)}if(n.length===1){return this}return n.map(e=>new E(e))}#p(){if(this.#i.length>1){return null}const e=this.#t.match(/^([^\[]*)\[(.*)\]([^\]]*)$/);if(e===null){return null}else if(e[1]!==""){if(e[1].trim().endsWith("<")){return null}else{throw new SyntaxError(`Garbage '${e[1]}' before tuple in type declaration '${this}' (for generics, use the syntax 'ContainerType<Type>')`)}}else if(e[3]!==""){throw new SyntaxError(`Unexpected token '${e[3]}' in type declaration '${this}'`)}const t=e[2];const n=this.#k(t,",");if(n[0]===""){if(n.length===1){return[]}else{throw new SyntaxError(`Expected type name before ',' token in generic in type declaration '${this}'`)}}else if(n.at(-1)===""){throw new SyntaxError(`Expected type name after ',' token in generic in type declaration '${this}'`)}else if(n.some(e=>e==="")){throw new SyntaxError(`Unexpected token ',' in type declaration '${this}'`)}return n.map(e=>new E(e))}#$(){if(this.#i.length>1){return null}if(this.#u!==null){return"Array"}const e=this.#t.replace(/<.+$/s,"").trim();const t=e.match(/[^a-zA-Z\u00aa-\uffdc0-9_$\.\s*]/)?.[0];if(t!==undefined){throw new SyntaxError(`Invalid character '${t} in type declaration '${this}`)}if(e===""){throw new SyntaxError(`Missing type name before generic in type declaration '${this}'`)}else if(/\s/.test(e)){throw new SyntaxError(`Unexpected token '${e.split(/\s+/)[1]}' in type declaration '${this}'`)}else if(/^[0-9]/.test(e)){throw new SyntaxError(`Type names can't start with numbers, got '${e}'`)}return e}#m(){if(this.#i.length>1||this.#u!==null){return null}const e=this.#t.match(/^[^<]+<(.*)>([^>]*)$/);if(e===null){return null}const t=e[1];if(e[2]!==""){throw new SyntaxError(`Unexpected token '${e[2]}' in type declaration '${this}'`)}else if(t===""){throw new SyntaxError(`Empty generic in type declaration '${this}'`)}const n=this.#k(t,",");if(n[0]===""){throw new SyntaxError(`Expected type name before ',' token in generic in type declaration '${this}'`)}else if(n.at(-1)===""){throw new SyntaxError(`Expected type name after ',' token in generic in type declaration '${this}'`)}else if(n.some(e=>e==="")){throw new SyntaxError(`Unexpected token ',' in type declaration '${this}'`)}const r=["Array","Set","Map"];if(!r.includes(this.#o)){throw new TypeError(`Generics are only supported on ${r}, not on '${this.#o}'`)}switch(n.length){case 1:if(this.#o==="Map"){throw new TypeError(`Too few arguments for ${this.#o} generic in type declaration '${this}'`)}break;case 2:if(this.#o==="Map"){break}default:throw new TypeError(`Too many arguments for ${this.#o} generic in type declaration '${this}'`)}return n.map(e=>new E(e))}isinstance(n){switch(this.#o){case null:return this.#i.some(e=>e.isinstance(n));case"var":return true;case"null":return n===null;case"undefined":case"void":return n===undefined;case"NaN":return typeof n==="number"&&isNaN(n);case"function":return n instanceof Function&&!n.toString().startsWith("class");case"function*":return n instanceof $&&!n.toString().startsWith("class");case"async":return n instanceof w&&!n.toString().startsWith("class");case"async*":return n instanceof m&&!n.toString().startsWith("class");case"class":return n instanceof Function&&n.hasOwnProperty("prototype")&&!(n instanceof $||n instanceof m);default:const r=this.#o.split(".");let t=y[r[0]]??p(r[0]);for(let e of r.slice(1)){t=t?.[e]}if(t===undefined){throw new ReferenceError(`'${this.#o}' in type declaration is not defined`)}else if(!i.isinstance(t)){throw new TypeError(`'${this.#o}' in type declaration does not name a type`)}if(!x.isinstance(n,t)){return false}if(this.#u!==null){return n.length===this.#u.length&&this.#u.every((e,t)=>e.isinstance(n[t]))}else if(this.#l?.length===2){for(let e of n){if(!this.#l[0].isinstance(e[0])||!this.#l[1].isinstance(e[1])){return false}}}else if(this.#l?.length===1){for(let e of n){if(!this.#l[0].isinstance(e)){return false}}}return true}}}const i=new E("class");class b{name;type=null;parent;children=[];g=false;S=null;T=false;constructor(e,t=null){Object.seal(this);this.name=e;this.parent=t}}class k{name;parameters=[];N=null;j;constructor(e,i){Object.seal(this);this.name=e;const r=/^\s*\/\*:(.+?)\*\//is;let s=0;let o=false;let a=null;let c=[];const l=(e=true,t=true)=>{let n;while(n=i.slice(s).match(e?/^\s*(\/\*:?|\/\/)/:/^\s*(\/\*[^:]|\/\/)/)){if(n[1]==="/*:"&&t){const r=i.slice(s,i.indexOf("*/",s+2)+2).trim();throw new SyntaxError(`Unexpected type declaration '${r}'`)}else if(n[1]==="//"){s=i.indexOf("\n",s)}else{s=i.indexOf("*/",s+2)+2}e=true;t=true}};const f=()=>{const e=i[s];if(!"\"'`".includes(e)){return}s++;while(i[s]!==e){if(i[s]==="\\"){s++}s++}s++};let t="";let n=0;while(n>0||/^\s*([a-z_$]|(\/[\/\*]|\[))/i.test(i.slice(s))){if(i.slice(s).trim()[0]==="["){n++;s++}else if(n>0){f();switch(i[s]){case"[":n++;break;case"]":n--;break}s++}else{s+=i.slice(s).search(/\S/);if(/^[a-z_$]/i.test(i.slice(s))){const h=s;s+=i.slice(s).search(/[^a-z0-9_$\*]/i);t=i.slice(h,s)}}l()}s+=i.slice(s).search(/\S/);if(i[s]==="("){s++}else if(i.substr(s,2)==="=>"){this.parameters=[new b(t)];this.j=true;return}else{throw new SyntaxError(`Error when parsing typechecked function ${this.name}: Unexpected character '${i[s]}' when parsing type declaration`)}while(o||!/^\s*\)/.test(i.slice(s))){l(!o);let t;let n=false;if(o){const w=a.children.map(e=>e.name).join(", ");if(a.S===Array){a.name=`[${w}]`}else{a.name=`{${w}}`}}else{let e;while(e=i.slice(s).match(/^\s*(\.\.\.)?\s*([\[\{])/)){a=new b("",a);s+=e[0].length;switch(e[2]){case"[":a.S=Array;break;case"{":a.S=Object;break}if(e[1]!==undefined){a.T=true}l()}const $=i.slice(s).match(/^\s*(\.\.\.)?\s*([a-z_$][a-z0-9_$]*)/i);if($[2]!==""&&c.includes($[2])){throw new SyntaxError(`Error when parsing typechecked function ${this.name}: Duplicate parameter name '${$[2]}' in typechecked function`)}t=$[2];s+=$[0].length;if($[1]!==undefined){n=true}}l(false);const d=i.slice(s).match(r);const p=o?a:new b(t,a);p.T||=n;if(d!==null){if(d[1].trim()==="void"){throw new SyntaxError(`Error when parsing typechecked function ${this.name}: void can only be used as a return type`)}p.type=new E(d[1])}if(o){a=a.parent}l(true,false);p.g=/^\s*=/.test(i.slice(s));if(p.g){let e=0;let t=0;let n=0;s=i.indexOf("=",s);l();while(e>0||t>0||n>0||!/^\s*[,)]/.test(i.slice(s))){switch(i[s]){case'"':case"'":case"`":f();s--;break;case"[":e++;break;case"]":e--;break;case"{":t++;break;case"}":t--;break;case"(":n++;break;case")":n--;break}if(e<0||t<0){break}s++;l();if(s>=i.length){throw new SyntaxError(`Error when parsing typechecked function ${this.name}: Unexpected end of file when typechecking function`)}}}else if(a?.S!==Object){if((a?.children??this.parameters).some(e=>e.g)){throw new SyntaxError(`Error when parsing typechecked function ${this.name}: Parameter '${p.name}' is non-optional but is placed after an optional parameter`)}}if(a===null){this.parameters.push(p)}else{a.children.push(p)}const y=i.slice(s).match(/^\s*([\]\},])/);if(y!==null){o=y[1]!==",";s+=y[0].length}else{o=false}if(s>=i.length){throw new SyntaxError(`Error when parsing typechecked function ${this.name}: Unexpected end of file when typechecking function`)}}s=i.indexOf(")",s)+1;l(false);const u=i.slice(s).match(r);if(u!==null){this.N=new E(u[1])}l(true,false);this.j=/^\s*=>/.test(i.slice(s))}O(t,n=this.parameters,r=this.name){const e=n.filter(e=>!e.g&&!e.T).length;const i=this.j||n.at(-1)?.T?Infinity:n.length;if(t.length<e){throw new TypeError(`${t.length} arguments passed to ${r}, but at least ${e} were expected.`)}if(t.length>i){throw new TypeError(`${t.length} arguments passed to ${r}, but at most ${i} were expected.`)}for(let e=0;e<n.length&&(e<t.length||n[e].T);e++){const s=n[e].T?t.slice(e):t[e];if(!(n[e].type?.isinstance(s)??true)){throw new TypeError(`Expected parameter '${n[e].name}' of ${r} to be of type '${n[e].type}', got '${g(s)}'`)}if(n[e].S===Array){this.O(s,n[e].children,`destructured parameter '${n[e].name}' of ${r}`)}else if(n[e].S===Object){this.v(s,n[e].children,`destructured parameter '${n[e].name}' of ${r}`)}}}v(t,n,r){for(let e of n){if(!(e.name in Object(t))){if(e.g){continue}else{throw new TypeError(`Parameter passed as ${r} does not have a property named ${e.name}`)}}const i=t[e.name];if(!(e.type?.isinstance(i)??true)){throw new TypeError(`Expected parameter '${e.name}' of ${r} to be of type '${e.type}', got '${g(i)}'`)}if(e.S===Array){this.O(i,e.children,`destructured parameter '${e.name}' of ${r}`)}else if(e.S===Object){this.v(i,e.children,`destructured parameter '${e.name}' of ${r}`)}}}U(e){if(this.N!==null&&!this.N.isinstance(e)){throw new TypeError(`Expected return value of ${this.name} to be of type '${this.N}', got '${g(e)}'`)}}}function g(r){if(r===null){return"null"}else if(typeof r==="number"&&isNaN(r)){return"NaN"}else if(r instanceof Array||r instanceof Set){let t=new Set;for(let e of r){if(e===null){t.add("null")}else if(typeof e==="number"&&isNaN(e)){t.add("NaN")}else{t.add(String(e?.constructor.name))}}if(t.size>0){return`${r.constructor.name}<${[...t].join(" | ")}>`}}else if(r instanceof Map){let t=new Set;let n=new Set;for(let e of r){if(e[0]===null){t.add("null")}else if(typeof e[0]==="number"&&isNaN(e[0])){containedTypes.add("NaN")}else{t.add(String(e[0]?.constructor.name))}if(e[1]===null){n.add("null")}else if(typeof e[1]==="number"&&isNaN(e[1])){containedTypes.add("NaN")}else{n.add(String(e[1]?.constructor.name))}}if(t.size>0){return`${r.constructor.name}<${[...t].join(" | ")}, ${[...n].join(" | ")}>`}}return String(r?.constructor.name)}function x(r,{name:i=r.name,kind:s=r.toString().startsWith("class")?"class":"function"}={}){if(typeof r!=="function"){throw new TypeError(`Expected parameter 'undecorated' of function 'typechecked' to be of type 'function | class', got '${g(r)}'`)}if(typeof i!=="string"){throw new TypeError(`Expected parameter 'name' of function 'typechecked' to be of type 'String', got '${g(type)}'`)}if(typeof s!=="string"){throw new TypeError(`Expected parameter 'kind' of function 'typechecked' to be of type 'String', got '${g(s)}'`)}const o=i!==""?`'${i}'`:"<anonymous>";const a=i.split(".").at(-1);switch(s){case"class":if(i!==""&&!i.includes(".")){if(i in y||p(i)!==undefined){throw new ReferenceError(`Redefinition of class ${o} (typecheck.js doesn't support multiple typechecked classes with the same name, not even in different modules)`)}y[i]=r}const c=[...Object.entries(Object.getOwnPropertyDescriptors(r)).map(([e,t])=>{t.A=true;t.name=e;return t}),...Object.entries(Object.getOwnPropertyDescriptors(r.prototype)).map(([e,t])=>{t.A=false;t.name=e;return t})];for(let t of c){if(t.name==="constructor"){continue}if(t.writable===false){if(t.value instanceof Function||t.get instanceof Function||t.set instanceof Function){console.warn(i+"."+t.name+" is not writable and can't be typechecked.")}continue}const u=t.A?r:r.prototype;if(t.value instanceof Function){u[t.name]=x(t.value,{kind:x.isinstance(t.value,"function")?"method":"class",name:i+"."+t.name})}else if(t.get instanceof Function||t.set instanceof Function){let e={};if(t.get instanceof Function){e.get=x(t.get,{kind:"getter",name:t.name,A:t.A})}if(t.set instanceof Function){e.set=x(t.set,{kind:"setter",name:t.name,A:t.A})}Object.defineProperty(u,t.name,e)}}const l=r.toString();let e=0;let t=0;for(let e=0;e<l.length;e++){if(l.substr(e,2)==="//"){e=l.indexOf("\n",e)}else if(l.substr(e,2)==="/*"){e=l.indexOf("*/",e+2)+1}else if(l[e]==='"'||l[e]==="'"||l[e]==="`"){const h=l[e];e++;while(l[e]!==h){if(l[e]==="\\"){e++}e++}}else if(l[e]==="{"){t++}else if(l[e]==="}"){t--}else if(t===1&&l.slice(e).startsWith("constructor")){const d=new k(`${o} constructor`,l.slice(e));if(d.N!==null){throw new SyntaxError("Constructors can't have return types")}return{[a]:class extends r{constructor(...e){d.O(e);super(...e)}}}[a]}}return r;case"function":case"method":case"getter":case"setter":const f=new k(o,r.toString());if(s==="setter"&&f.N!==null){throw new SyntaxError("Setters can't have return types")}let n;if(r instanceof w){n=async function(...e){f.O(e);const t=await(f.j?r(...e):r.call(this,...e));f.U(t);return t}}else if(r instanceof $){n=function*(...e){f.O(e);const t=r.call(this,...e);for(let e=t.next();!e.done;e=t.next()){f.U(e.value);yield e}}}else if(r instanceof m){n=async function*(...e){f.O(e);const t=r.call(this,...e);for(let e=await t.next();!e.done;e=await t.next()){f.U(e.value);yield e}}}else{n=function(...e){f.O(e);const t=f.j?r(...e):r.call(this,...e);if(s==="setter"){if(t!==undefined){throw new TypeError("Setters should not return anything")}}else{f.U(t)}return t}}Object.defineProperty(n,"name",{value:a,writable:false});return n;default:throw new TypeError("typechecked is only allowed on classes, functions, methods, getters or setters, got "+context.kind)}}x.isinstance=function(e,t){if(t===null){return e===null}else if(t===undefined){return e===undefined}else if(Object.is(t,NaN)){return Object.is(e,NaN)}else if(i.isinstance(t)){if(e===null||e===undefined){return false}else if(t===Number){return typeof e==="number"&&!isNaN(e)}else if(t===String){return typeof e==="string"}else if(t===Boolean){return typeof e==="boolean"}else if(t===Symbol){return typeof e==="symbol"}else if(t===BigInt){return typeof e==="bigint"}else{return Object(e)instanceof t}}else if(typeof t==="string"){return new E(t).isinstance(e)}else{throw new TypeError(`Expected parameter 'type' of function 'typechecked.isinstance' to be of type 'String | class | null | undefined | NaN', got '${g(t)}'`)}};x.add=x(function(...t/*: Array<class> */){for(let e of t){if(e.name===""){throw new ReferenceError("Cannot call typechecked.add on anonymous classes.")}const n=e.name;if(n in y||p(n)!==undefined){if(y[n]===e){continue}else if(i.isinstance(y[n])&&e.prototype instanceof y[n]){throw new ReferenceError(`Cannot call typechecked.add on class '${n}': class is already known by typechecked. You don't need to call typechecked.add on classes that are themselves typechecked.`)}else if(p(n)===e){throw new ReferenceError(`Cannot call typechecked.add on class '${n}': class is already known by typechecked. You don't need to call typechecked.add on classes that are members of globalThis.`)}else{throw new ReferenceError(`Redefinition of class '${n}' (typecheck.js doesn't support multiple typechecked classes with the same name, not even in different modules)`)}}y[n]=e}},{name:"typechecked.add"});return Object.freeze(x)}(function(){if(globalThis[arguments[0]]!==undefined){return globalThis[arguments[0]]}if(eval(`typeof ${arguments[0]}`)==="undefined"){return undefined}return eval(arguments[0])});if(typeof window==="undefined"){module.exports=typechecked}if(0)typeof await/2;//2;export default typechecked;