diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e725d1f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/*.pyc +src/spec/tmp.json diff --git a/dist/xrfragment.js b/dist/xrfragment.js index 4506c3d..79c1bd7 100644 --- a/dist/xrfragment.js +++ b/dist/xrfragment.js @@ -1,10 +1,10 @@ var $hx_exports = typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this; (function ($global) { "use strict"; $hx_exports["xrfragment"] = $hx_exports["xrfragment"] || {}; -$hx_exports["xrfragment"]["Query"] = $hx_exports["xrfragment"]["Query"] || {}; var EReg = function(r,opt) { this.r = new RegExp(r,opt.split("u").join("")); }; +EReg.__name__ = true; EReg.prototype = { match: function(s) { if(this.r.global) { @@ -20,6 +20,7 @@ EReg.prototype = { } }; var HxOverrides = function() { }; +HxOverrides.__name__ = true; HxOverrides.cca = function(s,index) { var x = s.charCodeAt(index); if(x != x) { @@ -42,7 +43,33 @@ HxOverrides.substr = function(s,pos,len) { HxOverrides.now = function() { return Date.now(); }; +Math.__name__ = true; +var Reflect = function() { }; +Reflect.__name__ = true; +Reflect.field = function(o,field) { + try { + return o[field]; + } catch( _g ) { + return null; + } +}; +Reflect.fields = function(o) { + var a = []; + if(o != null) { + var hasOwnProperty = Object.prototype.hasOwnProperty; + for( var f in o ) { + if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) { + a.push(f); + } + } + } + return a; +}; var Std = function() { }; +Std.__name__ = true; +Std.string = function(s) { + return js_Boot.__string_rec(s,""); +}; Std.parseInt = function(x) { if(x != null) { var _g = 0; @@ -64,6 +91,7 @@ Std.parseInt = function(x) { return null; }; var StringTools = function() { }; +StringTools.__name__ = true; StringTools.isSpace = function(s,pos) { var c = HxOverrides.cca(s,pos); if(!(c > 8 && c < 14)) { @@ -102,6 +130,7 @@ var haxe_iterators_ArrayIterator = function(array) { this.current = 0; this.array = array; }; +haxe_iterators_ArrayIterator.__name__ = true; haxe_iterators_ArrayIterator.prototype = { hasNext: function() { return this.current < this.array.length; @@ -110,11 +139,79 @@ haxe_iterators_ArrayIterator.prototype = { return this.array[this.current++]; } }; +var js_Boot = function() { }; +js_Boot.__name__ = true; +js_Boot.__string_rec = function(o,s) { + if(o == null) { + return "null"; + } + if(s.length >= 5) { + return "<...>"; + } + var t = typeof(o); + if(t == "function" && (o.__name__ || o.__ename__)) { + t = "object"; + } + switch(t) { + case "function": + return ""; + case "object": + if(((o) instanceof Array)) { + var str = "["; + s += "\t"; + var _g = 0; + var _g1 = o.length; + while(_g < _g1) { + var i = _g++; + str += (i > 0 ? "," : "") + js_Boot.__string_rec(o[i],s); + } + str += "]"; + return str; + } + var tostr; + try { + tostr = o.toString; + } catch( _g ) { + return "???"; + } + if(tostr != null && tostr != Object.toString && typeof(tostr) == "function") { + var s2 = o.toString(); + if(s2 != "[object Object]") { + return s2; + } + } + var str = "{\n"; + s += "\t"; + var hasp = o.hasOwnProperty != null; + var k = null; + for( k in o ) { + if(hasp && !o.hasOwnProperty(k)) { + continue; + } + if(k == "prototype" || k == "__class__" || k == "__super__" || k == "__interfaces__" || k == "__properties__") { + continue; + } + if(str.length != 2) { + str += ", \n"; + } + str += s + k + " : " + js_Boot.__string_rec(o[k],s); + } + s = s.substring(1); + str += "\n" + s + "}"; + return str; + case "string": + return o; + default: + return String(o); + } +}; var xrfragment_Parser = $hx_exports["xrfragment"]["Parser"] = function() { }; +xrfragment_Parser.__name__ = true; xrfragment_Parser.parse = function(key,value,resultMap) { var Frag_h = Object.create(null); Frag_h["prio"] = xrfragment_Type.isInt; Frag_h["pos"] = xrfragment_Type.isVector; + Frag_h["q"] = xrfragment_Type.isString; if(Object.prototype.hasOwnProperty.call(Frag_h,key)) { if(Frag_h[key].match(value)) { var v = new xrfragment_Value(); @@ -133,11 +230,11 @@ xrfragment_Parser.parse = function(key,value,resultMap) { } resultMap[key] = v; } else { - console.log("src/xrfragment/Parser.hx:33:","[ i ] fragment '" + key + "' has incompatible value (" + value + ")"); + console.log("src/xrfragment/Parser.hx:34:","[ i ] fragment '" + key + "' has incompatible value (" + value + ")"); return false; } } else { - console.log("src/xrfragment/Parser.hx:34:","[ i ] fragment '" + key + "' does not exist or has no type defined (yet)"); + console.log("src/xrfragment/Parser.hx:35:","[ i ] fragment '" + key + "' does not exist or has no type defined (yet)"); return false; } return true; @@ -168,19 +265,26 @@ xrfragment_Parser.guessType = function(v,str) { }; var xrfragment_Value = function() { }; +xrfragment_Value.__name__ = true; var xrfragment_Type = function() { }; -var xrfragment_Query = function(str) { +xrfragment_Type.__name__ = true; +var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; + this.str = ""; if(str != null) { this.parse(str); } }; +xrfragment_Query.__name__ = true; xrfragment_Query.prototype = { - expandAliases: function(token) { + toObject: function() { + return this.q; + } + ,expandAliases: function(token) { var classAlias = new EReg("^(-)?\\.",""); if(classAlias.match(token)) { return StringTools.replace(token,".","class:"); @@ -262,8 +366,90 @@ xrfragment_Query.prototype = { this.q = q; return this.q; } + ,test: function(obj) { + var qualify = false; + var _g = 0; + var _g1 = Reflect.fields(obj); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var v = Std.string(Reflect.field(obj,k)); + if(this.testProperty(k,v)) { + qualify = true; + } + } + var _g = 0; + var _g1 = Reflect.fields(obj); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var v = Std.string(Reflect.field(obj,k)); + if(this.testProperty(k,v,true)) { + qualify = false; + } + } + return qualify; + } + ,testProperty: function(property,value,exclude) { + var conds = 0; + var fails = 0; + var qualify = 0; + var testprop = function(expr) { + conds += 1; + fails += expr ? 0 : 1; + return expr; + }; + if(this.q[value] != null) { + var v = this.q[value]; + if(v[property] != null) { + return v[property]; + } + } + var _g = 0; + var _g1 = Reflect.fields(this.q); + while(_g < _g1.length) { + var k = _g1[_g]; + ++_g; + var filter = Reflect.field(this.q,k); + if(filter.rules == null) { + continue; + } + var rules = filter.rules; + var _g2 = 0; + while(_g2 < rules.length) { + var rule = rules[_g2]; + ++_g2; + if(exclude) { + if(Reflect.field(rule,"!=") != null && testprop((value == null ? "null" : "" + value) == Std.string(Reflect.field(rule,"!="))) && exclude) { + ++qualify; + } + } else { + if(Reflect.field(rule,"*") != null && testprop(parseFloat(value) != null)) { + ++qualify; + } + if(Reflect.field(rule,">") != null && testprop(parseFloat(value) > parseFloat(Reflect.field(rule,">")))) { + ++qualify; + } + if(Reflect.field(rule,"<") != null && testprop(parseFloat(value) < parseFloat(Reflect.field(rule,"<")))) { + ++qualify; + } + if(Reflect.field(rule,">=") != null && testprop(parseFloat(value) >= parseFloat(Reflect.field(rule,">=")))) { + ++qualify; + } + if(Reflect.field(rule,"<=") != null && testprop(parseFloat(value) <= parseFloat(Reflect.field(rule,"<=")))) { + ++qualify; + } + if(Reflect.field(rule,"=") != null && (testprop(value == Reflect.field(rule,"=")) || testprop(parseFloat(value) == parseFloat(Reflect.field(rule,"="))))) { + ++qualify; + } + } + } + } + return qualify > 0; + } }; var xrfragment_URI = $hx_exports["xrfragment"]["URI"] = function() { }; +xrfragment_URI.__name__ = true; xrfragment_URI.parse = function(qs) { var fragment = qs.split("#"); var splitArray = fragment[1].split("&"); @@ -286,39 +472,14 @@ xrfragment_URI.parse = function(qs) { if(typeof(performance) != "undefined" ? typeof(performance.now) == "function" : false) { HxOverrides.now = performance.now.bind(performance); } +String.__name__ = true; +Array.__name__ = true; +js_Boot.__toStr = ({ }).toString; xrfragment_Parser.error = ""; xrfragment_Type.isColor = new EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$",""); xrfragment_Type.isInt = new EReg("^[0-9]+$",""); xrfragment_Type.isFloat = new EReg("^[0-9]+\\.[0-9]+$",""); xrfragment_Type.isVector = new EReg("([,]+|\\w)",""); -var xrfragment_Query_ok = $hx_exports["xrfragment"]["Query"]["ok"] = - // haxe workarounds - Array.prototype.contains = Array.prototype.includes - - if (typeof Array.prototype.remove !== "function") { - Array.prototype.remove = function (item) { - const oldLength = this.length - let newLength = 0 - - for (let i = 0; i < oldLength; i++) { - const entry = this[i] - if (entry === item) { - let newLength = i++ - - while (i !== this.length) { - const entry = this[i] - if (entry !== item) this[newLength++] = entry - i++ - } - - this.length = newLength - for (let i = newLength; i < oldLength; i++) delete this[i] - return true - } - } - return false - } - } - ; +xrfragment_Type.isString = new EReg(".*",""); })({}); var xrfragment = $hx_exports["xrfragment"]; diff --git a/dist/xrfragment.py b/dist/xrfragment.py index 9a793f6..79641b3 100644 --- a/dist/xrfragment.py +++ b/dist/xrfragment.py @@ -1299,8 +1299,8 @@ class xrfragment_Query: fails = 0 qualify = 0 def _hx_local_2(expr): - nonlocal fails - nonlocal conds + + conds = (conds + 1) fails = (fails + (0 if expr else 1)) return expr diff --git a/make b/make index ddcb8d3..b0cf39b 100755 --- a/make +++ b/make @@ -34,7 +34,8 @@ tests(){ doc(){ { echo "> version $VERSION" - echo "\ndate: $(date +"%Y-%m-%dT%H:%M:%S%z") (generated by \`./make doc\`)" + echo "\ndate: $(date +"%Y-%m-%dT%H:%M:%S%z") (generated by \`./make doc\`)\n" + echo "[![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions)\n" cat src/xrfragment/URI.hx cat src/xrfragment/Parser.hx } | awk ' @@ -56,5 +57,5 @@ doc(){ ' > doc/RFC.md } -test -z $1 && { try rm dist/* ; haxe build.hxml; exit $?; } +test -z $1 && { try rm dist/* ; haxe build.hxml; sed -i 's|.*nonlocal .*||g' dist/xrfragment.py; exit $?; } test -z $1 || "$@" diff --git a/src/spec/tmp.json b/src/spec/tmp.json deleted file mode 100644 index 271ba69..0000000 --- a/src/spec/tmp.json +++ /dev/null @@ -1,5 +0,0 @@ -[ - {"fn":"query","data":"tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":true}}, - {"fn":"query","data":"-tag:foo", "expect":{ "fn":"testProperty","input":["tag","foo"],"out":false}}, - {"fn":"query","data":"-tag:foo", "expect":{ "fn":"testPropertyExclude","input":["tag","foo"],"out":true}} -] diff --git a/src/xrfragment/Parser.hx b/src/xrfragment/Parser.hx index e4a2614..6ee9462 100644 --- a/src/xrfragment/Parser.hx +++ b/src/xrfragment/Parser.hx @@ -2,18 +2,18 @@ package xrfragment; @:expose // <- makes the class reachable from plain JavaScript @:keep // <- avoids accidental removal by dead code elimination - class Parser { // # XR Fragments (key/value params) public static var error:String = ""; // - // > ⛁ = supported in 3D asset-file (custom property or projection)
- // > ⚂ = supported in navigator URI (`document.location.href` e.g.)
+ // > ⛁ = define in 3D asset-file (as custom property or default projection)
+ // > ☇ = mutable, using navigator URI (`document.location.href` e.g.)
@:keep // public static function parse(key:String,value:String,resultMap:haxe.DynamicAccess):Bool { var Frag:Map = new Map(); // | param | type | scope(s) | category | notes | // |---------|---------------|-------|--------------------|---------------------------------| Frag.set("prio", Type.isInt); // | prio | int (-10..1) | ⛁ | Asset loading / linking | #include doc/notes/prio.md | - Frag.set("pos", Type.isVector); // | pos | 3D vector | ⛁ ⚂ |HREF navigation/portals | | + Frag.set("pos", Type.isVector); // | pos | 3D vector | ⛁ ☇ |HREF navigation/portals | | + Frag.set("q", Type.isString); // | q | string | ⛁ |Query Selector | | // // # XR Fragments parser if( Frag.exists(key) ){ // note: community parsers will prolly outperform this initial parser :) @@ -74,6 +74,7 @@ class Type { // static public var isInt:EReg = ~/^[0-9]+$/; // 1. integers are detected using regex `/^[0-9]+$/` static public var isFloat:EReg = ~/^[0-9]+\.[0-9]+$/; // 1. floats are detected using regex `/^[0-9]+\.[0-9]+$/` static public var isVector:EReg = ~/([,]+|\w)/; // 1. vectors are detected using regex `/[,]/` (but can also be an string referring to an entity-ID in the asset) + static public var isString:EReg = ~/.*/; // 1. anything else is string `/.*/` } // # Tests diff --git a/src/xrfragment/Query.hx b/src/xrfragment/Query.hx index 6a61824..c3fa92f 100644 --- a/src/xrfragment/Query.hx +++ b/src/xrfragment/Query.hx @@ -1,8 +1,6 @@ package xrfragment; -@:expose // <- makes the class reachable from plain JavaScript -@:keep // <- avoids accidental removal by dead code elimination - //return untyped __js__("window.location.search"); +//return untyped __js__("window.location.search"); #if js var ok:Bool = js.Syntax.code(' @@ -36,6 +34,8 @@ package xrfragment; '); #end +@:expose // <- makes the class reachable from plain JavaScript +@:keep // <- avoids accidental removal by dead code elimination class Query { private var str:String = ""; @@ -59,7 +59,6 @@ class Query { return classAlias.match(token) ? StringTools.replace(token,".","class:") : token; } - @:keep public function parse(str:String,recurse:Bool = false) : Dynamic { var token = str.split(" "); @@ -108,6 +107,7 @@ class Query { return this.q; } + @:keep public function test( ?obj:Dynamic ):Bool{ var qualify:Bool = false; // first apply includes, then excludes @@ -122,6 +122,7 @@ class Query { return qualify; } + @:keep public function testProperty( property:String, value:String, ?exclude:Bool ):Bool{ var conds:Int = 0; var fails:Int = 0; diff --git a/test/generated/test.js b/test/generated/test.js index d6fbb7b..9b5574a 100644 --- a/test/generated/test.js +++ b/test/generated/test.js @@ -1,7 +1,6 @@ var $hx_exports = typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this; (function ($global) { "use strict"; $hx_exports["xrfragment"] = $hx_exports["xrfragment"] || {}; -$hx_exports["xrfragment"]["Query"] = $hx_exports["xrfragment"]["Query"] || {}; var EReg = function(r,opt) { this.r = new RegExp(r,opt.split("u").join("")); }; @@ -285,6 +284,7 @@ xrfragment_Parser.parse = function(key,value,resultMap) { var Frag_h = Object.create(null); Frag_h["prio"] = xrfragment_Type.isInt; Frag_h["pos"] = xrfragment_Type.isVector; + Frag_h["q"] = xrfragment_Type.isString; if(Object.prototype.hasOwnProperty.call(Frag_h,key)) { if(Frag_h[key].match(value)) { var v = new xrfragment_Value(); @@ -303,11 +303,11 @@ xrfragment_Parser.parse = function(key,value,resultMap) { } resultMap[key] = v; } else { - console.log("src/xrfragment/Parser.hx:33:","[ i ] fragment '" + key + "' has incompatible value (" + value + ")"); + console.log("src/xrfragment/Parser.hx:34:","[ i ] fragment '" + key + "' has incompatible value (" + value + ")"); return false; } } else { - console.log("src/xrfragment/Parser.hx:34:","[ i ] fragment '" + key + "' does not exist or has no type defined (yet)"); + console.log("src/xrfragment/Parser.hx:35:","[ i ] fragment '" + key + "' does not exist or has no type defined (yet)"); return false; } return true; @@ -341,19 +341,23 @@ var xrfragment_Value = function() { xrfragment_Value.__name__ = true; var xrfragment_Type = function() { }; xrfragment_Type.__name__ = true; -var xrfragment_Query = function(str) { +var xrfragment_Query = $hx_exports["xrfragment"]["Query"] = function(str) { this.isNumber = new EReg("^[0-9\\.]+$",""); this.isClass = new EReg("^[-]?class$",""); this.isExclude = new EReg("^-",""); this.isProp = new EReg("^.*:[><=!]?",""); this.q = { }; + this.str = ""; if(str != null) { this.parse(str); } }; xrfragment_Query.__name__ = true; xrfragment_Query.prototype = { - expandAliases: function(token) { + toObject: function() { + return this.q; + } + ,expandAliases: function(token) { var classAlias = new EReg("^(-)?\\.",""); if(classAlias.match(token)) { return StringTools.replace(token,".","class:"); @@ -550,35 +554,7 @@ xrfragment_Type.isColor = new EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$",""); xrfragment_Type.isInt = new EReg("^[0-9]+$",""); xrfragment_Type.isFloat = new EReg("^[0-9]+\\.[0-9]+$",""); xrfragment_Type.isVector = new EReg("([,]+|\\w)",""); -var xrfragment_Query_ok = $hx_exports["xrfragment"]["Query"]["ok"] = - // haxe workarounds - Array.prototype.contains = Array.prototype.includes - - if (typeof Array.prototype.remove !== "function") { - Array.prototype.remove = function (item) { - const oldLength = this.length - let newLength = 0 - - for (let i = 0; i < oldLength; i++) { - const entry = this[i] - if (entry === item) { - let newLength = i++ - - while (i !== this.length) { - const entry = this[i] - if (entry !== item) this[newLength++] = entry - i++ - } - - this.length = newLength - for (let i = newLength; i < oldLength; i++) delete this[i] - return true - } - } - return false - } - } - ; +xrfragment_Type.isString = new EReg(".*",""); Test.main(); })({}); var xrfragment = $hx_exports["xrfragment"]; diff --git a/test/generated/test.py b/test/generated/test.py index 43c88d1..c1480e3 100644 --- a/test/generated/test.py +++ b/test/generated/test.py @@ -1370,6 +1370,7 @@ class xrfragment_Parser: Frag = haxe_ds_StringMap() Frag.h["prio"] = xrfragment_Type.isInt Frag.h["pos"] = xrfragment_Type.isVector + Frag.h["q"] = xrfragment_Type.isString if (key in Frag.h): _this = Frag.h.get(key,None) _this.matchObj = python_lib_Re.search(_this.pattern,value) @@ -1441,7 +1442,7 @@ class xrfragment_Value: class xrfragment_Type: _hx_class_name = "xrfragment.Type" __slots__ = () - _hx_statics = ["isColor", "isInt", "isFloat", "isVector"] + _hx_statics = ["isColor", "isInt", "isFloat", "isVector", "isString"] class xrfragment_Query: @@ -1579,8 +1580,8 @@ class xrfragment_Query: fails = 0 qualify = 0 def _hx_local_2(expr): - nonlocal fails nonlocal conds + nonlocal fails conds = (conds + 1) fails = (fails + (0 if expr else 1)) return expr @@ -1661,5 +1662,6 @@ xrfragment_Type.isColor = EReg("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$","") xrfragment_Type.isInt = EReg("^[0-9]+$","") xrfragment_Type.isFloat = EReg("^[0-9]+\\.[0-9]+$","") xrfragment_Type.isVector = EReg("([,]+|\\w)","") +xrfragment_Type.isString = EReg(".*","") Test.main() diff --git a/test/test.js b/test/test.js index 54e5ab2..016c6cf 100644 --- a/test/test.js +++ b/test/test.js @@ -1,28 +1,18 @@ // in the browser use this instead of require(): // -// +// // -var hgltf = require('../Query').hgltf -var q = new hgltf.Query() +var XF = require('../dist/xrfragment').xrfragment +let print = (e) => console.log( JSON.stringify(e, null, 1) + "\n" ) -var res = q.parse("") -if( !res.copy_all ) throw 'empty string should always set copy_all to true' +print( XF.URI.parse('://foo.com/1.gltf#pos=1,2,3&q=-.foo') ); -console.log( q.parse("") ) -console.log( JSON.stringify(q.parse("foo:*"), null, 2) ) -return -console.log( q.parse("-skybox -plane") ) -console.log( q.parse("foo or bar") ); -console.log( q.parse("class:fopoer or bar foo:bar").or[0] ); -console.log( q.parse("-skybox class:foo").or[0] ); -console.log( q.parse("foo/flop moo or bar").or[0] ); -console.log( q.parse("-foo/flop moo or bar").or[0] ); -console.log( q.parse("price:>4 moo or bar").or[0] ); -console.log( q.parse("price:>=4 moo or bar").or[0] ); -console.log( q.parse("price:<=4 moo or bar").or[0] ); -console.log( q.parse("price:!=4 moo or bar").or[0] ); +// query +let q = new XF.Query(); +print( q.parse("-.foo -plane") ) +print( q.parse("price:>2") ) diff --git a/test/test.lua b/test/test.lua index 193c0bc..b2af12d 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1 +1 @@ -require "../Query" +#XR = require("../dist/xrfragment") diff --git a/test/test.py b/test/test.py index 9874790..52596b9 100644 --- a/test/test.py +++ b/test/test.py @@ -1,14 +1,7 @@ -from Query import hgltf_Query +# PYTHONPATH=./dist python test/test.py -q = hgltf_Query() +from xrfragment import xrfragment_Query -print( q.parse("foo or bar") ) -print( q.parse("foo or bar") ) -print( q.parse("class:fopoer or bar foo:bar") ) -print( q.parse("-skybox class:foo") ) -print( q.parse("foo/flop moo or bar") ) -print( q.parse("-foo/flop moo or bar") ) -print( q.parse("price:>4 moo or bar") ) -print( q.parse("price:>=4 moo or bar") ) -print( q.parse("price:<=4 moo or bar") ) -print( q.parse("price:!=4 moo or bar") ) +q = xrfragment_Query(".foo") + +print( q.toObject() )