@mtbdata711/twig-loader 1.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/.editorconfig ADDED
@@ -0,0 +1,2 @@
1
+ [*]
2
+ indent_size = 4
@@ -0,0 +1,7 @@
1
+ bracketSpacing: true
2
+ jsxBracketSameLine: false
3
+ printWidth: 80
4
+ semi: true
5
+ singleQuote: true
6
+ tabWidth: 4
7
+ trailingComma: all
package/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: node_js
2
+ node_js:
3
+ - "6"
4
+ - "8"
5
+ - "9"
6
+
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Zimmo.be
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # twig-loader
2
+ Webpack loader for compiling Twig.js templates. This loader will allow you to require Twig.js views to your code.
3
+
4
+ This is a fork of [@jfrk/twig-loader](https://github.com/jfrk/twig-loader) to support using Drupal's [Single Directory Components](https://www.drupal.org/docs/develop/theming-drupal/using-single-directory-components) in [Twig.js](https://github.com/twigjs/twig.js).
5
+
6
+ ## Installation
7
+
8
+ - Clone this repo
9
+
10
+ ## Usage
11
+
12
+ [Documentation: Using loaders](http://webpack.github.io/docs/using-loaders.html?branch=master)
13
+
14
+ ``` javascript
15
+
16
+ module.exports = {
17
+ //...
18
+
19
+ module: {
20
+ rules: [
21
+ {
22
+ test: /\.twig$/,
23
+ loader: "twig-loader",
24
+ options: {
25
+ // See options section below
26
+ },
27
+ }
28
+ ]
29
+ },
30
+
31
+ node: {
32
+ fs: "empty" // avoids error messages
33
+ }
34
+ };
35
+ ```
36
+
37
+ ### Options
38
+
39
+ - `extender`: optional; the full path to a module which exports a `function(Twig)`
40
+ which extends Twig (such as adding filters and functions). Must use `export default` instead of `module.exports`.
41
+ Example: `__dirname + "/src/extendTwig.js"`
42
+ - `paths`: optional; an array of absolute paths that contain Twig templates. When this option is included, paths that doesn’t begin with a `.` or `/` inside tags like `{% include %}` and `{% extends %}` will be considered relative to one of these paths instead of the file. This mimics the PHP implementation of Twig.
43
+ - `twigOptions`: optional; a map of options to be passed through to Twig.
44
+ Example: `{autoescape: true}`
45
+ - `sdc` - optional; object of namespaces and paths to SDC namespaces. Example: `{design_system: path.resolve(__dirname, './components')}`
46
+
47
+ ## Loading templates
48
+
49
+ ```twig
50
+ {# File: dialog.html.twig #}
51
+ <p>{{title}}</p>
52
+ ```
53
+
54
+ ```javascript
55
+ // File: app.js
56
+ var template = require("./dialog.html.twig");
57
+ // => returns pre-compiled template as a function and automatically includes Twig.js to your project
58
+
59
+ var html = template({title: 'dialog title'});
60
+ // => Render the view with the given context
61
+
62
+ ```
63
+
64
+ When you extend another view, it will also be added as a dependency. All twig functions that refer to additional templates are supported: import, include, extends & embed.
package/index.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require("./lib/loader");
@@ -0,0 +1,122 @@
1
+ var path = require('path');
2
+ var hashGenerator = require('hasha');
3
+ var _ = require('underscore');
4
+ var mapcache = require('./mapcache');
5
+ var fs = require('fs');
6
+
7
+ module.exports = function(options) {
8
+ return function(id, tokens, pathToTwig) {
9
+ var includes = [];
10
+ var resourcePath = mapcache.get(id);
11
+ var processDependency = function(token) {
12
+ let relativePath;
13
+ if (token.value.includes(':')) {
14
+ const [namespace, component] = token.value.split(":");
15
+ if (options.sdc[namespace]) {
16
+ resolvedPath = path.resolve(
17
+ options.sdc[namespace],
18
+ `${component}/${component}.twig`,
19
+ );
20
+ if (fs.existsSync(resolvedPath)) {
21
+ relativePath = `./${path.dirname(
22
+ resourcePath,
23
+ resolvedPath,
24
+ )}`;
25
+ includes.push(relativePath);
26
+ token.value = hashGenerator(resolvedPath);
27
+ }
28
+ }
29
+ } else if (!/^[.\/]/.test(token.value)) {
30
+ let resolvedPath;
31
+ (options.paths || []).some(templatePath => {
32
+ resolvedPath = path.resolve(templatePath, token.value);
33
+ if (fs.existsSync(resolvedPath)) {
34
+ relativePath =
35
+ './' +
36
+ path.relative(
37
+ path.dirname(resourcePath),
38
+ resolvedPath,
39
+ );
40
+ includes.push(relativePath);
41
+ token.value = hashGenerator(resolvedPath);
42
+ return true;
43
+ }
44
+ });
45
+ } else {
46
+ relativePath = token.value;
47
+ resolvedPath = path.resolve(
48
+ path.dirname(resourcePath),
49
+ token.value,
50
+ );
51
+ includes.push(relativePath);
52
+ token.value = hashGenerator(resolvedPath);
53
+ }
54
+ };
55
+
56
+ var processToken = function(token) {
57
+ if (token.type == 'logic' && token.token.type) {
58
+ switch (token.token.type) {
59
+ case 'Twig.logic.type.block':
60
+ case 'Twig.logic.type.if':
61
+ case 'Twig.logic.type.elseif':
62
+ case 'Twig.logic.type.else':
63
+ case 'Twig.logic.type.for':
64
+ case 'Twig.logic.type.spaceless':
65
+ case 'Twig.logic.type.macro':
66
+ _.each(token.token.output, processToken);
67
+ break;
68
+ case 'Twig.logic.type.extends':
69
+ case 'Twig.logic.type.include':
70
+ _.each(token.token.stack, processDependency);
71
+ break;
72
+ case 'Twig.logic.type.embed':
73
+ _.each(token.token.output, processToken);
74
+ _.each(token.token.stack, processDependency);
75
+ break;
76
+ case 'Twig.logic.type.import':
77
+ case 'Twig.logic.type.from':
78
+ if (token.token.expression != '_self') {
79
+ _.each(token.token.stack, processDependency);
80
+ }
81
+ break;
82
+ }
83
+ }
84
+ };
85
+
86
+ var parsedTokens = JSON.parse(tokens);
87
+
88
+ _.each(parsedTokens, processToken);
89
+
90
+ var opts = Object.assign({}, options.twigOptions, {
91
+ id: id,
92
+ data: parsedTokens,
93
+ allowInlineIncludes: true,
94
+ rethrow: true,
95
+ });
96
+ var output = [
97
+ 'var Twig = require("' + pathToTwig + '"),',
98
+ ' template = Twig.twig(' + JSON.stringify(opts) + ');\n',
99
+ ];
100
+
101
+ output.push(`
102
+ if(module && module.hot) {
103
+ Twig.cache(false);
104
+ }
105
+ `);
106
+
107
+ if (options.extender) {
108
+ output.push('require("' + options.extender + '").default(Twig);\n');
109
+ }
110
+ output.push(
111
+ 'module.exports = function(context) { return template.render(context); }',
112
+ );
113
+
114
+ if (includes.length > 0) {
115
+ _.each(_.uniq(includes), function(file) {
116
+ output.unshift('require(' + JSON.stringify(file) + ');\n');
117
+ });
118
+ }
119
+
120
+ return output.join('\n');
121
+ };
122
+ };
package/lib/loader.js ADDED
@@ -0,0 +1,57 @@
1
+ var Twig = require("twig");
2
+ var path = require("path");
3
+ var hashGenerator = require("hasha");
4
+ var mapcache = require("./mapcache");
5
+ var getOptions = require("loader-utils").getOptions;
6
+ var validateOptions = require("schema-utils");
7
+ var compilerFactory = require("./compiler");
8
+
9
+ var schema = {
10
+ type: "object",
11
+ properties: {
12
+ extender: {
13
+ type: "string",
14
+ },
15
+ twigOptions: {
16
+ type: "object",
17
+ },
18
+ },
19
+ };
20
+
21
+ Twig.cache(false);
22
+
23
+ module.exports = function(source) {
24
+ var path = require.resolve(this.resource),
25
+ id = hashGenerator(path),
26
+ options = getOptions(this),
27
+ tpl;
28
+
29
+ if (options) {
30
+ validateOptions(schema, options, "twig-loader");
31
+ } else {
32
+ options = {};
33
+ }
34
+
35
+ Twig.extend(function(Twig) {
36
+ var compiler = Twig.compiler;
37
+ compiler.module['webpack'] = compilerFactory(options);
38
+ });
39
+
40
+ mapcache.set(id, path)
41
+
42
+ this.cacheable && this.cacheable();
43
+
44
+ tpl = Twig.twig({
45
+ id: id,
46
+ path: path,
47
+ data: source,
48
+ allowInlineIncludes: true
49
+ });
50
+
51
+ tpl = tpl.compile({
52
+ module: 'webpack',
53
+ twig: 'twig'
54
+ });
55
+
56
+ this.callback(null, tpl);
57
+ };
@@ -0,0 +1,2 @@
1
+ var MapCache = require('map-cache');
2
+ module.exports = new MapCache();
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@mtbdata711/twig-loader",
3
+ "version": "1.1.0",
4
+ "description": "Webpack loader for compiling twig.js templates",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "mocha -R spec"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/mtbdata711/twig-loader.git"
12
+ },
13
+ "author": "Mathieu Maes @ Zimmo.be",
14
+ "license": "MIT",
15
+ "bugs": {
16
+ "url": "https://github.com/mtbdata711/twig-loader/issues"
17
+ },
18
+ "homepage": "https://github.com/mtbdata711/twig-loader#readme",
19
+ "dependencies": {
20
+ "hasha": "^3.0.0",
21
+ "loader-utils": "^1.1.0",
22
+ "map-cache": "^0.2.2",
23
+ "schema-utils": "^0.4.5",
24
+ "twig": "^1.17.1",
25
+ "underscore": "^1.11.0"
26
+ },
27
+ "devDependencies": {
28
+ "mocha": "*",
29
+ "prettier": "^1.19.1",
30
+ "should": "*"
31
+ }
32
+ }
@@ -0,0 +1,39 @@
1
+ var should = require("should");
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var runLoader = require("./fakeModuleSystem");
7
+ var twigLoader = require("../");
8
+
9
+ var fixtures = path.join(__dirname, "fixtures");
10
+
11
+ describe("embed", function() {
12
+ it("should generate proper require embed tag", function(done) {
13
+ var template = path.join(fixtures, "embed", "template.html.twig");
14
+ runLoader(twigLoader, path.join(fixtures, "extend"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
15
+ if(err) throw err;
16
+
17
+ result.should.have.type("string");
18
+
19
+ // verify the generated module imports the `embed`d templates
20
+ result.should.match(/require\(\"embed\.html\.twig\"\);/);
21
+
22
+ done();
23
+ });
24
+ });
25
+
26
+ it("should generate proper require include tag in block tag", function(done) {
27
+ var template = path.join(fixtures, "embed", "template.html.twig");
28
+ runLoader(twigLoader, path.join(fixtures, "extend"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
29
+ if(err) throw err;
30
+
31
+ result.should.have.type("string");
32
+
33
+ // verify the generated module imports the `include`d templates
34
+ result.should.match(/require\(\"include\.html\.twig\"\);/);
35
+
36
+ done();
37
+ });
38
+ });
39
+ });
@@ -0,0 +1,25 @@
1
+ var should = require("should");
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var runLoader = require("./fakeModuleSystem");
7
+ var twigLoader = require("../");
8
+
9
+ var fixtures = path.join(__dirname, "fixtures");
10
+
11
+ describe("extend", function() {
12
+ it("should generate proper require statements", function(done) {
13
+ var template = path.join(fixtures, "extend", "template.html.twig");
14
+ runLoader(twigLoader, path.join(fixtures, "extend"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
15
+ if(err) throw err;
16
+
17
+ result.should.have.type("string");
18
+
19
+ // verify the generated module imports the `include`d templates
20
+ result.should.match(/require\(\"a\.html\.twig\"\);/);
21
+
22
+ done();
23
+ });
24
+ });
25
+ });
@@ -0,0 +1,33 @@
1
+ var fs = require("fs");
2
+ var path = require("path");
3
+
4
+ module.exports = function runLoader(loader, directory, filename, arg, callback) {
5
+ var async = true;
6
+ var loaderContext = {
7
+ async: function() {
8
+ async = true;
9
+ return callback;
10
+ },
11
+ loaders: ["itself"],
12
+ loaderIndex: 0,
13
+ query: "",
14
+ resource: filename,
15
+ callback: function() {
16
+ async = true;
17
+ return callback.apply(this, arguments);
18
+ },
19
+ resolve: function(context, request, callback) {
20
+ callback(null, path.resolve(context, request));
21
+ },
22
+ loadModule: function(request, callback) {
23
+ request = request.replace(/^-?!+/, "");
24
+ request = request.split("!");
25
+ var content = fs.readFileSync(request.pop(), "utf-8");
26
+ if(request[0] && /stringify/.test(request[0]))
27
+ content = JSON.stringify(content);
28
+ return callback(null, content);
29
+ }
30
+ };
31
+ var res = loader.call(loaderContext, arg);
32
+ if(!async) callback(null, res);
33
+ }
@@ -0,0 +1,5 @@
1
+ {% embed 'embed.html.twig' %}
2
+ {% block body %}
3
+ {% include 'include.html.twig' %}
4
+ {% endblock %}
5
+ {% endembed %}
@@ -0,0 +1,2 @@
1
+ {% extends 'a.html.twig' %}
2
+ {% block body %}{% endblock %}
@@ -0,0 +1,25 @@
1
+ {% from './a.html.twig' import macroName %}
2
+
3
+ {% if true %}
4
+ {% from './b.html.twig' import macroName %}
5
+ {% elseif false %}
6
+ {% from './c.html.twig' import macroName %}
7
+ {% else %}
8
+ {% from './d.html.twig' import macroName %}
9
+ {% endif %}
10
+
11
+ {% for i in 0..10 %}
12
+ {% from './e.html.twig' import macroName %}
13
+ {% endfor %}
14
+
15
+ {% block myblock %}
16
+ {% from './f.html.twig' import macroName %}
17
+ {% endblock %}
18
+
19
+ {% spaceless %}
20
+ {% from './g.html.twig' import macroName %}
21
+ {% endspaceless %}
22
+
23
+ {% macro mymacro() %}
24
+ {% from './h.html.twig' import macroName %}
25
+ {% endmacro %}
@@ -0,0 +1,21 @@
1
+ {% include './a.html.twig' %}
2
+
3
+ {% if true %}
4
+ {% include './b.html.twig' %}
5
+ {% elseif false %}
6
+ {% include './c.html.twig' %}
7
+ {% else %}
8
+ {% include './d.html.twig' %}
9
+ {% endif %}
10
+
11
+ {% for i in 0..10 %}
12
+ {% include './e.html.twig' %}
13
+ {% endfor %}
14
+
15
+ {% block myblock %}
16
+ {% include './f.html.twig' %}
17
+ {% endblock %}
18
+
19
+ {% spaceless %}
20
+ {% include './g.html.twig' %}
21
+ {% endspaceless %}
@@ -0,0 +1 @@
1
+ Lorem ipsum {% if variable is true %}dolor{% endif %} sit amet.
@@ -0,0 +1 @@
1
+ {% include 'design_system:component-b' %}
@@ -0,0 +1 @@
1
+ <p>Hello World</p>
@@ -0,0 +1,32 @@
1
+ var should = require("should");
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var runLoader = require("./fakeModuleSystem");
7
+ var twigLoader = require("../");
8
+
9
+ var fixtures = path.join(__dirname, "fixtures");
10
+
11
+ describe("from", function() {
12
+ it("should generate correct code", function(done) {
13
+ var template = path.join(fixtures, "from", "template.html.twig");
14
+ runLoader(twigLoader, path.join(fixtures, "from"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
15
+ if(err) throw err;
16
+
17
+ result.should.have.type("string");
18
+
19
+ // verify the generated module imports the `from`d templates
20
+ result.should.match(/require\(\"\.\/a\.html\.twig\"\);/);
21
+ result.should.match(/require\(\"\.\/b\.html\.twig\"\);/);
22
+ result.should.match(/require\(\"\.\/c\.html\.twig\"\);/);
23
+ result.should.match(/require\(\"\.\/d\.html\.twig\"\);/);
24
+ result.should.match(/require\(\"\.\/e\.html\.twig\"\);/);
25
+ result.should.match(/require\(\"\.\/f\.html\.twig\"\);/);
26
+ result.should.match(/require\(\"\.\/g\.html\.twig\"\);/);
27
+ result.should.match(/require\(\"\.\/h\.html\.twig\"\);/);
28
+
29
+ done();
30
+ });
31
+ });
32
+ });
@@ -0,0 +1,31 @@
1
+ var should = require("should");
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var runLoader = require("./fakeModuleSystem");
7
+ var twigLoader = require("../");
8
+
9
+ var fixtures = path.join(__dirname, "fixtures");
10
+
11
+ describe("include", function() {
12
+ it("should generate correct code", function(done) {
13
+ var template = path.join(fixtures, "include", "template.html.twig");
14
+ runLoader(twigLoader, path.join(fixtures, "include"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
15
+ if(err) throw err;
16
+
17
+ result.should.have.type("string");
18
+
19
+ // verify the generated module imports the `include`d templates
20
+ result.should.match(/require\(\"\.\/a\.html\.twig\"\);/);
21
+ result.should.match(/require\(\"\.\/b\.html\.twig\"\);/);
22
+ result.should.match(/require\(\"\.\/c\.html\.twig\"\);/);
23
+ result.should.match(/require\(\"\.\/d\.html\.twig\"\);/);
24
+ result.should.match(/require\(\"\.\/e\.html\.twig\"\);/);
25
+ result.should.match(/require\(\"\.\/f\.html\.twig\"\);/);
26
+ result.should.match(/require\(\"\.\/g\.html\.twig\"\);/);
27
+
28
+ done();
29
+ });
30
+ });
31
+ });
@@ -0,0 +1,24 @@
1
+ var should = require("should");
2
+
3
+ var fs = require("fs");
4
+ var path = require("path");
5
+
6
+ var runLoader = require("./fakeModuleSystem");
7
+ var twigLoader = require("../");
8
+
9
+ var fixtures = path.join(__dirname, "fixtures");
10
+
11
+ describe("loader", function() {
12
+ it("should add require statement to the twig library", function(done) {
13
+ var template = path.join(fixtures, "loader", "template.html.twig");
14
+ runLoader(twigLoader, path.join(fixtures, "loader"), template, fs.readFileSync(template, "utf-8"), function(err, result) {
15
+ if(err) throw err;
16
+
17
+ result.should.have.type("string");
18
+
19
+ result.should.match(/require\(\"twig\"\)/);
20
+
21
+ done();
22
+ });
23
+ });
24
+ });
@@ -0,0 +1,33 @@
1
+ var should = require('should');
2
+
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+
6
+ var runLoader = require('./fakeModuleSystem');
7
+ var twigLoader = require('../');
8
+
9
+ var fixtures = path.join(__dirname, 'fixtures');
10
+
11
+ describe('sdc', function() {
12
+ it('sdc', function(done) {
13
+ var template = path.join(fixtures, 'sdc', 'component-a', 'component-a.twig');
14
+ runLoader(
15
+ twigLoader,
16
+ null,
17
+ template,
18
+ fs.readFileSync(template, 'utf-8'),
19
+ function(err, result) {
20
+ if (err) throw err;
21
+
22
+ result.should.have.type('string');
23
+
24
+ done();
25
+ },
26
+ {
27
+ sdc: {
28
+ design_system: path.resolve(__dirname, './fixtures')
29
+ }
30
+ }
31
+ );
32
+ });
33
+ });