├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.js ├── min.js ├── package.json ├── rollup.config.js └── test └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | coverage/ 3 | .DS_Store 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | img/ 3 | node_modules/ 4 | test/ 5 | _config.yml 6 | .DS_Store 7 | .gitignore 8 | .travis.yml 9 | package-lock.json 10 | rollup.config.js 11 | es.config.js 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | git: 5 | depth: 1 6 | branches: 7 | only: 8 | - master 9 | - /^greenkeeper/.*$/ 10 | after_success: 11 | - "npm run coveralls" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2019, Andrea Giammarchi, @WebReflection 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH 10 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 | PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Deprecated] - Qui-Gon Jinn Script 2 | 3 | [![Build Status](https://travis-ci.com/WebReflection/qui-gon.svg?branch=master)](https://travis-ci.com/WebReflection/qui-gon) [![Coverage Status](https://coveralls.io/repos/github/WebReflection/qui-gon/badge.svg?branch=master)](https://coveralls.io/github/WebReflection/qui-gon?branch=master) 4 | 5 | **Social Media Photo by [Thomas Griesbeck](https://unsplash.com/@jack_scorner) on [Unsplash](https://unsplash.com/)** 6 | 7 | This module is now called **[jdes](https://github.com/webreflection/jdes#readme)**. 8 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function QuiGonJS() {'use strict'; 2 | 3 | /*! (c) Andrea Giammarchi - ISC */ 4 | 5 | const { 6 | assign, 7 | create, 8 | defineProperty, 9 | freeze, 10 | getOwnPropertyNames, 11 | keys, 12 | seal, 13 | setPrototypeOf 14 | } = Object; 15 | 16 | /* istanbul ignore next */ 17 | const G = typeof(self) === 'object' ? self : global; 18 | 19 | const casts = new Map; 20 | const types = []; 21 | 22 | // basic primitives, casted via constructors 23 | // let {boolean: init} = 1; 24 | // const {number: nums} = [0, '1.2', 3]; 25 | [ 26 | {boolean: 'Boolean'}, 27 | {number: 'Number'}, 28 | {object: 'Object'}, 29 | {string: 'String'}, 30 | ] 31 | .forEach(definition => { 32 | const [type] = keys(definition); 33 | const Class = G[definition[type]]; 34 | const cast = self => typeof(self) === type ? self : Class(self); 35 | casts.set(type, cast); 36 | defineProperty(Array.prototype, type, {get: map(cast)}); 37 | defineProperty(Object.prototype, type, {get: fn(cast)}); 38 | types.push(definition); 39 | }); 40 | 41 | // primitives that cannot be casted (throws TypeError) 42 | // const {symbol: iterator} = Symbol.iterator; 43 | [ 44 | {symbol: 'Symbol'}, 45 | ] 46 | .forEach(definition => { 47 | const [type] = keys(definition); 48 | const name = definition[type]; 49 | /* istanbul ignore else */ 50 | if (typeof(G[name]) === 'function') { 51 | const cast = self => { 52 | if (typeof(self) === type) 53 | return self; 54 | throw new TypeError(String(self) + ' is not a ' + name); 55 | }; 56 | casts.set(type, cast); 57 | defineProperty(Array.prototype, type, {get: map(cast)}); 58 | defineProperty(Object.prototype, type, {get: fn(cast)}); 59 | types.push(definition); 60 | } 61 | }); 62 | 63 | // Rust like primitives (plus uc8) casted via value assignment 64 | // const {f32: coords} = [lat, long]; 65 | [ 66 | {f: 'Float32Array'}, 67 | {i: 'Int32Array'}, 68 | {u: 'Uint32Array'}, 69 | {f32: 'Float32Array'}, 70 | {f64: 'Float64Array'}, 71 | {i8: 'Int8Array'}, 72 | {i16: 'Int16Array'}, 73 | {i32: 'Int32Array'}, 74 | {u8: 'Uint8Array'}, 75 | {u16: 'Uint16Array'}, 76 | {u32: 'Uint32Array'}, 77 | // extra Qui-Gon Jinn Script type 78 | {uc8: 'Uint8ClampedArray'}, 79 | ] 80 | .forEach(definition => { 81 | const [type] = keys(definition); 82 | const Class = G[definition[type]]; 83 | /* istanbul ignore else */ 84 | if (typeof(Class) === 'function') { 85 | const reference = new Class(1); 86 | const cast = self => ((reference[0] = self), reference[0]); 87 | casts.set(type, cast); 88 | defineProperty(Array.prototype, type, { 89 | get() { return new Class(this); } 90 | }); 91 | defineProperty(Object.prototype, type, {get: fn(cast)}); 92 | types.push(definition); 93 | } 94 | }); 95 | 96 | // still Rust like values with different casting 97 | [ 98 | {i64: 'BigInt64Array'}, 99 | {u64: 'BigUint64Array'}, 100 | ] 101 | .forEach(definition => { 102 | const [type] = keys(definition); 103 | const Class = definition[type]; 104 | const cast = G[Class.slice(0, Class.indexOf('64'))]; 105 | if (typeof(cast) === 'function' && typeof(G[Class]) === 'function') { 106 | casts.set(type, cast); 107 | defineProperty(Array.prototype, type, {get: map(cast)}); 108 | defineProperty(Object.prototype, type, {get: fn(cast)}); 109 | types.push(definition); 110 | } 111 | }); 112 | 113 | // arrays (aka Rust mutable tuple) 114 | // const {array: numbers} = [1, 2, '3', 4]; 115 | [ 116 | {array: 'Array'} 117 | ] 118 | .forEach(definition => { 119 | const [type] = keys(definition); 120 | const Class = G[definition[type]]; 121 | const cast = self => Class.from(self); 122 | casts.set(type, cast); 123 | defineProperty(Array.prototype, type, {get() { return cast(this); }}); 124 | defineProperty(Object.prototype, type, {get: fn(cast)}); 125 | types.push(definition); 126 | }); 127 | 128 | // struct (simple Rust structs) 129 | // const {struct: Point} = [{i32: 'x'}, {i32: 'y'}]; 130 | defineProperty(Array.prototype, 'struct', {get() { 131 | const descriptors = create(null); 132 | const {prototype} = Struct; 133 | this.forEach(definition => { 134 | const [type] = keys(definition); 135 | const name = definition[type]; 136 | const cast = getCast(type); 137 | const _ = new WeakMap; 138 | descriptors[name] = { 139 | enumerable: true, 140 | get() { return _.get(this); }, 141 | set(value) { _.set(this, cast(value)); } 142 | }; 143 | }); 144 | freeze(prototype); 145 | return freeze(Struct); 146 | function Struct(self) { 147 | return seal(assign(create(prototype, descriptors), self)); 148 | } 149 | }}); 150 | 151 | // registered struct (simple Rust structs) 152 | // const {struct: Point} = {Point: [{f32: 'x'}, {f32: 'y'}]}; 153 | // const {Point: p} = Point(0, 0); 154 | defineProperty(Object.prototype, 'struct', {get() { 155 | const [type] = keys(this); 156 | register(type); 157 | return this[type].struct; 158 | }}); 159 | 160 | // const {enum: WebEvent} = [ 161 | // 'Loading', 162 | // 'Loaded', 163 | // {Click: [{i64: 'x'}, {i64: 'y'}] }} 164 | // ]; 165 | defineProperty(Array.prototype, 'enum', {get() { 166 | const Enum = create(null); 167 | this.forEach(definition => { 168 | if (typeof definition === 'string') { 169 | Enum[definition] = Symbol(definition); 170 | } else { 171 | const [name] = keys(definition); 172 | const assignments = []; 173 | definition[name].forEach(definition => { 174 | const [type] = keys(definition); 175 | const name = definition[type]; 176 | const cast = getCast(type); 177 | assignments.push({name, cast}); 178 | }); 179 | const fn = (self) => { 180 | assignments.forEach(definition => { 181 | const {name, cast} = definition; 182 | fn[name] = cast(self[name]); 183 | }); 184 | return fn; 185 | }; 186 | setPrototypeOf(fn, null); 187 | getOwnPropertyNames(fn).forEach(name => { 188 | delete fn[name]; 189 | }); 190 | Enum[name] = fn; 191 | } 192 | }); 193 | return freeze(Enum); 194 | }}); 195 | 196 | // registered enum (simple Rust enums) 197 | // const {enum: Color} = {Color: ['Red', 'Green', 'Blue']}; 198 | // console.log(Color.Red); 199 | defineProperty(Object.prototype, 'enum', {get() { 200 | const [type] = keys(this); 201 | register(type); 202 | return this[type].enum; 203 | }}); 204 | 205 | defineProperty(G, 'types', {value: types.map(type => keys(type)[0])}); 206 | 207 | function fn(cast) { 208 | return function () { 209 | return typeof(this) === 'function' ? 210 | wrapFn(cast, this) : 211 | cast(this); 212 | }; 213 | } 214 | 215 | function getCast(type) { 216 | if (!casts.has(type)) 217 | throw new TypeError('unknown type ' + type); 218 | return casts.get(type); 219 | } 220 | 221 | function map(cast) { 222 | return function () { 223 | return this.map(cast); 224 | }; 225 | } 226 | 227 | function register(type) { 228 | if (!types.includes(type)) { 229 | types.push(type); 230 | defineProperty(Object.prototype, type, {get() { return this; }}); 231 | } 232 | } 233 | 234 | function wrapFn(cast, fn) { 235 | return function () { 236 | return cast(fn.apply(this, arguments)); 237 | }; 238 | } 239 | 240 | }()); 241 | -------------------------------------------------------------------------------- /min.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";!function(){const{assign:t,create:r,defineProperty:e,freeze:n,getOwnPropertyNames:o,keys:s,seal:c,setPrototypeOf:p}=Object,u="object"==typeof self?self:global,i=new Map,y=[];function a(t){return function(){return"function"==typeof this?function(t,r){return function(){return t(r.apply(this,arguments))}}(t,this):t(this)}}function f(t){if(!i.has(t))throw new TypeError("unknown type "+t);return i.get(t)}function h(t){return function(){return this.map(t)}}function g(t){y.includes(t)||(y.push(t),e(Object.prototype,t,{get(){return this}}))}[{boolean:"Boolean"},{number:"Number"},{object:"Object"},{string:"String"}].forEach(t=>{const[r]=s(t),n=u[t[r]],o=t=>typeof t===r?t:n(t);i.set(r,o),e(Array.prototype,r,{get:h(o)}),e(Object.prototype,r,{get:a(o)}),y.push(t)}),[{symbol:"Symbol"}].forEach(t=>{const[r]=s(t),n=t[r];if("function"==typeof u[n]){const o=t=>{if(typeof t===r)return t;throw new TypeError(String(t)+" is not a "+n)};i.set(r,o),e(Array.prototype,r,{get:h(o)}),e(Object.prototype,r,{get:a(o)}),y.push(t)}}),[{f:"Float32Array"},{i:"Int32Array"},{u:"Uint32Array"},{f32:"Float32Array"},{f64:"Float64Array"},{i8:"Int8Array"},{i16:"Int16Array"},{i32:"Int32Array"},{u8:"Uint8Array"},{u16:"Uint16Array"},{u32:"Uint32Array"},{uc8:"Uint8ClampedArray"}].forEach(t=>{const[r]=s(t),n=u[t[r]];if("function"==typeof n){const o=new n(1),s=t=>(o[0]=t,o[0]);i.set(r,s),e(Array.prototype,r,{get(){return new n(this)}}),e(Object.prototype,r,{get:a(s)}),y.push(t)}}),[{i64:"BigInt64Array"},{u64:"BigUint64Array"}].forEach(t=>{const[r]=s(t),n=t[r],o=u[n.slice(0,n.indexOf("64"))];"function"==typeof o&&"function"==typeof u[n]&&(i.set(r,o),e(Array.prototype,r,{get:h(o)}),e(Object.prototype,r,{get:a(o)}),y.push(t))}),[{array:"Array"}].forEach(t=>{const[r]=s(t),n=u[t[r]],o=t=>n.from(t);i.set(r,o),e(Array.prototype,r,{get(){return o(this)}}),e(Object.prototype,r,{get:a(o)}),y.push(t)}),e(Array.prototype,"struct",{get(){const e=r(null),{prototype:o}=p;return this.forEach(t=>{const[r]=s(t),n=t[r],o=f(r),c=new WeakMap;e[n]={enumerable:!0,get(){return c.get(this)},set(t){c.set(this,o(t))}}}),n(o),n(p);function p(n){return c(t(r(o,e),n))}}}),e(Object.prototype,"struct",{get(){const[t]=s(this);return g(t),this[t].struct}}),e(Array.prototype,"enum",{get(){const t=r(null);return this.forEach(r=>{if("string"==typeof r)t[r]=Symbol(r);else{const[e]=s(r),n=[];r[e].forEach(t=>{const[r]=s(t),e=t[r],o=f(r);n.push({name:e,cast:o})});const c=t=>(n.forEach(r=>{const{name:e,cast:n}=r;c[e]=n(t[e])}),c);p(c,null),o(c).forEach(t=>{delete c[t]}),t[e]=c}}),n(t)}}),e(Object.prototype,"enum",{get(){const[t]=s(this);return g(t),this[t].enum}}),e(u,"types",{value:y.map(t=>s(t)[0])})}()}(); 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "qui-gon", 3 | "version": "0.0.6", 4 | "main": "index.js", 5 | "module": "index.js", 6 | "unpkg": "min.js", 7 | "scripts": { 8 | "build": "npm run rollup && npm run test && npm run size", 9 | "coveralls": "cat ./coverage/lcov.info | coveralls", 10 | "rollup": "rollup --config rollup.config.js", 11 | "size": "cat index.js | wc -c;cat min.js | wc -c;gzip -c9 min.js | wc -c", 12 | "test": "istanbul cover test/index.js" 13 | }, 14 | "keywords": [ 15 | "typed", 16 | "js", 17 | "types" 18 | ], 19 | "author": "Andrea Giammarchi", 20 | "license": "ISC", 21 | "devDependencies": { 22 | "coveralls": "^3.0.4", 23 | "istanbul": "^0.4.5", 24 | "rollup": "^1.16.6", 25 | "rollup-plugin-terser": "^5.1.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { terser } from 'rollup-plugin-terser'; 2 | export default { 3 | input: 'index.js', 4 | plugins: [terser()], 5 | context: 'null', 6 | moduleContext: 'null', 7 | output: { 8 | exports: 'named', 9 | file: 'min.js', 10 | format: 'iife', 11 | name: 'QuiGonJS' 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | require('../'); // qui-gon 2 | 3 | const {boolean: t} = true; 4 | const {boolean: f} = false; 5 | 6 | console.assert(t === true, 'true'); 7 | console.assert(f === false, 'false'); 8 | 9 | const {number: n} = '1.2'; 10 | console.assert(n === 1.2, 'n === 1.2'); 11 | 12 | const {number: ns} = ['1.2', 3.4]; 13 | console.assert(ns[0] === 1.2 && ns[1] === 3.4, 'ns'); 14 | 15 | const {symbol: s} = Symbol('OK'); 16 | console.assert(typeof s === 'symbol', 'symbol s'); 17 | 18 | try { 19 | const {symbol: nope} = 'OK'; 20 | console.assert(!!nope, 'symbol nope should not happen'); 21 | } catch(o_O) {} 22 | 23 | const {i8: si} = 1.2; 24 | console.assert(si === 1, 'si'); 25 | 26 | const {i8: sa} = [1.2, 3.4]; 27 | console.assert(sa[0] === 1 && sa[1] === 3, 'sa'); 28 | 29 | const {array: genericArray} = [1, '2', 3]; 30 | console.assert(genericArray.length === 3); 31 | 32 | try { 33 | const {struct: Fail} = [{unknown: 'nope'}]; 34 | console.assert(!Fail, 'unknown type should not happen'); 35 | } catch (OK) {} 36 | 37 | const {struct: Point} = [{i32: 'x'}, {i32: 'y'}]; 38 | const p = Point({x: 1.2, y: 3.4}); 39 | 40 | console.assert(p instanceof Point, 'Point'); 41 | console.assert(p.x === 1 && p.y === 3, 'p'); 42 | 43 | p.x = 4.1; 44 | console.assert(p.x === 4, 'p.x'); 45 | 46 | const {struct: Point3D} = {Point3D: [{f32: 'x'}, {f32: 'y'}, {f32: 'z'}]}; 47 | const p3d = Point3D({x: 0, y: 0, z: 0}); 48 | console.assert(p3d.x === 0 && p3d.y === 0 && p3d.z === 0, 'p3d'); 49 | 50 | const {Point3D: another} = Point3D({x: .1, y: .2, z: .3}); 51 | console.assert( 52 | another.x.toFixed(1) == .1 && 53 | another.y.toFixed(1) == .2 && 54 | another.z.toFixed(1) == .3, 55 | 'another' 56 | ); 57 | 58 | const {struct: Struct} = {Point3D: [{f32: 'x'}, {f32: 'y'}, {f32: 'z'}]}; 59 | console.assert(typeof Struct === 'function' && Struct !== Point3D, 'Struct != Point3D'); 60 | 61 | const {i32: foo} = ({i32: x}) => x * 2; 62 | console.assert(foo(2) === 4, 'foo(...)'); 63 | 64 | const {i32: bar} = ({i32: x}, {i32: y}) => x * y; 65 | console.assert(bar(3, 4) === 12, 'bar(...)'); 66 | 67 | console.assert(types, 'types'); 68 | 69 | const {enum: Color} = {Color: [ 70 | 'Red', 'Green', 'Blue', 71 | {RGB: [{u32: 'r'}, {u32: 'g'}, {u32: 'b'}, {u16: 'length'}]} 72 | ]}; 73 | 74 | console.assert(typeof Color.Red === 'symbol'); 75 | console.assert(typeof Color.Green === 'symbol'); 76 | console.assert(typeof Color.Blue === 'symbol'); 77 | console.assert(Color.RGB({r: 1, g: 2, b: 3, length: 3}) === Color.RGB, 'returns as enum'); 78 | console.assert(Color.RGB.r === 1); 79 | console.assert(Color.RGB.g === 2); 80 | console.assert(Color.RGB.b === 3); 81 | console.assert(Color.RGB.length === 3); 82 | --------------------------------------------------------------------------------