precedent 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ > 0.01%
@@ -0,0 +1 @@
1
+ > 0.01%
@@ -0,0 +1 @@
1
+ since 2018
@@ -0,0 +1,319 @@
1
+ (function (f) {
2
+ if (typeof exports === "object" && typeof module !== "undefined") {
3
+ module.exports = f();
4
+ } else if (typeof define === "function" && define.amd) {
5
+ define([], f);
6
+ } else {
7
+ var g;
8
+ if (typeof window !== "undefined") {
9
+ g = window;
10
+ } else if (typeof global !== "undefined") {
11
+ g = global;
12
+ } else if (typeof self !== "undefined") {
13
+ g = self;
14
+ } else {
15
+ g = this;
16
+ }
17
+ g.Precedent = f();
18
+ }
19
+ })(function () {
20
+ var define, module, exports;
21
+ return function () {
22
+ function r(e, n, t) {
23
+ function o(i, f) {
24
+ if (!n[i]) {
25
+ if (!e[i]) {
26
+ var c = "function" == typeof require && require;
27
+ if (!f && c) return c(i, !0);
28
+ if (u) return u(i, !0);
29
+ var a = new Error("Cannot find module '" + i + "'");
30
+ throw a.code = "MODULE_NOT_FOUND", a;
31
+ }
32
+ var p = n[i] = {
33
+ exports: {}
34
+ };
35
+ e[i][0].call(p.exports, function (r) {
36
+ var n = e[i][1][r];
37
+ return o(n || r);
38
+ }, p, p.exports, r, e, n, t);
39
+ }
40
+ return n[i].exports;
41
+ }
42
+ for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]);
43
+ return o;
44
+ }
45
+ return r;
46
+ }()({
47
+ 1: [function (require, module, exports) {
48
+ /**
49
+ * Simple browser shim loader - assign the npm module to a window global automatically
50
+ *
51
+ * @license MIT
52
+ * @author <steven@velozo.com>
53
+ */
54
+ var libNPMModuleWrapper = require('./Precedent.js');
55
+ if (typeof window == 'object' && !window.hasOwnProperty('Precedent')) {
56
+ window.Precedent = libNPMModuleWrapper;
57
+ }
58
+ module.exports = libNPMModuleWrapper;
59
+ }, {
60
+ "./Precedent.js": 2
61
+ }],
62
+ 2: [function (require, module, exports) {
63
+ /**
64
+ * Precedent Meta-Templating
65
+ *
66
+ * @license MIT
67
+ *
68
+ * @author Steven Velozo <steven@velozo.com>
69
+ *
70
+ * @description Process text streams, parsing out meta-template expressions.
71
+ */
72
+ var libWordTree = require(`./WordTree.js`);
73
+ var libStringParser = require(`./StringParser.js`);
74
+ class Precedent {
75
+ /**
76
+ * Precedent Constructor
77
+ */
78
+ constructor() {
79
+ this.WordTree = new libWordTree();
80
+ this.StringParser = new libStringParser();
81
+ this.ParseTree = this.WordTree.ParseTree;
82
+ }
83
+
84
+ /**
85
+ * Add a Pattern to the Parse Tree
86
+ * @method addPattern
87
+ * @param {Object} pTree - A node on the parse tree to push the characters into
88
+ * @param {string} pPattern - The string to add to the tree
89
+ * @param {number} pIndex - callback function
90
+ * @return {bool} True if adding the pattern was successful
91
+ */
92
+ addPattern(pPatternStart, pPatternEnd, pParser) {
93
+ return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);
94
+ }
95
+
96
+ /**
97
+ * Parse a string with the existing parse tree
98
+ * @method parseString
99
+ * @param {string} pString - The string to parse
100
+ * @param {object} pData - Data to pass in as the second argument
101
+ * @return {string} The result from the parser
102
+ */
103
+ parseString(pString, pData) {
104
+ return this.StringParser.parseString(pString, this.ParseTree, pData);
105
+ }
106
+ }
107
+ module.exports = Precedent;
108
+ }, {
109
+ "./StringParser.js": 3,
110
+ "./WordTree.js": 4
111
+ }],
112
+ 3: [function (require, module, exports) {
113
+ /**
114
+ * String Parser
115
+ *
116
+ * @license MIT
117
+ *
118
+ * @author Steven Velozo <steven@velozo.com>
119
+ *
120
+ * @description Parse a string, properly processing each matched token in the word tree.
121
+ */
122
+
123
+ class StringParser {
124
+ /**
125
+ * StringParser Constructor
126
+ */
127
+ constructor() {}
128
+
129
+ /**
130
+ * Create a fresh parsing state object to work with.
131
+ * @method newParserState
132
+ * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)
133
+ * @return {Object} A new parser state object for running a character parser on
134
+ * @private
135
+ */
136
+ newParserState(pParseTree) {
137
+ return {
138
+ ParseTree: pParseTree,
139
+ Output: '',
140
+ OutputBuffer: '',
141
+ Pattern: false,
142
+ PatternMatch: false,
143
+ PatternMatchOutputBuffer: ''
144
+ };
145
+ }
146
+
147
+ /**
148
+ * Assign a node of the parser tree to be the next potential match.
149
+ * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
150
+ * @method assignNode
151
+ * @param {Object} pNode - A node on the parse tree to assign
152
+ * @param {Object} pParserState - The state object for the current parsing task
153
+ * @private
154
+ */
155
+ assignNode(pNode, pParserState) {
156
+ pParserState.PatternMatch = pNode;
157
+
158
+ // If the pattern has a END we can assume it has a parse function...
159
+ if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) {
160
+ // ... this is the legitimate start of a pattern.
161
+ pParserState.Pattern = pParserState.PatternMatch;
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Append a character to the output buffer in the parser state.
167
+ * This output buffer is used when a potential match is being explored, or a match is being explored.
168
+ * @method appendOutputBuffer
169
+ * @param {string} pCharacter - The character to append
170
+ * @param {Object} pParserState - The state object for the current parsing task
171
+ * @private
172
+ */
173
+ appendOutputBuffer(pCharacter, pParserState) {
174
+ pParserState.OutputBuffer += pCharacter;
175
+ }
176
+
177
+ /**
178
+ * Flush the output buffer to the output and clear it.
179
+ * @method flushOutputBuffer
180
+ * @param {Object} pParserState - The state object for the current parsing task
181
+ * @private
182
+ */
183
+ flushOutputBuffer(pParserState) {
184
+ pParserState.Output += pParserState.OutputBuffer;
185
+ pParserState.OutputBuffer = '';
186
+ }
187
+
188
+ /**
189
+ * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
190
+ * @method checkPatternEnd
191
+ * @param {Object} pParserState - The state object for the current parsing task
192
+ * @private
193
+ */
194
+ checkPatternEnd(pParserState, pData) {
195
+ if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) {
196
+ // ... this is the end of a pattern, cut off the end tag and parse it.
197
+ // Trim the start and end tags off the output buffer now
198
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)), pData);
199
+ // Flush the output buffer.
200
+ this.flushOutputBuffer(pParserState);
201
+ // End pattern mode
202
+ pParserState.Pattern = false;
203
+ pParserState.PatternMatch = false;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Parse a character in the buffer.
209
+ * @method parseCharacter
210
+ * @param {string} pCharacter - The character to append
211
+ * @param {Object} pParserState - The state object for the current parsing task
212
+ * @private
213
+ */
214
+ parseCharacter(pCharacter, pParserState, pData) {
215
+ // (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....
216
+ if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) {
217
+ // ... assign the node as the matched node.
218
+ this.assignNode(pParserState.ParseTree[pCharacter], pParserState);
219
+ this.appendOutputBuffer(pCharacter, pParserState);
220
+ }
221
+ // (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)
222
+ else if (pParserState.PatternMatch) {
223
+ // If the pattern has a subpattern with this key
224
+ if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) {
225
+ // Continue matching patterns.
226
+ this.assignNode(pParserState.PatternMatch[pCharacter], pParserState);
227
+ }
228
+ this.appendOutputBuffer(pCharacter, pParserState);
229
+ if (pParserState.Pattern) {
230
+ // ... Check if this is the end of the pattern (if we are matching a valid pattern)...
231
+ this.checkPatternEnd(pParserState, pData);
232
+ }
233
+ }
234
+ // (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
235
+ else {
236
+ pParserState.Output += pCharacter;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Parse a string for matches, and process any template segments that occur.
242
+ * @method parseString
243
+ * @param {string} pString - The string to parse.
244
+ * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
245
+ * @param {Object} pData - The data to pass to the function as a second paramter
246
+ */
247
+ parseString(pString, pParseTree, pData) {
248
+ let tmpParserState = this.newParserState(pParseTree);
249
+ for (var i = 0; i < pString.length; i++) {
250
+ // TODO: This is not fast.
251
+ this.parseCharacter(pString[i], tmpParserState, pData);
252
+ }
253
+ this.flushOutputBuffer(tmpParserState);
254
+ return tmpParserState.Output;
255
+ }
256
+ }
257
+ module.exports = StringParser;
258
+ }, {}],
259
+ 4: [function (require, module, exports) {
260
+ /**
261
+ * Word Tree
262
+ *
263
+ * @license MIT
264
+ *
265
+ * @author Steven Velozo <steven@velozo.com>
266
+ *
267
+ * @description Create a tree (directed graph) of Javascript objects, one character per object.
268
+ */
269
+
270
+ class WordTree {
271
+ /**
272
+ * WordTree Constructor
273
+ */
274
+ constructor() {
275
+ this.ParseTree = {};
276
+ }
277
+
278
+ /**
279
+ * Add a child character to a Parse Tree node
280
+ * @method addChild
281
+ * @param {Object} pTree - A parse tree to push the characters into
282
+ * @param {string} pPattern - The string to add to the tree
283
+ * @param {number} pIndex - The index of the character in the pattern
284
+ * @returns {Object} The resulting leaf node that was added (or found)
285
+ * @private
286
+ */
287
+ addChild(pTree, pPattern, pIndex) {
288
+ if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {};
289
+ return pTree[pPattern[pIndex]];
290
+ }
291
+
292
+ /** Add a Pattern to the Parse Tree
293
+ * @method addPattern
294
+ * @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
295
+ * @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
296
+ * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.
297
+ * @return {bool} True if adding the pattern was successful
298
+ */
299
+ addPattern(pPatternStart, pPatternEnd, pParser) {
300
+ if (pPatternStart.length < 1) return false;
301
+ if (typeof pPatternEnd === 'string' && pPatternEnd.length < 1) return false;
302
+ let tmpLeaf = this.ParseTree;
303
+
304
+ // Add the tree of leaves iteratively
305
+ for (var i = 0; i < pPatternStart.length; i++) tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);
306
+ tmpLeaf.PatternStart = pPatternStart;
307
+ tmpLeaf.PatternEnd = typeof pPatternEnd === 'string' && pPatternEnd.length > 0 ? pPatternEnd : pPatternStart;
308
+ tmpLeaf.Parse = typeof pParser === 'function' ? pParser : typeof pParser === 'string' ? () => {
309
+ return pParser;
310
+ } : pData => {
311
+ return pData;
312
+ };
313
+ return true;
314
+ }
315
+ }
316
+ module.exports = WordTree;
317
+ }, {}]
318
+ }, {}, [1])(1);
319
+ });
@@ -0,0 +1,39 @@
1
+ !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Precedent=t()}}((function(){return function t(e,r,n){function a(s,f){if(!r[s]){if(!e[s]){var o="function"==typeof require&&require;if(!f&&o)return o(s,!0);if(u)return u(s,!0);var i=new Error("Cannot find module '"+s+"'");throw i.code="MODULE_NOT_FOUND",i}var P=r[s]={exports:{}};e[s][0].call(P.exports,(function(t){return a(e[s][1][t]||t)}),P,P.exports,t,e,r,n)}return r[s].exports}for(var u="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(t,e,r){
2
+ /**
3
+ * Simple browser shim loader - assign the npm module to a window global automatically
4
+ *
5
+ * @license MIT
6
+ * @author <steven@velozo.com>
7
+ */
8
+ var n=t("./Precedent.js");"object"!=typeof window||window.hasOwnProperty("Precedent")||(window.Precedent=n),e.exports=n},{"./Precedent.js":2}],2:[function(t,e,r){
9
+ /**
10
+ * Precedent Meta-Templating
11
+ *
12
+ * @license MIT
13
+ *
14
+ * @author Steven Velozo <steven@velozo.com>
15
+ *
16
+ * @description Process text streams, parsing out meta-template expressions.
17
+ */
18
+ var n=t("./WordTree.js"),a=t("./StringParser.js");e.exports=class{constructor(){this.WordTree=new n,this.StringParser=new a,this.ParseTree=this.WordTree.ParseTree}addPattern(t,e,r){return this.WordTree.addPattern(t,e,r)}parseString(t,e){return this.StringParser.parseString(t,this.ParseTree,e)}}},{"./StringParser.js":3,"./WordTree.js":4}],3:[function(t,e,r){e.exports=
19
+ /**
20
+ * String Parser
21
+ *
22
+ * @license MIT
23
+ *
24
+ * @author Steven Velozo <steven@velozo.com>
25
+ *
26
+ * @description Parse a string, properly processing each matched token in the word tree.
27
+ */
28
+ class{constructor(){}newParserState(t){return{ParseTree:t,Output:"",OutputBuffer:"",Pattern:!1,PatternMatch:!1,PatternMatchOutputBuffer:""}}assignNode(t,e){e.PatternMatch=t,e.PatternMatch.hasOwnProperty("PatternEnd")&&(e.Pattern=e.PatternMatch)}appendOutputBuffer(t,e){e.OutputBuffer+=t}flushOutputBuffer(t){t.Output+=t.OutputBuffer,t.OutputBuffer=""}checkPatternEnd(t,e){t.OutputBuffer.length>=t.Pattern.PatternEnd.length+t.Pattern.PatternStart.length&&t.OutputBuffer.substr(-t.Pattern.PatternEnd.length)===t.Pattern.PatternEnd&&(t.OutputBuffer=t.Pattern.Parse(t.OutputBuffer.substr(t.Pattern.PatternStart.length,t.OutputBuffer.length-(t.Pattern.PatternStart.length+t.Pattern.PatternEnd.length)),e),this.flushOutputBuffer(t),t.Pattern=!1,t.PatternMatch=!1)}parseCharacter(t,e,r){!e.PatternMatch&&e.ParseTree.hasOwnProperty(t)?(this.assignNode(e.ParseTree[t],e),this.appendOutputBuffer(t,e)):e.PatternMatch?(e.PatternMatch.hasOwnProperty(t)&&this.assignNode(e.PatternMatch[t],e),this.appendOutputBuffer(t,e),e.Pattern&&this.checkPatternEnd(e,r)):e.Output+=t}parseString(t,e,r){let n=this.newParserState(e);for(var a=0;a<t.length;a++)this.parseCharacter(t[a],n,r);return this.flushOutputBuffer(n),n.Output}}},{}],4:[function(t,e,r){e.exports=
29
+ /**
30
+ * Word Tree
31
+ *
32
+ * @license MIT
33
+ *
34
+ * @author Steven Velozo <steven@velozo.com>
35
+ *
36
+ * @description Create a tree (directed graph) of Javascript objects, one character per object.
37
+ */
38
+ class{constructor(){this.ParseTree={}}addChild(t,e,r){return t.hasOwnProperty(e[r])||(t[e[r]]={}),t[e[r]]}addPattern(t,e,r){if(t.length<1)return!1;if("string"==typeof e&&e.length<1)return!1;let n=this.ParseTree;for(var a=0;a<t.length;a++)n=this.addChild(n,t,a);return n.PatternStart=t,n.PatternEnd="string"==typeof e&&e.length>0?e:t,n.Parse="function"==typeof r?r:"string"==typeof r?()=>r:t=>t,!0}}},{}]},{},[1])(1)}));
39
+ //# sourceMappingURL=precedent.compatible.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["node_modules/browser-pack/_prelude.js","source/Precedent-Browser-Shim.js","precedent.compatible.min.js","source/Precedent.js","source/StringParser.js","source/WordTree.js"],"names":["f","exports","module","define","amd","window","global","self","this","Precedent","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","libNPMModuleWrapper","hasOwnProperty","libWordTree","libStringParser","constructor","WordTree","StringParser","ParseTree","addPattern","pPatternStart","pPatternEnd","pParser","parseString","pString","pData","newParserState","pParseTree","Output","OutputBuffer","Pattern","PatternMatch","PatternMatchOutputBuffer","assignNode","pNode","pParserState","appendOutputBuffer","pCharacter","flushOutputBuffer","checkPatternEnd","PatternEnd","PatternStart","substr","Parse","parseCharacter","tmpParserState","addChild","pTree","pPattern","pIndex","tmpLeaf"],"mappings":"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","file":"precedent.compatible.min.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;","(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Precedent = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;\n},{\"./Precedent.js\":2}],2:[function(require,module,exports){\n/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @param {object} pData - Data to pass in as the second argument\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString, pData)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree, pData);\n\t}\n}\n\nmodule.exports = Precedent;\n\n},{\"./StringParser.js\":3,\"./WordTree.js\":4}],3:[function(require,module,exports){\n/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState, pData)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&\n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)), pData);\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState, pData)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState, pData);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t * @param {Object} pData - The data to pass to the function as a second paramter\n\t */\n\tparseString (pString, pParseTree, pData)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState, pData);\n\t\t}\n\n\t\tthis.flushOutputBuffer(tmpParserState);\n\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n\n},{}],4:[function(require,module,exports){\n/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - The index of the character in the pattern\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pPatternStart - The starting string for the pattern (e.g. \"${\")\n\t * @param {string} pPatternEnd - The ending string for the pattern (e.g. \"}\")\n\t * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tif ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1))\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n\n},{}]},{},[1])(1)\n});\n\n","/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @param {object} pData - Data to pass in as the second argument\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString, pData)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree, pData);\n\t}\n}\n\nmodule.exports = Precedent;\n","/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState, pData)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&\n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)), pData);\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState, pData)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState, pData);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t * @param {Object} pData - The data to pass to the function as a second paramter\n\t */\n\tparseString (pString, pParseTree, pData)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState, pData);\n\t\t}\n\n\t\tthis.flushOutputBuffer(tmpParserState);\n\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n","/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - The index of the character in the pattern\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pPatternStart - The starting string for the pattern (e.g. \"${\")\n\t * @param {string} pPatternEnd - The ending string for the pattern (e.g. \"}\")\n\t * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tif ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1))\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n"]}
package/dist/precedent.js CHANGED
@@ -97,10 +97,11 @@
97
97
  * Parse a string with the existing parse tree
