create-outsystems-astro 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +7 -2
- package/integrations/bun.lock +25 -0
- package/integrations/deno.lock +51 -4
- package/integrations/package-lock.json +118 -90
- package/integrations/package.json +5 -2
- package/integrations/pnpm-lock.yaml +70 -7
- package/integrations/tsconfig.json +2 -1
- package/integrations/twig/client.ts +34 -0
- package/integrations/twig/index.ts +185 -0
- package/integrations/twig/server.ts +54 -0
- package/integrations/yarn.lock +71 -1
- package/package.json +1 -1
- package/template/AGENTS.md +47 -0
- package/template/astro.config.mjs +4 -0
- package/template/bun.lock +17 -65
- package/template/deno.lock +36 -30
- package/template/package-lock.json +98 -201
- package/template/package.json +3 -1
- package/template/pnpm-lock.yaml +42 -0
- package/template/src/env.d.ts +6 -0
- package/template/src/framework/twig/Demo.twig +100 -0
- package/template/src/framework/twig/Store.twig +45 -0
- package/template/src/images/twig.png +0 -0
- package/template/src/pages/multi/store.astro +10 -0
- package/template/src/pages/twig/twig-demo.astro +65 -0
- package/template/src/stores/framework.ts +1 -0
- package/template/test/e2e/twig/twig-demo.spec.ts +36 -0
- package/template/test/integration/twig/Demo.test.ts +84 -0
- package/template/vitest.config.ts +9 -0
- package/template/yarn.lock +52 -5
package/template/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"audit:deno": "deno audit",
|
|
8
8
|
"audit:npm": "better-npm-audit audit",
|
|
9
9
|
"audit:pnpm": "pnpm audit",
|
|
10
|
-
"audit:yarn": "yarn npm audit",
|
|
10
|
+
"audit:yarn": "yarn npm audit --no-deprecations",
|
|
11
11
|
"build": "astro build",
|
|
12
12
|
"dev": "astro dev",
|
|
13
13
|
"format": "prettier . --check",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"solid-js": "^1.9.13",
|
|
58
58
|
"svelte": "^5.55.9",
|
|
59
59
|
"tslib": "^2.8.1",
|
|
60
|
+
"twig": "^3.0.0",
|
|
60
61
|
"vue": "^3.5.34"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
@@ -91,6 +92,7 @@
|
|
|
91
92
|
"@types/node": "^25.9.1",
|
|
92
93
|
"@types/react": "^19.2.15",
|
|
93
94
|
"@types/react-dom": "^19.2.3",
|
|
95
|
+
"@types/twig": "^1.12.17",
|
|
94
96
|
"@vitejs/plugin-react": "^6.0.2",
|
|
95
97
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
96
98
|
"angular-eslint": "^21.4.0",
|
package/template/pnpm-lock.yaml
CHANGED
|
@@ -89,6 +89,9 @@ importers:
|
|
|
89
89
|
tslib:
|
|
90
90
|
specifier: ^2.8.1
|
|
91
91
|
version: 2.8.1
|
|
92
|
+
twig:
|
|
93
|
+
specifier: ^3.0.0
|
|
94
|
+
version: 3.0.0
|
|
92
95
|
vue:
|
|
93
96
|
specifier: ^3.5.34
|
|
94
97
|
version: 3.5.34(typescript@5.9.3)
|
|
@@ -186,6 +189,9 @@ importers:
|
|
|
186
189
|
'@types/react-dom':
|
|
187
190
|
specifier: ^19.2.3
|
|
188
191
|
version: 19.2.3(@types/react@19.2.15)
|
|
192
|
+
'@types/twig':
|
|
193
|
+
specifier: ^1.12.17
|
|
194
|
+
version: 1.12.17
|
|
189
195
|
'@vitejs/plugin-react':
|
|
190
196
|
specifier: ^6.0.2
|
|
191
197
|
version: 6.0.2(vite@8.0.14(@types/node@25.9.1)(esbuild@0.27.7)(sass@1.97.3)(yaml@2.9.0))
|
|
@@ -2786,6 +2792,9 @@ packages:
|
|
|
2786
2792
|
'@types/trusted-types@2.0.7':
|
|
2787
2793
|
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
|
|
2788
2794
|
|
|
2795
|
+
'@types/twig@1.12.17':
|
|
2796
|
+
resolution: {integrity: sha512-Lxcjgzt4mlDrv1xp1EdoBLPTxpjLAt9vtN3/qoblC5D6hMCYgZJOQHfaT/0gwCcAZENnKQ7Sga28DSsckPWa0g==}
|
|
2797
|
+
|
|
2789
2798
|
'@types/unist@3.0.3':
|
|
2790
2799
|
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
|
|
2791
2800
|
|
|
@@ -4109,6 +4118,9 @@ packages:
|
|
|
4109
4118
|
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
|
4110
4119
|
engines: {node: '>= 0.4'}
|
|
4111
4120
|
|
|
4121
|
+
foreachasync@3.0.0:
|
|
4122
|
+
resolution: {integrity: sha512-J+ler7Ta54FwwNcx6wQRDhTIbNeyDcARMkOcguEqnEdtm0jKvN3Li3PDAb2Du3ubJYEWfYL83XMROXdsXAXycw==}
|
|
4123
|
+
|
|
4112
4124
|
foreground-child@3.3.1:
|
|
4113
4125
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
|
4114
4126
|
engines: {node: '>=14'}
|
|
@@ -4796,6 +4808,10 @@ packages:
|
|
|
4796
4808
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
|
4797
4809
|
engines: {node: '>=10'}
|
|
4798
4810
|
|
|
4811
|
+
locutus@3.0.36:
|
|
4812
|
+
resolution: {integrity: sha512-ilsz33lqEd+KerV9JnSHM9EApVYOZ86/JTGKyafmWvhTFtjYauzT1WmZgdJ4JBGR3dY0N0PTfIq2uLvazw5QsQ==}
|
|
4813
|
+
engines: {node: '>= 22', yarn: '>= 1'}
|
|
4814
|
+
|
|
4799
4815
|
lodash.get@4.4.2:
|
|
4800
4816
|
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
|
|
4801
4817
|
deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
|
|
@@ -6107,6 +6123,11 @@ packages:
|
|
|
6107
6123
|
resolution: {integrity: sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==}
|
|
6108
6124
|
engines: {node: ^20.17.0 || >=22.9.0}
|
|
6109
6125
|
|
|
6126
|
+
twig@3.0.0:
|
|
6127
|
+
resolution: {integrity: sha512-cMfYLWAgdW15B7L5wmanmga113e4phQmo3rk5EFuUrQd99g7I3ncxgynS38P01m4ZXBDSdMYUTV1g3A66/Y56Q==}
|
|
6128
|
+
engines: {node: '>=22'}
|
|
6129
|
+
hasBin: true
|
|
6130
|
+
|
|
6110
6131
|
type-check@0.4.0:
|
|
6111
6132
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
|
6112
6133
|
engines: {node: '>= 0.8.0'}
|
|
@@ -6541,6 +6562,9 @@ packages:
|
|
|
6541
6562
|
typescript:
|
|
6542
6563
|
optional: true
|
|
6543
6564
|
|
|
6565
|
+
walk@2.3.15:
|
|
6566
|
+
resolution: {integrity: sha512-4eRTBZljBfIISK1Vnt69Gvr2w/wc3U6Vtrw7qiN5iqYJPH7LElcYh/iU4XWhdCy2dZqv1ToMyYlybDylfG/5Vg==}
|
|
6567
|
+
|
|
6544
6568
|
watchpack@2.5.1:
|
|
6545
6569
|
resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==}
|
|
6546
6570
|
engines: {node: '>=10.13.0'}
|
|
@@ -9032,6 +9056,8 @@ snapshots:
|
|
|
9032
9056
|
|
|
9033
9057
|
'@types/trusted-types@2.0.7': {}
|
|
9034
9058
|
|
|
9059
|
+
'@types/twig@1.12.17': {}
|
|
9060
|
+
|
|
9035
9061
|
'@types/unist@3.0.3': {}
|
|
9036
9062
|
|
|
9037
9063
|
'@types/whatwg-mimetype@3.0.2': {}
|
|
@@ -10793,6 +10819,8 @@ snapshots:
|
|
|
10793
10819
|
dependencies:
|
|
10794
10820
|
is-callable: 1.2.7
|
|
10795
10821
|
|
|
10822
|
+
foreachasync@3.0.0: {}
|
|
10823
|
+
|
|
10796
10824
|
foreground-child@3.3.1:
|
|
10797
10825
|
dependencies:
|
|
10798
10826
|
cross-spawn: 7.0.6
|
|
@@ -11308,6 +11336,7 @@ snapshots:
|
|
|
11308
11336
|
islands-integrations@file:.integrations(@types/node@25.9.1)(lightningcss@1.32.0)(rollup@4.60.4)(sass@1.97.3)(yaml@2.9.0):
|
|
11309
11337
|
dependencies:
|
|
11310
11338
|
astro: 6.3.7(@types/node@25.9.1)(lightningcss@1.32.0)(rollup@4.60.4)(sass@1.97.3)(yaml@2.9.0)
|
|
11339
|
+
twig: 3.0.0
|
|
11311
11340
|
transitivePeerDependencies:
|
|
11312
11341
|
- '@azure/app-configuration'
|
|
11313
11342
|
- '@azure/cosmos'
|
|
@@ -11543,6 +11572,8 @@ snapshots:
|
|
|
11543
11572
|
dependencies:
|
|
11544
11573
|
p-locate: 5.0.0
|
|
11545
11574
|
|
|
11575
|
+
locutus@3.0.36: {}
|
|
11576
|
+
|
|
11546
11577
|
lodash.get@4.4.2: {}
|
|
11547
11578
|
|
|
11548
11579
|
lodash.memoize@4.1.2: {}
|
|
@@ -13375,6 +13406,13 @@ snapshots:
|
|
|
13375
13406
|
transitivePeerDependencies:
|
|
13376
13407
|
- supports-color
|
|
13377
13408
|
|
|
13409
|
+
twig@3.0.0:
|
|
13410
|
+
dependencies:
|
|
13411
|
+
'@babel/runtime': 7.29.2
|
|
13412
|
+
locutus: 3.0.36
|
|
13413
|
+
minimatch: 10.2.5
|
|
13414
|
+
walk: 2.3.15
|
|
13415
|
+
|
|
13378
13416
|
type-check@0.4.0:
|
|
13379
13417
|
dependencies:
|
|
13380
13418
|
prelude-ls: 1.2.1
|
|
@@ -13769,6 +13807,10 @@ snapshots:
|
|
|
13769
13807
|
optionalDependencies:
|
|
13770
13808
|
typescript: 5.9.3
|
|
13771
13809
|
|
|
13810
|
+
walk@2.3.15:
|
|
13811
|
+
dependencies:
|
|
13812
|
+
foreachasync: 3.0.0
|
|
13813
|
+
|
|
13772
13814
|
watchpack@2.5.1:
|
|
13773
13815
|
dependencies:
|
|
13774
13816
|
glob-to-regexp: 0.4.1
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{#
|
|
2
|
+
Twig counter demo component, authored as a native .twig file.
|
|
3
|
+
|
|
4
|
+
Available props (passed as island attributes and used as the Twig context):
|
|
5
|
+
- initialCount: starting counter value (default 0)
|
|
6
|
+
- showMessage: name of a window handler to call with the current count
|
|
7
|
+
- outSystemsLogo / astroLogo: image URLs, passed in from the .astro page
|
|
8
|
+
#}
|
|
9
|
+
|
|
10
|
+
{% set count = initialCount|default(0) %}
|
|
11
|
+
{% set handler = showMessage|default('') %}
|
|
12
|
+
|
|
13
|
+
<div class="counter-title">Twig Demo Component</div>
|
|
14
|
+
<div class="twig-demo">
|
|
15
|
+
<div class="card-grid">
|
|
16
|
+
<div class="card">
|
|
17
|
+
<strong>Twig counter component</strong>
|
|
18
|
+
<div class="card-content">
|
|
19
|
+
Internal counter controls. It keeps state within the component.
|
|
20
|
+
<div class="counter-controls">
|
|
21
|
+
<button class="subtract">-</button>
|
|
22
|
+
<pre class="count">{{ count }}</pre>
|
|
23
|
+
<button class="add">+</button>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
The button sends the current count value to a function in the parent
|
|
27
|
+
component.
|
|
28
|
+
<div class="card-content">
|
|
29
|
+
<div>
|
|
30
|
+
<button class="card-btn send">Send value</button>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
<div class="card">
|
|
35
|
+
<strong>Nano Stores</strong>
|
|
36
|
+
<div class="card-content">
|
|
37
|
+
<div>
|
|
38
|
+
<strong>Value:</strong>
|
|
39
|
+
<div class="nanostore-value"></div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="card unused">
|
|
44
|
+
<strong>Slot content (not supported)</strong>
|
|
45
|
+
<div class="card-content"></div>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="counter-logos">
|
|
49
|
+
{% if outSystemsLogo %}<img alt="OutSystems logo" src="{{ outSystemsLogo }}" />{% endif %}
|
|
50
|
+
{% if astroLogo %}<img alt="Astro logo" src="{{ astroLogo }}" />{% endif %}
|
|
51
|
+
</div>
|
|
52
|
+
<script>
|
|
53
|
+
(function () {
|
|
54
|
+
const container = (document.currentScript && document.currentScript.parentElement) || document.querySelector('.twig-demo');
|
|
55
|
+
let count = {{ count }};
|
|
56
|
+
const countEl = container.querySelector('.count');
|
|
57
|
+
const addBtn = container.querySelector('.add');
|
|
58
|
+
const subtractBtn = container.querySelector('.subtract');
|
|
59
|
+
const sendBtn = container.querySelector('.send');
|
|
60
|
+
const nanostoreEl = container.querySelector('.nanostore-value');
|
|
61
|
+
|
|
62
|
+
addBtn.addEventListener('click', function () {
|
|
63
|
+
count += 1;
|
|
64
|
+
countEl.textContent = count;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
subtractBtn.addEventListener('click', function () {
|
|
68
|
+
count -= 1;
|
|
69
|
+
countEl.textContent = count;
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
sendBtn.addEventListener('click', function () {
|
|
73
|
+
if ('{{ handler }}' && window['{{ handler }}']) {
|
|
74
|
+
window['{{ handler }}'](count);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (!window.Stores) window.Stores = {};
|
|
79
|
+
if (!window.Stores['twigStore']) {
|
|
80
|
+
let _value = 'Test Value';
|
|
81
|
+
const _subs = [];
|
|
82
|
+
window.Stores['twigStore'] = {
|
|
83
|
+
get: function () { return _value; },
|
|
84
|
+
set: function (v) { _value = v; _subs.forEach(function (fn) { fn(v); }); },
|
|
85
|
+
subscribe: function (fn) {
|
|
86
|
+
fn(_value);
|
|
87
|
+
_subs.push(fn);
|
|
88
|
+
return function () { _subs.splice(_subs.indexOf(fn), 1); };
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const store = window.Stores['twigStore'];
|
|
94
|
+
nanostoreEl.textContent = store.get();
|
|
95
|
+
store.subscribe(function (value) {
|
|
96
|
+
nanostoreEl.textContent = value;
|
|
97
|
+
});
|
|
98
|
+
})();
|
|
99
|
+
</script>
|
|
100
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{#
|
|
2
|
+
Twig store demo component, authored as a native .twig file.
|
|
3
|
+
|
|
4
|
+
Shares the `framework` Nano Store with the other framework islands through
|
|
5
|
+
`window.Stores['framework']`, which the page registers before the islands
|
|
6
|
+
hydrate. This lets a string-rendered Twig island stay in sync with the
|
|
7
|
+
binding-based islands (React, Vue, ...).
|
|
8
|
+
|
|
9
|
+
Props:
|
|
10
|
+
- logo: the Twig logo URL, passed in from the .astro page
|
|
11
|
+
#}
|
|
12
|
+
|
|
13
|
+
<div class="card twig-store">
|
|
14
|
+
<strong>Twig Store</strong>
|
|
15
|
+
<div class="card-content">
|
|
16
|
+
{% if logo %}<img alt="Twig logo" height="150" src="{{ logo }}" />{% endif %}
|
|
17
|
+
<div>
|
|
18
|
+
<strong>Value:</strong>
|
|
19
|
+
<div class="framework-value"></div>
|
|
20
|
+
</div>
|
|
21
|
+
<div>
|
|
22
|
+
<button class="card-btn select-btn">Select Twig</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<script>
|
|
26
|
+
(function () {
|
|
27
|
+
const container = (document.currentScript && document.currentScript.parentElement)
|
|
28
|
+
|| document.querySelector('.twig-store');
|
|
29
|
+
const valueEl = container.querySelector('.framework-value');
|
|
30
|
+
const btn = container.querySelector('.select-btn');
|
|
31
|
+
|
|
32
|
+
const store = window.Stores && window.Stores['framework'];
|
|
33
|
+
|
|
34
|
+
if (store) {
|
|
35
|
+
store.subscribe(function (value) {
|
|
36
|
+
valueEl.textContent = value;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
btn.addEventListener('click', function () {
|
|
41
|
+
if (store) store.set('Twig');
|
|
42
|
+
});
|
|
43
|
+
})();
|
|
44
|
+
</script>
|
|
45
|
+
</div>
|
|
Binary file
|
|
@@ -5,12 +5,21 @@ import PreactStore from "../../framework/preact/Store";
|
|
|
5
5
|
import ReactStore from "../../framework/react/Store";
|
|
6
6
|
import SolidStore from "../../framework/solid/Store";
|
|
7
7
|
import SvelteStore from "../../framework/svelte/Store.svelte";
|
|
8
|
+
import TwigStore from "../../framework/twig/Store.twig";
|
|
8
9
|
import VueStore from "../../framework/vue/Store.vue";
|
|
10
|
+
import TwigLogo from "../../images/twig.png?url";
|
|
9
11
|
import styles from "../../styles/index.css?url";
|
|
10
12
|
---
|
|
11
13
|
<html lang="en">
|
|
12
14
|
<head>
|
|
13
15
|
<link href={styles} rel="stylesheet" />
|
|
16
|
+
<script>
|
|
17
|
+
// Expose the shared framework Nano Store so string-rendered islands
|
|
18
|
+
// (such as the Twig store) can subscribe to it before they hydrate.
|
|
19
|
+
import { framework } from "../../stores/framework";
|
|
20
|
+
window.Stores = window.Stores || {};
|
|
21
|
+
window.Stores["framework"] = framework;
|
|
22
|
+
</script>
|
|
14
23
|
</head>
|
|
15
24
|
<body>
|
|
16
25
|
<div class="card-grid">
|
|
@@ -20,6 +29,7 @@ import styles from "../../styles/index.css?url";
|
|
|
20
29
|
<ReactStore client:only="react" />
|
|
21
30
|
<SolidStore client:only="solid-js" />
|
|
22
31
|
<SvelteStore client:only="svelte" />
|
|
32
|
+
<TwigStore client:load logo={TwigLogo} />
|
|
23
33
|
<VueStore client:only="vue" />
|
|
24
34
|
</div>
|
|
25
35
|
</body>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
import AstroLogo from "../../images/astro.png?url";
|
|
3
|
+
import OutSystemsLogo from "../../images/outsystems.png?url";
|
|
4
|
+
import styles from "../../styles/index.css?url";
|
|
5
|
+
import DemoComponent from "../../framework/twig/Demo.twig";
|
|
6
|
+
const initialCount = 5;
|
|
7
|
+
const showMessage = "showMessage";
|
|
8
|
+
---
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<link href={styles} rel="stylesheet" />
|
|
12
|
+
<script>
|
|
13
|
+
import { setupStore } from "../../stores/demo";
|
|
14
|
+
setupStore("twigStore");
|
|
15
|
+
window["showMessage"] = (count) => {
|
|
16
|
+
document.getElementById("counter").textContent = count;
|
|
17
|
+
};
|
|
18
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
19
|
+
const input = document.getElementById("store");
|
|
20
|
+
input.value = window.Stores["twigStore"].get();
|
|
21
|
+
});
|
|
22
|
+
</script>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<div class="counter-title">Astro Page</div>
|
|
26
|
+
<div class="card-grid">
|
|
27
|
+
<div class="card">
|
|
28
|
+
<strong>Counter component</strong>
|
|
29
|
+
<div class="card-content">
|
|
30
|
+
<div style="text-align: center; margin-top: 30px;">
|
|
31
|
+
Counter value:
|
|
32
|
+
<div>
|
|
33
|
+
<span id="counter"></span>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="card">
|
|
39
|
+
<strong>Nano Stores</strong>
|
|
40
|
+
<div class="card-content">
|
|
41
|
+
<div style="text-align: center; margin-top: 30px;">
|
|
42
|
+
<input
|
|
43
|
+
id="store"
|
|
44
|
+
placeholder="Type something..."
|
|
45
|
+
type="text"
|
|
46
|
+
/><button
|
|
47
|
+
class="card-btn"
|
|
48
|
+
onclick="window.Stores['twigStore'].set(document.getElementById('store').value)"
|
|
49
|
+
>Update Store</button
|
|
50
|
+
>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
<hr />
|
|
56
|
+
<DemoComponent
|
|
57
|
+
astroLogo={AstroLogo}
|
|
58
|
+
client:load
|
|
59
|
+
initialCount={initialCount}
|
|
60
|
+
outSystemsLogo={OutSystemsLogo}
|
|
61
|
+
showMessage={showMessage}
|
|
62
|
+
>
|
|
63
|
+
</DemoComponent>
|
|
64
|
+
</body>
|
|
65
|
+
</html>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
test.beforeEach(async ({ page }) => {
|
|
4
|
+
await page.goto("/twig/twig-demo");
|
|
5
|
+
});
|
|
6
|
+
|
|
7
|
+
test.describe("Has values", () => {
|
|
8
|
+
test("Should have header", async ({ page }) => {
|
|
9
|
+
await expect(page.getByText("Twig Demo Component")).toBeVisible();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test.describe("Change counter", () => {
|
|
14
|
+
test("Should increment counter when clicking + button", async ({ page }) => {
|
|
15
|
+
await page.getByRole("button", { name: "+" }).click();
|
|
16
|
+
await expect(page.locator("pre")).toContainText("6");
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test("Should decrement counter when clicking - button", async ({ page }) => {
|
|
20
|
+
await page.getByRole("button", { name: "-" }).click();
|
|
21
|
+
await expect(page.locator("pre")).toContainText("4");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("Should show message on Send value", async ({ page }) => {
|
|
25
|
+
await page.getByRole("button", { name: "Send value" }).click();
|
|
26
|
+
await expect(page.locator("span#counter")).toContainText("5");
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test.describe("Update Nano Store", () => {
|
|
31
|
+
test("Should update Nano Store", async ({ page }) => {
|
|
32
|
+
await page.locator("#store").fill("Updated Value");
|
|
33
|
+
await page.getByRole("button", { name: "Update Store" }).click();
|
|
34
|
+
await expect(page.locator(".nanostore-value")).toHaveText("Updated Value");
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { fireEvent, screen } from "@testing-library/dom";
|
|
2
|
+
import Twig from "twig";
|
|
3
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
|
|
5
|
+
import template from "../../../src/framework/twig/Demo.twig?raw";
|
|
6
|
+
|
|
7
|
+
function renderDemo(props: Record<string, unknown> = {}) {
|
|
8
|
+
document.body.innerHTML = Twig.twig({ data: template }).render(props);
|
|
9
|
+
document.body.querySelectorAll("script").forEach((script) => {
|
|
10
|
+
new Function(script.textContent ?? "")();
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("Demo", () => {
|
|
15
|
+
let capturedListener: ((val: string) => void) | undefined;
|
|
16
|
+
let storeValue = "Mocked Nano Value";
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
(window as any).mockFunction = vi.fn();
|
|
21
|
+
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
(window as any).Stores = {
|
|
24
|
+
twigStore: {
|
|
25
|
+
get: vi.fn(() => storeValue),
|
|
26
|
+
set: vi.fn((v: string) => {
|
|
27
|
+
storeValue = v;
|
|
28
|
+
capturedListener?.(v);
|
|
29
|
+
}),
|
|
30
|
+
subscribe: vi.fn((fn: (val: string) => void) => {
|
|
31
|
+
capturedListener = fn;
|
|
32
|
+
fn(storeValue);
|
|
33
|
+
return () => {};
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
vi.clearAllMocks();
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
42
|
+
delete (window as any).mockFunction;
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
44
|
+
delete (window as any).Stores;
|
|
45
|
+
capturedListener = undefined;
|
|
46
|
+
storeValue = "Mocked Nano Value";
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("renders the initial count", () => {
|
|
50
|
+
renderDemo({ initialCount: 5 });
|
|
51
|
+
expect(screen.getByText("5")).toBeInTheDocument();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("increments count when add button is clicked", () => {
|
|
55
|
+
renderDemo({ initialCount: 5 });
|
|
56
|
+
fireEvent.click(screen.getByRole("button", { name: "+" }));
|
|
57
|
+
expect(screen.getByText("6")).toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("decrements count when subtract button is clicked", () => {
|
|
61
|
+
renderDemo({ initialCount: 5 });
|
|
62
|
+
fireEvent.click(screen.getByRole("button", { name: "-" }));
|
|
63
|
+
expect(screen.getByText("4")).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("calls the show message function with the current count", () => {
|
|
67
|
+
renderDemo({ initialCount: 5, showMessage: "mockFunction" });
|
|
68
|
+
fireEvent.click(screen.getByRole("button", { name: "Send value" }));
|
|
69
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
+
expect((window as any).mockFunction).toHaveBeenCalledWith(5);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("displays the initial nanostore value", () => {
|
|
74
|
+
renderDemo({});
|
|
75
|
+
expect(screen.getByText("Mocked Nano Value")).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("updates the display when the nanostore value changes", () => {
|
|
79
|
+
renderDemo({});
|
|
80
|
+
expect(screen.getByText("Mocked Nano Value")).toBeInTheDocument();
|
|
81
|
+
capturedListener?.("Updated Value");
|
|
82
|
+
expect(screen.getByText("Updated Value")).toBeInTheDocument();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -78,6 +78,15 @@ export default defineConfig(({ mode }) => ({
|
|
|
78
78
|
setupFiles: ["test/setup-test-env.ts"],
|
|
79
79
|
},
|
|
80
80
|
},
|
|
81
|
+
{
|
|
82
|
+
test: {
|
|
83
|
+
environment: "happy-dom",
|
|
84
|
+
globals: true,
|
|
85
|
+
include: ["test/integration/twig/**/*.test.ts"],
|
|
86
|
+
name: "twig",
|
|
87
|
+
setupFiles: ["test/setup-test-env.ts"],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
81
90
|
{
|
|
82
91
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
83
92
|
plugins: [vue() as any],
|
package/template/yarn.lock
CHANGED
|
@@ -1160,7 +1160,7 @@ __metadata:
|
|
|
1160
1160
|
languageName: node
|
|
1161
1161
|
linkType: hard
|
|
1162
1162
|
|
|
1163
|
-
"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.23.2":
|
|
1163
|
+
"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.8.4":
|
|
1164
1164
|
version: 7.29.2
|
|
1165
1165
|
resolution: "@babel/runtime@npm:7.29.2"
|
|
1166
1166
|
checksum: 10c0/30b80a0140d16467792e1bbeb06f655b0dab70407da38dfac7fedae9c859f9ae9d846ef14ad77bd3814c064295fe9b1bc551f1541ea14646ae9f22b71a8bc17a
|
|
@@ -4464,6 +4464,13 @@ __metadata:
|
|
|
4464
4464
|
languageName: node
|
|
4465
4465
|
linkType: hard
|
|
4466
4466
|
|
|
4467
|
+
"@types/twig@npm:^1.12.17":
|
|
4468
|
+
version: 1.12.17
|
|
4469
|
+
resolution: "@types/twig@npm:1.12.17"
|
|
4470
|
+
checksum: 10c0/a54d62abb979ecc81707c7da9ffe641cdbb12c5e73d782c5fbed69c41123d7c2142c8c79fe7a92295bc13eea7abbafd68863e5f0eb3f54094a26b179e3a2d653
|
|
4471
|
+
languageName: node
|
|
4472
|
+
linkType: hard
|
|
4473
|
+
|
|
4467
4474
|
"@types/unist@npm:*, @types/unist@npm:^3.0.0":
|
|
4468
4475
|
version: 3.0.3
|
|
4469
4476
|
resolution: "@types/unist@npm:3.0.3"
|
|
@@ -6179,6 +6186,7 @@ __metadata:
|
|
|
6179
6186
|
"@types/node": "npm:^25.9.1"
|
|
6180
6187
|
"@types/react": "npm:^19.2.15"
|
|
6181
6188
|
"@types/react-dom": "npm:^19.2.3"
|
|
6189
|
+
"@types/twig": "npm:^1.12.17"
|
|
6182
6190
|
"@vitejs/plugin-react": "npm:^6.0.2"
|
|
6183
6191
|
"@vitejs/plugin-vue": "npm:^6.0.7"
|
|
6184
6192
|
angular-eslint: "npm:^21.4.0"
|
|
@@ -6219,6 +6227,7 @@ __metadata:
|
|
|
6219
6227
|
svelte-eslint-parser: "npm:^1.6.1"
|
|
6220
6228
|
ts-node: "npm:^10.9.2"
|
|
6221
6229
|
tslib: "npm:^2.8.1"
|
|
6230
|
+
twig: "npm:^3.0.0"
|
|
6222
6231
|
typescript: "npm:^5.9.3"
|
|
6223
6232
|
typescript-eslint: "npm:^8.59.4"
|
|
6224
6233
|
vite: "npm:^8.0.14"
|
|
@@ -7985,6 +7994,13 @@ __metadata:
|
|
|
7985
7994
|
languageName: node
|
|
7986
7995
|
linkType: hard
|
|
7987
7996
|
|
|
7997
|
+
"foreachasync@npm:^3.0.0":
|
|
7998
|
+
version: 3.0.0
|
|
7999
|
+
resolution: "foreachasync@npm:3.0.0"
|
|
8000
|
+
checksum: 10c0/8ad877008da351fa78939e850c6014e94b8b9c6de3d12751b2b906ef96f8c80945310d998b2a704854e126c508237dc9951f6900685ccc42c93db15b09a0c4b3
|
|
8001
|
+
languageName: node
|
|
8002
|
+
linkType: hard
|
|
8003
|
+
|
|
7988
8004
|
"foreground-child@npm:^3.1.0":
|
|
7989
8005
|
version: 3.3.1
|
|
7990
8006
|
resolution: "foreground-child@npm:3.3.1"
|
|
@@ -9158,11 +9174,12 @@ __metadata:
|
|
|
9158
9174
|
linkType: hard
|
|
9159
9175
|
|
|
9160
9176
|
"islands-integrations@file:./.integrations::locator=create-outsystems-astro%40workspace%3A.":
|
|
9161
|
-
version: 0.
|
|
9162
|
-
resolution: "islands-integrations@file:./.integrations#./.integrations::hash=
|
|
9177
|
+
version: 0.11.0
|
|
9178
|
+
resolution: "islands-integrations@file:./.integrations#./.integrations::hash=e4b13b&locator=create-outsystems-astro%40workspace%3A."
|
|
9163
9179
|
dependencies:
|
|
9164
9180
|
astro: "npm:^6.3.7"
|
|
9165
|
-
|
|
9181
|
+
twig: "npm:^3.0.0"
|
|
9182
|
+
checksum: 10c0/160be42ec5a6ddfb575a118558a15d54a81497d70779a27c89379885b523669c5c8c561dd2c9cf819b1569c19acd084fe28e88bf3f38579c45bbe288bd429fb5
|
|
9166
9183
|
languageName: node
|
|
9167
9184
|
linkType: hard
|
|
9168
9185
|
|
|
@@ -9655,6 +9672,13 @@ __metadata:
|
|
|
9655
9672
|
languageName: node
|
|
9656
9673
|
linkType: hard
|
|
9657
9674
|
|
|
9675
|
+
"locutus@npm:^3.0.9":
|
|
9676
|
+
version: 3.0.36
|
|
9677
|
+
resolution: "locutus@npm:3.0.36"
|
|
9678
|
+
checksum: 10c0/54a04ecddeaeadd924f2362c31d888e333bb717bd48dd9d40ac6ddccb352a924791223e09b782d03196808c1404a1f74210a388ce4475c3650dcb8d7b0a75730
|
|
9679
|
+
languageName: node
|
|
9680
|
+
linkType: hard
|
|
9681
|
+
|
|
9658
9682
|
"lodash.get@npm:^4.4.2":
|
|
9659
9683
|
version: 4.4.2
|
|
9660
9684
|
resolution: "lodash.get@npm:4.4.2"
|
|
@@ -10459,7 +10483,7 @@ __metadata:
|
|
|
10459
10483
|
languageName: node
|
|
10460
10484
|
linkType: hard
|
|
10461
10485
|
|
|
10462
|
-
"minimatch@npm:^10.0.3, minimatch@npm:^10.1.1, minimatch@npm:^10.2.2":
|
|
10486
|
+
"minimatch@npm:^10, minimatch@npm:^10.0.3, minimatch@npm:^10.1.1, minimatch@npm:^10.2.2":
|
|
10463
10487
|
version: 10.2.5
|
|
10464
10488
|
resolution: "minimatch@npm:10.2.5"
|
|
10465
10489
|
dependencies:
|
|
@@ -13491,6 +13515,20 @@ __metadata:
|
|
|
13491
13515
|
languageName: node
|
|
13492
13516
|
linkType: hard
|
|
13493
13517
|
|
|
13518
|
+
"twig@npm:^3.0.0":
|
|
13519
|
+
version: 3.0.0
|
|
13520
|
+
resolution: "twig@npm:3.0.0"
|
|
13521
|
+
dependencies:
|
|
13522
|
+
"@babel/runtime": "npm:^7.8.4"
|
|
13523
|
+
locutus: "npm:^3.0.9"
|
|
13524
|
+
minimatch: "npm:^10"
|
|
13525
|
+
walk: "npm:2.3.x"
|
|
13526
|
+
bin:
|
|
13527
|
+
twigjs: bin/twigjs
|
|
13528
|
+
checksum: 10c0/a727b665d34c9b7db9cf5fa99072472ef1dd9291d6f29a4b1de88ca95493d16c667f47d7e87f4aaea05275ea184f6550dc3c32cb42026b819d154690f48cff76
|
|
13529
|
+
languageName: node
|
|
13530
|
+
linkType: hard
|
|
13531
|
+
|
|
13494
13532
|
"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
|
|
13495
13533
|
version: 0.4.0
|
|
13496
13534
|
resolution: "type-check@npm:0.4.0"
|
|
@@ -14349,6 +14387,15 @@ __metadata:
|
|
|
14349
14387
|
languageName: node
|
|
14350
14388
|
linkType: hard
|
|
14351
14389
|
|
|
14390
|
+
"walk@npm:2.3.x":
|
|
14391
|
+
version: 2.3.15
|
|
14392
|
+
resolution: "walk@npm:2.3.15"
|
|
14393
|
+
dependencies:
|
|
14394
|
+
foreachasync: "npm:^3.0.0"
|
|
14395
|
+
checksum: 10c0/c390221ff6fdb8e95f9b03d90fa9980edc2c01ce9efac44c0ade2036ee2823bf2bc9abfae388bdf64ab59e9262610e7cf6634ad54acac018e62621b85edad2cf
|
|
14396
|
+
languageName: node
|
|
14397
|
+
linkType: hard
|
|
14398
|
+
|
|
14352
14399
|
"watchpack@npm:2.5.1":
|
|
14353
14400
|
version: 2.5.1
|
|
14354
14401
|
resolution: "watchpack@npm:2.5.1"
|