diff --git a/dist/xrfragment.aframe.js b/dist/xrfragment.aframe.js index 574432b..cb29f96 100644 --- a/dist/xrfragment.aframe.js +++ b/dist/xrfragment.aframe.js @@ -260,6 +260,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/dist/xrfragment.js b/dist/xrfragment.js index bbf0d14..8374a5f 100644 --- a/dist/xrfragment.js +++ b/dist/xrfragment.js @@ -260,6 +260,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/dist/xrfragment.lua b/dist/xrfragment.lua index 4f27671..b315695 100644 --- a/dist/xrfragment.lua +++ b/dist/xrfragment.lua @@ -1622,6 +1622,9 @@ __xrfragment_Parser.parse = function(key,value,store) __haxe_Log.trace(Std.string(Std.string(Std.string("✔ ") .. Std.string(key)) .. Std.string(": ")) .. Std.string(v.string), _hx_o({__fields__={fileName=true,lineNumber=true,className=true,methodName=true},fileName="src/xrfragment/Parser.hx",lineNumber=83,className="xrfragment.Parser",methodName="parse"})); end; else + if (__lua_Boot.__instanceof(value, String)) then + v:guessType(v, value); + end; store[Std.string("_") .. Std.string(key)] = v; end; do return true end; diff --git a/dist/xrfragment.module.js b/dist/xrfragment.module.js index f1c57c1..d69b3ed 100644 --- a/dist/xrfragment.module.js +++ b/dist/xrfragment.module.js @@ -260,6 +260,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/dist/xrfragment.py b/dist/xrfragment.py index d0f5b32..8c1d970 100644 --- a/dist/xrfragment.py +++ b/dist/xrfragment.py @@ -1334,6 +1334,8 @@ class xrfragment_Parser: if xrfragment_Parser.debug: print(str(((("✔ " + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string)))) else: + if Std.isOfType(value,str): + v.guessType(v,value) key1 = ("_" + ("null" if key is None else key)) setattr(store,(("_hx_" + key1) if ((key1 in python_Boot.keywords)) else (("_hx_" + key1) if (((((len(key1) > 2) and ((ord(key1[0]) == 95))) and ((ord(key1[1]) == 95))) and ((ord(key1[(len(key1) - 1)]) != 95)))) else key1)),v) return True diff --git a/dist/xrfragment.three.js b/dist/xrfragment.three.js index f6ae44b..392bd0b 100644 --- a/dist/xrfragment.three.js +++ b/dist/xrfragment.three.js @@ -260,6 +260,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/dist/xrfragment.three.module.js b/dist/xrfragment.three.module.js index 985c8ac..a48f216 100644 --- a/dist/xrfragment.three.module.js +++ b/dist/xrfragment.three.module.js @@ -260,6 +260,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/src/xrfragment/Parser.hx b/src/xrfragment/Parser.hx index 477c37f..a12715e 100644 --- a/src/xrfragment/Parser.hx +++ b/src/xrfragment/Parser.hx @@ -54,14 +54,17 @@ class Parser { Frag.set("session", XRF.ASSET | XRF.T_URL | XRF.PV_OVERRIDE | XRF.NAVIGATOR | XRF.EMBEDDED | XRF.PROMPT ); /** - * # XR Fragments parser + * # Spec * - * > icanhazcode? yes, see [Parser.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Parser.hx) - * the gist of it: + * > version 1.0.0 [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z") + * + * In case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec: */ + // 1. requirement: receive arguments: key (string), value (string), store (writable associative array/object) + // dynamic fragments cases: predefined views & assign/binds - if( value.length == 0 && key.length > 0 && !Frag.exists(key) ){ + if( value.length == 0 && key.length > 0 && !Frag.exists(key) ){ // 1. add keys without values to store as [predefined view](predefined_view) var v:XRF = new XRF(key, XRF.PV_EXECUTE | XRF.NAVIGATOR ); v.validate(key); // will fail but will parse multiple args for us (separated by |) store.set(key, v ); @@ -75,13 +78,14 @@ class Parser { // regular fragments: var v:XRF = new XRF(key, Frag.get(key)); if( Frag.exists(key) ){ // 1. check if fragment is official XR Fragment - if( !v.validate(value) ){ + if( !v.validate(value) ){ // 1. guess the type of the value (string,int,float,x,y,z,color,args,query) trace("⚠ fragment '"+key+"' has incompatible value ("+value+")");// 1. don't add to store if value-type is incorrect return false; } store.set(key, v ); // 1. if valid, add to store if( debug ) trace("✔ "+key+": "+v.string); }else{ // 1. prefix non-offical fragment key's with underscore (and add to store) + if( Std.isOfType(value, String) ) v.guessType(v,value); store.set("_"+key,v); } @@ -90,7 +94,11 @@ class Parser { } +/** + * > icanhazcode? yes, see [Parser.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Parser.hx) + * + * # Tests + * + * the spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages. + */ -/// # Tests -/// -/// the spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages. diff --git a/src/xrfragment/Query.hx b/src/xrfragment/Query.hx index 70d7a09..4030963 100644 --- a/src/xrfragment/Query.hx +++ b/src/xrfragment/Query.hx @@ -40,13 +40,23 @@ package xrfragment; @:keep // <- avoids accidental removal by dead code elimination class Query { + /** + * # Spec + * + * > version 1.0.0 [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z") + * + * In case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Query.parse(str)` using the spec: + */ + + // 1. requirement: receive arguments: query (string) + private var str:String = ""; - private var q:haxe.DynamicAccess = {}; - private var isProp:EReg = ~/^.*:[><=!]?/; - private var isExclude:EReg = ~/^-/; - private var isRoot:EReg = ~/^[-]?\//; - private var isClass:EReg = ~/^[-]?class$/; - private var isNumber:EReg = ~/^[0-9\.]+$/; + private var q:haxe.DynamicAccess = {}; // 1. create an associative array/object to store query-arguments as objects + private var isProp:EReg = ~/^.*:[><=!]?/; // 1. detect object id's & properties `foo:1` and `foo` (reference regex: `/^.*:[><=!]?/` ) + private var isExclude:EReg = ~/^-/; // 1. detect excluders like `-foo`,`-foo:1`,`-.foo`,`-/foo` (reference regex: `/^-/` ) + private var isRoot:EReg = ~/^[-]?\//; // 1. detect root selectors like `/foo` (reference regex: `/^[-]?\//` ) + private var isClass:EReg = ~/^[-]?class$/; // 1. detect class selectors like `.foo` (reference regex: `/^[-]?class$/` ) + private var isNumber:EReg = ~/^[0-9\.]+$/; // 1. detect number values like `foo:1` (reference regex: `/^[0-9\.]+$/` ) public function new(str:String){ if( str != null ) this.parse(str); @@ -59,7 +69,7 @@ class Query { public function expandAliases(token:String) : String { // expand '.foo' to 'class:foo' var classAlias = ~/^(-)?\./; - return classAlias.match(token) ? StringTools.replace(token,".","class:") : token; + return classAlias.match(token) ? StringTools.replace(token,".","class:") : token; // 1. expand aliases like `.foo` into `class:foo` } public function get() : Dynamic { @@ -73,24 +83,23 @@ class Query { function process(str,prefix = ""){ str = StringTools.trim(str); - var k:String = str.split(":")[0]; + var k:String = str.split(":")[0]; // 1. for every query token split string on `:` var v:String = str.split(":")[1]; // retrieve existing filter if any var filter:haxe.DynamicAccess = {}; if( q.get(prefix+k) ) filter = q.get(prefix+k); - filter['rules'] = filter['rules'] != null ? filter['rules'] : new Array(); + filter['rules'] = filter['rules'] != null ? filter['rules'] : new Array(); // 1. create an empty array `rules` - if( isProp.match(str) ){ + if( isProp.match(str) ){ // 1. WHEN when a `:` key/value is detected: var oper:String = ""; - if( str.indexOf("*") != -1 ) oper = "*"; - if( str.indexOf(">") != -1 ) oper = ">"; - if( str.indexOf("<") != -1 ) oper = "<"; - if( str.indexOf(">=") != -1 ) oper = ">="; - if( str.indexOf("<=") != -1 ) oper = "<="; - if( isExclude.match(k) ){ + if( str.indexOf("*") != -1 ) oper = "*"; // 1. then scan for `*` operator (means include all objects for [src](#src) embedded fragment) + if( str.indexOf(">") != -1 ) oper = ">"; // 1. then scan for `>` operator + if( str.indexOf("<") != -1 ) oper = "<"; // 1. then scan for `<` operator + if( str.indexOf(">=") != -1 ) oper = ">="; // 1. then scan for `>=` operator + if( str.indexOf("<=") != -1 ) oper = "<="; // 1. then scan for `<=` operator oper = "!="; - k = k.substr(1); // convert "-foo" into "foo" - }else v = v.substr(oper.length); // change ">=foo" into "foo" (strip operator) + k = k.substr(1); // 1. then strip key-operator: convert "-foo" into "foo" + }else v = v.substr(oper.length); // 1. then strip value operator: change value ">=foo" into "foo" if( oper.length == 0 ) oper = "="; if( isClass.match(k) ){ filter[ prefix+ k ] = oper != "!="; @@ -99,16 +108,16 @@ class Query { var rule:haxe.DynamicAccess = {}; if( isNumber.match(v) ) rule[ oper ] = Std.parseFloat(v); else rule[oper] = v; - filter['rules'].push( rule ); + filter['rules'].push( rule ); // 1. add operator and value to rule-array q.set( k, filter ); } return; - }else{ // id - filter[ "id" ] = isExclude.match(str) ? false: true; - filter[ "root" ] = isRoot.match(str) ? true: false; + }else{ // 1. ELSE we are dealing with an object + filter[ "id" ] = isExclude.match(str) ? false: true; // 1. therefore we we set `id` to `true` or `false` (false=excluder `-`) + filter[ "root" ] = isRoot.match(str) ? true: false; // 1. and we set `root` to `true` or `false` (true=`/` root selector is present) if( isExclude.match(str) ) str = str.substr(1); // convert '-foo' into 'foo' - if( isRoot.match(str) ) str = str.substr(1); // convert '/foo' into 'foo' - q.set( str ,filter ); + if( isRoot.match(str) ) str = str.substr(1); // 1. we convert key '/foo' into 'foo' + q.set( str ,filter ); // 1. finally we add the key/value to the store (`store.foo = {id:false,root:true}` e.g.) } } for( i in 0...token.length ) process( expandAliases(token[i]) ); @@ -174,3 +183,10 @@ class Query { return qualify > 0; } } +/** + * > icanhazcode? yes, see [Parser.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/Query.hx) + * + * # Tests + * + * the spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages. + */ diff --git a/src/xrfragment/URI.hx b/src/xrfragment/URI.hx index d95bdb1..8907fe8 100644 --- a/src/xrfragment/URI.hx +++ b/src/xrfragment/URI.hx @@ -6,38 +6,27 @@ import xrfragment.Parser; import xrfragment.XRF; /** - * - * + * # Spec * - * > version 1.0.0 - * - * date: $(date +"%Y-%m-%dT%H:%M:%S%z") (generated by \`./make doc\`)
- * [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) - * - * # XRFragment Grammar + * > version 1.0.0 [![Actions Status](https://github.com/coderofsalvation/xrfragment/workflows/test/badge.svg)](https://github.com/coderofsalvation/xrfragment/actions) generated by `make doc` @ $(date +"%Y-%m-%dT%H:%M:%S%z") + * + * ### XR Fragment URI Grammar * * ``` * reserved = gen-delims / sub-delims * gen-delims = "#" / "&" - * sub-delims = "," / "|" / "=" + * sub-delims = "," / "=" * ``` - *
* * > Example: `://foo.com/my3d.asset#pos=1,0,0&prio=-5&t=0,100|100,200` * - *
- * * | Explanation | | * |-|-| - * | `x=1,2,3` | vector/coordinate argument e.g. | - * | `x=foo\|bar|1,2,3|1.0` | the `\|` character is used for:
1.specifying `n` arguments for xrfragment `x`
2. roundrobin of values (in case provided arguments exceeds `n` of `x` for #1) when triggered by browser URI (clicking `href` e.g.)| - * | `https://x.co/1.gltf||xyz://x.co/1.gltf` | multi-protocol/fallback urls | - * | `.mygroup` | query-alias for `class:mygroup` | + * | `pos=1,2,3` | vector/coordinate argument e.g. | + * | `pos=1,2,3&rot=0,90,0&q=.foo` | combinators | * - * > Focus: hasslefree 3D vector-data (`,`), multi-protocol/fallback-linking & dynamic values (`|`), and CSS-piggybacking (`.mygroup`) + * In case your programming language has no parser ([check here](https://github.com/coderofsalvation/xrfragment/tree/main/dist)) you can [crosscompile it](https://github.com/coderofsalvation/xrfragment/blob/main/build.hxml), or roll your own `Parser.parse(k,v,store)` using the spec: * - * # URI parser - * > icanhazcode? yes, see [URI.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/URI.hx) */ @:expose // <- makes the class reachable from plain JavaScript @@ -45,7 +34,7 @@ import xrfragment.XRF; class URI { @:keep public static function parse(url:String,filter:Int):haxe.DynamicAccess { - var store:haxe.DynamicAccess = {}; // 1. store key/values into a associative array or dynamic object + var store:haxe.DynamicAccess = {}; // 1. store key/values into a associative array or dynamic object if( url == null || url.indexOf("#") == -1 ) return store; var fragment:Array = url.split("#"); // 1. fragment URI starts with `#` var splitArray:Array = fragment[1].split('&'); // 1. fragments are split by `&` @@ -58,7 +47,7 @@ class URI { if (splitByEqual.length > 1) { value = StringTools.urlDecode(regexPlus.split(splitByEqual[1]).join(" ")); } - var ok:Bool = Parser.parse(key,value,store); // 1. every recognized fragment key/value-pair is added to a central map/associative array/object + var ok:Bool = Parser.parse(key,value,store); // 1. for every recognized fragment key/value-pair call [Parser.parse](#%E2%86%AA%20Parser.parse%28k%2Cv%2Cstore%29) } if( filter != null && filter != 0 ){ for (key in store.keys()) { @@ -71,3 +60,11 @@ class URI { return store; } } + +/** + * > icanhazcode? yes, see [URI.hx](https://github.com/coderofsalvation/xrfragment/blob/main/src/xrfragment/URI.hx) + * + * # Tests + * + * the spec is tested with [JSON unittests](./../src/spec) consumed by [Test.hx](./../src/Test.hx) to cross-test all languages. + */ diff --git a/test/generated/test.js b/test/generated/test.js index 1b5d0cd..5562b22 100644 --- a/test/generated/test.js +++ b/test/generated/test.js @@ -374,6 +374,9 @@ xrfragment_Parser.parse = function(key,value,store) { console.log("src/xrfragment/Parser.hx:83:","✔ " + key + ": " + v.string); } } else { + if(typeof(value) == "string") { + v.guessType(v,value); + } store["_" + key] = v; } return true; diff --git a/test/generated/test.py b/test/generated/test.py index 2cfbb97..9dcefea 100644 --- a/test/generated/test.py +++ b/test/generated/test.py @@ -1451,6 +1451,8 @@ class xrfragment_Parser: if xrfragment_Parser.debug: print(str(((("✔ " + ("null" if key is None else key)) + ": ") + HxOverrides.stringOrNull(v.string)))) else: + if Std.isOfType(value,str): + v.guessType(v,value) key1 = ("_" + ("null" if key is None else key)) setattr(store,(("_hx_" + key1) if ((key1 in python_Boot.keywords)) else (("_hx_" + key1) if (((((len(key1) > 2) and ((ord(key1[0]) == 95))) and ((ord(key1[1]) == 95))) and ((ord(key1[(len(key1) - 1)]) != 95)))) else key1)),v) return True @@ -1606,8 +1608,8 @@ class xrfragment_Query: fails = 0 qualify = 0 def _hx_local_2(expr): - nonlocal conds nonlocal fails + nonlocal conds conds = (conds + 1) fails = (fails + (0 if expr else 1)) return expr