98
98
  * @method parseString
99
99
  * @param {string} pString - The string to parse
100
+ * @param {object} pData - Data to pass in as the second argument
100
101
  * @return {string} The result from the parser
101
102
  */
102
- parseString(pString) {
103
- return this.StringParser.parseString(pString, this.ParseTree);
103
+ parseString(pString, pData) {
104
+ return this.StringParser.parseString(pString, this.ParseTree, pData);
104
105
  }
105
106
  }
106
107
  module.exports = Precedent;
@@ -190,11 +191,11 @@
190
191
  * @param {Object} pParserState - The state object for the current parsing task
191
192
  * @private
192
193
  */
193
- checkPatternEnd(pParserState) {
194
+ checkPatternEnd(pParserState, pData) {
194
195
  if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) {
195
196
  // ... this is the end of a pattern, cut off the end tag and parse it.
196
197
  // Trim the start and end tags off the output buffer now
197
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)));
198
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)), pData);
198
199
  // Flush the output buffer.
199
200
  this.flushOutputBuffer(pParserState);
200
201
  // End pattern mode
@@ -210,7 +211,7 @@
210
211
  * @param {Object} pParserState - The state object for the current parsing task
211
212
  * @private
212
213
  */
213
- parseCharacter(pCharacter, pParserState) {
214
+ parseCharacter(pCharacter, pParserState, pData) {
214
215
  // (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....
215
216
  if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) {
216
217
  // ... assign the node as the matched node.
@@ -227,7 +228,7 @@
227
228
  this.appendOutputBuffer(pCharacter, pParserState);
228
229
  if (pParserState.Pattern) {
229
230
  // ... Check if this is the end of the pattern (if we are matching a valid pattern)...
230
- this.checkPatternEnd(pParserState);
231
+ this.checkPatternEnd(pParserState, pData);
231
232
  }
232
233
  }
233
234
  // (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
@@ -241,12 +242,13 @@
241
242
  * @method parseString
242
243
  * @param {string} pString - The string to parse.
243
244
  * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
245
+ * @param {Object} pData - The data to pass to the function as a second paramter
244
246
  */
245
- parseString(pString, pParseTree) {
247
+ parseString(pString, pParseTree, pData) {
246
248
  let tmpParserState = this.newParserState(pParseTree);
247
249
  for (var i = 0; i < pString.length; i++) {
248
250
  // TODO: This is not fast.
249
- this.parseCharacter(pString[i], tmpParserState);
251
+ this.parseCharacter(pString[i], tmpParserState, pData);
250
252
  }
251
253
  this.flushOutputBuffer(tmpParserState);
252
254
  return tmpParserState.Output;
@@ -278,25 +280,25 @@
278
280
  * @method addChild
279
281
  * @param {Object} pTree - A parse tree to push the characters into
280
282
  * @param {string} pPattern - The string to add to the tree
281
- * @param {number} pIndex - callback function
283
+ * @param {number} pIndex - The index of the character in the pattern
282
284
  * @returns {Object} The resulting leaf node that was added (or found)
283
285
  * @private
284
286
  */
285
287
  addChild(pTree, pPattern, pIndex) {
286
- if (pIndex > pPattern.length) return pTree;
287
288
  if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {};
288
289
  return pTree[pPattern[pIndex]];
289
290
  }
290
291
 
291
292
  /** Add a Pattern to the Parse Tree
292
293
  * @method addPattern
293
- * @param {Object} pTree - A node on the parse tree to push the characters into
294
- * @param {string} pPattern - The string to add to the tree
295
- * @param {number} pIndex - callback function
294
+ * @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
295
+ * @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
296
+ * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.
296
297
  * @return {bool} True if adding the pattern was successful
297
298
  */
298
299
  addPattern(pPatternStart, pPatternEnd, pParser) {
299
300
  if (pPatternStart.length < 1) return false;
301
+ if (typeof pPatternEnd === 'string' && pPatternEnd.length < 1) return false;
300
302
  let tmpLeaf = this.ParseTree;
301
303
 
302
304
  // Add the tree of leaves iteratively
@@ -15,7 +15,7 @@ var n=t("./Precedent.js");"object"!=typeof window||window.hasOwnProperty("Preced
15
15
  *
16
16
  * @description Process text streams, parsing out meta-template expressions.
17
17
  */
18
- var n=t("./WordTree.js"),a=t("./StringParser.js");e.exports=class{constructor(){this.WordTree=new n,this.StringParser=new a,this.ParseTree=this.WordTree.ParseTree}addPattern(t,e,r){return this.WordTree.addPattern(t,e,r)}parseString(t){return this.StringParser.parseString(t,this.ParseTree)}}},{"./StringParser.js":3,"./WordTree.js":4}],3:[function(t,e,r){e.exports=
18
+ var n=t("./WordTree.js"),a=t("./StringParser.js");e.exports=class{constructor(){this.WordTree=new n,this.StringParser=new a,this.ParseTree=this.WordTree.ParseTree}addPattern(t,e,r){return this.WordTree.addPattern(t,e,r)}parseString(t,e){return this.StringParser.parseString(t,this.ParseTree,e)}}},{"./StringParser.js":3,"./WordTree.js":4}],3:[function(t,e,r){e.exports=
19
19
  /**
20
20
  * String Parser
21
21
  *
@@ -25,7 +25,7 @@ var n=t("./WordTree.js"),a=t("./StringParser.js");e.exports=class{constructor(){
25
25
  *
26
26
  * @description Parse a string, properly processing each matched token in the word tree.
27
27
  */
28
- class{constructor(){}newParserState(t){return{ParseTree:t,Output:"",OutputBuffer:"",Pattern:!1,PatternMatch:!1,PatternMatchOutputBuffer:""}}assignNode(t,e){e.PatternMatch=t,e.PatternMatch.hasOwnProperty("PatternEnd")&&(e.Pattern=e.PatternMatch)}appendOutputBuffer(t,e){e.OutputBuffer+=t}flushOutputBuffer(t){t.Output+=t.OutputBuffer,t.OutputBuffer=""}checkPatternEnd(t){t.OutputBuffer.length>=t.Pattern.PatternEnd.length+t.Pattern.PatternStart.length&&t.OutputBuffer.substr(-t.Pattern.PatternEnd.length)===t.Pattern.PatternEnd&&(t.OutputBuffer=t.Pattern.Parse(t.OutputBuffer.substr(t.Pattern.PatternStart.length,t.OutputBuffer.length-(t.Pattern.PatternStart.length+t.Pattern.PatternEnd.length))),this.flushOutputBuffer(t),t.Pattern=!1,t.PatternMatch=!1)}parseCharacter(t,e){!e.PatternMatch&&e.ParseTree.hasOwnProperty(t)?(this.assignNode(e.ParseTree[t],e),this.appendOutputBuffer(t,e)):e.PatternMatch?(e.PatternMatch.hasOwnProperty(t)&&this.assignNode(e.PatternMatch[t],e),this.appendOutputBuffer(t,e),e.Pattern&&this.checkPatternEnd(e)):e.Output+=t}parseString(t,e){let r=this.newParserState(e);for(var n=0;n<t.length;n++)this.parseCharacter(t[n],r);return this.flushOutputBuffer(r),r.Output}}},{}],4:[function(t,e,r){e.exports=
28
+ class{constructor(){}newParserState(t){return{ParseTree:t,Output:"",OutputBuffer:"",Pattern:!1,PatternMatch:!1,PatternMatchOutputBuffer:""}}assignNode(t,e){e.PatternMatch=t,e.PatternMatch.hasOwnProperty("PatternEnd")&&(e.Pattern=e.PatternMatch)}appendOutputBuffer(t,e){e.OutputBuffer+=t}flushOutputBuffer(t){t.Output+=t.OutputBuffer,t.OutputBuffer=""}checkPatternEnd(t,e){t.OutputBuffer.length>=t.Pattern.PatternEnd.length+t.Pattern.PatternStart.length&&t.OutputBuffer.substr(-t.Pattern.PatternEnd.length)===t.Pattern.PatternEnd&&(t.OutputBuffer=t.Pattern.Parse(t.OutputBuffer.substr(t.Pattern.PatternStart.length,t.OutputBuffer.length-(t.Pattern.PatternStart.length+t.Pattern.PatternEnd.length)),e),this.flushOutputBuffer(t),t.Pattern=!1,t.PatternMatch=!1)}parseCharacter(t,e,r){!e.PatternMatch&&e.ParseTree.hasOwnProperty(t)?(this.assignNode(e.ParseTree[t],e),this.appendOutputBuffer(t,e)):e.PatternMatch?(e.PatternMatch.hasOwnProperty(t)&&this.assignNode(e.PatternMatch[t],e),this.appendOutputBuffer(t,e),e.Pattern&&this.checkPatternEnd(e,r)):e.Output+=t}parseString(t,e,r){let n=this.newParserState(e);for(var a=0;a<t.length;a++)this.parseCharacter(t[a],n,r);return this.flushOutputBuffer(n),n.Output}}},{}],4:[function(t,e,r){e.exports=
29
29
  /**
30
30
  * Word Tree
31
31
  *
@@ -35,5 +35,5 @@ class{constructor(){}newParserState(t){return{ParseTree:t,Output:"",OutputBuffer
35
35
  *
36
36
  * @description Create a tree (directed graph) of Javascript objects, one character per object.
37
37
  */
38
- class{constructor(){this.ParseTree={}}addChild(t,e,r){return r>e.length?t:(t.hasOwnProperty(e[r])||(t[e[r]]={}),t[e[r]])}addPattern(t,e,r){if(t.length<1)return!1;let n=this.ParseTree;for(var a=0;a<t.length;a++)n=this.addChild(n,t,a);return n.PatternStart=t,n.PatternEnd="string"==typeof e&&e.length>0?e:t,n.Parse="function"==typeof r?r:"string"==typeof r?()=>r:t=>t,!0}}},{}]},{},[1])(1)}));
38
+ class{constructor(){this.ParseTree={}}addChild(t,e,r){return t.hasOwnProperty(e[r])||(t[e[r]]={}),t[e[r]]}addPattern(t,e,r){if(t.length<1)return!1;if("string"==typeof e&&e.length<1)return!1;let n=this.ParseTree;for(var a=0;a<t.length;a++)n=this.addChild(n,t,a);return n.PatternStart=t,n.PatternEnd="string"==typeof e&&e.length>0?e:t,n.Parse="function"==typeof r?r:"string"==typeof r?()=>r:t=>t,!0}}},{}]},{},[1])(1)}));
39
39
  //# sourceMappingURL=precedent.min.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["node_modules/browser-pack/_prelude.js","source/Precedent-Browser-Shim.js","precedent.min.js","source/Precedent.js","source/StringParser.js","source/WordTree.js"],"names":["f","exports","module","define","amd","window","global","self","this","Precedent","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","libNPMModuleWrapper","hasOwnProperty","libWordTree","libStringParser","constructor","WordTree","StringParser","ParseTree","addPattern","pPatternStart","pPatternEnd","pParser","parseString","pString","newParserState","pParseTree","Output","OutputBuffer","Pattern","PatternMatch","PatternMatchOutputBuffer","assignNode","pNode","pParserState","appendOutputBuffer","pCharacter","flushOutputBuffer","checkPatternEnd","PatternEnd","PatternStart","substr","Parse","parseCharacter","tmpParserState","addChild","pTree","pPattern","pIndex","tmpLeaf","pData"],"mappings":"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","file":"precedent.min.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;","(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Precedent = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;\n},{\"./Precedent.js\":2}],2:[function(require,module,exports){\n/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\t\t\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\t\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\t\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree);\n\t}\n}\n\nmodule.exports = Precedent;\n\n},{\"./StringParser.js\":3,\"./WordTree.js\":4}],3:[function(require,module,exports){\n/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\t\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\t\t\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\t\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\t\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\t\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) && \n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)));\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\t\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\t\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t */\n\tparseString (pString, pParseTree)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState);\n\t\t}\n\t\t\n\t\tthis.flushOutputBuffer(tmpParserState);\n\t\t\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n\n},{}],4:[function(require,module,exports){\n/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (pIndex > pPattern.length)\n\t\t\treturn pTree;\n\t\t\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n\n},{}]},{},[1])(1)\n});\n\n","/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\t\t\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\t\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\t\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree);\n\t}\n}\n\nmodule.exports = Precedent;\n","/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\t\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\t\t\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\t\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\t\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\t\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) && \n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)));\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\t\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\t\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t */\n\tparseString (pString, pParseTree)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState);\n\t\t}\n\t\t\n\t\tthis.flushOutputBuffer(tmpParserState);\n\t\t\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n","/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (pIndex > pPattern.length)\n\t\t\treturn pTree;\n\t\t\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n"]}
