1
+
2
+ /**
3
+ * Returns all the steps of the given blockName of the given recipe
4
+ *
5
+ * @param {String } recipe
6
+ * @param {String } blockName
7
+ *
8
+ * @return Array<Object>
9
+ */
10
+ function prepareBlock ( recipe , blockName )
11
+ {
12
+ var steps = [ ] ;
13
+ var block = recipe [ blockName ] ;
14
+ for ( var stepName in block )
15
+ {
16
+ var prepared = prepareStep ( recipe , blockName , stepName ) ;
17
+ steps . push ( prepared ) ;
18
+ }
19
+ return steps ;
20
+ }
21
+
22
+ /**
23
+ * Returns the number of sub matches in the given regular expression (as
24
+ * a string)
25
+ *
26
+ * @param {String } re
27
+ *
28
+ * @return integer
29
+ */
30
+ function numberOfSubmatches ( re )
31
+ {
32
+ var submatches = re
33
+ . replace ( / \\ ./ g, "%" ) // disable any escaped character
34
+ . replace ( / \[ .* ?\] / g, "%" ) // disable any character class
35
+ . match ( / \( (? ! \? ) / g ) // match any open parenthesis, not followed by a ?
36
+ ;
37
+ var result = ( submatches || [ ] ) . length ;
38
+ return result ;
39
+ }
40
+
41
+ /**
42
+ * Returns a step built from the given stepName of the given blockName
43
+ * of the given recipe
44
+ *
45
+ * @param {String } recipe
46
+ * @param {String } blockName
47
+ * @param {String } stepName
48
+ *
49
+ * @return Object
50
+ */
51
+ function prepareStep ( recipe , blockName , stepName )
52
+ {
53
+ var step = recipe [ blockName ] [ stepName ] ;
54
+ var exp = ( typeof step . _match == "string" )
55
+ ? step . _match
56
+ : step . _match . source ;
57
+ var replacement = step . _replace
58
+ ? step . _replace
59
+ : '<span class="$0">$$</span>' ;
60
+ var result = {
61
+ recipe : recipe ,
62
+ blockName : blockName ,
63
+ stepName : stepName ,
64
+ exp : '(' + exp + ')' , // new exp will have 1 more submatch
65
+ length : numberOfSubmatches ( exp ) + 1 ,
66
+ replacement : replacement
67
+ } ;
68
+ return result ;
69
+ }
70
+
71
+ /**
72
+ * Returns the given steps, with back references in the regular
73
+ * expression of each step renumbered according to the number of back
74
+ * references found in any previous step
75
+ *
76
+ * @param {Array } steps
77
+ *
78
+ * @return Array
79
+ */
80
+ function adjustBackReferences ( steps )
81
+ {
82
+ var prevLength = 1 ;
83
+ var exps = [ ] ;
84
+ for ( var i = 0 , iTop = steps . length ; i < iTop ; i ++ ) {
85
+ var exp = steps [ i ] . exp ;
86
+ exp = exp . replace ( / \\ \\ | \\ ( \d + ) / g,
87
+ function ( m , aNum )
88
+ {
89
+ return ! aNum ? m : "\\" + ( prevLength + 1 + parseInt ( aNum , 10 ) ) ;
90
+ }
91
+ ) ;
92
+ exps . push ( exp ) ;
93
+ prevLength += steps [ i ] . length ;
94
+ }
95
+ return exps ;
96
+ }
97
+
98
+ /**
99
+ * Returns a regular expression built from all the given steps
100
+ *
101
+ * @param {Array } steps
102
+ *
103
+ * @return RegExp
104
+ */
105
+ function knowHow ( steps , flags )
106
+ {
107
+ var prolog = '((?:\\s|\\S)*?)' ;
108
+ var epilog = '((?:\\s|\\S)+)' ;
109
+ var exps = adjustBackReferences ( steps ) ;
110
+ var source = '(?:' + exps . join ( '|' ) + ')' ;
111
+ source = prolog + source + '|' + epilog ;
112
+ return new RegExp ( source , flags ) ;
113
+ }
114
+
115
+ /**
116
+ * Returns the given replacement, after adding the given prefix to all
117
+ * classes of all SPANs
118
+ *
119
+ * @param {String } prefix
120
+ * @param {String } replacement
121
+ *
122
+ * @return String
123
+ */
124
+ function addPrefix ( prefix , replacement )
125
+ {
126
+ var lookFor = / ( < s p a n \s + c l a s s \s * = \s * ( [ " ' ] ) ) ( (?: (? ! _ _ ) \w ) + \2\s * > ) / ig;
127
+ var replaceWith = '$1' + prefix + '__$3' ;
128
+ var aux = replacement . replace ( lookFor , replaceWith ) ;
129
+ return aux ;
130
+ }
131
+
132
+ /**
133
+ * Returns the step in the given steps and its matches in the given
134
+ * allMatches
135
+ *
136
+ * @param {Object } steps the steps of a recipe
137
+ * @param {Array } allMatches the corresponding matches
138
+ *
139
+ * @return Object
140
+ */
141
+ function locateStepMatches ( steps , allMatches )
142
+ {
143
+ var matchesIndex = 2 ;
144
+ for ( var i = 0 , iTop = steps . length ; i < iTop ; i ++ )
145
+ {
146
+ var step = steps [ i ] ;
147
+ var stepMatches = allMatches [ matchesIndex ] ;
148
+ if ( stepMatches ) break ;
149
+ matchesIndex += step . length ;
150
+ }
151
+ var matches = allMatches . slice ( matchesIndex , matchesIndex + step . length ) ;
152
+ var offset = allMatches [ allMatches . length - 2 ] ;
153
+ var original = allMatches [ allMatches . length - 1 ] ;
154
+ matches . push ( offset ) ;
155
+ matches . push ( original ) ;
156
+ return { step : step , matches : matches } ;
157
+ }
158
+
159
+ /**
160
+ * Returns the replacement for the given stepMatches, based on the
161
+ * function in stepMatches.step.replacement
162
+ *
163
+ * @param {Object } stepMatches
164
+ *
165
+ * @return String
166
+ */
167
+ function functionReplacement ( stepMatches )
168
+ {
169
+ var that =
170
+ {
171
+ x : function ( subject , module )
172
+ {
173
+ var result = applyModule ( subject , module , stepMatches . step ) ;
174
+ return result ;
175
+ }
176
+ } ;
177
+ var result = stepMatches . step . replacement . apply ( that , stepMatches . matches ) ;
178
+ return result ;
179
+ }
180
+
181
+ /**
182
+ * Returns the replacement for the given stepMatches, based on the
183
+ * template in stepMatches.step.replacement
184
+ *
185
+ * @param {Object } stepMatches
186
+ *
187
+ * @return String
188
+ */
189
+ function templateReplacement ( stepMatches )
190
+ {
191
+ var re = / ( \\ \$ ) | (?: \$ \$ ) | (?: \$ ( \d + ) ) / g;
192
+ var substitution = function ( m , escaped , K )
193
+ {
194
+ var result = '' ;
195
+ if ( escaped ) /* \$ */
196
+ {
197
+ result = "$" ;
198
+ }
199
+ else if ( ! K ) /* $$ */
200
+ {
201
+ result = escapeHtmlSpecialChars ( stepMatches . matches [ 0 ] ) ; //stepMatches
202
+ }
203
+ else if ( K == "0" ) /* $0 */
204
+ {
205
+ result = stepMatches . step . stepName ;
206
+ }
207
+ else /* $K */
208
+ {
209
+ result = escapeHtmlSpecialChars ( stepMatches . matches [ K ] ) ;
210
+ }
211
+ return result ;
212
+ } ;
213
+ var result = stepMatches . step . replacement . replace ( re , substitution ) ;
214
+ return result ;
215
+ }
216
+
217
+ /**
218
+ * Returns the replacement for any match found. This is a callback
219
+ * function passed to String.replace()
220
+ *
221
+ * @return String
222
+ */
223
+ function chef ( steps , replaceArgs )
224
+ {
225
+ var result = '' ;
226
+ var anyMatch = replaceArgs [ 0 ] ;
227
+ if ( ! anyMatch ) return result ;
228
+
229
+ var epilog = replaceArgs [ replaceArgs . length - 3 ] ;
230
+ if ( epilog ) {
231
+ result = escapeHtmlSpecialChars ( epilog ) ;
232
+ return result ;
233
+ }
234
+ var stepMatches = locateStepMatches ( steps , replaceArgs ) ;
235
+ result = $ . isFunction ( stepMatches . step . replacement )
236
+ ? functionReplacement ( stepMatches )
237
+ : templateReplacement ( stepMatches )
238
+ ;
239
+ var prolog = replaceArgs [ 1 ] ;
240
+ prolog = escapeHtmlSpecialChars ( prolog ) ;
241
+ result = addPrefix ( stepMatches . step . recipe . _name , result ) ;
242
+ result = prolog + result ;
243
+ return result ;
244
+ }
245
+
246
+ /**
247
+ * Returns the given ingredients, after applying the given blockName of
248
+ * the given recipe to it
249
+ *
250
+ * @param {String } ingredients
251
+ * @param {Object } recipe
252
+ * @param {String } blockName
253
+ *
254
+ * @return String
255
+ */
256
+ function cook ( ingredients , recipe , blockName )
257
+ {
258
+ if ( ! blockName )
259
+ {
260
+ blockName = '_main' ;
261
+ checkSpices ( recipe ) ;
262
+ }
263
+ if ( ! blockName in recipe ) return escapeHtmlSpecialChars ( ingredients ) ;
264
+ var steps = prepareBlock ( recipe , blockName ) ;
265
+ var flags = recipe . _case
266
+ ? "g"
267
+ : "gi" ;
268
+ var kh = knowHow ( steps , flags ) ;
269
+ var perfect = ingredients . replace ( kh ,
270
+ function ( )
271
+ {
272
+ var args = Array . prototype . slice . call ( arguments ) ;
273
+ var result = chef ( steps , args ) ;
274
+ return result ;
275
+ }
276
+ ) ;
277
+ return perfect ;
278
+ }
279
+
280
+
0 commit comments