@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/lib/swig.js CHANGED
@@ -14,7 +14,7 @@ var utils = require('./utils'),
14
14
  *
15
15
  * @type {String}
16
16
  */
17
- exports.version = "2.4.3";
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;
@@ -10,14 +10,14 @@
10
10
  *
11
11
  * @param {string} parentFile Relative path to the file that this template extends.
12
12
  */
13
- // Phase 2 (#T15): extends is a parse-time declaration, not an emit-time
14
- // construct. The engine's getParents / remapBlocks resolves the parent
15
- // chain before the backend walks the token tree, so by compile-time
16
- // there is nothing to emit. No IRExtends node exists — the Template IR
17
- // already carries `.parent` / `.blocks` metadata for flavors that want
18
- // to reason about inheritance before lowering. The compile function
19
- // returns undefined and the backend skips it via the `result === undefined`
20
- // check at the top of the emit loop. This stays this way post-Phase 2.
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 () {
@@ -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; Session 14+ work).
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
- // Phase 2 Session 14b Commit 11: filter-in-test fallback lifts into
47
- // `IRLegacyJS` rather than a raw string. `if.lowerExpr` bails to
48
- // `undefined` when the test contains FILTER/FILTEREMPTY because
49
- // per-operand filter precedence (`a === b|upper` binds the filter to
50
- // `b` only) can't be captured in flat IR — same widening recipe as
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 = [],
@@ -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
- // Phase 2 (#T22): async-codegen branch. Parse stashed `[{path}, alias]`
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
- // Phase 2 (#T15): macro.compile now returns an IRMacro node
158
- // rather than a JS source string. Render it through the shared
159
- // backend so import.js still gets the JS source it performs
160
- // regex-surgery on for namespace-prefixing. The +'\n' trailing
161
- // newline matches the pre-Phase-2 compile output exactly.
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
  });
@@ -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
- // Phase 2: the block tag now returns `IRBlock { body: [...] }`.
39
- // Splice the matched parent block's body into an IRParent node;
40
- // the backend emits body verbatim plus a trailing newline for
41
- // byte-identity with the pre-Phase-2 JS-string emission shape.
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 per Session
40
- // 14b Commit 10's narrow scope the bracket-lvalue contract is a
41
- // cross-flavor design call and is deferred to a dedicated session.
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 yet Session
74
- // 14+ Output-site work) or a nested ASSIGNMENT (parseExpr does not
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.4.3",
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.4.3"
24
+ "@rhinostone/swig-core": "2.5.1"
25
25
  },
26
26
  "devDependencies": {
27
- "blanket": "~1.1",
28
27
  "esbuild": "^0.28.0",
29
- "eslint": "^8.57.1",
28
+ "eslint": "^9",
30
29
  "expect.js": "~0.2",
31
- "express": "~3",
32
- "lodash": "~1.3.1",
33
- "mocha": "1.12.0",
34
- "mocha-phantomjs": "~3.1",
30
+ "express": "^4",
31
+ "globals": "^16",
32
+ "lodash": "^4",
35
33
  "path-browserify": "^1.0.1",
36
- "phantomjs": "~1.9.1",
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 test-browser && make coverage cov-reporter=travis-cov",
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
- }