1
+ {"version":3,"sources":["node_modules/browser-pack/_prelude.js","source/Precedent-Browser-Shim.js","precedent.min.js","source/Precedent.js","source/StringParser.js","source/WordTree.js"],"names":["f","exports","module","define","amd","window","global","self","this","Precedent","r","e","n","t","o","i","c","require","u","a","Error","code","p","call","length","libNPMModuleWrapper","hasOwnProperty","libWordTree","libStringParser","constructor","WordTree","StringParser","ParseTree","addPattern","pPatternStart","pPatternEnd","pParser","parseString","pString","pData","newParserState","pParseTree","Output","OutputBuffer","Pattern","PatternMatch","PatternMatchOutputBuffer","assignNode","pNode","pParserState","appendOutputBuffer","pCharacter","flushOutputBuffer","checkPatternEnd","PatternEnd","PatternStart","substr","Parse","parseCharacter","tmpParserState","addChild","pTree","pPattern","pIndex","tmpLeaf"],"mappings":"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","file":"precedent.min.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()","/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;","(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Precedent = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){\n/**\n* Simple browser shim loader - assign the npm module to a window global automatically\n*\n* @license MIT\n* @author <steven@velozo.com>\n*/\nvar libNPMModuleWrapper = require('./Precedent.js');\n\nif ((typeof(window) == 'object') && (!window.hasOwnProperty('Precedent')))\n{\n\twindow.Precedent = libNPMModuleWrapper;\n}\n\nmodule.exports = libNPMModuleWrapper;\n},{\"./Precedent.js\":2}],2:[function(require,module,exports){\n/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @param {object} pData - Data to pass in as the second argument\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString, pData)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree, pData);\n\t}\n}\n\nmodule.exports = Precedent;\n\n},{\"./StringParser.js\":3,\"./WordTree.js\":4}],3:[function(require,module,exports){\n/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState, pData)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&\n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)), pData);\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState, pData)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState, pData);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t * @param {Object} pData - The data to pass to the function as a second paramter\n\t */\n\tparseString (pString, pParseTree, pData)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState, pData);\n\t\t}\n\n\t\tthis.flushOutputBuffer(tmpParserState);\n\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n\n},{}],4:[function(require,module,exports){\n/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - The index of the character in the pattern\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pPatternStart - The starting string for the pattern (e.g. \"${\")\n\t * @param {string} pPatternEnd - The ending string for the pattern (e.g. \"}\")\n\t * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tif ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1))\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n\n},{}]},{},[1])(1)\n});\n\n","/**\n* Precedent Meta-Templating\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Process text streams, parsing out meta-template expressions.\n*/\nvar libWordTree = require(`./WordTree.js`);\nvar libStringParser = require(`./StringParser.js`);\n\nclass Precedent\n{\n\t/**\n\t * Precedent Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.WordTree = new libWordTree();\n\n\t\tthis.StringParser = new libStringParser();\n\n\t\tthis.ParseTree = this.WordTree.ParseTree;\n\t}\n\n\t/**\n\t * Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pTree - A node on the parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - callback function\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern(pPatternStart, pPatternEnd, pParser)\n\t{\n\t\treturn this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);\n\t}\n\n\t/**\n\t * Parse a string with the existing parse tree\n\t * @method parseString\n\t * @param {string} pString - The string to parse\n\t * @param {object} pData - Data to pass in as the second argument\n\t * @return {string} The result from the parser\n\t */\n\tparseString(pString, pData)\n\t{\n\t\treturn this.StringParser.parseString(pString, this.ParseTree, pData);\n\t}\n}\n\nmodule.exports = Precedent;\n","/**\n* String Parser\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Parse a string, properly processing each matched token in the word tree.\n*/\n\nclass StringParser\n{\n\t/**\n\t * StringParser Constructor\n\t */\n\tconstructor()\n\t{\n\t}\n\n\t/**\n\t * Create a fresh parsing state object to work with.\n\t * @method newParserState\n\t * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)\n\t * @return {Object} A new parser state object for running a character parser on\n\t * @private\n\t */\n\tnewParserState (pParseTree)\n\t{\n\t\treturn (\n\t\t{\n\t\t\tParseTree: pParseTree,\n\n\t\t\tOutput: '',\n\t\t\tOutputBuffer: '',\n\n\t\t\tPattern: false,\n\n\t\t\tPatternMatch: false,\n\t\t\tPatternMatchOutputBuffer: ''\n\t\t});\n\t}\n\n\t/**\n\t * Assign a node of the parser tree to be the next potential match.\n\t * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).\n\t * @method assignNode\n\t * @param {Object} pNode - A node on the parse tree to assign\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tassignNode (pNode, pParserState)\n\t{\n\t\tpParserState.PatternMatch = pNode;\n\n\t\t// If the pattern has a END we can assume it has a parse function...\n\t\tif (pParserState.PatternMatch.hasOwnProperty('PatternEnd'))\n\t\t{\n\t\t\t// ... this is the legitimate start of a pattern.\n\t\t\tpParserState.Pattern = pParserState.PatternMatch;\n\t\t}\n\t}\n\n\t/**\n\t * Append a character to the output buffer in the parser state.\n\t * This output buffer is used when a potential match is being explored, or a match is being explored.\n\t * @method appendOutputBuffer\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tappendOutputBuffer (pCharacter, pParserState)\n\t{\n\t\tpParserState.OutputBuffer += pCharacter;\n\t}\n\n\t/**\n\t * Flush the output buffer to the output and clear it.\n\t * @method flushOutputBuffer\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tflushOutputBuffer (pParserState)\n\t{\n\t\tpParserState.Output += pParserState.OutputBuffer;\n\t\tpParserState.OutputBuffer = '';\n\t}\n\n\n\t/**\n\t * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.\n\t * @method checkPatternEnd\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tcheckPatternEnd (pParserState, pData)\n\t{\n\t\tif ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&\n\t\t\t(pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))\n\t\t{\n\t\t\t// ... this is the end of a pattern, cut off the end tag and parse it.\n\t\t\t// Trim the start and end tags off the output buffer now\n\t\t\tpParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)), pData);\n\t\t\t// Flush the output buffer.\n\t\t\tthis.flushOutputBuffer(pParserState);\n\t\t\t// End pattern mode\n\t\t\tpParserState.Pattern = false;\n\t\t\tpParserState.PatternMatch = false;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a character in the buffer.\n\t * @method parseCharacter\n\t * @param {string} pCharacter - The character to append\n\t * @param {Object} pParserState - The state object for the current parsing task\n\t * @private\n\t */\n\tparseCharacter (pCharacter, pParserState, pData)\n\t{\n\t\t// (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....\n\t\tif (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))\n\t\t{\n\t\t\t// ... assign the node as the matched node.\n\t\t\tthis.assignNode(pParserState.ParseTree[pCharacter], pParserState);\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t}\n\t\t// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)\n\t\telse if (pParserState.PatternMatch)\n\t\t{\n\t\t\t// If the pattern has a subpattern with this key\n\t\t\tif (pParserState.PatternMatch.hasOwnProperty(pCharacter))\n\t\t\t{\n\t\t\t\t// Continue matching patterns.\n\t\t\t\tthis.assignNode(pParserState.PatternMatch[pCharacter], pParserState);\n\t\t\t}\n\t\t\tthis.appendOutputBuffer(pCharacter, pParserState);\n\t\t\tif (pParserState.Pattern)\n\t\t\t{\n\t\t\t\t// ... Check if this is the end of the pattern (if we are matching a valid pattern)...\n\t\t\t\tthis.checkPatternEnd(pParserState, pData);\n\t\t\t}\n\t\t}\n\t\t// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....\n\t\telse\n\t\t{\n\t\t\tpParserState.Output += pCharacter;\n\t\t}\n\t}\n\n\t/**\n\t * Parse a string for matches, and process any template segments that occur.\n\t * @method parseString\n\t * @param {string} pString - The string to parse.\n\t * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)\n\t * @param {Object} pData - The data to pass to the function as a second paramter\n\t */\n\tparseString (pString, pParseTree, pData)\n\t{\n\t\tlet tmpParserState = this.newParserState(pParseTree);\n\n\t\tfor (var i = 0; i < pString.length; i++)\n\t\t{\n\t\t\t// TODO: This is not fast.\n\t\t\tthis.parseCharacter(pString[i], tmpParserState, pData);\n\t\t}\n\n\t\tthis.flushOutputBuffer(tmpParserState);\n\n\t\treturn tmpParserState.Output;\n\t}\n}\n\nmodule.exports = StringParser;\n","/**\n* Word Tree\n*\n* @license MIT\n*\n* @author Steven Velozo <steven@velozo.com>\n*\n* @description Create a tree (directed graph) of Javascript objects, one character per object.\n*/\n\nclass WordTree\n{\n\t/**\n\t * WordTree Constructor\n\t */\n\tconstructor()\n\t{\n\t\tthis.ParseTree = {};\n\t}\n\t\n\t/** \n\t * Add a child character to a Parse Tree node\n\t * @method addChild\n\t * @param {Object} pTree - A parse tree to push the characters into\n\t * @param {string} pPattern - The string to add to the tree\n\t * @param {number} pIndex - The index of the character in the pattern\n\t * @returns {Object} The resulting leaf node that was added (or found)\n\t * @private\n\t */\n\taddChild (pTree, pPattern, pIndex)\n\t{\n\t\tif (!pTree.hasOwnProperty(pPattern[pIndex]))\n\t\t\tpTree[pPattern[pIndex]] = {};\n\t\t\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\t\n\t/** Add a Pattern to the Parse Tree\n\t * @method addPattern\n\t * @param {Object} pPatternStart - The starting string for the pattern (e.g. \"${\")\n\t * @param {string} pPatternEnd - The ending string for the pattern (e.g. \"}\")\n\t * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.\n\t * @return {bool} True if adding the pattern was successful\n\t */\n\taddPattern (pPatternStart, pPatternEnd, pParser)\n\t{\n\t\tif (pPatternStart.length < 1)\n\t\t\treturn false;\n\n\t\tif ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length < 1))\n\t\t\treturn false;\n\n\t\tlet tmpLeaf = this.ParseTree;\n\n\t\t// Add the tree of leaves iteratively\n\t\tfor (var i = 0; i < pPatternStart.length; i++)\n\t\t\ttmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);\n\n\t\ttmpLeaf.PatternStart = pPatternStart;\n\t\ttmpLeaf.PatternEnd = ((typeof(pPatternEnd) === 'string') && (pPatternEnd.length > 0)) ? pPatternEnd : pPatternStart;\n\t\ttmpLeaf.Parse = (typeof(pParser) === 'function') ? pParser : \n\t\t\t\t\t\t(typeof(pParser) === 'string') ? () => { return pParser; } :\n\t\t\t\t\t\t(pData) => { return pData; };\n\n\t\treturn true;\n\t}\n}\n\nmodule.exports = WordTree;\n"]}
@@ -0,0 +1,11 @@
1
+ {
2
+ "EntrypointInputSourceFile": "./source/Precedent-Browser-Shim.js",
3
+
4
+ "LibraryObjectName": "Precedent",
5
+
6
+ "LibraryOutputFolder": "./dist/",
7
+
8
+ "LibraryUniminifiedFileName": "precedent.compatible.js",
9
+
10
+ "LibraryMinifiedFileName": "precedent.compatible.min.js"
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "EntrypointInputSourceFile": "./source/Precedent-Browser-Shim.js",
3
+
4
+ "LibraryObjectName": "Precedent",
5
+
6
+ "LibraryOutputFolder": "./dist/",
7
+
8
+ "LibraryUniminifiedFileName": "precedent.compatible.js",
9
+
10
+ "LibraryMinifiedFileName": "precedent.compatible.min.js"
11
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "EntrypointInputSourceFile": "./source/Precedent-Browser-Shim.js",
3
+
4
+ "LibraryObjectName": "Precedent",
5
+
6
+ "LibraryOutputFolder": "./dist/",
7
+
8
+ "LibraryUniminifiedFileName": "precedent.js",
9
+
10
+ "LibraryMinifiedFileName": "precedent.min.js"
11
+ }
package/gulpfile.js CHANGED
@@ -1,27 +1,108 @@
1
1
  'use strict';
