2023-05-23 11:30:39 +02:00
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 Leon van Kammen/NLNET
2023-04-14 14:45:50 +02:00
package xrfragment ;
2023-04-28 14:27:30 +02:00
@ : expose // <- makes the class reachable from plain JavaScript
@ : keep // <- avoids accidental removal by dead code elimination
2023-04-14 14:45:50 +02:00
class XRF {
/ *
* this class r e p r e s e n t s a f r a g m e n t ( v a l u e )
* /
// public static inline readonly ASSET
2023-04-14 17:37:33 +02:00
// scope types (powers of 2)
2023-04-28 17:16:13 +02:00
public static var ASSET: Int = 1 ; // fragment is immutable
public static var PROP_BIND: Int = 2 ; // fragment binds/controls one property with another
2023-11-10 18:22:47 +01:00
public static var QUERY_OPERATOR: Int = 4 ; // fragment will be applied to result of filterselecto
2023-04-28 17:16:13 +02:00
public static var PROMPT: Int = 8 ; // ask user whether this fragment value can be changed
public static var ROUNDROBIN: Int = 16 ; // evaluation of this (multi) value can be roundrobined
2023-06-22 08:48:52 +02:00
public static var NAVIGATOR: Int = 32 ; // fragment can be overridden by (manual) browser URI change
2023-08-15 18:27:26 +02:00
public static var METADATA: Int = 64 ; // fragment can be overridden by an embedded URL
2023-06-22 08:48:52 +02:00
public static var PV_OVERRIDE: Int = 128 ; // embedded fragment can be overridden when specified in predefined view value
public static var PV_EXECUTE: Int = 256 ; // predefined view
2023-04-14 15:19:52 +02:00
2023-04-14 17:37:33 +02:00
// high-level value-types (powers of 2)
2023-04-28 17:16:13 +02:00
public static var T_COLOR: Int = 8192 ;
public static var T_INT: Int = 16384 ;
public static var T_FLOAT: Int = 32768 ;
public static var T_VECTOR2: Int = 65536 ;
public static var T_VECTOR3: Int = 131072 ;
public static var T_URL: Int = 262144 ;
public static var T_PREDEFINED_VIEW: Int = 524288 ;
public static var T_STRING: Int = 1048576 ;
public static var T_STRING_OBJ: Int = 2097152 ;
public static var T_STRING_OBJ_PROP: Int = 4194304 ;
2023-04-14 14:45:50 +02:00
// regexes
public static var isColor: EReg = ~/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/ ; // 1. hex colors are detected using regex `/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/`
2023-10-30 16:15:08 +01:00
public static var isInt: EReg = ~/^[-0-9]+$/ ; // 1. integers are detected using regex `/^[0-9]+$/`
public static var isFloat: EReg = ~/^[-0-9]+\.[0-9]+$/ ; // 1. floats are detected using regex `/^[0-9]+\.[0-9]+$/`
2023-04-14 14:45:50 +02:00
public static var isVector: EReg = ~/([,]+|\w)/ ; // 1. vectors are detected using regex `/[,]/` (but can also be an string referring to an entity-ID in the asset)
public static var isUrl: EReg = ~/(:\/\/)?\..*/ ; // 1. url/file */`
public static var isUrlOrPretypedView: EReg = ~/(^#|:\/\/)?\..*/ ; // 1. url/file */`
public static var isString: EReg = ~/.*/ ; // 1. anything else is string `/.*/`
// value holder(s) // |------|------|--------|----------------------------------|
public var fragment: String ;
public var flags: Int ;
2023-11-16 14:50:57 +01:00
public var index: Int ;
2023-04-14 14:45:50 +02:00
public var x: Float ; // |vector| x,y,z| comma-separated | #pos=1,2,3 |
public var y: Float ;
public var z: Float ;
2023-10-26 13:19:03 +02:00
public var w: Float ;
2023-04-14 14:45:50 +02:00
public var color: String ; // |string| color| FFFFFF (hex) | #fog=5m,FFAACC |
public var string: String ; // |string| | | #q=-sun |
public var int: Int ; // |int | | [-]x[xxxxx] | #price:>=100 |
public var float: Float ; // |float | | [-]x[.xxxx] (ieee)| #prio=-20 |
2023-11-10 18:22:47 +01:00
public var filter: Filter ;
2023-09-14 10:21:16 +02:00
public var noXRF: Bool ;
2023-04-14 14:45:50 +02:00
//
2023-11-16 14:50:57 +01:00
public function n e w ( _fragment : String , _flags : Int , ? _index : Int ) {
2023-04-14 14:45:50 +02:00
fragment = _fragment ;
flags = _flags ;
2023-11-16 14:50:57 +01:00
index = _index ;
2023-04-14 14:45:50 +02:00
}
public function is ( flag : Int ) : Bool {
2023-10-30 16:15:08 +01:00
if ( ! Std . isOfType ( flags , Int ) ) flags = 0 ;
2023-04-14 14:45:50 +02:00
return ( flags & flag ) != 0 ;
}
public static function set ( flag : Int , flags : Int ) : Int {
return flags | flag ;
}
public static function unset ( flag : Int , flags : Int ) : Int {
return flags & ~ flag ;
}
public function validate ( value : String ) : Bool {
guessType ( this , value ) ; // 1. extract the type
// validate
var ok: Bool = true ;
2023-10-30 16:15:08 +01:00
if ( ! is ( T_FLOAT ) && is ( T_VECTOR2 ) && ! ( Std . isOfType ( x , Float ) && Std . isOfType ( y , Float ) ) ) ok = false ;
if ( ! is ( T_VECTOR2 ) && is ( T_VECTOR3 ) && ! ( Std . isOfType ( x , Float ) && Std . isOfType ( y , Float ) && Std . isOfType ( z , Float ) ) ) ok = false ;
2023-04-14 14:45:50 +02:00
return ok ;
}
@ : keep
public function guessType ( v : XRF , str : String ) : Void {
v . string = str ;
2023-11-10 18:22:47 +01:00
if ( ! Std . isOfType ( str , String ) ) return ;
if ( str . length > 0 ) {
if ( str . split ( " , " ) . length > 1 ) { // 1. `,` assumes 1D/2D/3D vector-values like x[,y[,z]]
var xyzw: Array < String > = str . split ( " , " ) ; // 1. parseFloat(..) and parseInt(..) is applied to vector/float and int values
if ( xyzw . length > 0 ) v . x = Std . parseFloat ( xyzw [ 0 ] ) ; // 1. anything else will be treated as string-value
if ( xyzw . length > 1 ) v . y = Std . parseFloat ( xyzw [ 1 ] ) ; // 1. incompatible value-types will be dropped / not used
if ( xyzw . length > 2 ) v . z = Std . parseFloat ( xyzw [ 2 ] ) ; //
if ( xyzw . length > 3 ) v . w = Std . parseFloat ( xyzw [ 3 ] ) ; //
} // > the xrfragment specification should stay simple enough
// > for anyone to write a parser using either regexes or grammar/lexers
if ( isColor . match ( str ) ) v . color = str ; // > therefore expressions/comprehensions are not supported (max wildcard/comparison operators for queries e.g.)
if ( isFloat . match ( str ) ) {
v . x = Std . parseFloat ( str ) ;
v . float = v . x ;
}
if ( isInt . match ( str ) ) {
v . int = Std . parseInt ( str ) ;
v . x = cast ( v . int ) ;
}
2023-11-16 14:50:57 +01:00
v . filter = new Filter ( v . fragment + " = " + v . string ) ;
} e lse v . filter = new Filter ( v . fragment ) ;
2023-04-14 14:45:50 +02:00
}
}