diff --git a/async_fixtures/multiple_stacks/compiled.js b/async_fixtures/multiple_stacks/compiled.js
new file mode 100644
index 0000000..e581b51
--- /dev/null
+++ b/async_fixtures/multiple_stacks/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.stacks.create('css');
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/multiple_stacks/index.edge b/async_fixtures/multiple_stacks/index.edge
new file mode 100644
index 0000000..4728cba
--- /dev/null
+++ b/async_fixtures/multiple_stacks/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@stack('css')
\ No newline at end of file
diff --git a/async_fixtures/multiple_stacks/index.json b/async_fixtures/multiple_stacks/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/multiple_stacks/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/multiple_stacks/index.txt b/async_fixtures/multiple_stacks/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/async_fixtures/push_once_to/compiled.js b/async_fixtures/push_once_to/compiled.js
new file mode 100644
index 0000000..9e76d34
--- /dev/null
+++ b/async_fixtures/push_once_to/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compilePartial('push_once_to/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += await template.compilePartial('push_once_to/script')(template,state,$context);
+out += "\n";
+$lineNumber = 4;
+out += await template.compilePartial('push_once_to/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_once_to/index.edge b/async_fixtures/push_once_to/index.edge
new file mode 100644
index 0000000..d9acfb7
--- /dev/null
+++ b/async_fixtures/push_once_to/index.edge
@@ -0,0 +1,4 @@
+@stack('js')
+@include('push_once_to/script')
+@include('push_once_to/script')
+@include('push_once_to/script')
\ No newline at end of file
diff --git a/async_fixtures/push_once_to/index.json b/async_fixtures/push_once_to/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_once_to/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_once_to/index.txt b/async_fixtures/push_once_to/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/async_fixtures/push_once_to/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_once_to/script.edge b/async_fixtures/push_once_to/script.edge
new file mode 100644
index 0000000..bf0aa0e
--- /dev/null
+++ b/async_fixtures/push_once_to/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_using_variables/compiled.js b/async_fixtures/push_once_to_using_variables/compiled.js
new file mode 100644
index 0000000..eb89f03
--- /dev/null
+++ b/async_fixtures/push_once_to_using_variables/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+out += "\n";
+$lineNumber = 2;
+out += await template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += await template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+out += "\n";
+$lineNumber = 4;
+out += await template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_using_variables/index.edge b/async_fixtures/push_once_to_using_variables/index.edge
new file mode 100644
index 0000000..ad92366
--- /dev/null
+++ b/async_fixtures/push_once_to_using_variables/index.edge
@@ -0,0 +1,4 @@
+@stack(stackName)
+@include('push_once_to_using_variables/script')
+@include('push_once_to_using_variables/script')
+@include('push_once_to_using_variables/script')
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_using_variables/index.json b/async_fixtures/push_once_to_using_variables/index.json
new file mode 100644
index 0000000..ea5f424
--- /dev/null
+++ b/async_fixtures/push_once_to_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "stackName": "js"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_using_variables/index.txt b/async_fixtures/push_once_to_using_variables/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/async_fixtures/push_once_to_using_variables/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_using_variables/script.edge b/async_fixtures/push_once_to_using_variables/script.edge
new file mode 100644
index 0000000..7d5608e
--- /dev/null
+++ b/async_fixtures/push_once_to_using_variables/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo(stackName)
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_via_components/compiled.js b/async_fixtures/push_once_to_via_components/compiled.js
new file mode 100644
index 0000000..3107f6c
--- /dev/null
+++ b/async_fixtures/push_once_to_via_components/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 3;
+out += await template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 4;
+out += await template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_via_components/index.edge b/async_fixtures/push_once_to_via_components/index.edge
new file mode 100644
index 0000000..88ee490
--- /dev/null
+++ b/async_fixtures/push_once_to_via_components/index.edge
@@ -0,0 +1,4 @@
+@stack('js')
+@!component('push_once_to_via_components/script')
+@!component('push_once_to_via_components/script')
+@!component('push_once_to_via_components/script')
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_via_components/index.json b/async_fixtures/push_once_to_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_once_to_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_via_components/index.txt b/async_fixtures/push_once_to_via_components/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/async_fixtures/push_once_to_via_components/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_once_to_via_components/script.edge b/async_fixtures/push_once_to_via_components/script.edge
new file mode 100644
index 0000000..bf0aa0e
--- /dev/null
+++ b/async_fixtures/push_once_to_via_components/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to/compiled.js b/async_fixtures/push_to/compiled.js
new file mode 100644
index 0000000..2095f6f
--- /dev/null
+++ b/async_fixtures/push_to/compiled.js
@@ -0,0 +1,19 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to/index.edge b/async_fixtures/push_to/index.edge
new file mode 100644
index 0000000..c98f3d1
--- /dev/null
+++ b/async_fixtures/push_to/index.edge
@@ -0,0 +1,7 @@
+@stack('js')
+
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to/index.json b/async_fixtures/push_to/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to/index.txt b/async_fixtures/push_to/index.txt
new file mode 100644
index 0000000..bddac57
--- /dev/null
+++ b/async_fixtures/push_to/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_conditionals/compiled.js b/async_fixtures/push_to_conditionals/compiled.js
new file mode 100644
index 0000000..c95312f
--- /dev/null
+++ b/async_fixtures/push_to_conditionals/compiled.js
@@ -0,0 +1,25 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+if (true) {
+out += "\n";
+$lineNumber = 4;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = ";
+$lineNumber = 6;
+stack_1 += `${state.requireFoo}`;
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+}
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_conditionals/index.edge b/async_fixtures/push_to_conditionals/index.edge
new file mode 100644
index 0000000..a8915a5
--- /dev/null
+++ b/async_fixtures/push_to_conditionals/index.edge
@@ -0,0 +1,9 @@
+@stack('js')
+
+@if(true)
+ @pushTo('js')
+
+ @end
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_conditionals/index.json b/async_fixtures/push_to_conditionals/index.json
new file mode 100644
index 0000000..dd1dfc6
--- /dev/null
+++ b/async_fixtures/push_to_conditionals/index.json
@@ -0,0 +1,4 @@
+{
+ "username": "virk",
+ "requireFoo": "require('a')"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_conditionals/index.txt b/async_fixtures/push_to_conditionals/index.txt
new file mode 100644
index 0000000..8a255c4
--- /dev/null
+++ b/async_fixtures/push_to_conditionals/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_times/compiled.js b/async_fixtures/push_to_multiple_times/compiled.js
new file mode 100644
index 0000000..3344a87
--- /dev/null
+++ b/async_fixtures/push_to_multiple_times/compiled.js
@@ -0,0 +1,29 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+out += "\n";
+out += "";
+$lineNumber = 9;
+let stack_2 = "";
+stack_2 += " \u003Cscript\u003E";
+stack_2 += "\n";
+stack_2 += " var b = require('b')";
+stack_2 += "\n";
+stack_2 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_2);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_times/index.edge b/async_fixtures/push_to_multiple_times/index.edge
new file mode 100644
index 0000000..0e26860
--- /dev/null
+++ b/async_fixtures/push_to_multiple_times/index.edge
@@ -0,0 +1,13 @@
+@stack('js')
+
+@pushTo('js')
+
+@end
+
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_times/index.json b/async_fixtures/push_to_multiple_times/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to_multiple_times/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_times/index.txt b/async_fixtures/push_to_multiple_times/index.txt
new file mode 100644
index 0000000..79f95c9
--- /dev/null
+++ b/async_fixtures/push_to_multiple_times/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/compiled.js b/async_fixtures/push_to_multiple_via_components/compiled.js
new file mode 100644
index 0000000..37f0448
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/compiled.js
@@ -0,0 +1,15 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compileComponent('push_to_multiple_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 3;
+out += await template.compileComponent('push_to_multiple_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/index.edge b/async_fixtures/push_to_multiple_via_components/index.edge
new file mode 100644
index 0000000..7ccb5de
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/index.edge
@@ -0,0 +1,3 @@
+@stack('js')
+@!component('push_to_multiple_via_components/script')
+@!component('push_to_multiple_via_components/script')
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/index.json b/async_fixtures/push_to_multiple_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/index.txt b/async_fixtures/push_to_multiple_via_components/index.txt
new file mode 100644
index 0000000..f91a60b
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/script.edge b/async_fixtures/push_to_multiple_via_components/script.edge
new file mode 100644
index 0000000..bc8ba05
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/script.edge
@@ -0,0 +1 @@
+@include('push_to_multiple_via_components/script_partial')
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_components/script_partial.edge b/async_fixtures/push_to_multiple_via_components/script_partial.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_components/script_partial.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_paritals/compiled.js b/async_fixtures/push_to_multiple_via_paritals/compiled.js
new file mode 100644
index 0000000..229a5f4
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_paritals/compiled.js
@@ -0,0 +1,15 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compilePartial('push_to_multiple_via_components/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += await template.compilePartial('push_to_multiple_via_components/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_paritals/index.edge b/async_fixtures/push_to_multiple_via_paritals/index.edge
new file mode 100644
index 0000000..ab14b4d
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_paritals/index.edge
@@ -0,0 +1,3 @@
+@stack('js')
+@include('push_to_multiple_via_components/script')
+@include('push_to_multiple_via_components/script')
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_paritals/index.json b/async_fixtures/push_to_multiple_via_paritals/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_paritals/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_paritals/index.txt b/async_fixtures/push_to_multiple_via_paritals/index.txt
new file mode 100644
index 0000000..f91a60b
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_paritals/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_multiple_via_paritals/script.edge b/async_fixtures/push_to_multiple_via_paritals/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/async_fixtures/push_to_multiple_via_paritals/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_using_variables/compiled.js b/async_fixtures/push_to_using_variables/compiled.js
new file mode 100644
index 0000000..d43ed41
--- /dev/null
+++ b/async_fixtures/push_to_using_variables/compiled.js
@@ -0,0 +1,19 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo(state.stackName, stack_1);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_using_variables/index.edge b/async_fixtures/push_to_using_variables/index.edge
new file mode 100644
index 0000000..7e50f24
--- /dev/null
+++ b/async_fixtures/push_to_using_variables/index.edge
@@ -0,0 +1,7 @@
+@stack(stackName)
+
+@pushTo(stackName)
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_using_variables/index.json b/async_fixtures/push_to_using_variables/index.json
new file mode 100644
index 0000000..ea5f424
--- /dev/null
+++ b/async_fixtures/push_to_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "stackName": "js"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_using_variables/index.txt b/async_fixtures/push_to_using_variables/index.txt
new file mode 100644
index 0000000..bddac57
--- /dev/null
+++ b/async_fixtures/push_to_using_variables/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_components/compiled.js b/async_fixtures/push_to_via_components/compiled.js
new file mode 100644
index 0000000..d20f4c7
--- /dev/null
+++ b/async_fixtures/push_to_via_components/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compileComponent('push_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_components/index.edge b/async_fixtures/push_to_via_components/index.edge
new file mode 100644
index 0000000..5843ab3
--- /dev/null
+++ b/async_fixtures/push_to_via_components/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@!component('push_to_via_components/script')
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_components/index.json b/async_fixtures/push_to_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_components/index.txt b/async_fixtures/push_to_via_components/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/async_fixtures/push_to_via_components/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_components/script.edge b/async_fixtures/push_to_via_components/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/async_fixtures/push_to_via_components/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_partial/compiled.js b/async_fixtures/push_to_via_partial/compiled.js
new file mode 100644
index 0000000..7835ccf
--- /dev/null
+++ b/async_fixtures/push_to_via_partial/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += await template.compilePartial('push_to_via_partial/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_partial/index.edge b/async_fixtures/push_to_via_partial/index.edge
new file mode 100644
index 0000000..44aaa44
--- /dev/null
+++ b/async_fixtures/push_to_via_partial/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@include('push_to_via_partial/script')
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_partial/index.json b/async_fixtures/push_to_via_partial/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/push_to_via_partial/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_partial/index.txt b/async_fixtures/push_to_via_partial/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/async_fixtures/push_to_via_partial/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/async_fixtures/push_to_via_partial/script.edge b/async_fixtures/push_to_via_partial/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/async_fixtures/push_to_via_partial/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/async_fixtures/stack/compiled.js b/async_fixtures/stack/compiled.js
new file mode 100644
index 0000000..2156ee5
--- /dev/null
+++ b/async_fixtures/stack/compiled.js
@@ -0,0 +1,9 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/stack/index.edge b/async_fixtures/stack/index.edge
new file mode 100644
index 0000000..669d966
--- /dev/null
+++ b/async_fixtures/stack/index.edge
@@ -0,0 +1 @@
+@stack('js')
\ No newline at end of file
diff --git a/async_fixtures/stack/index.json b/async_fixtures/stack/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/stack/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/stack/index.txt b/async_fixtures/stack/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/async_fixtures/stack_using_variables/compiled.js b/async_fixtures/stack_using_variables/compiled.js
new file mode 100644
index 0000000..110957e
--- /dev/null
+++ b/async_fixtures/stack_using_variables/compiled.js
@@ -0,0 +1,9 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/async_fixtures/stack_using_variables/index.edge b/async_fixtures/stack_using_variables/index.edge
new file mode 100644
index 0000000..8cf7307
--- /dev/null
+++ b/async_fixtures/stack_using_variables/index.edge
@@ -0,0 +1 @@
+@stack(stackName)
\ No newline at end of file
diff --git a/async_fixtures/stack_using_variables/index.json b/async_fixtures/stack_using_variables/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/async_fixtures/stack_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/async_fixtures/stack_using_variables/index.txt b/async_fixtures/stack_using_variables/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/fixtures/multiple_stacks/compiled.js b/fixtures/multiple_stacks/compiled.js
new file mode 100644
index 0000000..e581b51
--- /dev/null
+++ b/fixtures/multiple_stacks/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.stacks.create('css');
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/multiple_stacks/index.edge b/fixtures/multiple_stacks/index.edge
new file mode 100644
index 0000000..4728cba
--- /dev/null
+++ b/fixtures/multiple_stacks/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@stack('css')
\ No newline at end of file
diff --git a/fixtures/multiple_stacks/index.json b/fixtures/multiple_stacks/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/multiple_stacks/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/multiple_stacks/index.txt b/fixtures/multiple_stacks/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/fixtures/push_once_to/compiled.js b/fixtures/push_once_to/compiled.js
new file mode 100644
index 0000000..c3c1556
--- /dev/null
+++ b/fixtures/push_once_to/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compilePartial('push_once_to/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += template.compilePartial('push_once_to/script')(template,state,$context);
+out += "\n";
+$lineNumber = 4;
+out += template.compilePartial('push_once_to/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_once_to/index.edge b/fixtures/push_once_to/index.edge
new file mode 100644
index 0000000..d9acfb7
--- /dev/null
+++ b/fixtures/push_once_to/index.edge
@@ -0,0 +1,4 @@
+@stack('js')
+@include('push_once_to/script')
+@include('push_once_to/script')
+@include('push_once_to/script')
\ No newline at end of file
diff --git a/fixtures/push_once_to/index.json b/fixtures/push_once_to/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_once_to/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_once_to/index.txt b/fixtures/push_once_to/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/fixtures/push_once_to/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_once_to/script.edge b/fixtures/push_once_to/script.edge
new file mode 100644
index 0000000..bf0aa0e
--- /dev/null
+++ b/fixtures/push_once_to/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_once_to_using_variables/compiled.js b/fixtures/push_once_to_using_variables/compiled.js
new file mode 100644
index 0000000..ca9d0c2
--- /dev/null
+++ b/fixtures/push_once_to_using_variables/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+out += "\n";
+$lineNumber = 2;
+out += template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+out += "\n";
+$lineNumber = 4;
+out += template.compilePartial('push_once_to_using_variables/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_once_to_using_variables/index.edge b/fixtures/push_once_to_using_variables/index.edge
new file mode 100644
index 0000000..ad92366
--- /dev/null
+++ b/fixtures/push_once_to_using_variables/index.edge
@@ -0,0 +1,4 @@
+@stack(stackName)
+@include('push_once_to_using_variables/script')
+@include('push_once_to_using_variables/script')
+@include('push_once_to_using_variables/script')
\ No newline at end of file
diff --git a/fixtures/push_once_to_using_variables/index.json b/fixtures/push_once_to_using_variables/index.json
new file mode 100644
index 0000000..ea5f424
--- /dev/null
+++ b/fixtures/push_once_to_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "stackName": "js"
+}
\ No newline at end of file
diff --git a/fixtures/push_once_to_using_variables/index.txt b/fixtures/push_once_to_using_variables/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/fixtures/push_once_to_using_variables/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_once_to_using_variables/script.edge b/fixtures/push_once_to_using_variables/script.edge
new file mode 100644
index 0000000..7d5608e
--- /dev/null
+++ b/fixtures/push_once_to_using_variables/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo(stackName)
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_once_to_via_components/compiled.js b/fixtures/push_once_to_via_components/compiled.js
new file mode 100644
index 0000000..4fac2e9
--- /dev/null
+++ b/fixtures/push_once_to_via_components/compiled.js
@@ -0,0 +1,18 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 3;
+out += template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 4;
+out += template.compileComponent('push_once_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_once_to_via_components/index.edge b/fixtures/push_once_to_via_components/index.edge
new file mode 100644
index 0000000..88ee490
--- /dev/null
+++ b/fixtures/push_once_to_via_components/index.edge
@@ -0,0 +1,4 @@
+@stack('js')
+@!component('push_once_to_via_components/script')
+@!component('push_once_to_via_components/script')
+@!component('push_once_to_via_components/script')
\ No newline at end of file
diff --git a/fixtures/push_once_to_via_components/index.json b/fixtures/push_once_to_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_once_to_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_once_to_via_components/index.txt b/fixtures/push_once_to_via_components/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/fixtures/push_once_to_via_components/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_once_to_via_components/script.edge b/fixtures/push_once_to_via_components/script.edge
new file mode 100644
index 0000000..bf0aa0e
--- /dev/null
+++ b/fixtures/push_once_to_via_components/script.edge
@@ -0,0 +1,5 @@
+@pushOnceTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to/compiled.js b/fixtures/push_to/compiled.js
new file mode 100644
index 0000000..2095f6f
--- /dev/null
+++ b/fixtures/push_to/compiled.js
@@ -0,0 +1,19 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to/index.edge b/fixtures/push_to/index.edge
new file mode 100644
index 0000000..c98f3d1
--- /dev/null
+++ b/fixtures/push_to/index.edge
@@ -0,0 +1,7 @@
+@stack('js')
+
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to/index.json b/fixtures/push_to/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to/index.txt b/fixtures/push_to/index.txt
new file mode 100644
index 0000000..bddac57
--- /dev/null
+++ b/fixtures/push_to/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_to_conditionals/compiled.js b/fixtures/push_to_conditionals/compiled.js
new file mode 100644
index 0000000..c95312f
--- /dev/null
+++ b/fixtures/push_to_conditionals/compiled.js
@@ -0,0 +1,25 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+if (true) {
+out += "\n";
+$lineNumber = 4;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = ";
+$lineNumber = 6;
+stack_1 += `${state.requireFoo}`;
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+}
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_conditionals/index.edge b/fixtures/push_to_conditionals/index.edge
new file mode 100644
index 0000000..a8915a5
--- /dev/null
+++ b/fixtures/push_to_conditionals/index.edge
@@ -0,0 +1,9 @@
+@stack('js')
+
+@if(true)
+ @pushTo('js')
+
+ @end
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_conditionals/index.json b/fixtures/push_to_conditionals/index.json
new file mode 100644
index 0000000..dd1dfc6
--- /dev/null
+++ b/fixtures/push_to_conditionals/index.json
@@ -0,0 +1,4 @@
+{
+ "username": "virk",
+ "requireFoo": "require('a')"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_conditionals/index.txt b/fixtures/push_to_conditionals/index.txt
new file mode 100644
index 0000000..8a255c4
--- /dev/null
+++ b/fixtures/push_to_conditionals/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_times/compiled.js b/fixtures/push_to_multiple_times/compiled.js
new file mode 100644
index 0000000..3344a87
--- /dev/null
+++ b/fixtures/push_to_multiple_times/compiled.js
@@ -0,0 +1,29 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_1);
+out += "\n";
+out += "";
+$lineNumber = 9;
+let stack_2 = "";
+stack_2 += " \u003Cscript\u003E";
+stack_2 += "\n";
+stack_2 += " var b = require('b')";
+stack_2 += "\n";
+stack_2 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo('js', stack_2);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_times/index.edge b/fixtures/push_to_multiple_times/index.edge
new file mode 100644
index 0000000..0e26860
--- /dev/null
+++ b/fixtures/push_to_multiple_times/index.edge
@@ -0,0 +1,13 @@
+@stack('js')
+
+@pushTo('js')
+
+@end
+
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_times/index.json b/fixtures/push_to_multiple_times/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to_multiple_times/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_times/index.txt b/fixtures/push_to_multiple_times/index.txt
new file mode 100644
index 0000000..79f95c9
--- /dev/null
+++ b/fixtures/push_to_multiple_times/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/compiled.js b/fixtures/push_to_multiple_via_components/compiled.js
new file mode 100644
index 0000000..3c51c7a
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/compiled.js
@@ -0,0 +1,15 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compileComponent('push_to_multiple_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+out += "\n";
+$lineNumber = 3;
+out += template.compileComponent('push_to_multiple_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/index.edge b/fixtures/push_to_multiple_via_components/index.edge
new file mode 100644
index 0000000..7ccb5de
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/index.edge
@@ -0,0 +1,3 @@
+@stack('js')
+@!component('push_to_multiple_via_components/script')
+@!component('push_to_multiple_via_components/script')
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/index.json b/fixtures/push_to_multiple_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/index.txt b/fixtures/push_to_multiple_via_components/index.txt
new file mode 100644
index 0000000..f91a60b
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/script.edge b/fixtures/push_to_multiple_via_components/script.edge
new file mode 100644
index 0000000..bc8ba05
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/script.edge
@@ -0,0 +1 @@
+@include('push_to_multiple_via_components/script_partial')
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_components/script_partial.edge b/fixtures/push_to_multiple_via_components/script_partial.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/fixtures/push_to_multiple_via_components/script_partial.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_partials/compiled.js b/fixtures/push_to_multiple_via_partials/compiled.js
new file mode 100644
index 0000000..10fcbb6
--- /dev/null
+++ b/fixtures/push_to_multiple_via_partials/compiled.js
@@ -0,0 +1,15 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compilePartial('push_to_multiple_via_partials/script')(template,state,$context);
+out += "\n";
+$lineNumber = 3;
+out += template.compilePartial('push_to_multiple_via_partials/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_partials/index.edge b/fixtures/push_to_multiple_via_partials/index.edge
new file mode 100644
index 0000000..c04a946
--- /dev/null
+++ b/fixtures/push_to_multiple_via_partials/index.edge
@@ -0,0 +1,3 @@
+@stack('js')
+@include('push_to_multiple_via_partials/script')
+@include('push_to_multiple_via_partials/script')
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_partials/index.json b/fixtures/push_to_multiple_via_partials/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to_multiple_via_partials/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_partials/index.txt b/fixtures/push_to_multiple_via_partials/index.txt
new file mode 100644
index 0000000..f91a60b
--- /dev/null
+++ b/fixtures/push_to_multiple_via_partials/index.txt
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/fixtures/push_to_multiple_via_partials/script.edge b/fixtures/push_to_multiple_via_partials/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/fixtures/push_to_multiple_via_partials/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_using_variables/compiled.js b/fixtures/push_to_using_variables/compiled.js
new file mode 100644
index 0000000..d43ed41
--- /dev/null
+++ b/fixtures/push_to_using_variables/compiled.js
@@ -0,0 +1,19 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+out += "\n";
+out += "";
+$lineNumber = 3;
+let stack_1 = "";
+stack_1 += " \u003Cscript\u003E";
+stack_1 += "\n";
+stack_1 += " var a = require('a')";
+stack_1 += "\n";
+stack_1 += " \u003C\u002Fscript\u003E";
+template.stacks.pushTo(state.stackName, stack_1);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_using_variables/index.edge b/fixtures/push_to_using_variables/index.edge
new file mode 100644
index 0000000..7e50f24
--- /dev/null
+++ b/fixtures/push_to_using_variables/index.edge
@@ -0,0 +1,7 @@
+@stack(stackName)
+
+@pushTo(stackName)
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_using_variables/index.json b/fixtures/push_to_using_variables/index.json
new file mode 100644
index 0000000..ea5f424
--- /dev/null
+++ b/fixtures/push_to_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "stackName": "js"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_using_variables/index.txt b/fixtures/push_to_using_variables/index.txt
new file mode 100644
index 0000000..bddac57
--- /dev/null
+++ b/fixtures/push_to_using_variables/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_to_via_components/compiled.js b/fixtures/push_to_via_components/compiled.js
new file mode 100644
index 0000000..808d208
--- /dev/null
+++ b/fixtures/push_to_via_components/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compileComponent('push_to_via_components/script')(template, template.getComponentState({}, { $context: Object.assign({}, $context), main: function () { return "" } }, { filename: $filename, line: $lineNumber, col: 0 }), $context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_via_components/index.edge b/fixtures/push_to_via_components/index.edge
new file mode 100644
index 0000000..5843ab3
--- /dev/null
+++ b/fixtures/push_to_via_components/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@!component('push_to_via_components/script')
\ No newline at end of file
diff --git a/fixtures/push_to_via_components/index.json b/fixtures/push_to_via_components/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to_via_components/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_via_components/index.txt b/fixtures/push_to_via_components/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/fixtures/push_to_via_components/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_to_via_components/script.edge b/fixtures/push_to_via_components/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/fixtures/push_to_via_components/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/push_to_via_partial/compiled.js b/fixtures/push_to_via_partial/compiled.js
new file mode 100644
index 0000000..feb02f1
--- /dev/null
+++ b/fixtures/push_to_via_partial/compiled.js
@@ -0,0 +1,12 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+out += "\n";
+$lineNumber = 2;
+out += template.compilePartial('push_to_via_partial/script')(template,state,$context);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/push_to_via_partial/index.edge b/fixtures/push_to_via_partial/index.edge
new file mode 100644
index 0000000..44aaa44
--- /dev/null
+++ b/fixtures/push_to_via_partial/index.edge
@@ -0,0 +1,2 @@
+@stack('js')
+@include('push_to_via_partial/script')
\ No newline at end of file
diff --git a/fixtures/push_to_via_partial/index.json b/fixtures/push_to_via_partial/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/push_to_via_partial/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/push_to_via_partial/index.txt b/fixtures/push_to_via_partial/index.txt
new file mode 100644
index 0000000..fbf6e71
--- /dev/null
+++ b/fixtures/push_to_via_partial/index.txt
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/fixtures/push_to_via_partial/script.edge b/fixtures/push_to_via_partial/script.edge
new file mode 100644
index 0000000..602ad22
--- /dev/null
+++ b/fixtures/push_to_via_partial/script.edge
@@ -0,0 +1,5 @@
+@pushTo('js')
+
+@end
\ No newline at end of file
diff --git a/fixtures/stack/compiled.js b/fixtures/stack/compiled.js
new file mode 100644
index 0000000..2156ee5
--- /dev/null
+++ b/fixtures/stack/compiled.js
@@ -0,0 +1,9 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create('js');
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/stack/index.edge b/fixtures/stack/index.edge
new file mode 100644
index 0000000..669d966
--- /dev/null
+++ b/fixtures/stack/index.edge
@@ -0,0 +1 @@
+@stack('js')
\ No newline at end of file
diff --git a/fixtures/stack/index.json b/fixtures/stack/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/stack/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/stack/index.txt b/fixtures/stack/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/fixtures/stack_using_variables/compiled.js b/fixtures/stack_using_variables/compiled.js
new file mode 100644
index 0000000..110957e
--- /dev/null
+++ b/fixtures/stack_using_variables/compiled.js
@@ -0,0 +1,9 @@
+let out = "";
+let $lineNumber = 1;
+let $filename = "{{__dirname}}index.edge";
+try {
+out += template.stacks.create(state.stackName);
+} catch (error) {
+template.reThrow(error, $filename, $lineNumber);
+}
+return out;
\ No newline at end of file
diff --git a/fixtures/stack_using_variables/index.edge b/fixtures/stack_using_variables/index.edge
new file mode 100644
index 0000000..8cf7307
--- /dev/null
+++ b/fixtures/stack_using_variables/index.edge
@@ -0,0 +1 @@
+@stack(stackName)
\ No newline at end of file
diff --git a/fixtures/stack_using_variables/index.json b/fixtures/stack_using_variables/index.json
new file mode 100644
index 0000000..d5f5540
--- /dev/null
+++ b/fixtures/stack_using_variables/index.json
@@ -0,0 +1,3 @@
+{
+ "username": "virk"
+}
\ No newline at end of file
diff --git a/fixtures/stack_using_variables/index.txt b/fixtures/stack_using_variables/index.txt
new file mode 100644
index 0000000..e69de29
diff --git a/src/edge/stacks.ts b/src/edge/stacks.ts
new file mode 100644
index 0000000..705f2da
--- /dev/null
+++ b/src/edge/stacks.ts
@@ -0,0 +1,86 @@
+/*
+ * edge.js
+ *
+ * (c) EdgeJS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { EOL } from 'node:os'
+
+export default class Stacks {
+ /**
+ * Pre-seeded content before the placeholder has been
+ * defined.
+ */
+ #seededPlaceholders: Map = new Map()
+
+ /**
+ * Placeholders to be flushed
+ */
+ #placeholders: Map = new Map()
+
+ /**
+ * Returns the placeholder name for a given stack
+ */
+ #createPlaceholder(name: string) {
+ return ``
+ }
+
+ /**
+ * Create a new stack placeholder. Multiple calls to this method
+ * with the same name results in an exception.
+ */
+ create(name: string) {
+ if (this.#placeholders.has(name)) {
+ throw new Error(`Cannot declare stack "${name}" for multiple times`)
+ }
+
+ /**
+ * Copy content from the seeded placeholders and delete it
+ */
+ const seededPlaceholder = this.#seededPlaceholders.get(name) || []
+ this.#seededPlaceholders.delete(name)
+
+ this.#placeholders.set(name, [...seededPlaceholder])
+ return this.#createPlaceholder(name)
+ }
+
+ /**
+ * Push content inside a given stack. Content can be pre-seeded
+ * without creating a stack
+ */
+ pushTo(name: string, contents: string) {
+ let placeholder = this.#placeholders.get(name)
+
+ if (!placeholder) {
+ if (!this.#seededPlaceholders.has(name)) {
+ this.#seededPlaceholders.set(name, [])
+ }
+ const seededPlaceholder = this.#seededPlaceholders.get(name)!
+ seededPlaceholder.push(contents)
+ return this
+ }
+
+ /**
+ * Defined content for the unique key inside a given
+ * stack
+ */
+ placeholder.push(contents)
+ return this
+ }
+
+ /**
+ * Fill placeholders with their actual content
+ */
+ fillPlaceholders(contents: string) {
+ for (let [name, sources] of this.#placeholders) {
+ contents = contents.replace(this.#createPlaceholder(name), sources.join(EOL))
+ }
+
+ this.#placeholders.clear()
+ this.#seededPlaceholders.clear()
+ return contents
+ }
+}
diff --git a/src/tags/main.ts b/src/tags/main.ts
index da7ee26..5c82ad2 100644
--- a/src/tags/main.ts
+++ b/src/tags/main.ts
@@ -13,12 +13,15 @@ export { eachTag as each } from './each.js'
export { slotTag as slot } from './slot.js'
export { elseTag as else } from './else.js'
export { evalTag as eval } from './eval.js'
+export { stackTag as stack } from './stack.js'
export { assignTag as assign } from './assign.js'
export { injectTag as inject } from './inject.js'
export { unlessTag as unless } from './unless.js'
export { elseIfTag as elseif } from './else_if.js'
+export { pushToTag as pushTo } from './push_to.js'
export { includeTag as include } from './include.js'
export { debuggerTag as debugger } from './debugger.js'
export { newErrorTag as newError } from './new_error.js'
export { componentTag as component } from './component.js'
export { includeIfTag as includeIf } from './include_if.js'
+export { pushOnceToTag as pushOnceTo } from './push_once_to.js'
diff --git a/src/tags/push_once_to.ts b/src/tags/push_once_to.ts
new file mode 100644
index 0000000..9ee9a4b
--- /dev/null
+++ b/src/tags/push_once_to.ts
@@ -0,0 +1,131 @@
+/*
+ * edge.js
+ *
+ * (c) Harminder Virk
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { EdgeError } from 'edge-error'
+import { expressions } from 'edge-parser'
+
+import { nanoid } from '../utils.js'
+import { TagContract } from '../types.js'
+import type { Template } from '../template.js'
+
+declare module '../template.js' {
+ export interface Template {
+ stackSources: Record
+ trackStackSource(stack: string, filename: string, line: string, col: string): boolean
+ }
+}
+
+/**
+ * Stack tag to define stack placeholders
+ */
+export const pushOnceToTag: TagContract & { generateId(): string } = {
+ tagName: 'pushOnceTo',
+ block: true,
+ seekable: true,
+ noNewLine: true,
+ generateId() {
+ return `stack_${nanoid()}`
+ },
+ boot(template) {
+ /**
+ * Tracking stack sources to avoid duplicate calls
+ * from the same file:line:col
+ */
+ template.getter(
+ 'stackSources',
+ () => {
+ return {}
+ },
+ true
+ )
+
+ template.macro('trackStackSource', function (this: Template, stack, filename, line, col) {
+ const key = `${stack}_${filename}_${line}_${col}`
+ if (this.stackSources[key]) {
+ return false
+ }
+
+ this.stackSources[key] = true
+ return true
+ })
+ },
+ compile(parser, buffer, token) {
+ const parsed = parser.utils.transformAst(
+ parser.utils.generateAST(token.properties.jsArg, token.loc, token.filename),
+ token.filename,
+ parser
+ )
+
+ /**
+ * Disallow sequence expressions
+ */
+ if (expressions.SequenceExpression.includes(parsed.type)) {
+ throw new EdgeError(
+ `"${token.properties.jsArg}" is not a valid argument type for the "@pushOnceTo" tag`,
+ 'E_UNALLOWED_EXPRESSION',
+ {
+ ...parser.utils.getExpressionLoc(parsed),
+ filename: token.filename,
+ }
+ )
+ }
+
+ /**
+ * Each stack must be unique
+ */
+ const stackId = this.generateId()
+ const stackName = parser.utils.stringify(parsed)
+
+ /**
+ * Create a custom buffer for the stack. Since we do not want to the write
+ * to the main buffer
+ */
+ const stackBuffer = buffer.create(token.filename, { outputVar: stackId })
+
+ const { line, col } = token.loc.start
+ const normalizedFileName = token.filename.replace(/\\|\//g, '_')
+ const conditional = `template.trackStackSource(${stackName}, '${normalizedFileName}', ${line}, ${col})`
+
+ /**
+ * Start if block
+ */
+ buffer.writeStatement(`if (${conditional}) {`, token.filename, line)
+
+ /**
+ * Process children
+ */
+ for (let child of token.children) {
+ parser.processToken(child, stackBuffer)
+ }
+
+ /**
+ * Flush the stack buffer content to the main buffer
+ */
+ buffer.writeStatement(
+ stackBuffer
+ .disableFileAndLineVariables()
+ .disableReturnStatement()
+ .disableTryCatchBlock()
+ .flush(),
+ token.filename,
+ line
+ )
+
+ buffer.writeExpression(
+ `template.stacks.pushTo(${parser.utils.stringify(parsed)}, ${stackId})`,
+ token.filename,
+ line
+ )
+
+ /**
+ * End if block
+ */
+ buffer.writeStatement('}', token.filename, line)
+ },
+}
diff --git a/src/tags/push_to.ts b/src/tags/push_to.ts
new file mode 100644
index 0000000..c5c26d6
--- /dev/null
+++ b/src/tags/push_to.ts
@@ -0,0 +1,84 @@
+/*
+ * edge.js
+ *
+ * (c) Harminder Virk
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { EdgeError } from 'edge-error'
+import { expressions } from 'edge-parser'
+import { TagContract } from '../types.js'
+import { nanoid } from '../utils.js'
+
+/**
+ * Stack tag to define stack placeholders
+ */
+export const pushToTag: TagContract & { generateId(): string } = {
+ tagName: 'pushTo',
+ block: true,
+ seekable: true,
+ noNewLine: true,
+ generateId() {
+ return `stack_${nanoid()}`
+ },
+ compile(parser, buffer, token) {
+ const parsed = parser.utils.transformAst(
+ parser.utils.generateAST(token.properties.jsArg, token.loc, token.filename),
+ token.filename,
+ parser
+ )
+
+ /**
+ * Disallow sequence expressions
+ */
+ if (expressions.SequenceExpression.includes(parsed.type)) {
+ throw new EdgeError(
+ `"${token.properties.jsArg}" is not a valid argument type for the "@pushTo" tag`,
+ 'E_UNALLOWED_EXPRESSION',
+ {
+ ...parser.utils.getExpressionLoc(parsed),
+ filename: token.filename,
+ }
+ )
+ }
+
+ /**
+ * Each stack must be unique
+ */
+ const stackId = this.generateId()
+
+ /**
+ * Create a custom buffer for the stack. Since we do not want to the write
+ * to the main buffer
+ */
+ const stackBuffer = buffer.create(token.filename, { outputVar: stackId })
+
+ /**
+ * Process children
+ */
+ for (let child of token.children) {
+ parser.processToken(child, stackBuffer)
+ }
+
+ /**
+ * Flush the stack buffer content to the main buffer
+ */
+ buffer.writeStatement(
+ stackBuffer
+ .disableFileAndLineVariables()
+ .disableReturnStatement()
+ .disableTryCatchBlock()
+ .flush(),
+ token.filename,
+ token.loc.start.line
+ )
+
+ buffer.writeExpression(
+ `template.stacks.pushTo(${parser.utils.stringify(parsed)}, ${stackId})`,
+ token.filename,
+ token.loc.start.line
+ )
+ },
+}
diff --git a/src/tags/stack.ts b/src/tags/stack.ts
new file mode 100644
index 0000000..b317127
--- /dev/null
+++ b/src/tags/stack.ts
@@ -0,0 +1,53 @@
+/*
+ * edge.js
+ *
+ * (c) Harminder Virk
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { EdgeError } from 'edge-error'
+import { expressions } from 'edge-parser'
+import { TagContract } from '../types.js'
+
+/**
+ * Stack tag to define stack placeholders
+ */
+export const stackTag: TagContract = {
+ tagName: 'stack',
+ block: false,
+ seekable: true,
+ noNewLine: false,
+ compile(parser, buffer, token) {
+ const parsed = parser.utils.transformAst(
+ parser.utils.generateAST(token.properties.jsArg, token.loc, token.filename),
+ token.filename,
+ parser
+ )
+
+ /**
+ * Disallow sequence expressions
+ */
+ if (expressions.SequenceExpression.includes(parsed.type)) {
+ throw new EdgeError(
+ `"${token.properties.jsArg}" is not a valid argument type for the "@stack" tag`,
+ 'E_UNALLOWED_EXPRESSION',
+ {
+ ...parser.utils.getExpressionLoc(parsed),
+ filename: token.filename,
+ }
+ )
+ }
+
+ /**
+ * Create stack
+ */
+ buffer.outputExpression(
+ `template.stacks.create(${parser.utils.stringify(parsed)})`,
+ token.filename,
+ token.loc.start.line,
+ false
+ )
+ },
+}
diff --git a/src/template.ts b/src/template.ts
index f3ce1b2..09f4815 100644
--- a/src/template.ts
+++ b/src/template.ts
@@ -12,6 +12,7 @@ import { EdgeError } from 'edge-error'
import lodash from '@poppinss/utils/lodash'
import Macroable from '@poppinss/macroable'
+import Stacks from './edge/stacks.js'
import { Compiler } from './compiler.js'
import { Processor } from './processor.js'
import { Props } from './migrate/props.js'
@@ -56,6 +57,13 @@ export class Template extends Macroable {
*/
#sharedState: Record
+ /**
+ * Template stacks holds a collection of placeholders
+ * and their content to be filled before returning
+ * the output.
+ */
+ stacks = new Stacks()
+
constructor(compiler: Compiler, globals: any, locals: any, processor: Processor) {
super()
this.#compiler = compiler
@@ -88,11 +96,13 @@ export class Template extends Macroable {
if (this.#compiler.async) {
return compiledTemplate(this, templateState, $context).then((output: string) => {
output = this.#trimTopBottomNewLines(output)
+ output = this.stacks.fillPlaceholders(output)
return this.#processor.executeOutput({ output, template: this, state: templateState })
})
}
- const output = this.#trimTopBottomNewLines(compiledTemplate(this, templateState, $context))
+ let output = this.#trimTopBottomNewLines(compiledTemplate(this, templateState, $context))
+ output = this.stacks.fillPlaceholders(output)
return this.#processor.executeOutput({ output, template: this, state: templateState })
}
diff --git a/src/utils.ts b/src/utils.ts
index 545e15d..9a3efb8 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -316,3 +316,17 @@ export function stringifyAttributes(props: any, namespace?: string): string {
}, [])
.join(' ')
}
+
+/**
+ * Copy-pasted from
+ * https://github.com/ai/nanoid/blob/main/nanoid.js
+ */
+const seed = 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
+export let nanoid = (length = 15) => {
+ let output = ''
+ const random = crypto.getRandomValues(new Uint8Array(length))
+ for (let n = 0; n < length; n++) {
+ output += seed[63 & random[n]]
+ }
+ return output
+}
diff --git a/tests/async_fixtures.spec.ts b/tests/async_fixtures.spec.ts
index 6197b83..3569ed0 100644
--- a/tests/async_fixtures.spec.ts
+++ b/tests/async_fixtures.spec.ts
@@ -26,12 +26,20 @@ import { normalizeNewLines, normalizeFilename } from '../tests_helpers/index.js'
const basePath = join(dirname(fileURLToPath(import.meta.url)), '../async_fixtures')
+let counter = 0
const loader = new Loader()
loader.mount('default', basePath)
-
const processor = new Processor()
+
test.group('Async Fixtures', (group) => {
+ group.each.setup(() => {
+ counter = 1
+ })
+
group.setup(() => {
+ tags.pushTo.generateId = () => `stack_${counter++}`
+ tags.pushOnceTo.generateId = () => `stack_${counter++}`
+
Object.keys(tags).forEach((tag) => {
tags[tag as keyof typeof tags].boot?.(Template)
})
@@ -56,7 +64,6 @@ test.group('Async Fixtures', (group) => {
const compatMode = dir.endsWith('-compat')
test(dir, async ({ assert }) => {
- const template = new Template(compiler, {}, {}, processor)
compiler.compat = compatMode
/**
@@ -83,8 +90,11 @@ test.group('Async Fixtures', (group) => {
*/
const out = readFileSync(join(dirBasePath, 'index.txt'), 'utf-8')
const state = JSON.parse(readFileSync(join(dirBasePath, 'index.json'), 'utf-8'))
- const output = await template.render(`${dir}/index.edge`, state)
- const outputRaw = await template.renderRaw(
+ const output = await new Template(compiler, {}, {}, processor).render(
+ `${dir}/index.edge`,
+ state
+ )
+ const outputRaw = await new Template(compiler, {}, {}, processor).renderRaw(
readFileSync(join(dirBasePath, 'index.edge'), 'utf-8'),
state
)
@@ -95,7 +105,14 @@ test.group('Async Fixtures', (group) => {
})
test.group('Async Fixtures | Cached', (group) => {
+ group.each.setup(() => {
+ counter = 1
+ })
+
group.setup(() => {
+ tags.pushTo.generateId = () => `stack_${counter++}`
+ tags.pushOnceTo.generateId = () => `stack_${counter++}`
+
Object.keys(tags).forEach((tag) => {
tags[tag as keyof typeof tags].boot?.(Template)
})
@@ -120,7 +137,6 @@ test.group('Async Fixtures | Cached', (group) => {
const compatMode = dir.endsWith('-compat')
test(dir, async ({ assert }) => {
- const template = new Template(compiler, {}, {}, processor)
compiler.compat = compatMode
/**
@@ -147,8 +163,11 @@ test.group('Async Fixtures | Cached', (group) => {
*/
const out = readFileSync(join(dirBasePath, 'index.txt'), 'utf-8')
const state = JSON.parse(readFileSync(join(dirBasePath, 'index.json'), 'utf-8'))
- const output = await template.render(`${dir}/index.edge`, state)
- const outputRaw = await template.renderRaw(
+ const output = await new Template(compiler, {}, {}, processor).render(
+ `${dir}/index.edge`,
+ state
+ )
+ const outputRaw = await new Template(compiler, {}, {}, processor).renderRaw(
readFileSync(join(dirBasePath, 'index.edge'), 'utf-8'),
state
)
diff --git a/tests/fixtures.spec.ts b/tests/fixtures.spec.ts
index 282550f..d007ca1 100644
--- a/tests/fixtures.spec.ts
+++ b/tests/fixtures.spec.ts
@@ -25,13 +25,21 @@ import * as compatTags from '../src/migrate/tags/main.js'
import { normalizeNewLines, normalizeFilename } from '../tests_helpers/index.js'
const basePath = join(dirname(fileURLToPath(import.meta.url)), '../fixtures')
+let counter = 0
const loader = new Loader()
const processor = new Processor()
loader.mount('default', basePath)
test.group('Fixtures', (group) => {
+ group.each.setup(() => {
+ counter = 1
+ })
+
group.setup(() => {
+ tags.pushTo.generateId = () => `stack_${counter++}`
+ tags.pushOnceTo.generateId = () => `stack_${counter++}`
+
Object.keys(tags).forEach((tag) => {
tags[tag as keyof typeof tags].boot?.(Template)
})
@@ -56,7 +64,6 @@ test.group('Fixtures', (group) => {
const compatMode = dir.endsWith('-compat')
test(dir, ({ assert }) => {
- const template = new Template(compiler, {}, {}, processor)
compiler.compat = compatMode
/**
@@ -82,8 +89,11 @@ test.group('Fixtures', (group) => {
*/
const out = readFileSync(join(dirBasePath, 'index.txt'), 'utf-8')
const state = readFileSync(join(dirBasePath, 'index.json'), 'utf-8')
- const output = template.render(`${dir}/index.edge`, JSON.parse(state)) as string
- const outputRaw = template.renderRaw(
+ const output = new Template(compiler, {}, {}, processor).render(
+ `${dir}/index.edge`,
+ JSON.parse(state)
+ ) as string
+ const outputRaw = new Template(compiler, {}, {}, processor).renderRaw(
readFileSync(join(dirBasePath, 'index.edge'), 'utf-8'),
JSON.parse(state)
)
@@ -94,7 +104,14 @@ test.group('Fixtures', (group) => {
})
test.group('Fixtures | Cache', (group) => {
+ group.each.setup(() => {
+ counter = 1
+ })
+
group.setup(() => {
+ tags.pushTo.generateId = () => `stack_${counter++}`
+ tags.pushOnceTo.generateId = () => `stack_${counter++}`
+
Object.keys(tags).forEach((tag) => {
tags[tag as keyof typeof tags].boot?.(Template)
})
@@ -119,7 +136,6 @@ test.group('Fixtures | Cache', (group) => {
const compatMode = dir.endsWith('-compat')
test(dir, ({ assert }) => {
- const template = new Template(compiler, {}, {}, processor)
compiler.compat = compatMode
/**
@@ -145,8 +161,11 @@ test.group('Fixtures | Cache', (group) => {
*/
const out = readFileSync(join(dirBasePath, 'index.txt'), 'utf-8')
const state = readFileSync(join(dirBasePath, 'index.json'), 'utf-8')
- const output = template.render(`${dir}/index.edge`, JSON.parse(state)) as string
- const outputRaw = template.renderRaw(
+ const output = new Template(compiler, {}, {}, processor).render(
+ `${dir}/index.edge`,
+ JSON.parse(state)
+ ) as string
+ const outputRaw = new Template(compiler, {}, {}, processor).renderRaw(
readFileSync(join(dirBasePath, 'index.edge'), 'utf-8'),
JSON.parse(state)
)
diff --git a/tests/stacks.spec.ts b/tests/stacks.spec.ts
new file mode 100644
index 0000000..261c662
--- /dev/null
+++ b/tests/stacks.spec.ts
@@ -0,0 +1,61 @@
+/*
+ * edge.js
+ *
+ * (c) EdgeJS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+import { EOL } from 'node:os'
+import { test } from '@japa/runner'
+import Stacks from '../src/edge/stacks.js'
+
+test.group('Stacks', () => {
+ test('create a stack placeholder', ({ assert }) => {
+ const stacks = new Stacks()
+ assert.equal(stacks.create('js'), '')
+ })
+
+ test('create multiple stack placeholders', ({ assert }) => {
+ const stacks = new Stacks()
+ assert.equal(stacks.create('js'), '')
+ assert.equal(stacks.create('css'), '')
+ })
+
+ test('raise error when same stack is created multiple times', ({ assert }) => {
+ const stacks = new Stacks()
+
+ stacks.create('js')
+ assert.throws(() => stacks.create('js'), 'Cannot declare stack "js" for multiple times')
+ })
+
+ test('push contents to stack', ({ assert }) => {
+ const stacks = new Stacks()
+
+ const contents = stacks.create('js')
+ stacks.pushTo('js', 'hello world')
+
+ assert.equal(stacks.fillPlaceholders(contents), 'hello world')
+ })
+
+ test('push contents multiple times to stack', ({ assert }) => {
+ const stacks = new Stacks()
+
+ const contents = stacks.create('js')
+ stacks.pushTo('js', 'hello world')
+ stacks.pushTo('js', 'hi world')
+
+ assert.equal(stacks.fillPlaceholders(contents), `hello world${EOL}hi world`)
+ })
+
+ test('push contents before creating the stack', ({ assert }) => {
+ const stacks = new Stacks()
+
+ stacks.pushTo('js', 'hello world')
+ stacks.pushTo('js', 'hi world')
+ const contents = stacks.create('js')
+
+ assert.equal(stacks.fillPlaceholders(contents), `hello world${EOL}hi world`)
+ })
+})