2
2
 
3
- // We aren't abstracting this yet but here's the ... "Config"
4
- const _CONFIG = (
5
- {
6
- // The input source file that should be passed to browserify:
7
- // (if you need to auto-instantiate an object, for instance)
8
- EntrypointInputSourceFile: `${__dirname}/source/Precedent-Browser-Shim.js`,
3
+ /*
4
+ After hours of reading and trying various ways of using gulp-env, environment variables
5
+ and babel browesrslistrc / package.json environments it is clear that the state of using
6
+ these tools is a mess. There are ways of getting it to work but none of them feel like
7
+ they will work well in the long term (all of the examples seem to be in bands of about
8
+ a year or two of working before the pattern changes entirely).
9
9
 
10
- // The name of the packaged object to be passed to browserify:
11
- // (browserify sets this to global scope and window.SOMEOBJECTNAMEHERE where SOMEOBJECTNAMEHERE is the string below)
12
- LibraryObjectName: `Precedent`,
10
+ WHY did we need such a crazy compatible version? wkhtmltopdf is why. It uses a very
11
+ old incompatible version of the QT browser.
13
12
 
14
- // The folder to write the library files and maps out to:
15
- LibraryOutputFolder: `${__dirname}/dist/`,
13
+ Therefore, we will use a very old and simple method.
16
14
 
17
- // The name of the unminified version of the packaged library, for easy debugging:
18
- LibraryUniminifiedFileName: `precedent.js`,
15
+ 1) There is a config file (gulpfile-config.json), documented here, describing the inputs and outputs for the build operation.
19
16
 
20
- // The name of the minified version of the packaged library, for production release:
21
- LibraryMinifiedFileName: `precedent.min.js`
22
- });
17
+ const _CONFIG = (
18
+ {
19
+ // The input source file that should be passed to browserify:
20
+ // (if you need to auto-instantiate an object, for instance)
21
+ EntrypointInputSourceFile: `${__dirname}/source/Fable-Browser-Shim.js`,
22
+
23
+ // The name of the packaged object to be passed to browserify:
24
+ // (browserify sets this to global scope and window.SOMEOBJECTNAMEHERE where SOMEOBJECTNAMEHERE is the string below)
25
+ LibraryObjectName: `Fable`,
26
+
27
+ // The folder to write the library files and maps out to:
28
+ LibraryOutputFolder: `${__dirname}/dist/`,
29
+
30
+ // The name of the unminified version of the packaged library, for easy debugging:
31
+ LibraryUniminifiedFileName: `fable.js`,
32
+
33
+ // The name of the minified version of the packaged library, for production release:
34
+ LibraryMinifiedFileName: `fable.min.js`
35
+ });
36
+
37
+ 2) We are using a .browserslistrc file... this is what tells gulp-babel, through the
38
+ magic of the @babel/preset-env library, how to transpile the library into a compatible
39
+ enough format for our targets.
40
+
41
+ For example as of writing this, there are two targets we want:
42
+
43
+ * Modern browsers in the last five years, expressed as a .browserslistrc with the string "since 2018"
44
+ * Very old janky browsers expressed as a .browserslistrc with the string "> 0.01%"
45
+ ... which is interpreted as anything more than 0.01% of browsers in existence or something like that
46
+
47
+ 3) Because we want multiple outputs, and, the tools do fine if we want one output but some of
48
+ the toolchain doesn't like making different targets well, we're just going to have multiple
49
+ configurations and .browserslistrc files. So if our spec above says we need a ".browserslistrc"
50
+ file and a "gulpfile-config.json", we're going to make the following two sets of configuration:
51
+
52
+ * .browserslistrc_default, .gulpfile-config_default.json
53
+ * .browserslistrc_compatible, .gulpfile-config_compatible.json
54
+
55
+ 4) We will copy, synchronously, these files to where the rest of our toolchain expects
56
+ them, before we begin the build. This will be done by looking at the GULP_CUSTOM_BUILD_TARGET
57
+ environment variable. This allows us to create new targets to experiment by copying a couple files,
58
+ jimmying the settings and setting an environment variable before running the pipeline.
59
+
60
+ 5) We will run the toolchain and it will happily think it's just doing a single build and kinda work.
61
+
62
+ */
63
+ // BEGINNING OF STEP 3 and STEP 4 ABOVE
64
+ const libFS = require('fs');
65
+ const _GULP_CUSTOM_BUILD_TARGET = (typeof(process.env.GULP_CUSTOM_BUILD_TARGET) == 'undefined') ? 'default' : process.env.GULP_CUSTOM_BUILD_TARGET;
66
+ console.log(`--> Gulp custom build target set to: [${_GULP_CUSTOM_BUILD_TARGET}]`);
67
+ const _GULP_CONFIG = `./gulpfile-config_${_GULP_CUSTOM_BUILD_TARGET}.json`;
68
+ const _GULP_CONFIG_TARGET = `./gulpfile-config.json`;
69
+ console.log(` : Environment set gulp config [${_GULP_CONFIG}] will be copied to [${_GULP_CONFIG_TARGET}]`);
70
+ if (!libFS.existsSync(`./${_GULP_CONFIG}`))
71
+ {
72
+ console.log(`!!!> Enviromnent set gulp config doesn't exist!`);
73
+ process.exit(1);
74
+ }
75
+ else
76
+ {
77
+ libFS.copyFileSync(_GULP_CONFIG, _GULP_CONFIG_TARGET);
78
+ console.log(` > Environment Gulp Config copied`);
79
+ }
80
+ const _BROWSERSLISTRC = `./.browserslistrc_${_GULP_CUSTOM_BUILD_TARGET}`;
81
+ const _BROWSERSLISTRC_TARGET = `./.browserslistrc`;
82
+ console.log(` : Environment set browserslistrc [${_BROWSERSLISTRC}] will be copied to [${_BROWSERSLISTRC_TARGET}]`);
83
+ if (!libFS.existsSync(`./${_GULP_CONFIG}`))
84
+ {
85
+ console.log(`!!!> Enviromnent set browserslistrc doesn't exist!`);
86
+ process.exit(1);
87
+ }
88
+ else
89
+ {
90
+ libFS.copyFileSync(_BROWSERSLISTRC, _BROWSERSLISTRC_TARGET);
91
+ console.log(` > Environment Gulp Config copied`);
92
+ }
93
+ console.log(`---> The browserslistrc compatibility set is: ${libFS.readFileSync(_BROWSERSLISTRC_TARGET, 'utf8')}`);
94
+ // END OF STEP 3 and STEP 4 ABOVE
95
+
96
+
97
+ // ---> Now load the config and get on with building <--- \\
98
+ console.log(``);
99
+ console.log(`---> Loading the gulp config...`);
100
+ const _CONFIG = require('./gulpfile-config.json');
101
+ console.log(` > Building to [${_CONFIG.LibraryUniminifiedFileName}] and [${_CONFIG.LibraryMinifiedFileName}]`)
23
102
 
24
103
  // ---> Boilerplate Browser Uglification and Packaging <--- \\
104
+ console.log(``);
105
+ console.log(`--> Gulp is taking over!`);
25
106
 
26
107
  const libBrowserify = require('browserify');
27
108
  const libGulp = require('gulp');
@@ -37,47 +118,47 @@ const libTerser = require('gulp-terser');
37
118
  // Build the module for the browser
38
119
  libGulp.task('minified',
39
120
  () => {
40
- // set up the custom browserify instance for this task
41
- var tmpBrowserify = libBrowserify(
42
- {
43
- entries: _CONFIG.EntrypointInputSourceFile,
44
- standalone: _CONFIG.LibraryObjectName,
45
- debug: true
46
- });
47
-
48
- return tmpBrowserify.bundle()
49
- .pipe(libVinylSourceStream(_CONFIG.LibraryMinifiedFileName))
50
- .pipe(libVinylBuffer())
51
- .pipe(libSourcemaps.init({loadMaps: true}))
52
- // Add transformation tasks to the pipeline here.
53
- .pipe(libBabel())
54
- .pipe(libTerser())
55
- .on('error', libGulpUtil.log)
56
- .pipe(libSourcemaps.write('./'))
57
- .pipe(libGulp.dest(_CONFIG.LibraryOutputFolder));
121
+ // set up the custom browserify instance for this task
122
+ var tmpBrowserify = libBrowserify(
123
+ {
124
+ entries: _CONFIG.EntrypointInputSourceFile,
125
+ standalone: _CONFIG.LibraryObjectName,
126
+ debug: true
127
+ });
128
+
129
+ return tmpBrowserify.bundle()
130
+ .pipe(libVinylSourceStream(_CONFIG.LibraryMinifiedFileName))
131
+ .pipe(libVinylBuffer())
132
+ .pipe(libSourcemaps.init({loadMaps: true}))
133
+ // Add transformation tasks to the pipeline here.
134
+ .pipe(libBabel())
135
+ .pipe(libTerser())
136
+ .on('error', libGulpUtil.log)
137
+ .pipe(libSourcemaps.write('./'))
138
+ .pipe(libGulp.dest(_CONFIG.LibraryOutputFolder));
58
139
  });
59
140
 
60
141
  // Build the module for the browser
61
142
  libGulp.task('debug',
62
- () => {
63
- // set up the custom browserify instance for this task
64
- var tmpBrowserify = libBrowserify(
65
- {
66
- entries: _CONFIG.EntrypointInputSourceFile,
67
- standalone: _CONFIG.LibraryObjectName,
68
- debug: true
69
- });
70
-
71
- return tmpBrowserify.bundle()
72
- .pipe(libVinylSourceStream(_CONFIG.LibraryUniminifiedFileName))
73
- .pipe(libVinylBuffer())
74
- .pipe(libBabel())
75
- .on('error', libGulpUtil.log)
76
- .pipe(libGulp.dest(_CONFIG.LibraryOutputFolder));
77
- });
143
+ () => {
144
+ // set up the custom browserify instance for this task
145
+ var tmpBrowserify = libBrowserify(
146
+ {
147
+ entries: _CONFIG.EntrypointInputSourceFile,
148
+ standalone: _CONFIG.LibraryObjectName,
149
+ debug: true
150
+ });
151
+
152
+ return tmpBrowserify.bundle()
153
+ .pipe(libVinylSourceStream(_CONFIG.LibraryUniminifiedFileName))
154
+ .pipe(libVinylBuffer())
155
+ .pipe(libBabel())
156
+ .on('error', libGulpUtil.log)
157
+ .pipe(libGulp.dest(_CONFIG.LibraryOutputFolder));
158
+ });
78
159
 
79
160
  libGulp.task
80
161
  (
81
- 'build',
82
- libGulp.series('debug', 'minified')
162
+ 'build',
163
+ libGulp.series('debug', 'minified')
83
164
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "precedent",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Precedent Meta-Templating",
5
5
  "main": "source/Precedent.js",
6
6
  "bin": {
@@ -12,7 +12,8 @@
12
12
  "test": "./node_modules/.bin/mocha -u tdd -R spec",
13
13
  "docker-dev-build-image": "docker build ./ -f Dockerfile_LUXURYCode -t retold/precedent:local",
14
14
  "docker-dev-run": "docker run -it -d --name precedent-dev -p 127.0.0.1:12340:8080 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/precedent\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold/precedent:local",
15
- "build": "./node_modules/.bin/gulp build"
15
+ "build": "./node_modules/.bin/gulp build",
16
+ "build-compatible": "GULP_CUSTOM_BUILD_TARGET=compatible ./node_modules/.bin/gulp build"
16
17
  },
17
18
  "repository": {
18
19
  "type": "git",
@@ -45,10 +46,13 @@
45
46
  ]
46
47
  },
47
48
  "devDependencies": {
49
+ "@babel/core": "^7.21.5",
50
+ "@babel/preset-env": "^7.21.5",
48
51
  "browserify": "^17.0.0",
49
52
  "chai": "4.3.7",
50
53
  "gulp": "^4.0.2",
51
54
  "gulp-babel": "^8.0.0",
55
+ "gulp-env": "^0.4.0",
52
56
  "gulp-sourcemaps": "^3.0.0",
53
57
  "gulp-terser": "^2.1.0",
54
58
  "gulp-util": "^3.0.8",
@@ -18,12 +18,12 @@ class Precedent
18
18
  constructor()
19
19
  {
20
20
  this.WordTree = new libWordTree();
21
-
21
+
22
22
  this.StringParser = new libStringParser();
23
23
 
24
24
  this.ParseTree = this.WordTree.ParseTree;
25
25
  }
26
-
26
+
27
27
  /**
28
28
  * Add a Pattern to the Parse Tree
29
29
  * @method addPattern
@@ -36,16 +36,17 @@ class Precedent
36
36
  {
37
37
  return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);
38
38
  }
39
-
39
+
40
40
  /**
41
41
  * Parse a string with the existing parse tree
42
42
  * @method parseString
43
43
  * @param {string} pString - The string to parse
44
+ * @param {object} pData - Data to pass in as the second argument
44
45
  * @return {string} The result from the parser
45
46
  */
46
- parseString(pString)
47
+ parseString(pString, pData)
47
48
  {
48
- return this.StringParser.parseString(pString, this.ParseTree);
49
+ return this.StringParser.parseString(pString, this.ParseTree, pData);
49
50
  }
50
51
  }
51
52
 
@@ -16,7 +16,7 @@ class StringParser
16
16
  constructor()
17
17
  {
18
18
  }
19
-
19
+
20
20
  /**
21
21
  * Create a fresh parsing state object to work with.
22
22
  * @method newParserState
@@ -39,7 +39,7 @@ class StringParser
39
39
  PatternMatchOutputBuffer: ''
40
40
  });
41
41
  }
42
-
42
+
43
43
  /**
44
44
  * Assign a node of the parser tree to be the next potential match.
45
45
  * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
@@ -59,7 +59,7 @@ class StringParser
59
59
  pParserState.Pattern = pParserState.PatternMatch;
60
60
  }
61
61
  }
62
-
62
+
63
63
  /**
64
64
  * Append a character to the output buffer in the parser state.
65
65
  * This output buffer is used when a potential match is being explored, or a match is being explored.
@@ -72,7 +72,7 @@ class StringParser
72
72
  {
73
73
  pParserState.OutputBuffer += pCharacter;
74
74
  }
75
-
75
+
76
76
  /**
77
77
  * Flush the output buffer to the output and clear it.
78
78
  * @method flushOutputBuffer
@@ -85,21 +85,21 @@ class StringParser
85
85
  pParserState.OutputBuffer = '';
86
86
  }
87
87
 
88
-
88
+
89
89
  /**
90
90
  * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
91
91
  * @method checkPatternEnd
92
92
  * @param {Object} pParserState - The state object for the current parsing task
93
93
  * @private
94
94
  */
95
- checkPatternEnd (pParserState)
95
+ checkPatternEnd (pParserState, pData)
96
96
  {
97
- if ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&
97
+ if ((pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length+pParserState.Pattern.PatternStart.length) &&
98
98
  (pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd))
99
99
  {
100
100
  // ... this is the end of a pattern, cut off the end tag and parse it.
101
101
  // Trim the start and end tags off the output buffer now
102
- pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)));
102
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length+pParserState.Pattern.PatternEnd.length)), pData);
103
103
  // Flush the output buffer.
