@fnet/cli 0.3.15 → 0.4.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.
Files changed (28) hide show
  1. package/dist/fnet/index.js +9 -9
  2. package/dist/fnode/{index.hd9ty41n.js → index.937tt8st.js} +1 -1
  3. package/dist/fnode/index.js +1 -1
  4. package/package.json +1 -1
  5. package/template/fnet/node/src/default/blocks/assign.js.njk +10 -48
  6. package/template/fnet/node/src/default/blocks/call.js.njk +110 -156
  7. package/template/fnet/node/src/default/blocks/for.js.njk +59 -95
  8. package/template/fnet/node/src/default/blocks/form.js.njk +21 -59
  9. package/template/fnet/node/src/default/blocks/http.js.njk +125 -147
  10. package/template/fnet/node/src/default/blocks/modules.js.njk +10 -52
  11. package/template/fnet/node/src/default/blocks/new.js.njk +40 -85
  12. package/template/fnet/node/src/default/blocks/next.js.njk +10 -32
  13. package/template/fnet/node/src/default/blocks/output.js.njk +10 -48
  14. package/template/fnet/node/src/default/blocks/parallel.js.njk +60 -106
  15. package/template/fnet/node/src/default/blocks/pipeline.js.njk +100 -137
  16. package/template/fnet/node/src/default/blocks/raise.js.njk +9 -25
  17. package/template/fnet/node/src/default/blocks/retry.js.njk +63 -87
  18. package/template/fnet/node/src/default/blocks/return.js.njk +13 -25
  19. package/template/fnet/node/src/default/blocks/schedule.js.njk +56 -73
  20. package/template/fnet/node/src/default/blocks/signal.js.njk +10 -32
  21. package/template/fnet/node/src/default/blocks/steps.js.njk +32 -55
  22. package/template/fnet/node/src/default/blocks/switch.js.njk +37 -74
  23. package/template/fnet/node/src/default/blocks/tryexcept.js.njk +58 -52
  24. package/template/fnet/node/src/default/blocks/wait.js.njk +10 -30
  25. package/template/fnet/node/src/default/macros/block-body-header.js.njk +1 -1
  26. package/template/fnet/node/src/default/macros/block-next.js.njk +0 -1
  27. package/template/fnet/node/src/default/types/block.js.njk +133 -0
  28. package/template/fnet/node/src/default/workflow.js.njk +1 -1
@@ -1,107 +1,71 @@
1
+ {% set assign=true %}
2
+ {% set signal=true %}
3
+ {% set resolve=true %}
4
+
5
+ {% import "src/default/types/block.js.njk" as block with context %}
6
+
7
+ {% call block.header() %}
8
+ {% if childs.length %}
9
+ {% if not childs[0].definition.dynamic %}
10
+ // FIRST CHILD: {{childs[0].indexKey}}
11
+ import {{childs[0].codeKey}} from "./{{childs[0].codeKey}}.js";
12
+ {% endif %}
13
+ {% endif%}
14
+ {% endcall %}
15
+
16
+ {% call block.definition() %}
17
+
18
+ {% if childs.length %}
19
+ {% if childs[0].definition.dynamic %}
20
+ // FIRST CHILD: {{childs[0].indexKey}}
21
+ const { default: {{childs[0].codeKey}} } = await import("./{{childs[0].codeKey}}.js");
22
+ {% endif %}
23
+ {% endif%}
24
+
25
+ for await(const {{context.transform.for.as | safe}} of {{context.transform.for.in | safe}}){
26
+ // Create Proxy for closure-like variable resolution
27
+ // Local variable shadows parent, but parent scope accessible via Proxy fallback
28
+ const localForVar = { {{context.transform.for.as | safe}}: {{context.transform.for.as | safe}} };
29
+ const forProxy = new Proxy(localForVar, {
30
+ get(target, prop) {
31
+ // Check local scope first (shadowing)
32
+ if (prop in target) return target[prop];
33
+ // Fallback to parent scope
34
+ return c.for?.[prop];
35
+ }
36
+ });
1
37
 
2
- {% include "src/default/macros/block-header.js.njk" %}
3
-
4
- {% include "src/default/macros/block-next-header.js.njk" %}
5
-
6
- {% include "src/default/macros/block-modules-header.js.njk" %}
7
-
8
- {% if childs.length %}
9
- {% if not childs[0].definition.dynamic %}
10
- // FIRST CHILD: {{childs[0].indexKey}}
11
- import {{childs[0].codeKey}} from "./{{childs[0].codeKey}}.js";
12
- {% endif %}
13
- {% endif%}
38
+ // Create new context with updated for
39
+ const loopContext = { ...c, for: forProxy };
14
40
 
15
- export default function Block(context) {
41
+ {% if childs.length %}
42
+ let current= new {{childs[0].codeKey}}({ parent:_this, engine, flow, caller:loopContext });
43
+ let currentArgs=args;
16
44
 
17
- {% include "src/default/macros/block-body-header.js.njk" %}
45
+ do {
18
46
 
19
- this.run= function (){
20
-
21
- {% include "src/default/macros/block-entry-args.js.njk" %}
47
+ {% if workflow.parent.context.atom.doc.features.print_runners %}
48
+ console.log(new Date().toLocaleString(),' * ',_this.constructor.IndexKey,' -> ',current.constructor.IndexKey);
49
+ {% endif %}
22
50
 
23
- return new Promise(async (resolve,reject)=>{
24
-
25
- {% include "src/default/macros/block-run-header.js.njk" %}
26
-
27
- {% include "src/default/macros/page.js.njk" %}
28
-
29
- {% include "src/default/macros/block-modules.js.njk" %}
51
+ const nextBlock= typeof currentArgs==='undefined'? await current.run()
52
+ : Array.isArray(currentArgs)? await current.run.apply(current,currentArgs) : await current.run.call(current, currentArgs) ;
30
53
 
31
- {% if childs.length %}
32
- {% if childs[0].definition.dynamic %}
33
- // FIRST CHILD: {{childs[0].indexKey}}
34
- const { default: {{childs[0].codeKey}} } = await import("./{{childs[0].codeKey}}.js");
35
- {% endif %}
36
- {% endif%}
37
-
38
- for await(const {{context.transform.for.as | safe}} of {{context.transform.for.in | safe}}){
39
- // Create Proxy for closure-like variable resolution
40
- // Local variable shadows parent, but parent scope accessible via Proxy fallback
41
- const localForVar = { {{context.transform.for.as | safe}}: {{context.transform.for.as | safe}} };
42
- const forProxy = new Proxy(localForVar, {
43
- get(target, prop) {
44
- // Check local scope first (shadowing)
45
- if (prop in target) return target[prop];
46
- // Fallback to parent scope
47
- return c.for?.[prop];
48
- }
49
- });
50
-
51
- // Create new context with updated for
52
- const loopContext = { ...c, for: forProxy };
53
-
54
- {% if childs.length %}
55
- let current= new {{childs[0].codeKey}}({ parent:_this, engine, flow, caller:loopContext });
56
- let currentArgs=args;
57
-
58
- do {
59
-
60
- {% if workflow.parent.context.atom.doc.features.print_runners %}
61
- console.log(new Date().toLocaleString(),' * ',_this.constructor.IndexKey,' -> ',current.constructor.IndexKey);
62
- {% endif %}
63
-
64
- try {
65
- const nextBlock= typeof currentArgs==='undefined'? await current.run()
66
- : Array.isArray(currentArgs)? await current.run.apply(current,currentArgs) : await current.run.call(current, currentArgs) ;
67
-
68
- if(nextBlock?.type==='return') return resolve(nextBlock);
69
- else if(nextBlock?.type!=='block') break;
70
-
71
- if(nextBlock.toType.ParentTypeId!==_this.constructor.TypeId)
72
- return resolve(nextBlock);
73
-
74
- current=new nextBlock.toType({ parent:_this, engine, flow, caller:loopContext, onError, error });
75
- currentArgs=nextBlock.input;
76
- } catch (err) {
77
- if (onError) {
78
- return onError(err);
79
- }
80
- throw err;
81
- }
82
-
83
- } while(true);
84
-
85
- {% endif %}
86
- }
54
+ if(nextBlock?.type==='return') return resolve(nextBlock);
55
+ else if(nextBlock?.type!=='block') break;
87
56
 
88
- {% include "src/default/macros/block-assign.js.njk" %}
57
+ if(nextBlock.toType.ParentTypeId!==_this.constructor.TypeId)
58
+ return resolve(nextBlock);
89
59
 
90
- {% include "src/default/macros/block-signal.js.njk" %}
60
+ current=new nextBlock.toType({ parent:_this, engine, flow, caller:loopContext, error });
61
+ currentArgs=nextBlock.input;
91
62
 
92
- {% if context.transform.return %}
93
- resolve({type:'return',value: {{context.transform.return | safe}}});
94
- {% elseif context.next %}
95
- {% include "src/default/macros/block-next.js.njk" %}
96
- {% else %}
97
- resolve();
98
- {% endif %}
63
+ } while(true);
99
64
 
100
- {% include "src/default/macros/block-run-footer.js.njk" %}
101
- });
102
- }
65
+ {% endif %}
66
+ }
103
67
 
104
- Object.freeze(this);
105
- }
68
+ {% endcall %}
106
69
 
