@mtbdata711/twig-loader 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ });