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.
@@ -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",
@@ -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,6 @@
1
+ /// <reference types="astro/client" />
2
+
3
+ declare module "*.twig" {
4
+ const content: string;
5
+ export default content;
6
+ }
@@ -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>
@@ -7,6 +7,7 @@ export type CurrentSelectedFramework =
7
7
  | "React"
8
8
  | "Solid"
9
9
  | "Svelte"
10
+ | "Twig"
10
11
  | "Vue";
11
12
 
12
13
  export const framework = atom<CurrentSelectedFramework>("");
@@ -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],
@@ -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.10.0
9162
- resolution: "islands-integrations@file:./.integrations#./.integrations::hash=0a3fe0&locator=create-outsystems-astro%40workspace%3A."
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
- checksum: 10c0/033cce28aac04f7d5e45dca37281f17731b7f2ae63db0dbdb4577775a4dc5eb26602c8abd1307b54f2585496961ade795ed372fbe0c1235bfe8400b27b215816
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"