Skip to content

Commit 4d12a0a

Browse files
committed
Add Astro web framework support
1 parent d4fd4f8 commit 4d12a0a

File tree

20 files changed

+1333
-25
lines changed

20 files changed

+1333
-25
lines changed

.github/dependabot.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ updates:
1515
interval: daily
1616
open-pull-requests-limit: 10
1717
groups:
18+
astro:
19+
patterns:
20+
- "@astrojs/*"
1821
vue:
1922
patterns:
2023
- "@vue/*"

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
target/
1+
# Maven
2+
target/
3+
.polyglot.META-INF

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ and
1818

1919
* Kubernetes
2020
* Angular (Components & Templates, in TypeScript and HTML files)
21-
* React (JSX, TSX, embedded HTML)
21+
* [Astro](https://astro.build)
22+
* [React](https://react.dev/) (JSX, TSX, embedded HTML)
2223
* ESLint (for JavaScript and TypeScript)
23-
* Vue.js
24+
* [Vue.js](https://vuejs.org/)
2425

2526
Supported features for edition are
2627

org.eclipse.wildwebdeveloper.tests/.project

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,14 @@
2020
<arguments>
2121
</arguments>
2222
</buildCommand>
23+
<buildCommand>
24+
<name>org.eclipse.m2e.core.maven2Builder</name>
25+
<arguments>
26+
</arguments>
27+
</buildCommand>
2328
</buildSpec>
2429
<natures>
30+
<nature>org.eclipse.m2e.core.maven2Nature</nature>
2531
<nature>org.eclipse.pde.PluginNature</nature>
2632
<nature>org.eclipse.jdt.core.javanature</nature>
2733
</natures>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
activeProfiles=
2+
eclipse.preferences.version=1
3+
resolveWorkspaceProjects=true
4+
version=1
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Vegard IT GmbH and others.
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Sebastian Thomschke (Vegard IT GmbH) - initial implementation
12+
*******************************************************************************/
13+
package org.eclipse.wildwebdeveloper.tests;
14+
15+
import static org.junit.jupiter.api.Assertions.*;
16+
17+
import java.lang.reflect.Method;
18+
import java.net.URI;
19+
import java.nio.file.Paths;
20+
import java.util.Arrays;
21+
import java.util.concurrent.TimeUnit;
22+
import java.util.concurrent.atomic.AtomicReference;
23+
import java.util.stream.Collectors;
24+
25+
import org.eclipse.core.resources.IFolder;
26+
import org.eclipse.core.resources.IMarker;
27+
import org.eclipse.core.resources.IProject;
28+
import org.eclipse.core.resources.IResource;
29+
import org.eclipse.core.runtime.NullProgressMonitor;
30+
import org.eclipse.jface.text.ITextViewer;
31+
import org.eclipse.lsp4e.LSPEclipseUtils;
32+
import org.eclipse.lsp4e.LanguageServerWrapper;
33+
import org.eclipse.lsp4e.LanguageServers;
34+
import org.eclipse.lsp4e.LanguageServiceAccessor;
35+
import org.eclipse.lsp4j.ServerCapabilities;
36+
import org.eclipse.lsp4j.jsonrpc.messages.Either;
37+
import org.eclipse.swt.SWT;
38+
import org.eclipse.swt.widgets.Event;
39+
import org.eclipse.ui.PlatformUI;
40+
import org.eclipse.ui.editors.text.TextEditor;
41+
import org.eclipse.ui.ide.IDE;
42+
import org.eclipse.ui.part.FileEditorInput;
43+
import org.eclipse.ui.tests.harness.util.DisplayHelper;
44+
import org.eclipse.ui.texteditor.AbstractTextEditor;
45+
import org.eclipse.wildwebdeveloper.embedder.node.NodeJSManager;
46+
import org.junit.jupiter.api.AfterAll;
47+
import org.junit.jupiter.api.BeforeAll;
48+
import org.junit.jupiter.api.BeforeEach;
49+
import org.junit.jupiter.api.Test;
50+
51+
public class TestAstro {
52+
static IProject project;
53+
static IFolder pagesFolder;
54+
55+
@BeforeAll
56+
public static void setUp() throws Exception {
57+
AllCleanRule.closeIntro();
58+
AllCleanRule.enableLogging();
59+
60+
project = Utils.provisionTestProject("astro-app");
61+
ProcessBuilder builder = NodeJSManager.prepareNPMProcessBuilder("install", "--no-bin-links", "--ignore-scripts").directory(project
62+
.getLocation().toFile());
63+
Process process = builder.start();
64+
System.out.println(builder.command().toString());
65+
String result = process.errorReader().lines().collect(Collectors.joining("\n"));
66+
System.out.println("Error Stream: >>>\n" + result + "\n<<<");
67+
68+
result = process.inputReader().lines().collect(Collectors.joining("\n"));
69+
System.out.println("Output Stream: >>>\n" + result + "\n<<<");
70+
71+
assertEquals(0, process.waitFor(), "npm install didn't complete property");
72+
73+
project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor());
74+
assertTrue(project.exists());
75+
pagesFolder = project.getFolder("src").getFolder("pages");
76+
assertTrue(pagesFolder.exists());
77+
}
78+
79+
@BeforeEach
80+
public void setUpTestCase() {
81+
AllCleanRule.enableLogging();
82+
}
83+
84+
@AfterAll
85+
public static void tearDown() throws Exception {
86+
new AllCleanRule().afterEach(null);
87+
}
88+
89+
@Test
90+
@SuppressWarnings("restriction")
91+
void testAstroPage() throws Exception {
92+
final var indexPageFile = project.getFile("src/pages/index.astro");
93+
final var indexPageEditor = (TextEditor) IDE.openEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(),
94+
indexPageFile);
95+
final var display = indexPageEditor.getSite().getShell().getDisplay();
96+
final var doc = indexPageEditor.getDocumentProvider().getDocument(indexPageEditor.getEditorInput());
97+
98+
/*
99+
* ensure Astro Language Server is started and connected
100+
*/
101+
final var astroLS = new AtomicReference<LanguageServerWrapper>();
102+
DisplayHelper.waitForCondition(display, 10_000, () -> {
103+
astroLS.set(LanguageServiceAccessor.getStartedWrappers(doc, null, false).stream() //
104+
.filter(w -> "org.eclipse.wildwebdeveloper.astro".equals(w.serverDefinition.id)) //
105+
.findFirst().orElse(null));
106+
return astroLS.get() != null //
107+
&& astroLS.get().isActive() //
108+
&& astroLS.get().isConnectedTo(LSPEclipseUtils.toUri(doc));
109+
});
110+
111+
/*
112+
* ensure that a task marker is created for the unused node:path import statement
113+
*/
114+
assertTrue(DisplayHelper.waitForCondition(display, 10_000, () -> {
115+
try {
116+
return Arrays.stream(indexPageFile.findMarkers("org.eclipse.lsp4e.diagnostic", true, IResource.DEPTH_ZERO)) //
117+
.anyMatch(marker -> marker.getAttribute(IMarker.MESSAGE, "").contains("'path' is declared but its value is never read"));
118+
} catch (final Exception ex) {
119+
ex.printStackTrace();
120+
return false;
121+
}
122+
}), "Diagnostic not published in standalone component file");
123+
124+
/*
125+
* ensure "Open Declaration" works
126+
*/
127+
final var baseLayoutFile = project.getFile("src/layouts/base.astro");
128+
final var baseLayoutPath = baseLayoutFile.getLocation().toPath();
129+
int offset = doc.get().indexOf("BaseLayout");
130+
131+
// ensure "Open Definition" link exists
132+
assertTrue(DisplayHelper.waitForCondition(display, 10_000, () -> {
133+
try {
134+
final var params = LSPEclipseUtils.toTextDocumentPosistionParams(offset, doc);
135+
final var baseLayoutDefinitionLink = LanguageServers.forDocument(doc) //
136+
.withCapability(ServerCapabilities::getDefinitionProvider) //
137+
.collectAll(ls -> ls.getTextDocumentService().definition(LSPEclipseUtils.toDefinitionParams(params))) //
138+
.get(1, TimeUnit.SECONDS) //
139+
.stream().filter(Either::isRight) //
140+
.flatMap(e -> e.getRight().stream()) //
141+
.filter(locationLink -> Paths.get(URI.create(locationLink.getTargetUri())).equals(baseLayoutPath)) //
142+
.findFirst().orElse(null);
143+
return baseLayoutDefinitionLink != null;
144+
} catch (final Exception ex) {
145+
ex.printStackTrace();
146+
return false;
147+
}
148+
}));
149+
150+
// simulate pressing F3 "Open Declaration" for BaseLayout
151+
display.syncExec(() -> {
152+
try {
153+
indexPageEditor.selectAndReveal(offset, 0);
154+
155+
final Method getSourceViewerMethod = AbstractTextEditor.class.getDeclaredMethod("getSourceViewer"); //$NON-NLS-1$
156+
getSourceViewerMethod.setAccessible(true);
157+
final var viewer = (ITextViewer) getSourceViewerMethod.invoke(indexPageEditor);
158+
final var widget = viewer.getTextWidget();
159+
160+
final var keyDown = new Event();
161+
keyDown.type = SWT.KeyDown;
162+
keyDown.keyCode = SWT.F3;
163+
keyDown.widget = widget;
164+
widget.notifyListeners(SWT.KeyDown, keyDown);
165+
final var keyUp = new Event();
166+
keyUp.type = SWT.KeyUp;
167+
keyUp.keyCode = SWT.F3;
168+
keyUp.widget = widget;
169+
widget.notifyListeners(SWT.KeyUp, keyUp);
170+
} catch (final Exception ex) {
171+
fail(ex);
172+
}
173+
});
174+
175+
// ensure a new editor window was opened for "src/layouts/base.astro" file
176+
assertTrue(DisplayHelper.waitForCondition(display, 10_000, () -> {
177+
final var baseLayoutEditor = (TextEditor) PlatformUI.getWorkbench() //
178+
.getActiveWorkbenchWindow() //
179+
.getActivePage() //
180+
.findEditor(new FileEditorInput(baseLayoutFile));
181+
182+
if (baseLayoutEditor != null) {
183+
baseLayoutEditor.close(false);
184+
return true;
185+
}
186+
return false;
187+
}));
188+
189+
/*
190+
* cleanup
191+
*/
192+
indexPageEditor.close(false);
193+
}
194+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
dist/
2+
.astro/
3+
node_modules/
4+
npm-debug.log*
5+
package-lock.json
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<projectDescription>
3+
<name>wildwebdeveloper-astro-app</name>
4+
<comment></comment>
5+
<projects>
6+
</projects>
7+
<buildSpec>
8+
</buildSpec>
9+
<natures>
10+
</natures>
11+
</projectDescription>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// @ts-check
2+
import { defineConfig } from 'astro/config';
3+
4+
// https://astro.build/config
5+
export default defineConfig({});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "astro-app",
3+
"type": "module",
4+
"version": "0.0.1",
5+
"scripts": {
6+
"dev": "astro dev",
7+
"build": "astro build",
8+
"preview": "astro preview",
9+
"astro": "astro"
10+
},
11+
"dependencies": {
12+
"astro": "^5.8.0"
13+
}
14+
}

0 commit comments

Comments
 (0)