107
- {% include "src/default/macros/block-footer.js.njk" %}
70
+ {% call block.footer()%}
71
+ {% endcall %}
@@ -1,69 +1,31 @@
1
- import React from "react";
1
+ {% set waitForNext=true %}
2
+ {% set assign=true %}
3
+ {% set signal=true %}
2
4
 
3
- {% include "src/default/macros/block-header.js.njk" %}
5
+ {% import "src/default/types/block.js.njk" as block with context %}
4
6
 
5
- {% include "src/default/macros/block-next-header.js.njk" %}
7
+ {% call block.header() %}
6
8
 
7
- {% include "src/default/macros/block-library-header.js.njk" %}
9
+ {% include "src/default/macros/block-library-header.js.njk" %}
8
10
 
9
- {% include "src/default/macros/block-modules-header.js.njk" %}
11
+ import React from "react";
10
12
 
11
- export default function Block(context){
12
-
13
- {% include "src/default/macros/block-body-header.js.njk" %}
13
+ {% endcall %}
14
14
 
15
- this.run= function (){
16
-
17
- {% include "src/default/macros/block-entry-args.js.njk" %}
15
+ {% call block.definition() %}
18
16
 
19
- return new Promise(async (resolve,reject)=>{
17
+ {% if context.lib.type==='atom'%}
18
+ const formLib=LIBRARY;
19
+ {% elseif context.lib.type==='subworkflow' %}
20
+ const formLib={{context.lib.codeKey}};
21
+ {% else %}
22
+ const formLib=undefined;
23
+ throw new Error('Couldnt find form.');
24
+ {% endif %}
20
25
 
26
+ {% include "src/default/macros/block-run-form.js.njk" %}
21
27
 
22
- try{
23
- {% include "src/default/macros/block-run-header.js.njk" %}
24
-
25
- {% include "src/default/macros/page.js.njk" %}
28
+ {% endcall %}
26
29
 
27
- {% include "src/default/macros/block-modules.js.njk" %}
28
-
29
- flow.waitForNext({
30
- key:'{{indexKey}}',
31
- next: async () => {
32
- {% if context.transform.return %}
33
- resolve({type:'return',value: {{context.transform.return | safe}}});
34
- {% elseif context.next %}
35
- {% include "src/default/macros/block-next.js.njk" %}
36
- {% else %}
37
- resolve();
38
- {% endif %}
39
- }
40
- });
41
-
42
- {% if context.lib.type==='atom'%}
43
- const formLib=LIBRARY;
44
- {% elseif context.lib.type==='subworkflow' %}
45
- const formLib={{context.lib.codeKey}};
46
- {% else %}
47
- const formLib=undefined;
48
- throw new Error('Couldnt find form.');
49
- {% endif %}
50
-
51
- {% include "src/default/macros/block-run-form.js.njk" %}
52
-
53
- {% include "src/default/macros/block-assign.js.njk" %}
54
-
55
- {% include "src/default/macros/block-signal.js.njk" %}
56
-
57
- {% include "src/default/macros/block-run-footer.js.njk" %}
58
- }
59
- catch(error){
60
- reject(error);
61
- }
62
-
63
- });
64
- }
65
-
66
- Object.freeze(this);
67
- }
68
-
69
- {% include "src/default/macros/block-footer.js.njk" %}
30
+ {% call block.footer()%}
31
+ {% endcall %}
@@ -1,157 +1,135 @@
1
- {% include "src/default/macros/block-header.js.njk" %}
2
-
3
- {% include "src/default/macros/block-next-header.js.njk" %}
4
-
5
- {% include "src/default/macros/block-modules-header.js.njk" %}
6
-
7
- export default function Block(context){
8
-
9
- {% include "src/default/macros/block-body-header.js.njk" %}
10
-
11
- this.run= function (){
12
-
13
- {% include "src/default/macros/block-entry-args.js.njk" %}
14
-
15
- return new Promise(async (resolve,reject)=>{
16
- {% include "src/default/macros/block-run-header.js.njk" %}
17
-
18
- {% include "src/default/macros/page.js.njk" %}
19
-
20
- {% include "src/default/macros/block-modules.js.njk" %}
21
-
22
- // HTTP configuration
23
- let url = {{ context.transform.http.url | safe }};
24
- let method = "{{ context.transform.http.method }}";
25
- let headers = {{ context.transform.http.headers | dump | safe }};
26
- let timeout = {{ context.transform.http.timeout }};
27
- {% if context.transform.http.body !== undefined %}
28
- let body = {% if context.transform.http.body is string %}{{ context.transform.http.body | safe }}{% else %}{{ context.transform.http.body | dump | safe }}{% endif %};
29
- {% endif %}
30
- {% if context.transform.http.params %}
31
- let params = {{ context.transform.http.params | dump | safe }};
32
- {% endif %}
33
-
34
- // Create HTTP context for modules
35
- const httpContext = { url, method, headers, timeout, params: {% if context.transform.http.params %}params{% else %}undefined{% endif %}, body: {% if context.transform.http.body !== undefined %}body{% else %}undefined{% endif %} };
36
-
37
- // If any property is a module function (m::), call it with HTTP context
38
- if (typeof url === 'function') {
39
- url = await url(httpContext);
40
- }
1
+ {% set assign=true %}
2
+ {% set signal=true %}
3
+ {% set resolve=true %}
4
+ {% set result=true %}
5
+
6
+ {% import "src/default/types/block.js.njk" as block with context %}
7
+
8
+ {% call block.header() %}
9
+ {% endcall %}
10
+
11
+ {% call block.definition() %}
12
+
13
+ // HTTP configuration
14
+ let url = {{ context.transform.http.url | safe }};
15
+ let method = "{{ context.transform.http.method }}";
16
+ let headers = {{ context.transform.http.headers | dump | safe }};
17
+ let timeout = {{ context.transform.http.timeout }};
18
+ {% if context.transform.http.body !== undefined %}
19
+ let body = {% if context.transform.http.body is string %}{{ context.transform.http.body | safe }}{% else %}{{ context.transform.http.body | dump | safe }}{% endif %};
20
+ {% endif %}
21
+ {% if context.transform.http.params %}
22
+ let params = {{ context.transform.http.params | dump | safe }};
23
+ {% endif %}
24
+
25
+ // Create HTTP context for modules
26
+ const httpContext = { url, method, headers, timeout, params: {% if context.transform.http.params %}params{% else %}undefined{% endif %}, body: {% if context.transform.http.body !== undefined %}body{% else %}undefined{% endif %} };
27
+
28
+ // If any property is a module function (m::), call it with HTTP context
29
+ if (typeof url === 'function') {
30
+ url = await url(httpContext);
31
+ }
41
32
 
42
- if (typeof method === 'function') {
43
- method = await method(httpContext);
44
- }
33
+ if (typeof method === 'function') {
34
+ method = await method(httpContext);
35
+ }
45
36
 
46
- if (typeof headers === 'function') {
47
- headers = await headers(httpContext);
48
- }
37
+ if (typeof headers === 'function') {
38
+ headers = await headers(httpContext);
39
+ }
49
40
 
50
- if (typeof timeout === 'function') {
51
- timeout = await timeout(httpContext);
52
- }
41
+ if (typeof timeout === 'function') {
42
+ timeout = await timeout(httpContext);
43
+ }
53
44
 
54
- {% if context.transform.http.params %}
55
- if (typeof params === 'function') {
56
- params = await params(httpContext);
57
- }
58
- {% endif %}
45
+ {% if context.transform.http.params %}
46
+ if (typeof params === 'function') {
47
+ params = await params(httpContext);
48
+ }
49
+ {% endif %}
59
50
 
60
- {% if context.transform.http.body !== undefined %}
61
- if (typeof body === 'function') {
62
- body = await body(httpContext);
63
- }
64
- {% endif %}
65
-
66
- // Build URL with query parameters if provided
67
- let finalUrl = url;
68
- {% if context.transform.http.params %}
69
- if (params && Object.keys(params).length > 0) {
70
- const queryString = new URLSearchParams(params).toString();
71
- finalUrl = url + (url.includes('?') ? '&' : '?') + queryString;
72
- }
73
- {% endif %}
74
-
75
- // Prepare fetch options
76
- const fetchOptions = {
77
- method: method,
78
- headers: headers
79
- };
80
-
81
- // Add body if present (and not GET/HEAD)
82
- {% if context.transform.http.body %}
83
- if (body !== undefined && method !== 'GET' && method !== 'HEAD') {
84
- // Auto JSON.stringify if body is object
85
- if (typeof body === 'object' && body !== null) {
86
- fetchOptions.body = JSON.stringify(body);
87
- // Auto set Content-Type if not already set
88
- if (!fetchOptions.headers['Content-Type'] && !fetchOptions.headers['content-type']) {
89
- fetchOptions.headers['Content-Type'] = 'application/json';
90
- }
91
- } else {
92
- fetchOptions.body = body;
93
- }
51
+ {% if context.transform.http.body !== undefined %}
52
+ if (typeof body === 'function') {
53
+ body = await body(httpContext);
54
+ }
55
+ {% endif %}
56
+
57
+ // Build URL with query parameters if provided
58
+ let finalUrl = url;
59
+ {% if context.transform.http.params %}
60
+ if (params && Object.keys(params).length > 0) {
61
+ const queryString = new URLSearchParams(params).toString();
62
+ finalUrl = url + (url.includes('?') ? '&' : '?') + queryString;
63
+ }
64
+ {% endif %}
65
+
66
+ // Prepare fetch options
67
+ const fetchOptions = {
68
+ method: method,
69
+ headers: headers
70
+ };
71
+
72
+ // Add body if present (and not GET/HEAD)
73
+ {% if context.transform.http.body %}
74
+ if (body !== undefined && method !== 'GET' && method !== 'HEAD') {
75
+ // Auto JSON.stringify if body is object
76
+ if (typeof body === 'object' && body !== null) {
77
+ fetchOptions.body = JSON.stringify(body);
78
+ // Auto set Content-Type if not already set
79
+ if (!fetchOptions.headers['Content-Type'] && !fetchOptions.headers['content-type']) {
80
+ fetchOptions.headers['Content-Type'] = 'application/json';
94
81
  }
95
- {% endif %}
96
-
97
- // Create abort controller for timeout
98
- const controller = new AbortController();
99
- const timeoutId = setTimeout(() => controller.abort(), timeout);
100
- fetchOptions.signal = controller.signal;
101
-
82
+ } else {
83
+ fetchOptions.body = body;
84
+ }
85
+ }
86
+ {% endif %}
87
+
88
+ // Create abort controller for timeout
89
+ const controller = new AbortController();
90
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
91
+ fetchOptions.signal = controller.signal;
92
+
93
+ let result;
94
+
95
+ try {
96
+ // Execute HTTP request
97
+ const response = await fetch(finalUrl, fetchOptions);
98
+ clearTimeout(timeoutId);
99
+
100
+ // Check if response is successful (2xx)
101
+ if (!response.ok) {
102
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
103
+ }
104
+
105
+ // Parse response based on Content-Type
106
+ const contentType = response.headers.get('content-type');
107
+
108
+ if (contentType && contentType.includes('application/json')) {
109
+ result = await response.json();
110
+ } else if (contentType && contentType.includes('text/')) {
111
+ result = await response.text();
112
+ } else {
113
+ // Try JSON first, fallback to text
102
114
  try {
103
- // Execute HTTP request
104
- const response = await fetch(finalUrl, fetchOptions);
105
- clearTimeout(timeoutId);
106
-
107
- // Check if response is successful (2xx)
108
- if (!response.ok) {
109
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
110
- }
111
-
112
- // Parse response based on Content-Type
113
- const contentType = response.headers.get('content-type');
114
- let result;
115
-
116
- if (contentType && contentType.includes('application/json')) {
117
- result = await response.json();
118
- } else if (contentType && contentType.includes('text/')) {
119
- result = await response.text();
120
- } else {
121
- // Try JSON first, fallback to text
122
- try {
123
- result = await response.json();
124
- } catch (e) {
125
- result = await response.text();
126
- }
127
- }
128
-
129
- // Store result in flow variable
130
- flow.set('result', result);
131
-
132
- {% include "src/default/macros/block-assign.js.njk" %}
133
-
134
- } catch (error) {
135
- clearTimeout(timeoutId);
136
-
137
- // Handle timeout error
138
- if (error.name === 'AbortError') {
139
- const timeoutError = new Error(`HTTP request timeout after ${timeout}ms: ${finalUrl}`);
140
- onError ? onError(timeoutError) : reject(timeoutError);
141
- return;
142
- }
143
-
144
- // Handle other errors
145
- onError ? onError(error) : reject(error);
146
- return;
115
+ result = await response.json();
116
+ } catch (e) {
117
+ result = await response.text();
147
118
  }
148
-
149
- {% include "src/default/macros/block-next.js.njk" %}
150
-
151
- {% include "src/default/macros/block-run-footer.js.njk" %}
152
- });
119
+ }
120
+ } catch (error) {
121
+ clearTimeout(timeoutId);
122
+
123
+ // Handle timeout error
124
+ if (error.name === 'AbortError') {
125
+ const timeoutError = new Error(`HTTP request timeout after ${timeout}ms: ${finalUrl}`);
126
+ return reject(timeoutError);
127
+ }
128
+
129
+ // Handle other errors
130
+ return reject(error);
153
131
  }
154
- }
155
-
156
- {% include "src/default/macros/block-footer.js.njk" %}
132
+ {% endcall %}
157
133
 
134
+ {% call block.footer()%}
135
+ {% endcall %}
@@ -1,57 +1,15 @@
1
- {% include "src/default/macros/block-header.js.njk" %}
1
+ {% set assign=true %}
2
+ {% set signal=true %}
3
+ {% set resolve=true %}
2
4
 
3
- {% include "src/default/macros/block-next-header.js.njk" %}
5
+ {% import "src/default/types/block.js.njk" as block with context %}
4
6
 
5
- {% include "src/default/macros/block-modules-header.js.njk" %}
7
+ {% call block.header() %}
8
+ {% endcall %}
6
9
 
7
- export default function Block(context){
10
+ {% call block.definition() %}
8
11
 
9
- {% include "src/default/macros/block-body-header.js.njk" %}
12
+ {% endcall %}
10
13
 
11
- this.run= function (){
12
-
13
- {% include "src/default/macros/block-entry-args.js.njk" %}
14
-
15
- return new Promise(async (resolve,reject)=>{
16
-
17
- try{
18
- {% include "src/default/macros/block-run-header.js.njk" %}
19
-
20
- {% include "src/default/macros/page.js.njk" %}
21
-
22
- {% if context.next and context.transform.wait==='next' %}
23
- flow.waitForNext({
24
- key:'{{indexKey}}',
25
- next: async () => {
26
- {% include "src/default/macros/block-next.js.njk" %}
27
- }
28
- });
29
- {% endif %}
30
-
31
- {% include "src/default/macros/block-modules.js.njk" %}
32
-
33
-
34
- {% include "src/default/macros/block-assign.js.njk" %}
35
-
36
- {% include "src/default/macros/block-signal.js.njk" %}
37
-
38
- {% if context.transform.return %}
39
- resolve({type:'return',value: {{context.transform.return | safe}}});
40
- {% elseif context.next and context.transform.wait!=='next'%}
41
- {% include "src/default/macros/block-next.js.njk" %}
42
- {% elseif not context.next%}
43
- resolve();
44
- {% endif %}
45
-
46
- {% include "src/default/macros/block-run-footer.js.njk" %}
47
- }
48
- catch(error){
49
- reject(error);
50
- }
51
- });
52
- }
53
-
54
- Object.freeze(this);
55
- }
56
-
57
- {% include "src/default/macros/block-footer.js.njk" %}
14
+ {% call block.footer()%}
15
+ {% endcall %}