Help with plugin configuration parser (deep parse)

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
I have been tinkering around with an all-in-one function that will perform a deep parse on the stored JSON plugin configuration as well as apply default values to any property that is blank. What I have come up with does work, but I cannot help but think that my code could be improved upon. However, I have been staring at the code for so long, I cannot come up with anything. So, if anyone has any free time to check my code out and perhaps offer some feedback, that would be great!

You can find the code here : Deep JSON Configuration Parser
Or here : Deep JSON Configuration Parser
 
Last edited:

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,455
Reaction score
2,994
First Language
Binary
Primarily Uses
RMMZ
the '\' characters are hurting my brain.

you could be using es6 arrow function format for your callbacks, then you wouldnt need to store reference to 'self'.

you dont break; 'when array' at line 47, assume thats not intentional?

cant see much else atm :)
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
the '\' characters are hurting my brain.
Yeah ... the JSON'ed parameters are a bit extreme, heh. But I wanted to make certain the parser worked on a deep parse.



you could be using es6 arrow function format for your callbacks, then you wouldnt need to store reference to 'self'.
Unfortunately that would change the scope, and I would not be able to change the name of the parsed key. Typically a key is comprised of the name and the type of the property (e.g - myProperty__string). In the process of parsing the value of the property, I split the key at the double-underscores and re-name the key (e.g - let [_key, _type, _fnc]= 'myProperty__string'.split('__'); this[_key] = value;). To do that, I need 'this' to retain its original scope.

At least, with how the code is written now.



you dont break; 'when array' at line 47, assume thats not intentional?
Actually that is intentional. Since there is nothing going on in the 'string' entry, I save a line (whee) and let the next break exit out of the switch.
 

??????

Diabolical Codemaster
Veteran
Joined
May 11, 2012
Messages
6,455
Reaction score
2,994
First Language
Binary
Primarily Uses
RMMZ
fair enough then :)
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
Baaah ... I am going to be forever tinkering with this confounded function, heh.
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
523
Reaction score
230
First Language
English
Primarily Uses
RMMV
I don't really get what this is supposed to do...
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
@Solar_Flare Ah, well, basically if you have a plugin that has nested structs :

Code:
 * @param headerPluginOptions
 * @text Plugin Options
 * @type text
 * @default ------------------------------------
 *
 * @param testStruct__array
 * @text Struct Test
 * @desc 
 * @parent headerPluginOptions
 * @type struct<structLevelA>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @parent headerPluginOptions
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @parent headerPluginOptions
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @parent headerPluginOptions
 * @type boolean
 *
 * @param headerPluginProperties
 * @text Plugin Data
 * @type text
 * @default ------------------------------------
 *
 * @param gid
 * @text Global Identifier
 * @desc Global identification tag for internal use only. Do not change.
 * @parent headerPluginProperties
 * @default ossra-zO9wKkOE7HpTupE
 *
 */
// +===================================================|                        Structs |
// | [Plugin] Structs
// +====================================================================================+
/*~struct~structLevelA:
 * @param structTestA__array
 * @text Struct Test A
 * @desc 
 * @type struct<structLevelB>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
/*~struct~structLevelB:
 * @param structTestB__array
 * @text Struct Test B
 * @desc 
 * @type struct<structLevelC>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
/*~struct~structLevelC:
 * @param structTestC__array
 * @text Struct Test C
 * @desc 
 * @type struct<structLevelD>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
/*~struct~structLevelD:
 * @param structTestD__array
 * @text Struct Test D
 * @desc 
 * @type struct<structLevelE>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
/*~struct~structLevelE:
 * @param structTestE__array
 * @text Struct Test E
 * @desc 
 * @type struct<structLevelF>[]
 *
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
/*~struct~structLevelF:
 * @param testNumber__number
 * @text Test Number
 * @desc 
 * @type number
 * @default 125
 *
 * @param testString__string
 * @text Test String
 * @desc 
 * @type text
 *
 * @param testBool__boolean
 * @text Test Boolean
 * @desc 
 * @type boolean
 */
// +====================================================================================+

You have to perform a deep parse on all of the values. And since I am performing a deep parse on all of the values anyway, I may as well integrate the default values of each property at the same time. So, I created the function in the first post to do that. Parse all values, and if the value of a property is not present, place the default value there so I do not have to do so later on.

You can specify a default value of a struct in the plugin, of course. But once you start to nest structs, the value is rather lengthy and looks quite ugly. Plus, if the user somehow clears that default value, I want a fall-back value within the plugin itself.
 