104
104
  this.flushOutputBuffer(pParserState);
105
105
  // End pattern mode
@@ -107,7 +107,7 @@ class StringParser
107
107
  pParserState.PatternMatch = false;
108
108
  }
109
109
  }
110
-
110
+
111
111
  /**
112
112
  * Parse a character in the buffer.
113
113
  * @method parseCharacter
@@ -115,7 +115,7 @@ class StringParser
115
115
  * @param {Object} pParserState - The state object for the current parsing task
116
116
  * @private
117
117
  */
118
- parseCharacter (pCharacter, pParserState)
118
+ parseCharacter (pCharacter, pParserState, pData)
119
119
  {
120
120
  // (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....
121
121
  if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter))
@@ -137,7 +137,7 @@ class StringParser
137
137
  if (pParserState.Pattern)
138
138
  {
139
139
  // ... Check if this is the end of the pattern (if we are matching a valid pattern)...
140
- this.checkPatternEnd(pParserState);
140
+ this.checkPatternEnd(pParserState, pData);
141
141
  }
142
142
  }
143
143
  // (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
@@ -146,25 +146,26 @@ class StringParser
146
146
  pParserState.Output += pCharacter;
147
147
  }
148
148
  }
149
-
149
+
150
150
  /**
151
151
  * Parse a string for matches, and process any template segments that occur.
152
152
  * @method parseString
153
153
  * @param {string} pString - The string to parse.
154
154
  * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
155
+ * @param {Object} pData - The data to pass to the function as a second paramter
155
156
  */
