@rhinostone/swig 2.4.3 → 2.5.1
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/HISTORY.md +23 -1
- package/README.md +13 -6
- package/ROADMAP.md +14 -2
- package/dist/swig.js +93 -9
- package/dist/swig.min.js +2 -2
- package/dist/swig.min.js.map +1 -1
- package/eslint.config.js +32 -0
- package/lib/dateformatter.js +1 -1
- package/lib/swig.js +177 -1
- package/lib/tags/extends.js +8 -8
- package/lib/tags/filter.js +1 -1
- package/lib/tags/if.js +5 -6
- package/lib/tags/import.js +6 -6
- package/lib/tags/parent.js +4 -4
- package/lib/tags/set.js +5 -5
- package/package.json +8 -20
- package/.eslintrc.json +0 -24
package/lib/swig.js
CHANGED
|
@@ -14,7 +14,7 @@ var utils = require('./utils'),
|
|
|
14
14
|
*
|
|
15
15
|
* @type {String}
|
|
16
16
|
*/
|
|
17
|
-
exports.version = "2.
|
|
17
|
+
exports.version = "2.5.1";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
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.
|
|
@@ -336,17 +336,193 @@ exports.Swig = function (opts) {
|
|
|
336
336
|
* Export methods publicly
|
|
337
337
|
*/
|
|
338
338
|
defaultInstance = new exports.Swig();
|
|
339
|
+
/**
|
|
340
|
+
* Add a custom filter for swig variables.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* function replaceMs(input) { return input.replace(/m/g, 'f'); }
|
|
344
|
+
* swig.setFilter('replaceMs', replaceMs);
|
|
345
|
+
* // => {{ "onomatopoeia"|replaceMs }}
|
|
346
|
+
* // => onofatopeia
|
|
347
|
+
*
|
|
348
|
+
* @param {string} name Name of filter, used in templates. <strong>Will</strong> overwrite previously defined filters, if using the same name.
|
|
349
|
+
* @param {function} method Function that acts against the input. See <a href="/docs/filters/#custom">Custom Filters</a> for more information.
|
|
350
|
+
* @return {undefined}
|
|
351
|
+
*/
|
|
339
352
|
exports.setFilter = defaultInstance.setFilter;
|
|
353
|
+
/**
|
|
354
|
+
* Add a custom tag. To expose your own extensions to compiled template code, see <code data-language="js">swig.setExtension</code>.
|
|
355
|
+
*
|
|
356
|
+
* For a more in-depth explanation of writing custom tags, see <a href="../extending/#tags">Custom Tags</a>.
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* var tacotag = require('./tacotag');
|
|
360
|
+
* swig.setTag('tacos', tacotag.parse, tacotag.compile, tacotag.ends, tacotag.blockLevel);
|
|
361
|
+
* // => {% tacos %}Make this be tacos.{% endtacos %}
|
|
362
|
+
* // => Tacos tacos tacos tacos.
|
|
363
|
+
*
|
|
364
|
+
* @param {string} name Tag name.
|
|
365
|
+
* @param {function} parse Method for parsing tokens.
|
|
366
|
+
* @param {function} compile Method for compiling renderable output.
|
|
367
|
+
* @param {boolean} [ends=false] Whether or not this tag requires an <i>end</i> tag.
|
|
368
|
+
* @param {boolean} [blockLevel=false] If false, this tag will not be compiled outside of <code>block</code> tags when extending a parent template.
|
|
369
|
+
* @return {undefined}
|
|
370
|
+
*/
|
|
340
371
|
exports.setTag = defaultInstance.setTag;
|
|
372
|
+
/**
|
|
373
|
+
* Add extensions for custom tags. This allows any custom tag to access a globally available methods via a special globally available object, <var>_ext</var>, in templates.
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* swig.setExtension('trans', function (v) { return translate(v); });
|
|
377
|
+
* function compileTrans(compiler, args, content, parent, options) {
|
|
378
|
+
* return '_output += _ext.trans(' + args[0] + ');'
|
|
379
|
+
* };
|
|
380
|
+
* swig.setTag('trans', parseTrans, compileTrans, true);
|
|
381
|
+
*
|
|
382
|
+
* @param {string} name Key name of the extension. Accessed via <code data-language="js">_ext[name]</code>.
|
|
383
|
+
* @param {*} object The method, value, or object that should be available via the given name.
|
|
384
|
+
* @return {undefined}
|
|
385
|
+
*/
|
|
341
386
|
exports.setExtension = defaultInstance.setExtension;
|
|
387
|
+
/**
|
|
388
|
+
* Parse a given file into tokens.
|
|
389
|
+
* @param {string} pathname Full path to file to parse.
|
|
390
|
+
* @param {SwigOpts} [options={}] Swig options object.
|
|
391
|
+
* @return {object} parsed Template tokens object.
|
|
392
|
+
* @private
|
|
393
|
+
*/
|
|
342
394
|
exports.parseFile = defaultInstance.parseFile;
|
|
395
|
+
/**
|
|
396
|
+
* Pre-compile a source string into a cache-able template function.
|
|
397
|
+
*
|
|
398
|
+
* @example
|
|
399
|
+
* swig.precompile('{{ tacos }}');
|
|
400
|
+
* // => {
|
|
401
|
+
* // tpl: function (_swig, _locals, _filters, _utils, _fn) { ... },
|
|
402
|
+
* // tokens: {
|
|
403
|
+
* // name: undefined,
|
|
404
|
+
* // parent: null,
|
|
405
|
+
* // tokens: [...],
|
|
406
|
+
* // blocks: {}
|
|
407
|
+
* // }
|
|
408
|
+
* // }
|
|
409
|
+
*
|
|
410
|
+
* In order to render a pre-compiled template, you must have access to filters and utils from Swig. <var>efn</var> is simply an empty function that does nothing.
|
|
411
|
+
*
|
|
412
|
+
* @param {string} source Swig template source string.
|
|
413
|
+
* @param {SwigOpts} [options={}] Swig options object.
|
|
414
|
+
* @return {object} Renderable function and tokens object.
|
|
415
|
+
*/
|
|
343
416
|
exports.precompile = defaultInstance.precompile;
|
|
417
|
+
/**
|
|
418
|
+
* Compile string source into a renderable template function.
|
|
419
|
+
*
|
|
420
|
+
* @example
|
|
421
|
+
* var tpl = swig.compile('{{ tacos }}');
|
|
422
|
+
* // => {
|
|
423
|
+
* // [Function: compiled]
|
|
424
|
+
* // parent: null,
|
|
425
|
+
* // tokens: [{ compile: [Function] }],
|
|
426
|
+
* // blocks: {}
|
|
427
|
+
* // }
|
|
428
|
+
* tpl({ tacos: 'Tacos!!!!' });
|
|
429
|
+
* // => Tacos!!!!
|
|
430
|
+
*
|
|
431
|
+
* When compiling a source string, a file path should be specified in the options object in order for <var>extends</var>, <var>include</var>, and <var>import</var> to work properly. Do this by adding <code data-language="js">{ filename: '/absolute/path/to/mytpl.html' }</code> to the options argument.
|
|
432
|
+
*
|
|
433
|
+
* @param {string} source Swig template source string.
|
|
434
|
+
* @param {SwigOpts} [options={}] Swig options object.
|
|
435
|
+
* @return {function} Renderable function with keys for parent, blocks, and tokens.
|
|
436
|
+
*/
|
|
344
437
|
exports.compile = defaultInstance.compile;
|
|
438
|
+
/**
|
|
439
|
+
* Compile a source file into a renderable template function.
|
|
440
|
+
*
|
|
441
|
+
* @example
|
|
442
|
+
* var tpl = swig.compileFile('./mytpl.html');
|
|
443
|
+
* // => {
|
|
444
|
+
* // [Function: compiled]
|
|
445
|
+
* // parent: null,
|
|
446
|
+
* // tokens: [{ compile: [Function] }],
|
|
447
|
+
* // blocks: {}
|
|
448
|
+
* // }
|
|
449
|
+
* tpl({ tacos: 'Tacos!!!!' });
|
|
450
|
+
* // => Tacos!!!!
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* swig.compileFile('/myfile.txt', { varControls: ['<%=', '=%>'], tagControls: ['<%', '%>']});
|
|
454
|
+
* // => will compile 'myfile.txt' using the var and tag controls as specified.
|
|
455
|
+
*
|
|
456
|
+
* @param {string} pathname File location.
|
|
457
|
+
* @param {SwigOpts} [options={}] Swig options object.
|
|
458
|
+
* @param {Function} [cb] Asynchronous callback function. If not provided, <var>compileFile</var> will run synchronously.
|
|
459
|
+
* @return {function} Renderable function with keys for parent, blocks, and tokens.
|
|
460
|
+
*/
|
|
345
461
|
exports.compileFile = defaultInstance.compileFile;
|
|
346
462
|
exports.compileFileAsync = defaultInstance.compileFileAsync;
|
|
463
|
+
/**
|
|
464
|
+
* Compile and render a template string for final output.
|
|
465
|
+
*
|
|
466
|
+
* When rendering a source string, a file path should be specified in the options object in order for <var>extends</var>, <var>include</var>, and <var>import</var> to work properly. Do this by adding <code data-language="js">{ filename: '/absolute/path/to/mytpl.html' }</code> to the options argument.
|
|
467
|
+
*
|
|
468
|
+
* @example
|
|
469
|
+
* swig.render('{{ tacos }}', { locals: { tacos: 'Tacos!!!!' }});
|
|
470
|
+
* // => Tacos!!!!
|
|
471
|
+
*
|
|
472
|
+
* @param {string} source Swig template source string.
|
|
473
|
+
* @param {SwigOpts} [options={}] Swig options object.
|
|
474
|
+
* @return {string} Rendered output.
|
|
475
|
+
*/
|
|
347
476
|
exports.render = defaultInstance.render;
|
|
477
|
+
/**
|
|
478
|
+
* Compile and render a template file for final output. This is most useful for libraries like Express.js.
|
|
479
|
+
*
|
|
480
|
+
* When the active loader sets <code>loader.async === true</code> and a callback is provided, this method routes to the async-codegen dispatch path (added in v2.2.0) which supports dynamic <var>include</var> paths the sync path cannot. Otherwise it runs synchronously.
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* swig.renderFile('./template.html', {}, function (err, output) {
|
|
484
|
+
* if (err) {
|
|
485
|
+
* throw err;
|
|
486
|
+
* }
|
|
487
|
+
* console.log(output);
|
|
488
|
+
* });
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* swig.renderFile('./template.html', {});
|
|
492
|
+
* // => output
|
|
493
|
+
*
|
|
494
|
+
* @param {string} pathName File location.
|
|
495
|
+
* @param {object} [locals={}] Template variable context.
|
|
496
|
+
* @param {Function} [cb] Asynchronous callback function. If not provided, <var>renderFile</var> will run synchronously.
|
|
497
|
+
* @return {string} Rendered output.
|
|
498
|
+
*/
|
|
348
499
|
exports.renderFile = defaultInstance.renderFile;
|
|
349
500
|
exports.renderFileAsync = defaultInstance.renderFileAsync;
|
|
501
|
+
/**
|
|
502
|
+
* Run a pre-compiled template function. This is most useful in the browser when you've pre-compiled your templates with the Swig command-line tool.
|
|
503
|
+
*
|
|
504
|
+
* @example
|
|
505
|
+
* $ swig compile ./mytpl.html --wrap-start="var mytpl = " > mytpl.js
|
|
506
|
+
* @example
|
|
507
|
+
* <script src="mytpl.js"></script>
|
|
508
|
+
* <script>
|
|
509
|
+
* swig.run(mytpl, {});
|
|
510
|
+
* // => "rendered template..."
|
|
511
|
+
* </script>
|
|
512
|
+
*
|
|
513
|
+
* @param {function} tpl Pre-compiled Swig template function. Use the Swig CLI to compile your templates.
|
|
514
|
+
* @param {object} [locals={}] Template variable context.
|
|
515
|
+
* @param {string} [filepath] Filename used for caching the template.
|
|
516
|
+
* @return {string} Rendered output.
|
|
517
|
+
*/
|
|
350
518
|
exports.run = defaultInstance.run;
|
|
519
|
+
/**
|
|
520
|
+
* Clears the in-memory template cache.
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* swig.invalidateCache();
|
|
524
|
+
*
|
|
525
|
+
* @return {undefined}
|
|
526
|
+
*/
|
|
351
527
|
exports.invalidateCache = defaultInstance.invalidateCache;
|
|
352
528
|
exports.loaders = loaders;
|
package/lib/tags/extends.js
CHANGED
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @param {string} parentFile Relative path to the file that this template extends.
|
|
12
12
|
*/
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
13
|
+
// extends is a parse-time declaration, not an emit-time construct. The
|
|
14
|
+
// engine's getParents / remapBlocks resolves the parent chain before the
|
|
15
|
+
// backend walks the token tree, so by compile-time there is nothing to
|
|
16
|
+
// emit. No IRExtends node exists — the Template IR already carries
|
|
17
|
+
// `.parent` / `.blocks` metadata for flavors that want to reason about
|
|
18
|
+
// inheritance before lowering. The compile function returns undefined and
|
|
19
|
+
// the backend skips it via the `result === undefined` check at the top of
|
|
20
|
+
// the emit loop.
|
|
21
21
|
exports.compile = function () {};
|
|
22
22
|
|
|
23
23
|
exports.parse = function () {
|
package/lib/tags/filter.js
CHANGED
|
@@ -52,7 +52,7 @@ exports.lowerExpr = function (parser, tokens) {
|
|
|
52
52
|
// PARENCLOSE that balances the FUNCTION's paren. Bail (return
|
|
53
53
|
// undefined) on any nested FILTER / FILTEREMPTY — filter pipes inside
|
|
54
54
|
// the argument expression are not part of the expression grammar
|
|
55
|
-
// (Output-site concern;
|
|
55
|
+
// (Output-site concern; deferred).
|
|
56
56
|
var depth = 1,
|
|
57
57
|
start = i + 1,
|
|
58
58
|
slices = [],
|
package/lib/tags/if.js
CHANGED
|
@@ -43,12 +43,11 @@ var ir = require('@rhinostone/swig-core/lib/ir'),
|
|
|
43
43
|
* @param {...mixed} conditional Conditional statement that returns a truthy or falsy value.
|
|
44
44
|
*/
|
|
45
45
|
exports.compile = function (compiler, args, content, parents, options, blockName, token) {
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
// `IROutput.expr` (Session 14b Commit 9). Backend dispatches
|
|
46
|
+
// Filter-in-test fallback lifts into `IRLegacyJS` rather than a raw
|
|
47
|
+
// string. `if.lowerExpr` bails to `undefined` when the test contains
|
|
48
|
+
// FILTER/FILTEREMPTY because per-operand filter precedence
|
|
49
|
+
// (`a === b|upper` binds the filter to `b` only) can't be captured in
|
|
50
|
+
// flat IR — same widening recipe as `IROutput.expr`. Backend dispatches
|
|
52
51
|
// `LegacyJS` before `emitExpr`. String fallback still valid for
|
|
53
52
|
// userland `setTag` compile functions that build branches manually.
|
|
54
53
|
var branches = [],
|
package/lib/tags/import.js
CHANGED
|
@@ -28,7 +28,7 @@ var _dangerousProps = require('@rhinostone/swig-core/lib/security').dangerousPro
|
|
|
28
28
|
* @param {literal} varname Local-accessible object name to assign the macros to.
|
|
29
29
|
*/
|
|
30
30
|
exports.compile = function (compiler, args, content, parents, options) {
|
|
31
|
-
//
|
|
31
|
+
// Async-codegen branch. Parse stashed `[{path}, alias]`
|
|
32
32
|
// (no macro pre-render in async mode); emit IRImportDeferred so the
|
|
33
33
|
// backend's `_swig.getTemplate` + `.exports` bind happens at runtime.
|
|
34
34
|
if (options && options.codegenMode === 'async') {
|
|
@@ -154,11 +154,11 @@ exports.parse = function (str, line, parser, types, stack, opts, swig) {
|
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
156
|
macroName = token.args[0];
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
//
|
|
157
|
+
// macro.compile returns an IRMacro node rather than a JS source
|
|
158
|
+
// string. Render it through the shared backend so import.js still
|
|
159
|
+
// gets the JS source it performs regex-surgery on for
|
|
160
|
+
// namespace-prefixing. The +'\n' trailing newline matches the
|
|
161
|
+
// legacy compile output exactly.
|
|
162
162
|
out += backend.compile([token.compile(compiler, token.args, token.content, [], compileOpts)], [], compileOpts) + '\n';
|
|
163
163
|
self.out.push({compiled: out, name: macroName});
|
|
164
164
|
});
|
package/lib/tags/parent.js
CHANGED
|
@@ -35,10 +35,10 @@ exports.compile = function (compiler, args, content, parents, options, blockName
|
|
|
35
35
|
// Silly JSLint "Strange Loop" requires return to be in a conditional
|
|
36
36
|
if (breaker && parentFile !== parent.name) {
|
|
37
37
|
block = parent.blocks[blockName];
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
38
|
+
// The block tag returns `IRBlock { body: [...] }`. Splice the
|
|
39
|
+
// matched parent block's body into an IRParent node; the backend
|
|
40
|
+
// emits body verbatim plus a trailing newline for byte-identity
|
|
41
|
+
// with the legacy JS-string emission shape.
|
|
42
42
|
var blockNode = block.compile(compiler, [blockName], block.content, parents.slice(i + 1), options);
|
|
43
43
|
return ir.parent((blockNode && blockNode.body) ? blockNode.body.concat([ir.legacyJS('\n')]) : [ir.legacyJS('\n')]);
|
|
44
44
|
}
|
package/lib/tags/set.js
CHANGED
|
@@ -36,9 +36,9 @@ var ir = require('@rhinostone/swig-core/lib/ir'),
|
|
|
36
36
|
|
|
37
37
|
// Pure-dot LHS shape: `_ctx.foo` or `_ctx.foo.bar.baz`. Bracket-touched
|
|
38
38
|
// targets (`_ctx.foo["bar"]`, `_ctx.foo[bar]`, mixed dot+bracket) fail
|
|
39
|
-
// this match and stay on the transitional string fallback
|
|
40
|
-
//
|
|
41
|
-
//
|
|
39
|
+
// this match and stay on the transitional string fallback. The
|
|
40
|
+
// bracket-lvalue contract is a cross-flavor design call and is deferred
|
|
41
|
+
// to a dedicated session.
|
|
42
42
|
var _pureDotTarget = /^_ctx\.([a-zA-Z_$][\w$]*)((?:\.[a-zA-Z_$][\w$]*)*)$/;
|
|
43
43
|
|
|
44
44
|
exports.compile = function (compiler, args, content, parents, options, blockName, token) {
|
|
@@ -70,8 +70,8 @@ exports.lowerExpr = function (parser, tokens) {
|
|
|
70
70
|
// assignment operator; lowerExpr only concerns itself with the RHS.
|
|
71
71
|
// Locate the first ASSIGNMENT, slice the tail, and hand it to parseExpr.
|
|
72
72
|
// Fall back (return undefined) if the tail contains FILTER / FILTEREMPTY
|
|
73
|
-
// (filter pipes are not part of the expression grammar
|
|
74
|
-
//
|
|
73
|
+
// (filter pipes are not yet part of the expression grammar — pending
|
|
74
|
+
// output-site lowering) or a nested ASSIGNMENT (parseExpr does not
|
|
75
75
|
// lower assignments, and bracket-write-as-assignment on the RHS would
|
|
76
76
|
// misparse silently).
|
|
77
77
|
var assignIdx = -1, i;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rhinostone/swig",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
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,21 +21,17 @@
|
|
|
21
21
|
"Rhinostone <contact@gina.io>"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@rhinostone/swig-core": "2.
|
|
24
|
+
"@rhinostone/swig-core": "2.5.1"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"blanket": "~1.1",
|
|
28
27
|
"esbuild": "^0.28.0",
|
|
29
|
-
"eslint": "^
|
|
28
|
+
"eslint": "^9",
|
|
30
29
|
"expect.js": "~0.2",
|
|
31
|
-
"express": "
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"mocha-phantomjs": "~3.1",
|
|
30
|
+
"express": "^4",
|
|
31
|
+
"globals": "^16",
|
|
32
|
+
"lodash": "^4",
|
|
35
33
|
"path-browserify": "^1.0.1",
|
|
36
|
-
"
|
|
37
|
-
"terser": "^5.46.1",
|
|
38
|
-
"travis-cov": "~0.2"
|
|
34
|
+
"terser": "^5.46.1"
|
|
39
35
|
},
|
|
40
36
|
"license": "MIT",
|
|
41
37
|
"main": "index",
|
|
@@ -50,15 +46,7 @@
|
|
|
50
46
|
},
|
|
51
47
|
"scripts": {
|
|
52
48
|
"prepublish": "npm prune && make build",
|
|
53
|
-
"test": "make lint && make test reporter=spec && make
|
|
54
|
-
"travis-cov": {
|
|
55
|
-
"threshold": 95
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
"config": {
|
|
59
|
-
"blanket": {
|
|
60
|
-
"pattern": "swig/lib"
|
|
61
|
-
}
|
|
49
|
+
"test": "make lint && make test reporter=spec && make coverage"
|
|
62
50
|
},
|
|
63
51
|
"publishConfig": {
|
|
64
52
|
"access": "public"
|
package/.eslintrc.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"env": {
|
|
3
|
-
"node": true,
|
|
4
|
-
"mocha": true,
|
|
5
|
-
"es2017": true
|
|
6
|
-
},
|
|
7
|
-
"parserOptions": {
|
|
8
|
-
"ecmaVersion": 2017
|
|
9
|
-
},
|
|
10
|
-
"globals": {
|
|
11
|
-
"Promise": "readonly"
|
|
12
|
-
},
|
|
13
|
-
"rules": {
|
|
14
|
-
"max-len": ["error", { "code": 600 }],
|
|
15
|
-
"semi": ["error", "always"],
|
|
16
|
-
"no-eval": "off",
|
|
17
|
-
"no-new-func": "off",
|
|
18
|
-
"strict": "off",
|
|
19
|
-
"eqeqeq": "off",
|
|
20
|
-
"no-trailing-spaces": "error",
|
|
21
|
-
"no-undef": "error",
|
|
22
|
-
"no-redeclare": "error"
|
|
23
|
-
}
|
|
24
|
-
}
|