@rhinostone/swig 2.0.1 → 2.1.0
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/.changes/v2.1.0.md +8 -0
- package/.eslintrc.json +8 -1
- package/HISTORY.md +9 -0
- package/README.md +13 -1
- package/ROADMAP.md +6 -0
- package/dist/swig.js +491 -28
- package/dist/swig.min.js +24 -6
- package/dist/swig.min.js.map +1 -1
- package/lib/async/pre-walker.js +279 -0
- package/lib/swig.js +146 -2
- package/package.json +2 -2
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
var utils = require('../utils');
|
|
2
|
+
|
|
3
|
+
/*!
|
|
4
|
+
* Makes a string safe for a regular expression. Mirrors lib/parser.js.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
function escapeRegExp(str) {
|
|
8
|
+
return str.replace(/[\-\/\\\^$*+?.()|\[\]{}]/g, '\\$&');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/*!
|
|
12
|
+
* Build the splitter regex from the controls trio. Mirrors the regex that
|
|
13
|
+
* parser.parse() builds at parse-time so the pre-walker chunks the same
|
|
14
|
+
* way the real parser would.
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
function buildSplitter(controls) {
|
|
18
|
+
var anyChar = '[\\s\\S]*?',
|
|
19
|
+
varOpen = escapeRegExp(controls.varControls[0]),
|
|
20
|
+
varClose = escapeRegExp(controls.varControls[1]),
|
|
21
|
+
tagOpen = escapeRegExp(controls.tagControls[0]),
|
|
22
|
+
tagClose = escapeRegExp(controls.tagControls[1]),
|
|
23
|
+
cmtOpen = escapeRegExp(controls.cmtControls[0]),
|
|
24
|
+
cmtClose = escapeRegExp(controls.cmtControls[1]);
|
|
25
|
+
return new RegExp(
|
|
26
|
+
'(' +
|
|
27
|
+
tagOpen + anyChar + tagClose + '|' +
|
|
28
|
+
varOpen + anyChar + varClose + '|' +
|
|
29
|
+
cmtOpen + anyChar + cmtClose +
|
|
30
|
+
')'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/*!
|
|
35
|
+
* Strip tag controls and optional whitespace-control markers from a tag
|
|
36
|
+
* chunk, returning the trimmed tag body (e.g. `extends "x.html"`).
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
function stripTagBody(chunk, tagOpen, tagClose) {
|
|
40
|
+
var body = chunk.substr(tagOpen.length, chunk.length - tagOpen.length - tagClose.length);
|
|
41
|
+
if (body.charAt(0) === '-') {
|
|
42
|
+
body = body.substr(1);
|
|
43
|
+
}
|
|
44
|
+
if (body.charAt(body.length - 1) === '-') {
|
|
45
|
+
body = body.substr(0, body.length - 1);
|
|
46
|
+
}
|
|
47
|
+
return body.replace(/^\s+|\s+$/g, '');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Scan template source for static `{% extends|include|import|from "..." %}`
|
|
52
|
+
* targets. Pure function; performs no I/O.
|
|
53
|
+
*
|
|
54
|
+
* The scanner mirrors the real parser's chunk-splitter so it agrees on
|
|
55
|
+
* chunk boundaries even under non-default control characters. Dynamic
|
|
56
|
+
* paths (`{% extends parent_var %}`) and tag bodies whose first token
|
|
57
|
+
* isn't a string literal are silently skipped — they remain on the sync
|
|
58
|
+
* path, which throws appropriately at parse time.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* preWalker.scan('{% extends "layout.html" %}{% include "x" %}', {
|
|
62
|
+
* varControls: ['{{', '}}'],
|
|
63
|
+
* tagControls: ['{%', '%}'],
|
|
64
|
+
* cmtControls: ['{#', '#}'],
|
|
65
|
+
* rawTag: 'raw',
|
|
66
|
+
* keywords: ['extends', 'include', 'import']
|
|
67
|
+
* });
|
|
68
|
+
* // => [
|
|
69
|
+
* // { kind: 'extends', path: 'layout.html' },
|
|
70
|
+
* // { kind: 'include', path: 'x' }
|
|
71
|
+
* // ]
|
|
72
|
+
*
|
|
73
|
+
* @param {string} source
|
|
74
|
+
* @param {object} opts
|
|
75
|
+
* @param {array} opts.varControls e.g. <code>['{{', '}}']</code>.
|
|
76
|
+
* @param {array} opts.tagControls e.g. <code>['{%', '%}']</code>.
|
|
77
|
+
* @param {array} opts.cmtControls e.g. <code>['{#', '#}']</code>.
|
|
78
|
+
* @param {string} opts.rawTag Tag name that opens verbatim regions
|
|
79
|
+
* (<code>raw</code> for native swig).
|
|
80
|
+
* @param {array} opts.keywords Keywords whose first quoted argument is
|
|
81
|
+
* a template path. Native swig:
|
|
82
|
+
* <code>['extends', 'include', 'import']</code>.
|
|
83
|
+
* @return {array} List of <code>{ kind, path }</code> entries.
|
|
84
|
+
*/
|
|
85
|
+
exports.scan = function (source, opts) {
|
|
86
|
+
source = source.replace(/\r\n/g, '\n');
|
|
87
|
+
|
|
88
|
+
var splitter = buildSplitter(opts),
|
|
89
|
+
tagOpen = opts.tagControls[0],
|
|
90
|
+
tagClose = opts.tagControls[1],
|
|
91
|
+
rawTag = opts.rawTag,
|
|
92
|
+
endRawTag = 'end' + rawTag,
|
|
93
|
+
keywordRegex = new RegExp(
|
|
94
|
+
'^(' + opts.keywords.join('|') + ')\\s+["\\\']([^"\\\']+)["\\\']'
|
|
95
|
+
),
|
|
96
|
+
chunks = source.split(splitter),
|
|
97
|
+
results = [],
|
|
98
|
+
inRaw = false,
|
|
99
|
+
i,
|
|
100
|
+
chunk,
|
|
101
|
+
body,
|
|
102
|
+
name,
|
|
103
|
+
m;
|
|
104
|
+
|
|
105
|
+
for (i = 0; i < chunks.length; i += 1) {
|
|
106
|
+
chunk = chunks[i];
|
|
107
|
+
if (typeof chunk !== 'string' || !chunk) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (!utils.startsWith(chunk, tagOpen) || !utils.endsWith(chunk, tagClose)) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
body = stripTagBody(chunk, tagOpen, tagClose);
|
|
116
|
+
name = body.split(/\s+/)[0];
|
|
117
|
+
|
|
118
|
+
if (name === rawTag) {
|
|
119
|
+
inRaw = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (name === endRawTag) {
|
|
123
|
+
inRaw = false;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (inRaw) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
m = keywordRegex.exec(body);
|
|
131
|
+
if (m) {
|
|
132
|
+
results.push({ kind: m[1], path: m[2] });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return results;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Walk the dependency graph asynchronously starting from <var>entryPath</var>.
|
|
141
|
+
*
|
|
142
|
+
* Repeatedly loads, scans, and resolves child template paths in parallel
|
|
143
|
+
* via the user's async loader, until the dep graph closes. Returns a
|
|
144
|
+
* Promise resolving to a populated <code>{ resolvedPath: source }</code>
|
|
145
|
+
* map suitable for backing a memory loader.
|
|
146
|
+
*
|
|
147
|
+
* Cycles in the graph are tolerated — once a path is in the map or
|
|
148
|
+
* pending, subsequent enqueue requests are dropped. The synchronous
|
|
149
|
+
* renderer's existing circular-extends guard handles cycles at parse
|
|
150
|
+
* time on the second pass.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* preWalker.walk('/abs/entry.html', userLoader, scanOpts).then(function (memMap) {
|
|
154
|
+
* // memMap = { '/abs/entry.html': '...', '/abs/layout.html': '...', ... }
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* @param {string} entryPath Resolved path of the entry template.
|
|
158
|
+
* @param {object} loader User loader. Must expose:
|
|
159
|
+
* <code>resolve(to, from)</code> (sync, returns
|
|
160
|
+
* string) and
|
|
161
|
+
* <code>load(id, cb)</code> (async, calls
|
|
162
|
+
* <code>cb(err, source)</code>).
|
|
163
|
+
* @param {object} scanOpts Pass-through to {@link scan}.
|
|
164
|
+
* @return {Promise} Resolves to the populated memory map.
|
|
165
|
+
*/
|
|
166
|
+
exports.walk = function (entryPath, loader, scanOpts) {
|
|
167
|
+
var memMap = {};
|
|
168
|
+
var pending = {};
|
|
169
|
+
|
|
170
|
+
return new Promise(function (resolve, reject) {
|
|
171
|
+
var inFlight = 0;
|
|
172
|
+
var queue = [];
|
|
173
|
+
var hasError = false;
|
|
174
|
+
|
|
175
|
+
function enqueue(path) {
|
|
176
|
+
if (memMap.hasOwnProperty(path) || pending[path]) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
pending[path] = true;
|
|
180
|
+
queue.push(path);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function drain() {
|
|
184
|
+
while (queue.length > 0 && !hasError) {
|
|
185
|
+
var path = queue.shift();
|
|
186
|
+
inFlight += 1;
|
|
187
|
+
startLoad(path);
|
|
188
|
+
}
|
|
189
|
+
if (inFlight === 0 && !hasError && queue.length === 0) {
|
|
190
|
+
resolve(memMap);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function startLoad(resolvedPath) {
|
|
195
|
+
loader.load(resolvedPath, function (err, src) {
|
|
196
|
+
if (hasError) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (err) {
|
|
200
|
+
hasError = true;
|
|
201
|
+
reject(err);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (typeof src !== 'string') {
|
|
205
|
+
hasError = true;
|
|
206
|
+
reject(new Error('Async loader returned non-string source for "' + resolvedPath + '"'));
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
memMap[resolvedPath] = src;
|
|
210
|
+
|
|
211
|
+
var targets;
|
|
212
|
+
try {
|
|
213
|
+
targets = exports.scan(src, scanOpts);
|
|
214
|
+
} catch (e) {
|
|
215
|
+
hasError = true;
|
|
216
|
+
reject(e);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var i, resolvedChild;
|
|
221
|
+
for (i = 0; i < targets.length; i += 1) {
|
|
222
|
+
try {
|
|
223
|
+
resolvedChild = loader.resolve(targets[i].path, resolvedPath);
|
|
224
|
+
} catch (e) {
|
|
225
|
+
hasError = true;
|
|
226
|
+
reject(e);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
enqueue(resolvedChild);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
inFlight -= 1;
|
|
233
|
+
drain();
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
enqueue(entryPath);
|
|
238
|
+
drain();
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Build a sync memory wrapper around a pre-populated
|
|
244
|
+
* <code>{ resolvedPath: source }</code> map. Delegates <code>resolve</code>
|
|
245
|
+
* to the user loader so cache keys match what the pre-walker produced.
|
|
246
|
+
*
|
|
247
|
+
* @example
|
|
248
|
+
* var mem = preWalker.makeMemoryWrapper(userLoader, memMap);
|
|
249
|
+
* swig.options.loader = mem;
|
|
250
|
+
* swig.renderFile('/abs/entry.html', locals); // sync, hits memMap
|
|
251
|
+
*
|
|
252
|
+
* @param {object} userLoader Original async loader (used for resolve).
|
|
253
|
+
* @param {object} memMap Pre-populated source map.
|
|
254
|
+
* @return {object} A loader exposing <code>resolve</code> and
|
|
255
|
+
* <code>load</code>.
|
|
256
|
+
*/
|
|
257
|
+
exports.makeMemoryWrapper = function (userLoader, memMap) {
|
|
258
|
+
return {
|
|
259
|
+
resolve: function (to, from) {
|
|
260
|
+
return userLoader.resolve(to, from);
|
|
261
|
+
},
|
|
262
|
+
load: function (id, cb) {
|
|
263
|
+
var src = memMap[id];
|
|
264
|
+
if (typeof src !== 'string') {
|
|
265
|
+
var err = new Error('Pre-walked map missing path: "' + id + '"');
|
|
266
|
+
if (cb) {
|
|
267
|
+
cb(err);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
throw err;
|
|
271
|
+
}
|
|
272
|
+
if (cb) {
|
|
273
|
+
cb(null, src);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
return src;
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
};
|
package/lib/swig.js
CHANGED
|
@@ -4,16 +4,17 @@ var utils = require('./utils'),
|
|
|
4
4
|
parser = require('./parser'),
|
|
5
5
|
dateformatter = require('./dateformatter'),
|
|
6
6
|
loaders = require('./loaders'),
|
|
7
|
+
preWalker = require('./async/pre-walker'),
|
|
7
8
|
engine = require('@rhinostone/swig-core/lib/engine');
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Swig version number as a string.
|
|
11
12
|
* @example
|
|
12
|
-
* if (swig.version === "2.0
|
|
13
|
+
* if (swig.version === "2.1.0") { ... }
|
|
13
14
|
*
|
|
14
15
|
* @type {String}
|
|
15
16
|
*/
|
|
16
|
-
exports.version = "2.0
|
|
17
|
+
exports.version = "2.1.0";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Swig Options Object. This object can be passed to many of the API-level Swig methods to control various aspects of the engine. All keys are optional.
|
|
@@ -177,6 +178,147 @@ exports.Swig = function (opts) {
|
|
|
177
178
|
utils.throwError(err, null, options.filename);
|
|
178
179
|
}
|
|
179
180
|
});
|
|
181
|
+
|
|
182
|
+
var self = this;
|
|
183
|
+
|
|
184
|
+
function buildScanOpts() {
|
|
185
|
+
return {
|
|
186
|
+
varControls: self.options.varControls,
|
|
187
|
+
tagControls: self.options.tagControls,
|
|
188
|
+
cmtControls: self.options.cmtControls,
|
|
189
|
+
rawTag: 'raw',
|
|
190
|
+
keywords: ['extends', 'include', 'import']
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Render a template file asynchronously, supporting async loaders.
|
|
196
|
+
*
|
|
197
|
+
* Pre-walks <var>extends</var> / <var>include</var> / <var>import</var>
|
|
198
|
+
* targets in parallel via the user loader, populates an in-memory map,
|
|
199
|
+
* then runs the existing sync render pipeline against the populated map.
|
|
200
|
+
* Dynamic paths (e.g. <code>{% extends parent_var %}</code>) are not
|
|
201
|
+
* pre-resolved and will throw at render time as they would on the sync
|
|
202
|
+
* path.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* swig.setDefaults({ loader: myAsyncLoader });
|
|
206
|
+
* swig.renderFileAsync('page.html', { name: 'world' }, function (err, output) {
|
|
207
|
+
* if (err) { return done(err); }
|
|
208
|
+
* res.end(output);
|
|
209
|
+
* });
|
|
210
|
+
*
|
|
211
|
+
* @param {string} pathName Template path; resolved via the active loader.
|
|
212
|
+
* @param {object} [locals] Locals to render with.
|
|
213
|
+
* @param {Function} cb Node-style callback <code>(err, output)</code>.
|
|
214
|
+
* @return {undefined}
|
|
215
|
+
*/
|
|
216
|
+
this.renderFileAsync = function (pathName, locals, cb) {
|
|
217
|
+
if (typeof locals === 'function') {
|
|
218
|
+
cb = locals;
|
|
219
|
+
locals = undefined;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
var loader = self.options.loader;
|
|
223
|
+
var entry;
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
entry = loader.resolve(pathName);
|
|
227
|
+
} catch (e) {
|
|
228
|
+
cb(e);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
preWalker.walk(entry, loader, buildScanOpts()).then(function (memMap) {
|
|
233
|
+
var memWrapper = preWalker.makeMemoryWrapper(loader, memMap);
|
|
234
|
+
var origLoader = self.options.loader;
|
|
235
|
+
self.options.loader = memWrapper;
|
|
236
|
+
var output, error;
|
|
237
|
+
try {
|
|
238
|
+
output = self.renderFile(entry, locals);
|
|
239
|
+
} catch (e) {
|
|
240
|
+
error = e;
|
|
241
|
+
}
|
|
242
|
+
self.options.loader = origLoader;
|
|
243
|
+
if (error) {
|
|
244
|
+
cb(error);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
cb(null, output);
|
|
248
|
+
}, function (err) {
|
|
249
|
+
cb(err);
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Compile a template file asynchronously, supporting async loaders.
|
|
255
|
+
*
|
|
256
|
+
* Same pre-walk / memory-wrapper / sync-pipeline shape as
|
|
257
|
+
* {@link Swig#renderFileAsync}. Returns the compiled function (via
|
|
258
|
+
* <var>cb</var>) that takes a locals object and yields a rendered
|
|
259
|
+
* string. The returned function captures the pre-walked memory map and
|
|
260
|
+
* temporarily swaps the loader on each call, so subsequent runtime
|
|
261
|
+
* <var>include</var>s resolve correctly without re-running the pre-walk.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* swig.compileFileAsync('page.html', {}, function (err, fn) {
|
|
265
|
+
* if (err) { return done(err); }
|
|
266
|
+
* res.end(fn({ name: 'world' }));
|
|
267
|
+
* });
|
|
268
|
+
*
|
|
269
|
+
* @param {string} pathName Template path.
|
|
270
|
+
* @param {object} [options] Compilation options.
|
|
271
|
+
* @param {Function} cb Node-style callback <code>(err, fn)</code>.
|
|
272
|
+
* @return {undefined}
|
|
273
|
+
*/
|
|
274
|
+
this.compileFileAsync = function (pathName, options, cb) {
|
|
275
|
+
if (typeof options === 'function') {
|
|
276
|
+
cb = options;
|
|
277
|
+
options = {};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
var loader = self.options.loader;
|
|
281
|
+
var entry;
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
entry = loader.resolve(pathName);
|
|
285
|
+
} catch (e) {
|
|
286
|
+
cb(e);
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
preWalker.walk(entry, loader, buildScanOpts()).then(function (memMap) {
|
|
291
|
+
var memWrapper = preWalker.makeMemoryWrapper(loader, memMap);
|
|
292
|
+
var origLoader = self.options.loader;
|
|
293
|
+
self.options.loader = memWrapper;
|
|
294
|
+
var compiled, error;
|
|
295
|
+
try {
|
|
296
|
+
compiled = self.compileFile(entry, options);
|
|
297
|
+
} catch (e) {
|
|
298
|
+
error = e;
|
|
299
|
+
}
|
|
300
|
+
self.options.loader = origLoader;
|
|
301
|
+
if (error) {
|
|
302
|
+
cb(error);
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
var wrapped = function (locals) {
|
|
306
|
+
var origInner = self.options.loader;
|
|
307
|
+
self.options.loader = memWrapper;
|
|
308
|
+
try {
|
|
309
|
+
var output = compiled(locals);
|
|
310
|
+
self.options.loader = origInner;
|
|
311
|
+
return output;
|
|
312
|
+
} catch (e) {
|
|
313
|
+
self.options.loader = origInner;
|
|
314
|
+
throw e;
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
cb(null, wrapped);
|
|
318
|
+
}, function (err) {
|
|
319
|
+
cb(err);
|
|
320
|
+
});
|
|
321
|
+
};
|
|
180
322
|
};
|
|
181
323
|
|
|
182
324
|
/*!
|
|
@@ -190,8 +332,10 @@ exports.parseFile = defaultInstance.parseFile;
|
|
|
190
332
|
exports.precompile = defaultInstance.precompile;
|
|
191
333
|
exports.compile = defaultInstance.compile;
|
|
192
334
|
exports.compileFile = defaultInstance.compileFile;
|
|
335
|
+
exports.compileFileAsync = defaultInstance.compileFileAsync;
|
|
193
336
|
exports.render = defaultInstance.render;
|
|
194
337
|
exports.renderFile = defaultInstance.renderFile;
|
|
338
|
+
exports.renderFileAsync = defaultInstance.renderFileAsync;
|
|
195
339
|
exports.run = defaultInstance.run;
|
|
196
340
|
exports.invalidateCache = defaultInstance.invalidateCache;
|
|
197
341
|
exports.loaders = loaders;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rhinostone/swig",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A simple, powerful, and extendable templating engine for node.js and browsers, similar to Django, Jinja2, and Twig.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"template",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"Rhinostone <contact@gina.io>"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@rhinostone/swig-core": "2.0
|
|
24
|
+
"@rhinostone/swig-core": "2.1.0",
|
|
25
25
|
"terser": "^5.46.1",
|
|
26
26
|
"yargs": "^17.7.2"
|
|
27
27
|
},
|