156
- parseString (pString, pParseTree)
157
+ parseString (pString, pParseTree, pData)
157
158
  {
158
159
  let tmpParserState = this.newParserState(pParseTree);
159
160
 
160
161
  for (var i = 0; i < pString.length; i++)
161
162
  {
162
163
  // TODO: This is not fast.
163
- this.parseCharacter(pString[i], tmpParserState);
164
+ this.parseCharacter(pString[i], tmpParserState, pData);
164
165
  }
165
-
166
+
166
167
  this.flushOutputBuffer(tmpParserState);
167
-
168
+
168
169
  return tmpParserState.Output;
169
170
  }
170
171
  }
@@ -24,6 +24,10 @@ var configPrecedent = (pModule) =>
24
24
  pModule.addPattern('<%#', '%>', (pData)=>{return pData.length});
25
25
  // Replaces the string with the settings object...
26
26
  pModule.addPattern('<%=', '%>', (pData)=>{return JSON.stringify(pModule.settings);});
27
+ // Do a data thingy
28
+ pModule.addPattern('<*', '*>', (pHash, pData)=>{return `pData is [${pData}] with a hash of [${pHash}]`});
29
+ // Do a data thingy
30
+ pModule.addPattern('<^', '^>', (pHash, pData)=>{return `hash of [${pHash}] from pData is ${pData[pHash]}`});
27
31
  // This just escapes out pairs of $
