precedent 1.0.14 → 1.0.16
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.
- package/.babelrc +5 -0
- package/CONTRIBUTING.md +50 -0
- package/README.md +116 -43
- package/docs/.nojekyll +0 -0
- package/docs/README.md +142 -0
- package/docs/_sidebar.md +19 -0
- package/docs/_topbar.md +5 -0
- package/docs/api.md +209 -0
- package/docs/cover.md +15 -0
- package/docs/css/docuserve.css +73 -0
- package/docs/examples.md +429 -0
- package/docs/index.html +39 -0
- package/docs/retold-catalog.json +70 -0
- package/docs/retold-keyword-index.json +19 -0
- package/package.json +49 -62
- package/source/StringParser.js +92 -61
- package/source/WordTree.js +50 -12
- package/test/Precedent_tests.js +0 -3
- package/.browserslistrc_compatible +0 -1
- package/.browserslistrc_default +0 -1
- package/.travis.yml +0 -13
- package/Ideas.md +0 -4
- package/bower.json +0 -27
- package/dist/precedent.compatible.js +0 -310
- package/dist/precedent.compatible.min.js +0 -12
- package/dist/precedent.compatible.min.js.map +0 -1
- package/dist/precedent.js +0 -310
- package/dist/precedent.min.js +0 -12
- package/dist/precedent.min.js.map +0 -1
- package/gulpfile-config.json +0 -11
- package/gulpfile-config_compatible.json +0 -11
- package/gulpfile-config_default.json +0 -11
- package/gulpfile.js +0 -164
package/dist/precedent.js
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
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
|
-
* @author <steven@velozo.com>
|
|
52
|
-
*/
|
|
53
|
-
var libNPMModuleWrapper = require('./Precedent.js');
|
|
54
|
-
if (typeof window == 'object' && !window.hasOwnProperty('Precedent')) {
|
|
55
|
-
window.Precedent = libNPMModuleWrapper;
|
|
56
|
-
}
|
|
57
|
-
module.exports = libNPMModuleWrapper;
|
|
58
|
-
}, {
|
|
59
|
-
"./Precedent.js": 2
|
|
60
|
-
}],
|
|
61
|
-
2: [function (require, module, exports) {
|
|
62
|
-
/**
|
|
63
|
-
* Precedent Meta-Templating
|
|
64
|
-
*
|
|
65
|
-
* @license MIT
|
|
66
|
-
*
|
|
67
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
68
|
-
*
|
|
69
|
-
* @description Process text streams, parsing out meta-template expressions.
|
|
70
|
-
*/
|
|
71
|
-
var libWordTree = require(`./WordTree.js`);
|
|
72
|
-
var libStringParser = require(`./StringParser.js`);
|
|
73
|
-
class Precedent {
|
|
74
|
-
/**
|
|
75
|
-
* Precedent Constructor
|
|
76
|
-
*/
|
|
77
|
-
constructor() {
|
|
78
|
-
this.WordTree = new libWordTree();
|
|
79
|
-
this.StringParser = new libStringParser();
|
|
80
|
-
this.ParseTree = this.WordTree.ParseTree;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Add a Pattern to the Parse Tree
|
|
85
|
-
* @method addPattern
|
|
86
|
-
* @param {Object} pTree - A node on the parse tree to push the characters into
|
|
87
|
-
* @param {string} pPattern - The string to add to the tree
|
|
88
|
-
* @param {number} pIndex - callback function
|
|
89
|
-
* @return {bool} True if adding the pattern was successful
|
|
90
|
-
*/
|
|
91
|
-
addPattern(pPatternStart, pPatternEnd, pParser) {
|
|
92
|
-
return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Parse a string with the existing parse tree
|
|
97
|
-
* @method parseString
|
|
98
|
-
* @param {string} pString - The string to parse
|
|
99
|
-
* @param {object} pData - Data to pass in as the second argument
|
|
100
|
-
* @return {string} The result from the parser
|
|
101
|
-
*/
|
|
102
|
-
parseString(pString, pData) {
|
|
103
|
-
return this.StringParser.parseString(pString, this.ParseTree, pData);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
module.exports = Precedent;
|
|
107
|
-
}, {
|
|
108
|
-
"./StringParser.js": 3,
|
|
109
|
-
"./WordTree.js": 4
|
|
110
|
-
}],
|
|
111
|
-
3: [function (require, module, exports) {
|
|
112
|
-
/**
|
|
113
|
-
* String Parser
|
|
114
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
115
|
-
* @description Parse a string, properly processing each matched token in the word tree.
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
|
-
class StringParser {
|
|
119
|
-
/**
|
|
120
|
-
* StringParser Constructor
|
|
121
|
-
*/
|
|
122
|
-
constructor() {}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Create a fresh parsing state object to work with.
|
|
126
|
-
* @method newParserState
|
|
127
|
-
* @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)
|
|
128
|
-
* @return {Object} A new parser state object for running a character parser on
|
|
129
|
-
* @private
|
|
130
|
-
*/
|
|
131
|
-
newParserState(pParseTree) {
|
|
132
|
-
return {
|
|
133
|
-
ParseTree: pParseTree,
|
|
134
|
-
Asynchronous: false,
|
|
135
|
-
Output: '',
|
|
136
|
-
OutputBuffer: '',
|
|
137
|
-
Pattern: false,
|
|
138
|
-
PatternMatch: false,
|
|
139
|
-
PatternMatchOutputBuffer: ''
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Assign a node of the parser tree to be the next potential match.
|
|
145
|
-
* If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
|
|
146
|
-
* @method assignNode
|
|
147
|
-
* @param {Object} pNode - A node on the parse tree to assign
|
|
148
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
149
|
-
* @private
|
|
150
|
-
*/
|
|
151
|
-
assignNode(pNode, pParserState) {
|
|
152
|
-
pParserState.PatternMatch = pNode;
|
|
153
|
-
|
|
154
|
-
// If the pattern has a END we can assume it has a parse function...
|
|
155
|
-
if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) {
|
|
156
|
-
// ... this is the legitimate start of a pattern.
|
|
157
|
-
pParserState.Pattern = pParserState.PatternMatch;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Append a character to the output buffer in the parser state.
|
|
163
|
-
* This output buffer is used when a potential match is being explored, or a match is being explored.
|
|
164
|
-
* @method appendOutputBuffer
|
|
165
|
-
* @param {string} pCharacter - The character to append
|
|
166
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
167
|
-
* @private
|
|
168
|
-
*/
|
|
169
|
-
appendOutputBuffer(pCharacter, pParserState) {
|
|
170
|
-
pParserState.OutputBuffer += pCharacter;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Flush the output buffer to the output and clear it.
|
|
175
|
-
* @method flushOutputBuffer
|
|
176
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
177
|
-
* @private
|
|
178
|
-
*/
|
|
179
|
-
flushOutputBuffer(pParserState) {
|
|
180
|
-
pParserState.Output += pParserState.OutputBuffer;
|
|
181
|
-
pParserState.OutputBuffer = '';
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
|
|
186
|
-
* @method checkPatternEnd
|
|
187
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
188
|
-
* @private
|
|
189
|
-
*/
|
|
190
|
-
checkPatternEnd(pParserState, pData) {
|
|
191
|
-
if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) {
|
|
192
|
-
// ... this is the end of a pattern, cut off the end tag and parse it.
|
|
193
|
-
// Trim the start and end tags off the output buffer now
|
|
194
|
-
pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)), pData);
|
|
195
|
-
// Flush the output buffer.
|
|
196
|
-
this.flushOutputBuffer(pParserState);
|
|
197
|
-
// End pattern mode
|
|
198
|
-
pParserState.Pattern = false;
|
|
199
|
-
pParserState.PatternMatch = false;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Parse a character in the buffer.
|
|
205
|
-
* @method parseCharacter
|
|
206
|
-
* @param {string} pCharacter - The character to append
|
|
207
|
-
* @param {Object} pParserState - The state object for the current parsing task
|
|
208
|
-
* @private
|
|
209
|
-
*/
|
|
210
|
-
parseCharacter(pCharacter, pParserState, pData) {
|
|
211
|
-
// (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....
|
|
212
|
-
if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) {
|
|
213
|
-
// ... assign the node as the matched node.
|
|
214
|
-
this.assignNode(pParserState.ParseTree[pCharacter], pParserState);
|
|
215
|
-
this.appendOutputBuffer(pCharacter, pParserState);
|
|
216
|
-
}
|
|
217
|
-
// (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)
|
|
218
|
-
else if (pParserState.PatternMatch) {
|
|
219
|
-
// If the pattern has a subpattern with this key
|
|
220
|
-
if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) {
|
|
221
|
-
// Continue matching patterns.
|
|
222
|
-
this.assignNode(pParserState.PatternMatch[pCharacter], pParserState);
|
|
223
|
-
}
|
|
224
|
-
this.appendOutputBuffer(pCharacter, pParserState);
|
|
225
|
-
if (pParserState.Pattern) {
|
|
226
|
-
// ... Check if this is the end of the pattern (if we are matching a valid pattern)...
|
|
227
|
-
this.checkPatternEnd(pParserState, pData);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
// (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
|
|
231
|
-
else {
|
|
232
|
-
pParserState.Output += pCharacter;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Parse a string for matches, and process any template segments that occur.
|
|
238
|
-
* @method parseString
|
|
239
|
-
* @param {string} pString - The string to parse.
|
|
240
|
-
* @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
|
|
241
|
-
* @param {Object} pData - The data to pass to the function as a second parameter
|
|
242
|
-
*/
|
|
243
|
-
parseString(pString, pParseTree, pData) {
|
|
244
|
-
let tmpParserState = this.newParserState(pParseTree);
|
|
245
|
-
for (var i = 0; i < pString.length; i++) {
|
|
246
|
-
this.parseCharacter(pString[i], tmpParserState, pData);
|
|
247
|
-
}
|
|
248
|
-
this.flushOutputBuffer(tmpParserState);
|
|
249
|
-
return tmpParserState.Output;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
module.exports = StringParser;
|
|
253
|
-
}, {}],
|
|
254
|
-
4: [function (require, module, exports) {
|
|
255
|
-
/**
|
|
256
|
-
* Word Tree
|
|
257
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
258
|
-
* @description Create a tree (directed graph) of Javascript objects, one character per object.
|
|
259
|
-
*/
|
|
260
|
-
|
|
261
|
-
class WordTree {
|
|
262
|
-
/**
|
|
263
|
-
* WordTree Constructor
|
|
264
|
-
*/
|
|
265
|
-
constructor() {
|
|
266
|
-
this.ParseTree = {};
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Add a child character to a Parse Tree node
|
|
271
|
-
* @method addChild
|
|
272
|
-
* @param {Object} pTree - A parse tree to push the characters into
|
|
273
|
-
* @param {string} pPattern - The string to add to the tree
|
|
274
|
-
* @param {number} pIndex - The index of the character in the pattern
|
|
275
|
-
* @returns {Object} The resulting leaf node that was added (or found)
|
|
276
|
-
* @private
|
|
277
|
-
*/
|
|
278
|
-
addChild(pTree, pPattern, pIndex) {
|
|
279
|
-
if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {};
|
|
280
|
-
return pTree[pPattern[pIndex]];
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/** Add a Pattern to the Parse Tree
|
|
284
|
-
* @method addPattern
|
|
285
|
-
* @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
|
|
286
|
-
* @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
|
|
287
|
-
* @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.
|
|
288
|
-
* @return {bool} True if adding the pattern was successful
|
|
289
|
-
*/
|
|
290
|
-
addPattern(pPatternStart, pPatternEnd, pParser) {
|
|
291
|
-
if (pPatternStart.length < 1) return false;
|
|
292
|
-
if (typeof pPatternEnd === 'string' && pPatternEnd.length < 1) return false;
|
|
293
|
-
let tmpLeaf = this.ParseTree;
|
|
294
|
-
|
|
295
|
-
// Add the tree of leaves iteratively
|
|
296
|
-
for (var i = 0; i < pPatternStart.length; i++) tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);
|
|
297
|
-
tmpLeaf.PatternStart = pPatternStart;
|
|
298
|
-
tmpLeaf.PatternEnd = typeof pPatternEnd === 'string' && pPatternEnd.length > 0 ? pPatternEnd : pPatternStart;
|
|
299
|
-
tmpLeaf.Parse = typeof pParser === 'function' ? pParser : typeof pParser === 'string' ? () => {
|
|
300
|
-
return pParser;
|
|
301
|
-
} : pData => {
|
|
302
|
-
return pData;
|
|
303
|
-
};
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
module.exports = WordTree;
|
|
308
|
-
}, {}]
|
|
309
|
-
}, {}, [1])(1);
|
|
310
|
-
});
|
package/dist/precedent.min.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
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){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){
|
|
2
|
-
/**
|
|
3
|
-
* Precedent Meta-Templating
|
|
4
|
-
*
|
|
5
|
-
* @license MIT
|
|
6
|
-
*
|
|
7
|
-
* @author Steven Velozo <steven@velozo.com>
|
|
8
|
-
*
|
|
9
|
-
* @description Process text streams, parsing out meta-template expressions.
|
|
10
|
-
*/
|
|
11
|
-
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=class{constructor(){}newParserState(t){return{ParseTree:t,Asynchronous:!1,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=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)}));
|
|
12
|
-
//# sourceMappingURL=precedent.min.js.map
|
|
@@ -1 +0,0 @@
|
|
|
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","Asynchronous","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* @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* @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* @author Steven Velozo <steven@velozo.com>\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\tAsynchronous: false,\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\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 parameter\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\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* @author Steven Velozo <steven@velozo.com>\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\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\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\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* @author Steven Velozo <steven@velozo.com>\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\tAsynchronous: false,\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\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 parameter\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\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* @author Steven Velozo <steven@velozo.com>\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\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\n\t\treturn pTree[pPattern[pIndex]];\n\t}\n\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/gulpfile-config.json
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
-
}
|
package/gulpfile.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
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
|
-
|
|
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.
|
|
12
|
-
|
|
13
|
-
Therefore, we will use a very old and simple method.
|
|
14
|
-
|
|
15
|
-
1) There is a config file (gulpfile-config.json), documented here, describing the inputs and outputs for the build operation.
|
|
16
|
-
|
|
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}]`)
|
|
102
|
-
|
|
103
|
-
// ---> Boilerplate Browser Uglification and Packaging <--- \\
|
|
104
|
-
console.log(``);
|
|
105
|
-
console.log(`--> Gulp is taking over!`);
|
|
106
|
-
|
|
107
|
-
const libBrowserify = require('browserify');
|
|
108
|
-
const libGulp = require('gulp');
|
|
109
|
-
|
|
110
|
-
const libVinylSourceStream = require('vinyl-source-stream');
|
|
111
|
-
const libVinylBuffer = require('vinyl-buffer');
|
|
112
|
-
|
|
113
|
-
const libSourcemaps = require('gulp-sourcemaps');
|
|
114
|
-
const libGulpUtil = require('gulp-util');
|
|
115
|
-
const libBabel = require('gulp-babel');
|
|
116
|
-
const libTerser = require('gulp-terser');
|
|
117
|
-
|
|
118
|
-
// Build the module for the browser
|
|
119
|
-
libGulp.task('minified',
|
|
120
|
-
() => {
|
|
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));
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Build the module for the browser
|
|
142
|
-
libGulp.task('debug',
|
|
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
|
-
});
|
|
159
|
-
|
|
160
|
-
libGulp.task
|
|
161
|
-
(
|
|
162
|
-
'build',
|
|
163
|
-
libGulp.series('debug', 'minified')
|
|
164
|
-
);
|