Solar_Flare

Veteran
Veteran
Joined
Jun 6, 2020
Messages
523
Reaction score
230
First Language
English
Primarily Uses
RMMV
@Solar_Flare Ah, well, basically if you have a plugin that has nested structs :

<--snip-->

You have to perform a deep parse on all of the values.
Yes, this I was aware of, just didn't understand how your code actually does that...

And since I am performing a deep parse on all of the values anyway, I may as well integrate the default values of each property at the same time. So, I created the function in the first post to do that. Parse all values, and if the value of a property is not present, place the default value there so I do not have to do so later on.
Where do you get the default property from? As far as I know, the only way to do that is by parsing the plugin file to extract it from the comment...

The main thing I dislike from reading over your code (other than the ES6 style) is the apparent use of magic keys to specify the type of a parameter.
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
Yes, this I was aware of, just didn't understand how your code actually does that...
Ah, sorry about that.



Where do you get the default property from? As far as I know, the only way to do that is by parsing the plugin file to extract it from the comment...
I sort of extracted the class, function, and variables normally used when parsing plugin parameters so that the focus could be on the parsing function. Probably would have been better to share the framework and a small plugin to provide some context :

Framework
Plugin

The defaults are set in the initial part of the plugin and then passed to the parser when the 'setup' function is called.


The main thing I dislike from reading over your code (other than the ES6 style) is the apparent use of magic keys to specify the type of a parameter.
Yeah ... since I was using that format to include the usage of 'helper' functions during the parsing process anyway, I decided to use them on all of the other properties as well. For instance, naming a property as 'myPropertyName__function__getColor' will call the function 'getColor' while parsing. The key is re-named in the process, so when I access that property within a plugin I would only need to type 'myPropertyName'.

The code for a typical deep parser would be smaller and nicer to look at, but I wanted to incorporate setting defaults and running helper functions to keep the code dealing with all of that in a plugin to a minimum.



ES6 looks so clean and neat, though ... D;
 

LTN Games

Code Sorcerer
Veteran
Joined
Jun 25, 2015
Messages
700
Reaction score
623
First Language
English
Primarily Uses
RMMV
This should do it for you, if you want defaults, you can just check if the value === '' and return null or whatever you want instead.
Code:
function convertParameters (parameters) {
  function parseParameters (string) {
    try {
      return JSON.parse(string, (key, value) => {
        try {
          return parseParameters(value)
        } catch (e) {
          return value
        }
      })
    } catch (e) {
      return string
    }
  }
  return parseParameters(JSON.stringify(parameters))
}
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
@LTN Games Thank you, I will tinker around with that code.

... and maybe I should get rid of my semi-colons ...
 

Ossra

Formerly Exhydra
Veteran
Joined
Aug 21, 2013
Messages
1,076
Reaction score
845
First Language
English
Primarily Uses
RMMV
Alright, I managed to more or less halve the original parsing function and maintain the features I wanted. I also removed the requirement for terrible underscores in the parameter names. I think this method should be ... safe.

Code:
parse (json, defaults) {

  try {
    /* Use arrow function to pass 'this' into the scope of the JSON reviver function */
    return JSON.parse(json, (key, value) => {
      /* Assume any numeric key signifies an array */
      let _def = key >= 0 ? defaults[0] : defaults[key];
      /* Assign default value if value is empty */
      let _val = value === '' ? _def : value;

      /* Ignore values which have an undefined key */
      if (key) {
        if (typeof _def === 'function' && typeof _val !== 'function') {
          /* When default is a function and value is not, return a bound function */
          return this.helpers.get(_def.name.substr(6)).bind(this, _val);
        } else if (typeof _val !== typeof _def) {
          /* When the type of val does not equal the type of default, parse the value */
          return this.parse(_val, _def);
        }
      }

      return _val;
    });
  } catch (error) {
    return defaults;
  }

}
 

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

We start in 5 minutes!
I'm making MAGIC!
aww I am sad but happy for brackeys to decide to pursue something new but seing brackeys ending is so sad ;w;
Now RPG Maker has brought him here. He will never be rid of his need for it. He hates and loves the RPG Maker, just as he hates and loves himself. Featherbrain's life is a sad story. Yes, Featherbrain, he was called. Before the RPG Maker found him. Before it drove him mad.
Really struggling with XP animations but my game deserves my best.

Forum statistics

Threads
102,926
Messages
996,026
Members
134,380
Latest member
Marcussss
Top