28
32
  pModule.addPattern('$');
29
33
  };
@@ -65,13 +69,13 @@ suite
65
69
  (fDone) =>
66
70
  {
67
71
  var testPrecedent = loadPrecedentModule();
68
-
72
+
69
73
  Expect(Object.keys(testPrecedent.ParseTree).length).to.equal(0, 'There should be an empty tree on initialization.');
70
74
  configPrecedent(testPrecedent);
71
75
  Expect(Object.keys(testPrecedent.ParseTree).length).to.equal(2, 'The tree should grow properly.');
72
76
 
73
77
  //console.log(JSON.stringify(testPrecedent.tree,null,4));
74
-
78
+
75
79
  var tmpResult = testPrecedent.parseString('');
76
80
  Expect(tmpResult.length).to.equal(0, 'Parsing Empty Strings should Work...');
77
81
 
@@ -121,6 +125,34 @@ suite
121
125
  }
122
126
  );
123
127
  test
128
+ (
129
+ 'Leveraging pData a bit...',
130
+ (fDone) =>
131
+ {
132
+ var tmpTestString = 'The <*SomeValue*> pData up in here and a $comment$ as well.';
133
+ var tmpExpectedResult = 'The pData is [Yikes] with a hash of [SomeValue] pData up in here and a comment as well.';
134
+ var testPrecedent = loadPrecedentModule();
135
+ configPrecedent(testPrecedent);
136
+ var tmpResult = testPrecedent.parseString(tmpTestString, 'Yikes');
137
+ Expect(tmpResult).to.equal(tmpExpectedResult);
138
+ fDone();
139
+ }
140
+ );
141
+ test
142
+ (
143
+ 'Leveraging pData a using subobjects...',
144
+ (fDone) =>
145
+ {
146
+ var tmpTestString = 'The <^SomeValue^> pData up in here and a $comment$ as well.';
147
+ var tmpExpectedResult = 'The hash of [SomeValue] from pData is AirbornLight pData up in here and a comment as well.';
148
+ var testPrecedent = loadPrecedentModule();
149
+ configPrecedent(testPrecedent);
150
+ var tmpResult = testPrecedent.parseString(tmpTestString, {SomeValue:'AirbornLight'});
151
+ Expect(tmpResult).to.equal(tmpExpectedResult);
152
+ fDone();
153
+ }
154
+ );
155
+ test
124
156
  (
125
157
  'Bad pattern start parameter...',
126
158
  (fDone) =>
@@ -234,7 +266,7 @@ suite
234
266
  'AAA '+process.env.PATH+' } BBB',
235
267
 
236
268
  'AAA ${ ${PATH} BBB',
237
- // Two start parameters isn't okay ---
269
+ // Two start parameters isn't okay ---
238
270
  // ...it passes the pattern processor the following (without quotes):
239
271
  // " ${PATH"
240
272
  // Which is not going to match an environment variable. With the second
@@ -1,18 +0,0 @@
1
- /**
2
- * Precedent Meta-templating
3
- *
4
- * @license MIT
5
- *
6
- * @author Steven Velozo <steven@velozo.com>
7
- */
8
-
9
- console.log('Precedent meta-templating');
10
- console.log('Contact: Steven Velozo <steven@velozo.com>');
11
- console.log('');
12
- console.log('---');
13
- console.log('');
14
-
15
- // No frills, run it and use command arguments.
16
- var libPrecedent = require(__dirname+'/source/Precedent.js');
17
-
18
- module.exports = libPrecedent();
package/test.js DELETED
@@ -1 +0,0 @@
1
- console.log(JSON.stringify(process.env, null, 4));