Frontend uudelleenrakennettu: Astro-komponentit, Wasm pääsäikeessä, ei Workeria

Vanha frontend siirretty temp/. Uusi rakenne:
- StatusBar.astro, Terminal.astro, Editor.astro, Guide.astro
- global.css erillinen
- Wasm pääsäikeessä (ei Worker — yksinkertainen, debugattava)
- Tab-completion, dropdown, projektikortti, Monaco, GUIDE.md
- Ei tokenisointia eikä koodilaboratoriota

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaakko Vanhala
2026-04-09 20:17:39 +03:00
parent e3fdb91ac5
commit a8c4af0975
9617 changed files with 996171 additions and 5349 deletions

View File

@@ -0,0 +1,148 @@
/**
* @import {Element, Parents} from 'hast'
*/
import {whitespace} from 'hast-util-whitespace'
import {siblingAfter, siblingBefore} from './util/siblings.js'
import {closing} from './closing.js'
import {omission} from './omission.js'
export const opening = omission({
body,
colgroup,
head,
html,
tbody
})
/**
* Whether to omit `<html>`.
*
* @param {Element} node
* Element.
* @returns {boolean}
* Whether the opening tag can be omitted.
*/
function html(node) {
const head = siblingAfter(node, -1)
return !head || head.type !== 'comment'
}
/**
* Whether to omit `<head>`.
*
* @param {Element} node
* Element.
* @returns {boolean}
* Whether the opening tag can be omitted.
*/
function head(node) {
/** @type {Set<string>} */
const seen = new Set()
// Whether `srcdoc` or not,
// make sure the content model at least doesnt have too many `base`s/`title`s.
for (const child of node.children) {
if (
child.type === 'element' &&
(child.tagName === 'base' || child.tagName === 'title')
) {
if (seen.has(child.tagName)) return false
seen.add(child.tagName)
}
}
// “May be omitted if the element is empty,
// or if the first thing inside the head element is an element.”
const child = node.children[0]
return !child || child.type === 'element'
}
/**
* Whether to omit `<body>`.
*
* @param {Element} node
* Element.
* @returns {boolean}
* Whether the opening tag can be omitted.
*/
function body(node) {
const head = siblingAfter(node, -1, true)
return (
!head ||
(head.type !== 'comment' &&
!(head.type === 'text' && whitespace(head.value.charAt(0))) &&
!(
head.type === 'element' &&
(head.tagName === 'meta' ||
head.tagName === 'link' ||
head.tagName === 'script' ||
head.tagName === 'style' ||
head.tagName === 'template')
))
)
}
/**
* Whether to omit `<colgroup>`.
* The spec describes some logic for the opening tag, but its easier to
* implement in the closing tag, to the same effect, so we handle it there
* instead.
*
* @param {Element} node
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the opening tag can be omitted.
*/
function colgroup(node, index, parent) {
const previous = siblingBefore(parent, index)
const head = siblingAfter(node, -1, true)
// Previous colgroup was already omitted.
if (
parent &&
previous &&
previous.type === 'element' &&
previous.tagName === 'colgroup' &&
closing(previous, parent.children.indexOf(previous), parent)
) {
return false
}
return Boolean(head && head.type === 'element' && head.tagName === 'col')
}
/**
* Whether to omit `<tbody>`.
*
* @param {Element} node
* Element.
* @param {number | undefined} index
* Index of element in parent.
* @param {Parents | undefined} parent
* Parent of element.
* @returns {boolean}
* Whether the opening tag can be omitted.
*/
function tbody(node, index, parent) {
const previous = siblingBefore(parent, index)
const head = siblingAfter(node, -1)
// Previous table section was already omitted.
if (
parent &&
previous &&
previous.type === 'element' &&
(previous.tagName === 'thead' || previous.tagName === 'tbody') &&
closing(previous, parent.children.indexOf(previous), parent)
) {
return false
}
return Boolean(head && head.type === 'element' && head.tagName === 'tr')
}