org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher
- /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateSkeleton.mwe2
+ /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2
-p
rootPath=/${project.basedir}/..
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateSkeleton.mwe2 b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2
similarity index 50%
rename from emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateSkeleton.mwe2
rename to emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2
index 6f320cb..6ccb718 100644
--- a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateSkeleton.mwe2
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2
@@ -1,24 +1,34 @@
-module dev.jorisjonkers.deploykit.emf.syntax.GenerateSkeleton
+module dev.jorisjonkers.deploykit.emf.syntax.GenerateProjectIntent
+import org.eclipse.emf.mwe.utils.*
import org.eclipse.xtext.xtext.generator.*
import org.eclipse.xtext.xtext.generator.model.project.*
var rootPath = ".."
var generated = "${rootPath}/syntax/target/generated-sources/xtext"
-// Every Java file this writes, stubs included, lands under target/ and is
-// never committed (emf/docs/architecture.md#metamodels).
+// Every generated file lands under target/ except the two stubs the generator
+// writes once and this tree then owns: the runtime module and the standalone
+// setup, in src/main/java (emf/docs/architecture.md#concrete-syntax).
Workflow {
+ bean = StandaloneSetup {
+ scanClassPath = true
+ projectMapping = {
+ projectName = "dev.jorisjonkers.deploykit.emf.metamodel"
+ path = "${rootPath}/metamodel"
+ }
+ projectMapping = { projectName = "syntax" path = "${rootPath}/syntax" }
+ }
component = XtextGenerator {
configuration = {
project = StandardProjectConfig {
baseName = "syntax"
rootPath = rootPath
runtime = {
- src = generated
- srcGen = generated
- ecoreModel = "${rootPath}/syntax/target/generated-sources/xtext-model"
root = "${rootPath}/syntax"
+ src = "${rootPath}/syntax/src/main/java"
+ srcGen = generated
+ ecoreModel = "${generated}-model"
}
runtimeTest = { enabled = false }
eclipsePlugin = { enabled = false }
@@ -31,9 +41,10 @@ Workflow {
}
}
language = StandardLanguage {
- name = "dev.jorisjonkers.deploykit.emf.syntax.Skeleton"
- grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/Skeleton.xtext"
- fileExtensions = "skeleton"
+ name = "dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent"
+ grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext"
+ fileExtensions = "yml"
+ referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel"
serializer = { generateStub = false }
validator = { generateStub = false }
scopeProvider = { generateStub = false }
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext
new file mode 100644
index 0000000..439e89e
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext
@@ -0,0 +1,135 @@
+grammar dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent hidden(WS, SL_COMMENT)
+
+import "https://jorisjonkers.dev/deploy-kit/project-intent/1"
+import "http://www.eclipse.org/emf/2002/Ecore" as ecore
+
+// The YAML subset the authored project files use. Block structure arrives as
+// the synthetic BEGIN and END tokens the blocks package produces, so an
+// indented block and a flow mapping parse through one rule.
+
+Project returns Project:
+ (('apiVersion' ':' apiVersion=Text)
+ & ('kind' ':' kind=Text)
+ & ('schemaVersion' ':' schemaVersion=Text)
+ & ('project' ':' project=Text)
+ & ('owner' ':' owner=Text)
+ & ('applications' ':' BEGIN (DASH BEGIN applications+=Application END)+ END));
+
+Application returns Application:
+ (('id' ':' id=Text)
+ & ('observability' ':' BEGIN observability=Observability END)?
+ & ('exposure' ':' BEGIN (DASH BEGIN exposure+=Exposure END)+ END)?
+ & ('processes' ':' BEGIN (DASH BEGIN processes+=Process END)+ END));
+
+Observability returns Observability:
+ (('alertClass' ':' alertClass=AlertClass)
+ & ('scrape' ':' BEGIN scrape=Scrape END));
+
+Scrape returns Scrape:
+ (('process' ':' process=Text)
+ & ('surface' ':' surface=Text)
+ & ('path' ':' path=Text));
+
+Exposure returns Exposure:
+ (('name' ':' name=Text)
+ & ('host' ':' host=Text)
+ & ('audience' ':' audience=Audience)
+ & ('contentPolicy' ':' contentPolicy=ContentPolicy)
+ & ('routes' ':' BEGIN (DASH BEGIN routes+=Route END)+ END));
+
+Route returns Route:
+ (('path' ':' path=Text)
+ & ('match' ':' match=Match)
+ & ('process' ':' process=Text)
+ & ('surface' ':' surface=Text));
+
+Process returns Process:
+ (('name' ':' name=Text)
+ & ('lifecycle' ':' lifecycle=Lifecycle)
+ & ('image' ':' image=Text)
+ & ('runtime' ':' runtime=Runtime)
+ & ('provides' ':' BEGIN provides+=SurfacePort+ END)?
+ & ('placement' ':' BEGIN placement=Placement END)
+ & ('probes' ':' BEGIN probes=Probes END)?
+ & ('startupBudget' ':' startupBudget=Text)?
+ & ('cutover' ':' cutover=Cutover));
+
+SurfacePort returns SurfacePort:
+ key=Text ':' value=Port;
+
+Placement returns Placement:
+ (('memory' ':' memory=Text)
+ & ('cpu' ':' cpu=Text));
+
+Probes returns Probes:
+ (('readiness' ':' BEGIN readiness=Probe END)?
+ & ('liveness' ':' BEGIN liveness=Probe END)?);
+
+Probe returns Probe:
+ (('path' ':' path=Text)
+ & ('port' ':' port=Port));
+
+Port returns ecore::EInt:
+ INT;
+
+// A scalar, quoted or not. Every keyword above is also a scalar, so a value
+// that happens to read like a key is still a value.
+Text returns ecore::EString:
+ SCALAR | STRING | INT | Keyword;
+
+Keyword:
+ 'apiVersion' | 'kind' | 'schemaVersion' | 'project' | 'owner' | 'applications' | 'id' | 'observability' |
+ 'exposure' | 'processes' | 'alertClass' | 'scrape' | 'name' | 'host' | 'audience' | 'contentPolicy' |
+ 'routes' | 'match' | 'lifecycle' | 'image' | 'runtime' | 'provides' | 'placement' | 'probes' |
+ 'startupBudget' | 'cutover' | 'memory' | 'cpu' | 'readiness' | 'liveness' | 'path' | 'port' |
+ 'process' | 'surface' |
+ 'application' | 'job' | 'jvm' | 'python' | 'node' | 'static' | 'none' | 'rolling' | 'recreate' |
+ 'business-hours' | 'urgent' | 'page' | 'anonymous' | 'authenticated' | 'internal' | 'lan' |
+ 'strict' | 'admin' | 'workflow' | 'prefix' | 'exact';
+
+enum Lifecycle returns Lifecycle:
+ application='application' | job='job';
+
+enum Runtime returns Runtime:
+ jvm='jvm' | python='python' | node='node' | static='static' | none='none';
+
+enum Cutover returns Cutover:
+ rolling='rolling' | recreate='recreate';
+
+enum AlertClass returns AlertClass:
+ businessHours='business-hours' | urgent='urgent' | page='page';
+
+enum Audience returns Audience:
+ anonymous='anonymous' | authenticated='authenticated' | internal='internal' | lan='lan';
+
+enum ContentPolicy returns ContentPolicy:
+ strict='strict' | admin='admin' | workflow='workflow';
+
+enum Match returns Match:
+ prefix='prefix' | exact='exact';
+
+terminal BEGIN: 'synthetic:BEGIN';
+terminal END: 'synthetic:END';
+
+// The block markers the token source rewrites: a dash opens a sequence item,
+// and a flow collection opens and closes a block on one line. The parser never
+// sees FLOW_ or LIST_ tokens; they arrive as BEGIN and END.
+terminal DASH: '-';
+terminal FLOW_BEGIN: '{';
+terminal FLOW_END: '}';
+terminal FLOW_SEP: ',';
+terminal LIST_BEGIN: '[';
+terminal LIST_END: ']';
+
+terminal INT returns ecore::EInt: ('0'..'9')+;
+
+terminal SCALAR:
+ !(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#' | '"' | "'" | '-')
+ (!(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#'))*;
+
+terminal STRING:
+ '"' !('"')* '"' | "'" !("'")* "'";
+
+terminal SL_COMMENT: '#' !('\n' | '\r')*;
+
+terminal WS: (' ' | '\t' | '\r' | '\n')+;
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java
new file mode 100644
index 0000000..5f3fe65
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java
@@ -0,0 +1,9 @@
+/*
+ * generated by Xtext
+ */
+package dev.jorisjonkers.deploykit.emf.syntax;
+
+/**
+ * Use this class to register components to be used at runtime / without the Equinox extension registry.
+ */
+public class ProjectIntentRuntimeModule extends AbstractProjectIntentRuntimeModule {}
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java
new file mode 100644
index 0000000..2023b8e
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java
@@ -0,0 +1,14 @@
+/*
+ * generated by Xtext
+ */
+package dev.jorisjonkers.deploykit.emf.syntax;
+
+/**
+ * Initialization support for running Xtext languages without Equinox extension registry.
+ */
+public class ProjectIntentStandaloneSetup extends ProjectIntentStandaloneSetupGenerated {
+
+ public static void doSetup() {
+ new ProjectIntentStandaloneSetup().createInjectorAndDoEMFRegistration();
+ }
+}
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/Skeleton.xtext b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/Skeleton.xtext
deleted file mode 100644
index dda8d26..0000000
--- a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/Skeleton.xtext
+++ /dev/null
@@ -1,9 +0,0 @@
-grammar dev.jorisjonkers.deploykit.emf.syntax.Skeleton with org.eclipse.xtext.common.Terminals
-
-generate skeleton "https://jorisjonkers.dev/deploy-kit/emf/syntax/skeleton"
-
-Document:
- entries+=Entry*;
-
-Entry:
- key=ID ':' value=STRING;
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java
new file mode 100644
index 0000000..7867a89
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java
@@ -0,0 +1,126 @@
+package dev.jorisjonkers.deploykit.emf.syntax.blocks;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Queue;
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenSource;
+
+/**
+ * Turns the block structure of the authored YAML into the synthetic BEGIN and END tokens the grammar
+ * reads, so the grammar states the model's shape rather than the file's layout
+ * (emf/docs/architecture.md#concrete-syntax).
+ *
+ * A line indented further than the line before it opens a block, and every level it falls back
+ * closes one. A dash opens a block of its own around the item that follows it, so the first key of
+ * an item sits in the same block as the keys under it. A flow collection opens and closes a block on
+ * one line, and the comma between its entries becomes whitespace. Inside a flow collection
+ * indentation says nothing, so it is not read.
+ */
+public class BlockTokenSource implements TokenSource {
+
+ private final TokenSource delegate;
+ private final BlockTokens types;
+ private final Deque blocks = new ArrayDeque<>();
+ private final Queue pending = new ArrayDeque<>();
+ private boolean lineStart = true;
+ private boolean afterDash = false;
+ private int flowDepth = 0;
+
+ public BlockTokenSource(TokenSource delegate, BlockTokens types) {
+ this.delegate = delegate;
+ this.types = types;
+ blocks.push(0);
+ }
+
+ @Override
+ public Token nextToken() {
+ while (pending.isEmpty()) {
+ read(delegate.nextToken());
+ }
+ return pending.remove();
+ }
+
+ @Override
+ public String getSourceName() {
+ return delegate.getSourceName();
+ }
+
+ private void read(Token token) {
+ if (token.getType() == Token.EOF) {
+ closeTo(0, token);
+ pending.add(token);
+ } else if (token.getType() == types.whitespace() || token.getType() == types.comment()) {
+ lineStart |= token.getText().indexOf('\n') >= 0;
+ pending.add(token);
+ } else if (token.getType() == types.separator()) {
+ pending.add(hidden(token));
+ } else {
+ significant(token);
+ }
+ }
+
+ private void significant(Token token) {
+ if (lineStart && flowDepth == 0) {
+ indent(token);
+ }
+ lineStart = false;
+ if (types.opensFlow(token.getType())) {
+ afterDash = false;
+ flowDepth++;
+ pending.add(marker(types.begin(), token));
+ } else if (types.closesFlow(token.getType())) {
+ flowDepth--;
+ pending.add(marker(types.end(), token));
+ } else {
+ if (afterDash) {
+ afterDash = false;
+ blocks.push(token.getCharPositionInLine());
+ pending.add(marker(types.begin(), token));
+ }
+ pending.add(token);
+ afterDash = token.getType() == types.dash();
+ }
+ }
+
+ /** Opens or closes the blocks the column of the line's first token asks for. */
+ private void indent(Token token) {
+ int column = token.getCharPositionInLine();
+ if (column > current()) {
+ blocks.push(column);
+ pending.add(marker(types.begin(), token));
+ } else {
+ closeTo(column, token);
+ }
+ }
+
+ private void closeTo(int column, Token token) {
+ while (current() > column) {
+ blocks.pop();
+ pending.add(marker(types.end(), token));
+ }
+ }
+
+ private int current() {
+ return blocks.element();
+ }
+
+ /** A zero-width token at {@code at}, so the node model's text stays the file's. The lexer's tokens are
+ * {@link CommonToken}s, the end of file included. */
+ private Token marker(int type, Token at) {
+ CommonToken marker = new CommonToken(type, "");
+ marker.setLine(at.getLine());
+ marker.setCharPositionInLine(at.getCharPositionInLine());
+ int start = ((CommonToken) at).getStartIndex();
+ marker.setStartIndex(start);
+ marker.setStopIndex(start - 1);
+ return marker;
+ }
+
+ private Token hidden(Token token) {
+ CommonToken copy = new CommonToken(token);
+ copy.setType(types.whitespace());
+ return copy;
+ }
+}
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java
new file mode 100644
index 0000000..1543b23
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java
@@ -0,0 +1,38 @@
+package dev.jorisjonkers.deploykit.emf.syntax.blocks;
+
+/**
+ * The token types {@link BlockTokenSource} rewrites, as the generated parser numbers them.
+ *
+ * @param begin the synthetic token that opens a block
+ * @param end the synthetic token that closes one
+ * @param whitespace whitespace, which carries the line breaks and the indentation
+ * @param comment a comment, which is hidden and never opens a block
+ * @param dash the marker of a block sequence item
+ * @param flowBegin an opening brace
+ * @param flowEnd a closing brace
+ * @param listBegin an opening bracket
+ * @param listEnd a closing bracket
+ * @param separator the comma between flow entries
+ */
+public record BlockTokens(
+ int begin,
+ int end,
+ int whitespace,
+ int comment,
+ int dash,
+ int flowBegin,
+ int flowEnd,
+ int listBegin,
+ int listEnd,
+ int separator) {
+
+ /** Whether {@code type} opens a flow collection, which is a block on one line. */
+ public boolean opensFlow(int type) {
+ return type == flowBegin || type == listBegin;
+ }
+
+ /** Whether {@code type} closes one. */
+ public boolean closesFlow(int type) {
+ return type == flowEnd || type == listEnd;
+ }
+}
diff --git a/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java
new file mode 100644
index 0000000..e13916e
--- /dev/null
+++ b/emf/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java
@@ -0,0 +1,28 @@
+/*
+ * generated by Xtext, then owned here: the block rules are this language's, not the generator's.
+ */
+package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr;
+
+import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource;
+import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens;
+import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalProjectIntentParser;
+import org.antlr.runtime.TokenSource;
+
+public class ProjectIntentTokenSource extends BlockTokenSource {
+
+ public static final BlockTokens TYPES = new BlockTokens(
+ InternalProjectIntentParser.RULE_BEGIN,
+ InternalProjectIntentParser.RULE_END,
+ InternalProjectIntentParser.RULE_WS,
+ InternalProjectIntentParser.RULE_SL_COMMENT,
+ InternalProjectIntentParser.RULE_DASH,
+ InternalProjectIntentParser.RULE_FLOW_BEGIN,
+ InternalProjectIntentParser.RULE_FLOW_END,
+ InternalProjectIntentParser.RULE_LIST_BEGIN,
+ InternalProjectIntentParser.RULE_LIST_END,
+ InternalProjectIntentParser.RULE_FLOW_SEP);
+
+ public ProjectIntentTokenSource(TokenSource delegate) {
+ super(delegate, TYPES);
+ }
+}
diff --git a/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/SkeletonTest.java b/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/SkeletonTest.java
deleted file mode 100644
index e86f319..0000000
--- a/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/SkeletonTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package dev.jorisjonkers.deploykit.emf.syntax;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import dev.jorisjonkers.deploykit.emf.syntax.skeleton.Document;
-import dev.jorisjonkers.deploykit.emf.syntax.skeleton.Entry;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.xtext.resource.XtextResourceSet;
-import org.junit.jupiter.api.Test;
-
-// Walking skeleton (#81): a generated Xtext parser reads a document headless.
-// Deleted by the Task 1 syntax ticket, whose suite covers Xtext.
-class SkeletonTest {
-
- private static Resource parse(String text) throws IOException {
- XtextResourceSet resources = new SkeletonStandaloneSetup()
- .createInjectorAndDoEMFRegistration()
- .getInstance(XtextResourceSet.class);
- Resource resource = resources.createResource(URI.createURI("memory:/notes.skeleton"));
- resource.load(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), Map.of());
- return resource;
- }
-
- @Test
- void anXtextGrammarParsesAThreeLineDocument() throws IOException {
- Resource resource = parse("project: 'notes'\napplication: 'notes'\nprocess: 'web'\n");
-
- assertThat(resource.getErrors()).isEmpty();
- assertThat(((Document) resource.getContents().get(0)).getEntries())
- .extracting(Entry::getKey, Entry::getValue)
- .containsExactly(
- org.assertj.core.groups.Tuple.tuple("project", "notes"),
- org.assertj.core.groups.Tuple.tuple("application", "notes"),
- org.assertj.core.groups.Tuple.tuple("process", "web"));
- }
-
- @Test
- void aDocumentOutsideTheGrammarIsRefused() throws IOException {
- assertThat(parse("project 'notes'\n").getErrors()).isNotEmpty();
- }
-}
diff --git a/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java b/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java
new file mode 100644
index 0000000..42dc8fd
--- /dev/null
+++ b/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java
@@ -0,0 +1,121 @@
+package dev.jorisjonkers.deploykit.emf.syntax.blocks;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.ProjectIntentTokenSource;
+import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalProjectIntentParser;
+import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.lexer.InternalProjectIntentLexer;
+import java.util.ArrayList;
+import java.util.List;
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.junit.jupiter.api.Test;
+
+/** The block structure the grammar reads, as the tokens this source produces for authored YAML. */
+class BlockTokenSourceTest {
+
+ /** Every significant token of {@code text}, as "BEGIN", "END" or its own text. */
+ private static List blocks(String text) {
+ ProjectIntentTokenSource source =
+ new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream(text)));
+ List tokens = new ArrayList<>();
+ for (Token token = source.nextToken(); token.getType() != Token.EOF; token = source.nextToken()) {
+ if (token.getType() == InternalProjectIntentParser.RULE_BEGIN) {
+ tokens.add("BEGIN");
+ } else if (token.getType() == InternalProjectIntentParser.RULE_END) {
+ tokens.add("END");
+ } else if (token.getType() != InternalProjectIntentParser.RULE_WS
+ && token.getType() != InternalProjectIntentParser.RULE_SL_COMMENT) {
+ tokens.add(token.getText());
+ }
+ }
+ return tokens;
+ }
+
+ @Test
+ void theSourceNameIsTheOneTheLexerGives() {
+ assertThat(new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream("a: 1")))
+ .getSourceName())
+ .isEqualTo(new InternalProjectIntentLexer(new ANTLRStringStream("a: 1")).getSourceName());
+ }
+
+ @Test
+ void anIndentedLineOpensABlockAndFallingBackClosesIt() {
+ assertThat(blocks("a:\n b:\n c: 1\nd: 2\n"))
+ .containsExactly("a", ":", "BEGIN", "b", ":", "BEGIN", "c", ":", "1", "END", "END", "d", ":", "2");
+ }
+
+ @Test
+ void everyBlockStillOpenAtTheEndOfTheFileIsClosed() {
+ assertThat(blocks("a:\n b:\n c: 1")).endsWith("1", "END", "END");
+ }
+
+ @Test
+ void aDashOpensABlockAroundTheItemThatFollowsIt() {
+ assertThat(blocks("a:\n - b: 1\n c: 2\n - b: 3\n"))
+ .containsExactly(
+ "a", ":", "BEGIN", "-", "BEGIN", "b", ":", "1", "c", ":", "2", "END", "-", "BEGIN", "b", ":",
+ "3", "END", "END");
+ }
+
+ @Test
+ void aFlowMappingIsABlockOnOneLine() {
+ assertThat(blocks("a: { b: 1, c: 2 }\n"))
+ .containsExactly("a", ":", "BEGIN", "b", ":", "1", "c", ":", "2", "END");
+ }
+
+ @Test
+ void aDashFollowedByAFlowMappingOpensOneBlock() {
+ assertThat(blocks("a:\n - { b: 1 }\n - { b: 2 }\n"))
+ .containsExactly(
+ "a", ":", "BEGIN", "-", "BEGIN", "b", ":", "1", "END", "-", "BEGIN", "b", ":", "2", "END",
+ "END");
+ }
+
+ @Test
+ void aBlockOpenedByAFlowMappingIsClosedWithIt() {
+ assertThat(blocks("a: { b: 1 }\nc:\n d: 2\n"))
+ .containsExactly("a", ":", "BEGIN", "b", ":", "1", "END", "c", ":", "BEGIN", "d", ":", "2", "END");
+ }
+
+ @Test
+ void aSyntheticTokenSitsWhereTheTokenThatAskedForItSits() {
+ ProjectIntentTokenSource source =
+ new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream("a:\n b: 1\n")));
+ List tokens = new ArrayList<>();
+ for (Token token = source.nextToken(); token.getType() != Token.EOF; token = source.nextToken()) {
+ tokens.add(token);
+ }
+ Token begin = tokens.stream()
+ .filter(token -> token.getType() == InternalProjectIntentParser.RULE_BEGIN)
+ .findFirst()
+ .orElseThrow();
+ CommonToken key = (CommonToken) tokens.stream()
+ .filter(token -> "b".equals(token.getText()))
+ .findFirst()
+ .orElseThrow();
+
+ assertThat(begin.getText()).isEmpty();
+ assertThat(begin.getLine()).isEqualTo(key.getLine());
+ assertThat(begin.getCharPositionInLine()).isEqualTo(key.getCharPositionInLine());
+ assertThat(((CommonToken) begin).getStartIndex()).isEqualTo(key.getStartIndex());
+ assertThat(((CommonToken) begin).getStopIndex()).isEqualTo(key.getStartIndex() - 1);
+ }
+
+ @Test
+ void indentationInsideAFlowMappingIsNotRead() {
+ assertThat(blocks("a: { b: 1,\n c: 2 }\nd: 3\n"))
+ .containsExactly("a", ":", "BEGIN", "b", ":", "1", "c", ":", "2", "END", "d", ":", "3");
+ }
+
+ @Test
+ void aCommentLineOpensNoBlock() {
+ assertThat(blocks("a: 1\n # a comment, indented\nb: 2\n")).containsExactly("a", ":", "1", "b", ":", "2");
+ }
+
+ @Test
+ void aFlowSequenceIsAnEmptyBlockRatherThanAnItem() {
+ assertThat(blocks("a: []\n")).containsExactly("a", ":", "BEGIN", "END");
+ }
+}
diff --git a/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java b/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java
new file mode 100644
index 0000000..85f891a
--- /dev/null
+++ b/emf/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java
@@ -0,0 +1,41 @@
+package dev.jorisjonkers.deploykit.emf.syntax.blocks;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.jupiter.api.Test;
+
+/** Which token types open and close a flow collection. */
+class BlockTokensTest {
+
+ private static final BlockTokens TYPES = new BlockTokens(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+
+ @Test
+ void aBraceAndABracketOpenAndCloseAFlowCollection() {
+ assertThat(TYPES.opensFlow(TYPES.flowBegin())).isTrue();
+ assertThat(TYPES.opensFlow(TYPES.listBegin())).isTrue();
+ assertThat(TYPES.closesFlow(TYPES.flowEnd())).isTrue();
+ assertThat(TYPES.closesFlow(TYPES.listEnd())).isTrue();
+ }
+
+ @Test
+ void nothingElseOpensOrClosesOne() {
+ assertThat(TYPES.opensFlow(TYPES.flowEnd())).isFalse();
+ assertThat(TYPES.opensFlow(TYPES.dash())).isFalse();
+ assertThat(TYPES.closesFlow(TYPES.flowBegin())).isFalse();
+ assertThat(TYPES.closesFlow(TYPES.separator())).isFalse();
+ }
+
+ @Test
+ void theTypesAreTheOnesItWasGiven() {
+ assertThat(TYPES.begin()).isEqualTo(1);
+ assertThat(TYPES.end()).isEqualTo(2);
+ assertThat(TYPES.whitespace()).isEqualTo(3);
+ assertThat(TYPES.comment()).isEqualTo(4);
+ assertThat(TYPES.dash()).isEqualTo(5);
+ assertThat(TYPES.flowBegin()).isEqualTo(6);
+ assertThat(TYPES.flowEnd()).isEqualTo(7);
+ assertThat(TYPES.listBegin()).isEqualTo(8);
+ assertThat(TYPES.listEnd()).isEqualTo(9);
+ assertThat(TYPES.separator()).isEqualTo(10);
+ }
+}
diff --git a/eslint.config.js b/eslint.config.js
index c0f8ac8..3dce10c 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -17,6 +17,7 @@ export default defineConfig(
"dist/**",
"node_modules/**",
"reports/**",
+ ".stryker-tmp/**",
// Maven build output from the model-driven implementation under emf/.
"**/target/**",
],
diff --git a/package-lock.json b/package-lock.json
index f552b5f..3d6398d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,10 +9,13 @@
"version": "0.2.0",
"license": "LicenseRef-JorisJonkers-Proprietary-1.0",
"dependencies": {
+ "yaml": "2.9.1",
"zod": "^4.5.4"
},
"devDependencies": {
"@eslint/js": "10.0.1",
+ "@stryker-mutator/core": "10.0.0",
+ "@stryker-mutator/vitest-runner": "10.0.0",
"@types/node": "24.13.3",
"@vitest/coverage-v8": "4.1.11",
"@vitest/eslint-plugin": "1.6.27",
@@ -28,6 +31,536 @@
"node": ">=24"
}
},
+ "node_modules/@babel/code-frame": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0.tgz",
+ "integrity": "sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^8.0.0",
+ "js-tokens": "^10.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/code-frame/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.5.tgz",
+ "integrity": "sha512-YLsYoQMvL8l8WrGpN3Zj7O1wK5LEBN+cQtux7BcuHyxIXve724XG+zuJ1n3U1cUweRtTzQOA4IHbuQw3N34SZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.5.tgz",
+ "integrity": "sha512-2/oWkgTbBYoqioCWAE4XJobOrzwxTDa5/XjDP3tJ1BhDr/owcd9qnXBp4xc3/2G5X4bvXM04nrxbRJxFcXAxFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^8.0.0",
+ "@babel/generator": "^8.0.5",
+ "@babel/helper-compilation-targets": "^8.0.5",
+ "@babel/helpers": "^8.0.5",
+ "@babel/parser": "^8.0.5",
+ "@babel/template": "^8.0.0",
+ "@babel/traverse": "^8.0.5",
+ "@babel/types": "^8.0.5",
+ "@types/gensync": "^1.0.5",
+ "convert-source-map": "^2.0.0",
+ "empathic": "^2.0.1",
+ "gensync": "^1.0.0-beta.2",
+ "import-meta-resolve": "^4.2.0",
+ "json5": "^2.2.3",
+ "obug": "^2.1.1",
+ "verkit": "^0.3.2"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/parser": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.5.tgz",
+ "integrity": "sha512-51RXvQNFakaS0bTpYiGkxNbUVwkPO4kONv6EVLorZABxsx+KZ6Z7uSYvi/wmKS/+X+rfj9RvOw0/ZNh+cmI0Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.5.tgz",
+ "integrity": "sha512-f/TuhuMAxJqhwxEGNsJrswuG9VHmh0oNFoQoo6TbpgtFAz9wYZXcTAcWZMHfp7ljesr0RG04bp3Aos9GI59L7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^8.0.5",
+ "@babel/types": "^8.0.5",
+ "@jridgewell/gen-mapping": "0.4.0-beta.0",
+ "@jridgewell/trace-mapping": "^0.3.31",
+ "@types/jsesc": "^2.5.0",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@babel/parser": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.5.tgz",
+ "integrity": "sha512-51RXvQNFakaS0bTpYiGkxNbUVwkPO4kONv6EVLorZABxsx+KZ6Z7uSYvi/wmKS/+X+rfj9RvOw0/ZNh+cmI0Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/generator/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-8.0.0.tgz",
+ "integrity": "sha512-NSpMkMsvvZqzThJ0p1B02cbtA2ObEyfBvq950bmNkyxsxvcxwhvvCB036rKhlEnuBBo30bOrk13u3FzlKSoRrw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.5.tgz",
+ "integrity": "sha512-Qk8ahMGooH5mz6uuhoDvfZGkUf/Mf3RTBucVVl4MKx4LKMTv872TeW8O92h15iVtlN8wAROBIpI1aV6x1z0LCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^8.0.5",
+ "@babel/helper-validator-option": "^8.0.0",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^11.0.0",
+ "verkit": "^0.3.2"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-8.0.5.tgz",
+ "integrity": "sha512-ckUE7tmolBbW4QV02lD874sWSPy8da2A09i/h0qS+IWolR+WiNhpq7C/rHZm00uOIkUb0Cp6+0Cy1ku/wj5uQQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^8.0.0",
+ "@babel/helper-member-expression-to-functions": "^8.0.5",
+ "@babel/helper-optimise-call-expression": "^8.0.0",
+ "@babel/helper-replace-supers": "^8.0.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^8.0.0",
+ "@babel/traverse": "^8.0.5",
+ "verkit": "^0.3.2"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0.tgz",
+ "integrity": "sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-8.0.5.tgz",
+ "integrity": "sha512-GLe05QD98BkNFTkjaqeqF9QSRoHLKrrB4tpoplyQuuPrQJ72rtmkM4wvqJLX/sjZPqkbK5MUYSsuUTqdJoOVjA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^8.0.5",
+ "@babel/types": "^8.0.5"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-8.0.0.tgz",
+ "integrity": "sha512-NZ7mSS93o4ndX4KrbD7W8Sf3QT8Qe24PrnFyUcuOPDzK6faqDFKjY9RG7he7+I7FdiQ4llpnosFqzrXa+Vy3Ew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^8.0.0",
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-8.0.5.tgz",
+ "integrity": "sha512-lUsSqMD0l5cJKl+3vlTV/hPDA/IvNkcHWVI3zFud2Vur+C9bCKdpqbpkN9eABembedbdWwF0qow6nbdIpNlpcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4",
+ "@babel/traverse": "^8.0.5"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-8.0.0.tgz",
+ "integrity": "sha512-3W6satvtPuCUkUx63S2jMoW9EQNYkADgs1HTfufmL7gCmAulHMKupA/12WNz4A0GMMFn/YnWWwqOT9IZrJHQjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.1.tgz",
+ "integrity": "sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-8.0.1.tgz",
+ "integrity": "sha512-B1SZADIcy3tmH8CmWvj4SHi/oAPom4UL3uknTc2QRNsPVLFk/sPnZvQL/8kj7Y5omvjMqie0vklvs6XM4OLW5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^8.0.0",
+ "@babel/helper-optimise-call-expression": "^8.0.0",
+ "@babel/traverse": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-8.0.0.tgz",
+ "integrity": "sha512-xmCA9kP3IhySsqhzwIdWGlDN/1A4cCKNBO/uwZx/3YzmDoMePwno2Q5/Bq0q+tYaKbeF940YiKV/kaW8Mzvpjw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^8.0.0",
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
"node_modules/@babel/helper-string-parser": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
@@ -35,33 +568,504 @@
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=6.9.0"
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz",
+ "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.5.tgz",
+ "integrity": "sha512-fQtPOXjYOYv85PIdwotp2TJGVYOycX0PQq+l844fFAxOULtBy8BVF35GyeueX0r4KvDthqPH5xAI1clQPk/2uA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^8.0.0",
+ "@babel/types": "^8.0.5"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helpers/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helpers/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/helpers/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-decorators": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-8.0.2.tgz",
+ "integrity": "sha512-+C6O6KKXU7BBq1GNaIkFJxrALUVGRcr+WeWm4OcuRl3h+l/CmNfcTLMrT2Lm3uvGBimBH/8pEBRrXJFLoO67Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^8.0.1",
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/plugin-syntax-decorators": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-decorators": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-8.0.1.tgz",
+ "integrity": "sha512-NI+0S/6MvR6GlcQFwjDZ+WIc2qvG6TXN534lYs9llNldwW4b7Dh6KTtk030FA0xWdYGs4t1lWo+OEWN8wGB+Nw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-8.0.1.tgz",
+ "integrity": "sha512-n0jtCOxEovhU7METqSQjcZO9pX53nu9uNIjMS+hEt+Nt9jA7oOZoBIgbCxhhASmF6T6rPDGge5UAvh6Z4eFz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-8.0.3.tgz",
+ "integrity": "sha512-jmTPwps7oSQSZaV1SxkQ3C12UWyufGysGc5OzDpZzvPAIX4mO7dJT3hoqkWVrSImvkcMiknir1iLN1SNV/CZzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-8.0.5.tgz",
+ "integrity": "sha512-evjxc5fGvpXG2WMGSalpX8IJZVumLIDgk5r5eRhvXRDqFX/GPWq1BeRfJalPCcwJfrR5A/wvegUhx9W5Nr7/mg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-explicit-resource-management": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-8.0.5.tgz",
+ "integrity": "sha512-Vr20jk/ZxRGu30o0jYvcKl2Pf0tiyr8H9q2ZGxYD6yjOpv9DdP6//I85q0cSOdADZhsu/ZZoApjGVCfl4xnVJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/plugin-transform-destructuring": "^8.0.5"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-8.0.1.tgz",
+ "integrity": "sha512-PMuzulWrrzFNmY3lXSk/tV9NRb7y0eZZLJY4UEo2TKszroxvUZHAPPi+T9FDyrQhod+TQA+t+8/QYaaMpiEuhA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-transforms": "^8.0.1",
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-display-name": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-8.0.1.tgz",
+ "integrity": "sha512-soLishXlkyu6jcICPyO3HEP7A3GCzKEnn7XfvYrImuWEOwFAz93qShmWSYPf5ww0ZkO4By0zsN2bVIDF54fSdA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-8.0.1.tgz",
+ "integrity": "sha512-NgkoF7Uq+30TmOPDdNUimT0Nta02uVjqJRFNlVWKrbOCu/CkzfHa4aMnIs0lMpkMmZmWA1e42Va+F04i/pY1zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^8.0.0",
+ "@babel/helper-module-imports": "^8.0.0",
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/plugin-syntax-jsx": "^8.0.1",
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx-development": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-8.0.1.tgz",
+ "integrity": "sha512-Hb+HUZpV9KFHjm+F+P3aLDMi8QXU9l3ROCQv20z18Me2sGyW5nNNR5YTevNlgHvCpFek3BnAwhDGq/BRndXViw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/plugin-transform-react-jsx": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-jsx/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-react-pure-annotations": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-8.0.1.tgz",
+ "integrity": "sha512-7/8UwU8hoPBurXa9tUiTTC8aACTRy5tCqLUtqikHp2eGiWoEB57AduOdbQ71OOMTEvawKrGhv3WfzkDpI+/oSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^8.0.0",
+ "@babel/helper-plugin-utils": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-8.0.5.tgz",
+ "integrity": "sha512-o6XW6OngFfpEQat3J1MxUDEd94Rjh80BZQqWmOXa9YTtoyDnk8Zim3NXcx3RTgGiOgkoayCMYp+Xk5NxEmzoMg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^8.0.0",
+ "@babel/helper-create-class-features-plugin": "^8.0.5",
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^8.0.0",
+ "@babel/plugin-syntax-typescript": "^8.0.3"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/preset-react": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-8.0.1.tgz",
+ "integrity": "sha512-jrFuPp/pTddFZbtmWhdLNAYc6UMcpboeUPnw0BBrm4nOmcAko/1TRcFi1PzWCeOFRU+VaSiKmat87W1HvR7mIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/helper-validator-option": "^8.0.0",
+ "@babel/plugin-transform-react-display-name": "^8.0.1",
+ "@babel/plugin-transform-react-jsx": "^8.0.1",
+ "@babel/plugin-transform-react-jsx-development": "^8.0.1",
+ "@babel/plugin-transform-react-pure-annotations": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/preset-typescript": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-8.0.1.tgz",
+ "integrity": "sha512-qrPhQIN1NLrPmzgazF9XKQqXrOcp/WJly+K+6ReFonn24FZqRJO7clxOJo6Ni75L+2vAqI3cHVU2OJLBxoPp5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^8.0.1",
+ "@babel/helper-validator-option": "^8.0.0",
+ "@babel/plugin-transform-modules-commonjs": "^8.0.1",
+ "@babel/plugin-transform-typescript": "^8.0.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^8.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz",
+ "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^8.0.0",
+ "@babel/parser": "^8.0.0",
+ "@babel/types": "^8.0.0"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/template/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
}
},
- "node_modules/@babel/helper-validator-identifier": {
- "version": "7.29.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
- "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "node_modules/@babel/template/node_modules/@babel/parser": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.5.tgz",
+ "integrity": "sha512-51RXvQNFakaS0bTpYiGkxNbUVwkPO4kONv6EVLorZABxsx+KZ6Z7uSYvi/wmKS/+X+rfj9RvOw0/ZNh+cmI0Rw==",
"dev": true,
"license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
"engines": {
- "node": ">=6.9.0"
+ "node": "^22.18.0 || >=24.11.0"
}
},
- "node_modules/@babel/parser": {
- "version": "7.29.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
- "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "node_modules/@babel/template/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.29.8"
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.5.tgz",
+ "integrity": "sha512-XFfnuvapSc/vJOcUO7kwORSvpBIvraofKEZ2dhT0PjiF21BRCD7YbAFC8UEeDJNeLoQz82/gVqzgX5hCzkCbdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^8.0.0",
+ "@babel/generator": "^8.0.5",
+ "@babel/helper-globals": "^8.0.0",
+ "@babel/parser": "^8.0.5",
+ "@babel/template": "^8.0.0",
+ "@babel/types": "^8.0.5",
+ "obug": "^2.1.1"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@babel/parser": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.5.tgz",
+ "integrity": "sha512-51RXvQNFakaS0bTpYiGkxNbUVwkPO4kONv6EVLorZABxsx+KZ6Z7uSYvi/wmKS/+X+rfj9RvOw0/ZNh+cmI0Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.5"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
- "node": ">=6.0.0"
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
}
},
"node_modules/@babel/types": {
@@ -263,23 +1267,378 @@
"engines": {
"node": ">=12.22"
},
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@inquirer/ansi": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.8.tgz",
+ "integrity": "sha512-WpQM+Ti6Z40EFwwt+uL2p4UabT+W179zHp6HhLVOzfbwnVn05IPO/eXIZXGNqcT1jbQ15SujNLzQ39k4QPPxBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/checkbox": {
+ "version": "5.2.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.5.tgz",
+ "integrity": "sha512-bRt8J8m+Fot9CXv+zNQGXUq2ET0MggR1fPz7v6edN6MFYmsbfGnMmkmWZJEegMKqrAC8ej/o1sqisHZXZJMAfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.8",
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/figures": "^2.0.9",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "6.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.3.2.tgz",
+ "integrity": "sha512-Xvr/0HggjddPtGppuqVmxhTw+Hr8PvsZ/k0HmOEaAqQEt80OITNkFWnsdNmyT0/eM4Ab+iJLx2R8rctlEyfSVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "12.0.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-12.0.3.tgz",
+ "integrity": "sha512-wsSy0sznmXwkty+2PzZwx00Cazc/E0r0B7mAzdGROz2Ct+DFZXaK7WDjGZvgjRldxH5ZhFVfF2lgkYrqgOw2KA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.8",
+ "@inquirer/figures": "^2.0.9",
+ "@inquirer/type": "4.1.1",
+ "cli-width": "^4.1.0",
+ "fast-wrap-ansi": "^0.2.0",
+ "mute-stream": "^3.0.0",
+ "signal-exit": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.3.3.tgz",
+ "integrity": "sha512-YsKkS2q63IiLtaDK/9nqzdComN97SDQrmKiyNggN+ceP4ty+Z6VwyTz3FpjeUWeW1Efss2xHFKCC9sx7hnrsxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/external-editor": "^3.0.5",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.5.tgz",
+ "integrity": "sha512-uHuXLmXW+TtIfT/9vSBotypAkqn1n34Ul+CLGPos/xANyO4Ff5xZzkYhbKR4NEcfVK4a9mHQOpwVZzluSHFRGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.5.tgz",
+ "integrity": "sha512-f3QQJRIX5ZEneBHNUIuPjmbdzHnmRFJA8r2dkcb8q+OM5Uv5KtnuAttQumnrjcBVBM3mcTX1CkmtAkU58VRZxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.1",
+ "iconv-lite": "^0.7.2"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.9.tgz",
+ "integrity": "sha512-EAWgUTGQ/Umgga51dE3B2PUHbufuXarDfg86uVgoSgNHNNQnyFKcOrQLWVqYMghuSyHh8+2HUH0Js9cTC1WAdg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.6.tgz",
+ "integrity": "sha512-HtcJhB2QFVXbLuJ5S3syhNbTUVxYvwqV4VRBDkQceBloC9bmTViUoRFP5PbSaDZb3HzfPmpuU/gG4ybVBz4FHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.2.3.tgz",
+ "integrity": "sha512-6Yuwh1NGSbu1Lo4N1EWjXs1jKRntLg/ZCwhmeorEHde90v1XxAozdbd4Iu30eOQLW+6h1hp2O9ujNfLSbTPJnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.2.2.tgz",
+ "integrity": "sha512-W9zYdyzogK+6110mqwaSJWCBu2yA5Q/OfnGSjjZB1bNpHlmUozXxTl0+QOZBNeVd6Qo81/qT75gW05gLAtITxw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.8",
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "8.7.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.7.2.tgz",
+ "integrity": "sha512-QoRB4wFIjgH5iOhSjoIKMkTvSHDuV+O3OITlIqAYO0oK5x364GJILXiMBvlPiE+klg7Xx9tq5XVqQHcGUDYYPA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/checkbox": "^5.2.5",
+ "@inquirer/confirm": "^6.3.2",
+ "@inquirer/editor": "^5.3.3",
+ "@inquirer/expand": "^5.1.5",
+ "@inquirer/input": "^5.1.6",
+ "@inquirer/number": "^4.2.3",
+ "@inquirer/password": "^5.2.2",
+ "@inquirer/rawlist": "^5.3.5",
+ "@inquirer/search": "^4.3.3",
+ "@inquirer/select": "^5.2.5"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "5.3.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.5.tgz",
+ "integrity": "sha512-1oHky1ONfCOwNrnkQGDE1oaSij/3fI6HFMSf2H/WsGO2lEyDX9My82iggITSy9ddSZ8yk8j9v41OI0fVoSIoaA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.3.3.tgz",
+ "integrity": "sha512-fyuIU1Nbpvwlikjg3gXwJFDI11+EFjqQ7P+iByfmivIKQ1vmaykNrD/vy5unHuUqUpsOsnvJ25//tPF7E/RBRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/figures": "^2.0.9",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "5.2.5",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.5.tgz",
+ "integrity": "sha512-9kc15hr8r/kI+3DO/xLog5nOzTz1jqsHXa6JBFzmQKhkoJ8Slda1I1L/uD8ZSZ9tF1yp79wwXe7mclvX1rqR2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^2.0.8",
+ "@inquirer/core": "^12.0.3",
+ "@inquirer/figures": "^2.0.9",
+ "@inquirer/type": "4.1.1"
+ },
+ "engines": {
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
}
},
- "node_modules/@humanwhocodes/retry": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
- "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "node_modules/@inquirer/type": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.1.1.tgz",
+ "integrity": "sha512-yJoHYrMnxIsJZCY+0Vb66Dy3he3kL3e2wOBKhoSwWWAzZAY82emlxwgprCtp6yRixvNRNq9ztfRWQYPNr3Go7A==",
"dev": true,
- "license": "Apache-2.0",
+ "license": "MIT",
"engines": {
- "node": ">=18.18"
+ "node": ">=23.5.0 || ^22.13.0 || ^20.17.0"
},
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.4.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.4.0-beta.0.tgz",
+ "integrity": "sha512-JdGNkbE4GlNPYQhM0L95fBQr7ctLZJ276QXQLTad4t1oSdnnCI3fDq9DW3BqYAWv8Wc3+HS+4Gsii1oPMCfz1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.6.0-beta.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
@@ -430,9 +1789,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -450,9 +1806,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -470,9 +1823,6 @@
"ppc64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -490,9 +1840,6 @@
"s390x"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -510,9 +1857,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -530,9 +1874,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MIT",
"optional": true,
"os": [
@@ -600,6 +1941,26 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
+ "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@standard-schema/spec": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
@@ -607,6 +1968,213 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@stryker-mutator/api": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-10.0.0.tgz",
+ "integrity": "sha512-ZtAJ0ZT3MVRCWJTBE2h90XB/6E+4lifHYtcTyNG6nU2nLekPgTo4gD5esjX6Okxo1b/JB4jJzyxYB54fwKAoJw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "mutation-testing-metrics": "3.8.4",
+ "mutation-testing-report-schema": "3.8.4",
+ "tslib": "~2.8.0",
+ "typed-inject": "~5.0.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@stryker-mutator/core": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@stryker-mutator/core/-/core-10.0.0.tgz",
+ "integrity": "sha512-ZvMsRyaXQQ5e6Thcid9pkuODv6Fn9E3nrBQJUap+hcJuGJ4unm26afo3m6YKSjn8kinyxJ/3TXf0cTWRDaTxVw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@inquirer/prompts": "^8.0.0",
+ "@stryker-mutator/api": "10.0.0",
+ "@stryker-mutator/instrumenter": "10.0.0",
+ "@stryker-mutator/util": "10.0.0",
+ "ajv": "~8.20.0",
+ "chalk": "~5.6.0",
+ "commander": "~14.0.0",
+ "diff-match-patch": "1.0.5",
+ "emoji-regex": "~10.6.0",
+ "execa": "~9.6.0",
+ "json-rpc-2.0": "^1.7.0",
+ "lodash.groupby": "~4.6.0",
+ "minimatch": "~10.2.4",
+ "mutation-server-protocol": "~0.4.0",
+ "mutation-testing-elements": "3.8.4",
+ "mutation-testing-metrics": "3.8.4",
+ "mutation-testing-report-schema": "3.8.4",
+ "npm-run-path": "~6.0.0",
+ "progress": "~2.0.3",
+ "rxjs": "~7.8.1",
+ "semver": "^7.6.3",
+ "source-map": "~0.7.4",
+ "tree-kill": "~1.2.2",
+ "tslib": "2.8.1",
+ "typed-inject": "~5.0.0",
+ "typed-rest-client": "~2.3.0"
+ },
+ "bin": {
+ "stryker": "bin/stryker.js"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@stryker-mutator/core/node_modules/ajv": {
+ "version": "8.20.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz",
+ "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@stryker-mutator/core/node_modules/chalk": {
+ "version": "5.6.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+ "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@stryker-mutator/core/node_modules/commander": {
+ "version": "14.0.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
+ "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@stryker-mutator/core/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@stryker-mutator/instrumenter": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@stryker-mutator/instrumenter/-/instrumenter-10.0.0.tgz",
+ "integrity": "sha512-B7Wmn1KlEWyFeOz6D6oGvQGRfi5Xw3VemG6dEKvFQp4qLvxD9Mf4kcZghfxffgnYwXd3bFgqXsJ+ZGlhdfIOrQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@babel/core": "~8.0.0",
+ "@babel/generator": "~8.0.0",
+ "@babel/parser": "~8.0.0",
+ "@babel/plugin-proposal-decorators": "~8.0.0",
+ "@babel/plugin-transform-explicit-resource-management": "^8.0.0",
+ "@babel/preset-react": "~8.0.0",
+ "@babel/preset-typescript": "~8.0.0",
+ "@babel/traverse": "~8.0.4",
+ "@stryker-mutator/api": "10.0.0",
+ "@stryker-mutator/util": "10.0.0",
+ "angular-html-parser": "~10.11.0",
+ "semver": "~7.8.0",
+ "tslib": "2.8.1",
+ "weapon-regex": "~2.0.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@stryker-mutator/instrumenter/node_modules/@babel/helper-string-parser": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz",
+ "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@stryker-mutator/instrumenter/node_modules/@babel/helper-validator-identifier": {
+ "version": "8.0.4",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+ "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@stryker-mutator/instrumenter/node_modules/@babel/parser": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.5.tgz",
+ "integrity": "sha512-51RXvQNFakaS0bTpYiGkxNbUVwkPO4kONv6EVLorZABxsx+KZ6Z7uSYvi/wmKS/+X+rfj9RvOw0/ZNh+cmI0Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^8.0.5"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@stryker-mutator/instrumenter/node_modules/@babel/types": {
+ "version": "8.0.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.5.tgz",
+ "integrity": "sha512-eVdMqi3ej5aHhyQ2Si6yD2cAWeV8FJK9UrhK5aL0Sd8hu5GhT+YswhVNbVheOGVYMg8kuGuMaUpkB3stjj4z8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^8.0.0",
+ "@babel/helper-validator-identifier": "^8.0.4"
+ },
+ "engines": {
+ "node": "^22.18.0 || >=24.11.0"
+ }
+ },
+ "node_modules/@stryker-mutator/util": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-10.0.0.tgz",
+ "integrity": "sha512-LzOpHiJaCp2ABQgnPMlrQQcsK43bd5Vo/2FGL78aN62yDoeRQ+4j3tzeuXxK5OAHdC3fUz6TDoy4IsoAuLAd3w==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@stryker-mutator/vitest-runner": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@stryker-mutator/vitest-runner/-/vitest-runner-10.0.0.tgz",
+ "integrity": "sha512-SHK2/vfvRUpiz7jXPnQMBnr6zLdm69DK03Mo5mPhaZWcRSygrKUqYsPqWsXsK+5ySHzlMTfCyFK5NQ/X9sJFFw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@stryker-mutator/api": "10.0.0",
+ "@stryker-mutator/util": "10.0.0",
+ "semver": "^7.7.4",
+ "tslib": "~2.8.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ },
+ "peerDependencies": {
+ "@stryker-mutator/core": "10.0.0",
+ "vitest": ">=2.0.0"
+ }
+ },
"node_modules/@types/chai": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
@@ -639,6 +2207,20 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/gensync": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/gensync/-/gensync-1.0.5.tgz",
+ "integrity": "sha512-MbsRCT7mTikHwKZ0X+LVUTLRrZZRLipTuXEO9qOYO+zmjMVk81axyClMROf6uoPD9MRVu46bx8zoR0Ad9q3NAg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/jsesc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@types/jsesc/-/jsesc-2.5.1.tgz",
+ "integrity": "sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@@ -1134,6 +2716,16 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/angular-html-parser": {
+ "version": "10.11.0",
+ "resolved": "https://registry.npmjs.org/angular-html-parser/-/angular-html-parser-10.11.0.tgz",
+ "integrity": "sha512-3vERzJ65UFDr3C7uozLJwsNcQS3FS784dSh583oDgDTTZMgXe3/pdyXgKndxiP5R2lvYRfW6gSl145Hnyf2OFA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -1182,6 +2774,19 @@
"node": "18 || 20 || >=22"
}
},
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.23",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.23.tgz",
+ "integrity": "sha512-le521dGVfxM7yRX0EikCoSz+rOK+hHzdDt/E7mG1jOJB/6WAAUuwVroLwaB7ApaUsz5Q0kFlDXLSA9MheUIfRQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/brace-expansion": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
@@ -1195,6 +2800,92 @@
"node": "20 || >=22"
}
},
+ "node_modules/browserslist": {
+ "version": "4.28.9",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz",
+ "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.11.20",
+ "caniuse-lite": "^1.0.30001810",
+ "electron-to-chromium": "^1.5.420",
+ "node-releases": "^2.0.54",
+ "update-browserslist-db": "^1.3.2"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001810",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz",
+ "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
"node_modules/chai": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz",
@@ -1222,6 +2913,23 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/chardet": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz",
+ "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1360,14 +3068,71 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
- "node_modules/detect-libc": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
- "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "node_modules/des.js": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
+ "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "minimalistic-assert": "^1.0.0"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff-match-patch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
+ "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.428",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.428.tgz",
+ "integrity": "sha512-1JxbaFJj1bRKurj1uY3l4xxpU9kOUAUjcIgApj0qu1Pao5GhoIWI8iL0BeMYJ2njig1hBx0A7eKD9VGjH9wlHw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"dev": true,
- "license": "Apache-2.0",
+ "license": "MIT"
+ },
+ "node_modules/empathic": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz",
+ "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==",
+ "dev": true,
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=14"
}
},
"node_modules/enhanced-resolve": {
@@ -1384,6 +3149,16 @@
"node": ">=10.13.0"
}
},
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
@@ -1401,6 +3176,29 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -1579,6 +3377,33 @@
"node": ">=0.10.0"
}
},
+ "node_modules/execa": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
+ "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^4.0.0",
+ "cross-spawn": "^7.0.6",
+ "figures": "^6.1.0",
+ "get-stream": "^9.0.0",
+ "human-signals": "^8.0.1",
+ "is-plain-obj": "^4.1.0",
+ "is-stream": "^4.0.1",
+ "npm-run-path": "^6.0.0",
+ "pretty-ms": "^9.2.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^4.0.0",
+ "yoctocolors": "^2.1.1"
+ },
+ "engines": {
+ "node": "^18.19.0 || >=20.5.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
"node_modules/expect-type": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz",
@@ -1610,6 +3435,50 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/fast-string-truncated-width": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz",
+ "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-string-width": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz",
+ "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-truncated-width": "^3.0.2"
+ }
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz",
+ "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/fast-wrap-ansi": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz",
+ "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-string-width": "^3.0.2"
+ }
+ },
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -1628,6 +3497,22 @@
}
}
},
+ "node_modules/figures": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
+ "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-unicode-supported": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -1704,6 +3589,72 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -1746,6 +3697,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -1763,6 +3727,19 @@
"node": ">=8"
}
},
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/hasown": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
@@ -1783,6 +3760,33 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/human-signals": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
+ "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
+ "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
"node_modules/ignore": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@@ -1793,6 +3797,17 @@
"node": ">= 4"
}
},
+ "node_modules/import-meta-resolve": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz",
+ "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -1803,6 +3818,13 @@
"node": ">=0.8.19"
}
},
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/ini": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz",
@@ -1892,6 +3914,45 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz",
+ "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -1938,6 +3999,13 @@
"node": ">=8"
}
},
+ "node_modules/js-md4": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz",
+ "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/js-tokens": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz",
@@ -1945,6 +4013,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -1952,6 +4033,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/json-rpc-2.0": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/json-rpc-2.0/-/json-rpc-2.0-1.8.0.tgz",
+ "integrity": "sha512-4nw+XlJbk5XokA7BtqHGu+0PEiUPfAkRzXXd1Cgjy1c3F2UI/3Gy7yr76wyJEv3X1F1SRGGF8xPAPPhelBiGmA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -2156,9 +4244,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2180,9 +4265,6 @@
"arm64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2204,9 +4286,6 @@
"x64"
],
"dev": true,
- "libc": [
- "glibc"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2228,9 +4307,6 @@
"x64"
],
"dev": true,
- "libc": [
- "musl"
- ],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -2302,6 +4378,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash.groupby": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+ "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "11.5.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
+ "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -2340,6 +4433,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/minimalistic-assert": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+ "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/minimatch": {
"version": "10.2.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
@@ -2373,6 +4483,53 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/mutation-server-protocol": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/mutation-server-protocol/-/mutation-server-protocol-0.4.1.tgz",
+ "integrity": "sha512-SBGK0j8hLDne7bktgThKI8kGvGTx3rY3LAeQTmOKZ5bVnL/7TorLMvcVF7dIPJCu5RNUWhkkuF53kurygYVt3g==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "zod": "^4.1.12"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/mutation-testing-elements": {
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/mutation-testing-elements/-/mutation-testing-elements-3.8.4.tgz",
+ "integrity": "sha512-5CF1SNa7at5ZH33vEr+21wNebTSrtNIVvnzaUlxortHajOrIPaSLczIWvg6sI/fsExekQ7jookwf2cHftkckqQ==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/mutation-testing-metrics": {
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/mutation-testing-metrics/-/mutation-testing-metrics-3.8.4.tgz",
+ "integrity": "sha512-DZcmndJBH6nrNs3tpiB3OcMVq9KkG2cHCpJSnDxSxPwi9qrafRmoec40xjhkbzOoX1n7/4UkDqg5tIj4A6nvCw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "mutation-testing-report-schema": "3.8.4"
+ }
+ },
+ "node_modules/mutation-testing-report-schema": {
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/mutation-testing-report-schema/-/mutation-testing-report-schema-3.8.4.tgz",
+ "integrity": "sha512-s4G71R6Lt/PpZ0cqeglIcgyBdzLM8E+SeCHZAPg1wkSsPtRBa4XfPzAozYKdiJk/TLbNEEb7En9t0/bveuPuxA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/mute-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz",
+ "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
"node_modules/nanoid": {
"version": "3.3.19",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz",
@@ -2399,6 +4556,59 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/node-releases": {
+ "version": "2.0.55",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.55.tgz",
+ "integrity": "sha512-mIrE/Cw9y+9Au6dS5vDKDhQza9YvG6w+ZrS6X+ZzA7yFW/soAeaups4Qzn1bL6g5FVy8WtP79+0j82oPIbqRjQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/obug": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz",
@@ -2463,6 +4673,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse-ms": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
+ "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -2572,6 +4795,32 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
+ "node_modules/pretty-ms": {
+ "version": "9.3.1",
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz",
+ "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parse-ms": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -2596,6 +4845,22 @@
"node": ">=6"
}
},
+ "node_modules/qs": {
+ "version": "6.15.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz",
+ "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
@@ -2619,6 +4884,16 @@
"regexp-tree": "bin/regexp-tree"
}
},
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.12",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz",
@@ -2675,6 +4950,16 @@
"@rolldown/binding-win32-x64-msvc": "1.2.8"
}
},
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/safe-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz",
@@ -2685,6 +4970,13 @@
"regexp-tree": "~0.1.1"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
@@ -2721,6 +5013,82 @@
"node": ">=8"
}
},
+ "node_modules/side-channel": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz",
+ "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4",
+ "side-channel-list": "^1.0.1",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz",
+ "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/siginfo": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
@@ -2728,6 +5096,19 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -2735,6 +5116,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -2769,6 +5160,19 @@
"node": ">=4"
}
},
+ "node_modules/strip-final-newline": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
+ "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -2853,6 +5257,16 @@
"node": ">=14.0.0"
}
},
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
"node_modules/ts-api-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
@@ -2897,6 +5311,23 @@
"node": ">=10.13.0"
}
},
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+ }
+ },
"node_modules/type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@@ -2910,6 +5341,33 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/typed-inject": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/typed-inject/-/typed-inject-5.0.0.tgz",
+ "integrity": "sha512-0Ql2ORqBORLMdAW89TQKZsb1PQkFGImFfVmncXWe7a+AA3+7dh7Se9exxZowH4kbnlvKEFkMxUYdHUpjYWFJaA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/typed-rest-client": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-2.3.1.tgz",
+ "integrity": "sha512-k4kX5Up6qA68D0Cby2AK+6+vM5k3qTxe+/3FqhnHRExjY5cfbOnzjQZbP/LXleF8hVoDvDqxlgk9KK83HoBZlQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "des.js": "^1.1.0",
+ "js-md4": "^0.3.2",
+ "qs": "6.15.1",
+ "tunnel": "0.0.6",
+ "underscore": "^1.13.8"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ }
+ },
"node_modules/typescript": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
@@ -2948,6 +5406,13 @@
"typescript": ">=4.8.4 <6.1.0"
}
},
+ "node_modules/underscore": {
+ "version": "1.13.8",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz",
+ "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
@@ -2955,6 +5420,50 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz",
+ "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -2965,6 +5474,19 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/verkit": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/verkit/-/verkit-0.3.2.tgz",
+ "integrity": "sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
"node_modules/vite": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.3.0.tgz",
@@ -3146,6 +5668,13 @@
"node": "^22.13||^24||>=26"
}
},
+ "node_modules/weapon-regex": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/weapon-regex/-/weapon-regex-2.0.5.tgz",
+ "integrity": "sha512-BJZkSdtcae9Wb8+hKNtAqR+Q61EMOAuQnpCCHKwT50K7fIWg7/2/RnbKR27YB+sMcYxYLUVj+Asm5Y2XhD8mZg==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3189,6 +5718,21 @@
"node": ">=0.10.0"
}
},
+ "node_modules/yaml": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.1.tgz",
+ "integrity": "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==",
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ },
"node_modules/yocto-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
@@ -3202,6 +5746,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yoctocolors": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz",
+ "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/zod": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.5.4.tgz",
diff --git a/package.json b/package.json
index fce2781..9b171f0 100644
--- a/package.json
+++ b/package.json
@@ -28,10 +28,13 @@
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
+ "test:mutation": "stryker run",
"verify": "npm run lint && npm run format:check && npm run typecheck && npm run lint:adrs && npm run lint:links && npm run lint:manifests && npm run lint:requirements && npm run lint:rules && npm run lint:codes && npm run lint:docs && npm run lint:secrets && npm run lint:boundaries && npm run test:coverage"
},
"devDependencies": {
"@eslint/js": "10.0.1",
+ "@stryker-mutator/core": "10.0.0",
+ "@stryker-mutator/vitest-runner": "10.0.0",
"@types/node": "24.13.3",
"@vitest/coverage-v8": "4.1.11",
"@vitest/eslint-plugin": "1.6.27",
@@ -60,6 +63,7 @@
"gitops"
],
"dependencies": {
+ "yaml": "2.9.1",
"zod": "^4.5.4"
}
}
diff --git a/src/application/parse-project-intent.ts b/src/application/parse-project-intent.ts
new file mode 100644
index 0000000..c35535d
--- /dev/null
+++ b/src/application/parse-project-intent.ts
@@ -0,0 +1,13 @@
+import type { Result } from "../domain/diagnostic.ts";
+import {
+ validateProjectIntent,
+ type ValidatedProjectIntent,
+} from "../wire/project-intent/map.ts";
+import { readYaml } from "../wire/project-intent/read.ts";
+
+export function parseProjectIntent(
+ text: string,
+): Result {
+ const read = readYaml(text);
+ return read.ok ? validateProjectIntent(read.value) : read;
+}
diff --git a/src/domain/diagnostic.ts b/src/domain/diagnostic.ts
new file mode 100644
index 0000000..0c2f072
--- /dev/null
+++ b/src/domain/diagnostic.ts
@@ -0,0 +1,10 @@
+export interface Diagnostic {
+ readonly code: string;
+ readonly path: string;
+ readonly message: string;
+ readonly hint: string;
+}
+
+export type Result =
+ | { readonly ok: true; readonly value: T }
+ | { readonly ok: false; readonly diagnostics: readonly Diagnostic[] };
diff --git a/src/domain/project-intent/model.ts b/src/domain/project-intent/model.ts
new file mode 100644
index 0000000..3b4e38e
--- /dev/null
+++ b/src/domain/project-intent/model.ts
@@ -0,0 +1,62 @@
+import type {
+ AlertClass,
+ Audience,
+ ContentPolicy,
+ Cutover,
+ Lifecycle,
+ Match,
+ Runtime,
+} from "./vocabularies.ts";
+
+export interface Project {
+ readonly name: string;
+ readonly owner: string;
+ readonly applications: readonly Application[];
+}
+
+export interface Application {
+ readonly id: string;
+ readonly observability?: Observability;
+ readonly exposures: readonly Exposure[];
+ readonly processes: readonly Process[];
+}
+
+export interface SurfaceRef {
+ readonly process: string;
+ readonly surface: string;
+}
+
+export interface Observability {
+ readonly alertClass: AlertClass;
+ readonly scrape: SurfaceRef & { readonly path: string };
+}
+
+export interface Exposure {
+ readonly name: string;
+ readonly host: string;
+ readonly audience: Audience;
+ readonly contentPolicy: ContentPolicy;
+ readonly routes: readonly Route[];
+}
+
+export interface Route extends SurfaceRef {
+ readonly path: string;
+ readonly match: Match;
+}
+
+export interface Probe {
+ readonly path: string;
+ readonly port: number;
+}
+
+export interface Process {
+ readonly name: string;
+ readonly lifecycle: Lifecycle;
+ readonly image: string;
+ readonly runtime: Runtime;
+ readonly provides: ReadonlyMap;
+ readonly placement: { readonly memory: string; readonly cpu: string };
+ readonly probes: { readonly readiness?: Probe; readonly liveness?: Probe };
+ readonly startupBudget?: string;
+ readonly cutover: Cutover;
+}
diff --git a/src/domain/project-intent/vocabularies.ts b/src/domain/project-intent/vocabularies.ts
new file mode 100644
index 0000000..836cb5c
--- /dev/null
+++ b/src/domain/project-intent/vocabularies.ts
@@ -0,0 +1,23 @@
+// The closed vocabularies of spec/v1/10-project-intent.md#the-closed-vocabularies.
+// Each is declared here once; the wire schema enumerates from these lists.
+
+export const LIFECYCLES = ["application", "job"] as const;
+export const RUNTIMES = ["jvm", "python", "node", "static", "none"] as const;
+export const CUTOVERS = ["rolling", "recreate"] as const;
+export const ALERT_CLASSES = ["business-hours", "urgent", "page"] as const;
+export const AUDIENCES = [
+ "anonymous",
+ "authenticated",
+ "internal",
+ "lan",
+] as const;
+export const CONTENT_POLICIES = ["strict", "admin", "workflow"] as const;
+export const MATCHES = ["prefix", "exact"] as const;
+
+export type Lifecycle = (typeof LIFECYCLES)[number];
+export type Runtime = (typeof RUNTIMES)[number];
+export type Cutover = (typeof CUTOVERS)[number];
+export type AlertClass = (typeof ALERT_CLASSES)[number];
+export type Audience = (typeof AUDIENCES)[number];
+export type ContentPolicy = (typeof CONTENT_POLICIES)[number];
+export type Match = (typeof MATCHES)[number];
diff --git a/src/index.ts b/src/index.ts
index bc859cc..ac53d04 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1 +1,4 @@
+export { parseProjectIntent } from "./application/parse-project-intent.ts";
+export type { Diagnostic, Result } from "./domain/diagnostic.ts";
+export type * from "./domain/project-intent/model.ts";
export { canonicalJson } from "./infrastructure/canonical-json.ts";
diff --git a/src/wire/project-intent/map.ts b/src/wire/project-intent/map.ts
new file mode 100644
index 0000000..b087120
--- /dev/null
+++ b/src/wire/project-intent/map.ts
@@ -0,0 +1,64 @@
+import type { Diagnostic, Result } from "../../domain/diagnostic.ts";
+import type {
+ Application,
+ Process,
+ Project,
+} from "../../domain/project-intent/model.ts";
+import { projectIntent, type ProjectIntentDocument } from "./schema.ts";
+
+type WireApplication = ProjectIntentDocument["applications"][number];
+type WireProcess = WireApplication["processes"][number];
+
+const escape = (segment: PropertyKey): string =>
+ String(segment).replaceAll("~", "~0").replaceAll("/", "~1");
+
+function toProcess(process: WireProcess): Process {
+ const { provides, probes, ...rest } = process;
+ return {
+ ...rest,
+ provides: new Map(Object.entries(provides ?? {})),
+ probes: probes ?? {},
+ };
+}
+
+function toApplication(application: WireApplication): Application {
+ const { exposure, processes, ...rest } = application;
+ return {
+ ...rest,
+ exposures: exposure ?? [],
+ processes: processes.map(toProcess),
+ };
+}
+
+export interface ValidatedProjectIntent {
+ readonly document: ProjectIntentDocument;
+ readonly project: Project;
+}
+
+export function validateProjectIntent(
+ value: unknown,
+): Result {
+ const parsed = projectIntent.safeParse(value);
+ if (!parsed.success)
+ return {
+ ok: false,
+ diagnostics: parsed.error.issues.map((issue): Diagnostic => ({
+ code: "schema",
+ path: issue.path.map((segment) => `/${escape(segment)}`).join(""),
+ message: issue.message,
+ hint: "Correct the field against spec/v1/10-project-intent.md.",
+ })),
+ };
+ const { project, owner, applications } = parsed.data;
+ return {
+ ok: true,
+ value: {
+ document: parsed.data,
+ project: {
+ name: project,
+ owner,
+ applications: applications.map(toApplication),
+ },
+ },
+ };
+}
diff --git a/src/wire/project-intent/read.ts b/src/wire/project-intent/read.ts
new file mode 100644
index 0000000..5c9398e
--- /dev/null
+++ b/src/wire/project-intent/read.ts
@@ -0,0 +1,37 @@
+// Authored YAML in, a plain value out. Only the subset the model's files use is
+// read: one document, no anchors, aliases or explicit tags. Anything else is
+// refused rather than interpreted.
+import { isAlias, isNode, parseAllDocuments, visit } from "yaml";
+import type { Diagnostic, Result } from "../../domain/diagnostic.ts";
+
+const HINT =
+ "Write plain block or flow YAML: one document, no anchors, aliases or tags.";
+
+function refusal(message: string): Diagnostic {
+ return { code: "schema", path: "", message, hint: HINT };
+}
+
+export function readYaml(text: string): Result {
+ const documents = parseAllDocuments(text);
+ if (documents.length !== 1)
+ return {
+ ok: false,
+ diagnostics: [
+ refusal(`expected one YAML document, found ${documents.length}`),
+ ],
+ };
+ const [document] = documents as [(typeof documents)[number]];
+ const diagnostics = [...document.errors, ...document.warnings].map((error) =>
+ refusal(error.message),
+ );
+ visit(document, (_key, node) => {
+ if (isAlias(node)) diagnostics.push(refusal("an alias is not read"));
+ else if (isNode(node) && node.anchor !== undefined)
+ diagnostics.push(refusal("an anchor is not read"));
+ else if (isNode(node) && node.tag !== undefined)
+ diagnostics.push(refusal("an explicit tag is not read"));
+ });
+ return diagnostics.length > 0
+ ? { ok: false, diagnostics }
+ : { ok: true, value: document.toJS() as unknown };
+}
diff --git a/src/wire/project-intent/schema.ts b/src/wire/project-intent/schema.ts
new file mode 100644
index 0000000..64cc2bb
--- /dev/null
+++ b/src/wire/project-intent/schema.ts
@@ -0,0 +1,71 @@
+// The authoring shape of a Project Intent document, schemaVersion 1. It covers
+// the fields the minimal example uses; the rest of chapter 10 lands with #84.
+import { z } from "zod";
+import {
+ ALERT_CLASSES,
+ AUDIENCES,
+ CONTENT_POLICIES,
+ CUTOVERS,
+ LIFECYCLES,
+ MATCHES,
+ RUNTIMES,
+} from "../../domain/project-intent/vocabularies.ts";
+
+const text = z.string().min(1);
+const port = z.int().min(1).max(65535);
+
+const surfaceRef = { process: text, surface: text };
+
+const probe = z.strictObject({ path: text, port });
+
+const process = z.strictObject({
+ name: text,
+ lifecycle: z.enum(LIFECYCLES),
+ image: text,
+ runtime: z.enum(RUNTIMES),
+ provides: z.record(text, port).exactOptional(),
+ placement: z.strictObject({ memory: text, cpu: text }),
+ probes: z
+ .strictObject({
+ readiness: probe.exactOptional(),
+ liveness: probe.exactOptional(),
+ })
+ .exactOptional(),
+ startupBudget: text.exactOptional(),
+ cutover: z.enum(CUTOVERS),
+});
+
+const exposure = z.strictObject({
+ name: text,
+ host: text,
+ audience: z.enum(AUDIENCES),
+ contentPolicy: z.enum(CONTENT_POLICIES),
+ routes: z
+ .array(
+ z.strictObject({ path: text, match: z.enum(MATCHES), ...surfaceRef }),
+ )
+ .min(1),
+});
+
+const application = z.strictObject({
+ id: text,
+ observability: z
+ .strictObject({
+ alertClass: z.enum(ALERT_CLASSES),
+ scrape: z.strictObject({ ...surfaceRef, path: text }),
+ })
+ .exactOptional(),
+ exposure: z.array(exposure).exactOptional(),
+ processes: z.array(process).min(1),
+});
+
+export const projectIntent = z.strictObject({
+ apiVersion: z.literal("intent.jorisjonkers.dev/v1"),
+ kind: z.literal("Project"),
+ schemaVersion: z.string().regex(/^\d+\.\d+\.\d+$/),
+ project: text,
+ owner: text,
+ applications: z.array(application).min(1),
+});
+
+export type ProjectIntentDocument = z.output;
diff --git a/stryker.config.json b/stryker.config.json
new file mode 100644
index 0000000..94f1194
--- /dev/null
+++ b/stryker.config.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",
+ "testRunner": "vitest",
+ "vitest": {
+ "configFile": "vitest.mutation.config.ts"
+ },
+ "mutate": ["src/**/*.ts", "!src/cli/boundary.ts"],
+ "coverageAnalysis": "perTest",
+ "reporters": ["clear-text", "progress", "json"],
+ "jsonReporter": {
+ "fileName": "reports/mutation/mutation.json"
+ },
+ "tempDirName": ".stryker-tmp",
+ "thresholds": {
+ "high": 100,
+ "low": 100,
+ "break": 100
+ }
+}
diff --git a/test/model/project-intent.test.ts b/test/model/project-intent.test.ts
new file mode 100644
index 0000000..a4de65d
--- /dev/null
+++ b/test/model/project-intent.test.ts
@@ -0,0 +1,242 @@
+// REQ-021 (docs/requirements.md): an authored Project Intent file parses to its
+// committed intent oracle, and YAML or fields outside the language are refused.
+import { readFileSync } from "node:fs";
+import { join } from "node:path";
+import { describe, expect, it } from "vitest";
+import { canonicalJson, parseProjectIntent } from "../../src/index.ts";
+
+const EXAMPLES = join(
+ import.meta.dirname,
+ "..",
+ "..",
+ "spec",
+ "v1",
+ "examples",
+);
+const MINIMAL = readFileSync(
+ join(EXAMPLES, "minimal", "notes.project.yml"),
+ "utf8",
+);
+const ORACLE = readFileSync(
+ join(EXAMPLES, "minimal", "expected", "intent.json"),
+ "utf8",
+);
+
+const HEADER = `apiVersion: intent.jorisjonkers.dev/v1
+kind: Project
+schemaVersion: 1.0.0
+project: p
+owner: o
+`;
+
+const PROCESS = ` - name: worker
+ lifecycle: job
+ image: worker
+ runtime: none
+ placement: { memory: 64Mi, cpu: 10m }
+ cutover: recreate
+`;
+
+const withApplications = (applications: string): string =>
+ `${HEADER}applications:\n${applications}`;
+
+function refused(text: string) {
+ const result = parseProjectIntent(text);
+ if (result.ok) throw new Error("expected a refusal");
+ return result.diagnostics.map(({ code, path, message }) => ({
+ code,
+ path,
+ message,
+ }));
+}
+
+describe("parseProjectIntent", () => {
+ it("parses the minimal case to its committed intent oracle, byte for byte", () => {
+ const result = parseProjectIntent(MINIMAL);
+
+ expect(result.ok && canonicalJson(result.value.document)).toBe(ORACLE);
+ });
+
+ it("differs from the oracle when one authored field changes", () => {
+ const result = parseProjectIntent(MINIMAL.replace("cpu: 50m", "cpu: 60m"));
+
+ expect(result.ok && canonicalJson(result.value.document)).not.toBe(ORACLE);
+ });
+
+ it("maps the minimal case into the domain model", () => {
+ const result = parseProjectIntent(MINIMAL);
+
+ expect(result.ok && result.value.project).toStrictEqual({
+ name: "notes",
+ owner: "joris",
+ applications: [
+ {
+ id: "notes",
+ observability: {
+ alertClass: "business-hours",
+ scrape: { process: "notes-api", surface: "http", path: "/metrics" },
+ },
+ exposures: [
+ {
+ name: "public",
+ host: "notes.jorisjonkers.dev",
+ audience: "anonymous",
+ contentPolicy: "strict",
+ routes: [
+ {
+ path: "/",
+ match: "prefix",
+ process: "notes-api",
+ surface: "http",
+ },
+ ],
+ },
+ ],
+ processes: [
+ {
+ name: "notes-api",
+ lifecycle: "application",
+ image: "notes-api",
+ runtime: "node",
+ provides: new Map([["http", 8080]]),
+ placement: { memory: "256Mi", cpu: "50m" },
+ probes: {
+ readiness: { path: "/healthz/ready", port: 8080 },
+ liveness: { path: "/healthz/live", port: 8080 },
+ },
+ startupBudget: "20s",
+ cutover: "rolling",
+ },
+ ],
+ },
+ ],
+ });
+ });
+
+ it("maps an absent block to an empty one, and leaves an absent optional field absent", () => {
+ const result = parseProjectIntent(
+ withApplications(` - id: batch\n processes:\n${PROCESS}`),
+ );
+
+ expect(result.ok && result.value.project.applications).toStrictEqual([
+ {
+ id: "batch",
+ exposures: [],
+ processes: [
+ {
+ name: "worker",
+ lifecycle: "job",
+ image: "worker",
+ runtime: "none",
+ provides: new Map(),
+ placement: { memory: "64Mi", cpu: "10m" },
+ probes: {},
+ cutover: "recreate",
+ },
+ ],
+ },
+ ]);
+ expect(result.ok && canonicalJson(result.value.document)).not.toContain(
+ "startupBudget",
+ );
+ });
+
+ it.each([
+ ["no document", "", "expected one YAML document, found 0"],
+ [
+ "two documents",
+ `${HEADER}---\n${HEADER}`,
+ "expected one YAML document, found 2",
+ ],
+ ["an anchor", `${HEADER}applications: &a []\n`, "an anchor is not read"],
+ ["an alias", `x: &a 1\ny: *a\n`, "an alias is not read"],
+ [
+ "an explicit tag",
+ `${HEADER}applications: !!seq []\n`,
+ "an explicit tag is not read",
+ ],
+ ])("refuses %s rather than interpreting it", (_name, text, message) => {
+ expect(refused(text)).toContainEqual({ code: "schema", path: "", message });
+ });
+
+ it("refuses malformed YAML and a duplicated key at the document, before the schema runs", () => {
+ const batch = ` - id: batch\n processes:\n${PROCESS}`;
+
+ expect(
+ refused(withApplications(`${batch} - [\n`)).map(({ path }) => path),
+ ).toStrictEqual([""]);
+ expect(refused(`owner: again\n${withApplications(batch)}`)).toStrictEqual([
+ expect.objectContaining({ code: "schema", path: "" }),
+ ]);
+ });
+
+ it.each([
+ ["10.20.30", true],
+ ["v1.0.0", false],
+ ["1.0.0-rc.1", false],
+ ["1.0", false],
+ ])("reads schemaVersion %s as valid: %s", (version, valid) => {
+ const text = withApplications(
+ ` - id: batch\n processes:\n${PROCESS}`,
+ ).replace("schemaVersion: 1.0.0", `schemaVersion: "${version}"`);
+
+ expect(parseProjectIntent(text).ok).toBe(valid);
+ });
+
+ it("accepts several processes and refuses an application with none or an exposure with no route", () => {
+ expect(
+ parseProjectIntent(
+ withApplications(
+ ` - id: batch\n processes:\n${PROCESS}${PROCESS.replace("name: worker", "name: second")}`,
+ ),
+ ).ok,
+ ).toBe(true);
+ expect(
+ refused(
+ withApplications(
+ ` - id: batch\n processes: []\n - id: web\n exposure:\n - { name: e, host: h, audience: lan, contentPolicy: admin, routes: [] }\n processes:\n${PROCESS}`,
+ ),
+ ).map(({ path }) => path),
+ ).toStrictEqual([
+ "/applications/0/processes",
+ "/applications/1/exposure/0/routes",
+ ]);
+ });
+
+ it("refuses a field outside the language at its JSON Pointer", () => {
+ const diagnostics = refused(
+ withApplications(
+ ` - id: batch\n processes:\n${PROCESS.replace("runtime: none", "runtime: rust")} stateful: true\n`,
+ ),
+ );
+
+ expect(diagnostics.map(({ code, path }) => ({ code, path }))).toStrictEqual(
+ [
+ { code: "schema", path: "/applications/0/processes/0/runtime" },
+ { code: "schema", path: "/applications/0/processes/0" },
+ ],
+ );
+ });
+
+ it("escapes a pointer segment and refuses a port that is not an integer", () => {
+ const diagnostics = refused(
+ withApplications(
+ ` - id: batch\n processes:\n${PROCESS} provides: { "a/b~c": "8080" }\n`,
+ ),
+ );
+
+ expect(diagnostics.map(({ path }) => path)).toStrictEqual([
+ "/applications/0/processes/0/provides/a~1b~0c",
+ ]);
+ });
+
+ it("gives every diagnostic a hint", () => {
+ const diagnostics = ["", `${HEADER}applications: []\n`].flatMap((text) => {
+ const result = parseProjectIntent(text);
+ return result.ok ? [] : result.diagnostics;
+ });
+
+ expect(diagnostics).toHaveLength(2);
+ expect(diagnostics.every(({ hint }) => hint.length > 0)).toBe(true);
+ });
+});
diff --git a/test/mutation-contract.test.ts b/test/mutation-contract.test.ts
new file mode 100644
index 0000000..0bd1109
--- /dev/null
+++ b/test/mutation-contract.test.ts
@@ -0,0 +1,64 @@
+// REQ-022 (docs/requirements.md): the mutation gate over src/.
+import { readFileSync, readdirSync } from "node:fs";
+import { join, relative } from "node:path";
+import { describe, expect, it } from "vitest";
+
+const REPOSITORY = join(import.meta.dirname, "..");
+
+interface StrykerConfig {
+ readonly mutate: readonly string[];
+ readonly thresholds: { readonly break: number };
+ readonly vitest: { readonly configFile: string };
+}
+
+const config = JSON.parse(
+ readFileSync(join(REPOSITORY, "stryker.config.json"), "utf8"),
+) as StrykerConfig;
+
+// A suite that imports from src/ but cannot run in Stryker's sandbox, which
+// holds no git index, with the suite that kills its mutants instead.
+const OUTSIDE_THE_SANDBOX: Readonly> = {
+ "test/oracles.test.ts":
+ "lists oracle files from the git index; test/canonical-json.test.ts covers the writer",
+};
+
+function testFiles(dir: string): string[] {
+ return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
+ const path = join(dir, entry.name);
+ if (entry.isDirectory()) return testFiles(path);
+ return entry.name.endsWith(".test.ts") ? [relative(REPOSITORY, path)] : [];
+ });
+}
+
+describe("the mutation gate", () => {
+ it('mutates every module under src/ and breaks below the measured score, "break": 100', () => {
+ const text = readFileSync(join(REPOSITORY, "stryker.config.json"), "utf8");
+
+ expect(text).toContain('"break": 100');
+ expect(config.thresholds.break).toBe(100);
+ expect(config.mutate).toContain("src/**/*.ts");
+ });
+
+ it("runs every test file that imports from src/", () => {
+ const runner = readFileSync(
+ join(REPOSITORY, config.vitest.configFile),
+ "utf8",
+ );
+ const importing = testFiles(join(REPOSITORY, "test")).filter(
+ (file) =>
+ !(file in OUTSIDE_THE_SANDBOX) &&
+ /from "(\.\.\/)+src\//.test(
+ readFileSync(join(REPOSITORY, file), "utf8"),
+ ),
+ );
+
+ expect(importing.length).toBeGreaterThan(0);
+ for (const file of importing)
+ expect(
+ runner.includes(`"${file}"`) ||
+ (file.startsWith("test/model/") &&
+ runner.includes('"test/model/**/*.test.ts"')),
+ file,
+ ).toBe(true);
+ });
+});
diff --git a/tsconfig.json b/tsconfig.json
index 89bcbc3..b1a26f2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,6 +19,12 @@
"noEmit": true,
"skipLibCheck": true
},
- "include": ["src/**/*", "test/**/*", "scripts/**/*", "vitest.config.ts"],
+ "include": [
+ "src/**/*",
+ "test/**/*",
+ "scripts/**/*",
+ "vitest.config.ts",
+ "vitest.mutation.config.ts"
+ ],
"exclude": ["dist", "coverage", "node_modules"]
}
diff --git a/vitest.config.ts b/vitest.config.ts
index 30034bf..a1a1e08 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -23,16 +23,15 @@ export default defineConfig({
// A ratchet, per docs/adr/architecture/0101-coverage-is-a-ratchet.md:
// set from what the suite reaches, and only ever raised.
//
- // Measured 2026-09-14, after the first module under src/ (the canonical
- // JSON writer, at 100%): statements 786/799, branches 432/464,
- // functions 100%, lines 731/744. What is left uncovered is the one-line
- // command guard at the bottom of each gate and the branches for a tool
- // that cannot be started at all.
+ // Measured 2026-09-15, with the Project Intent parser under src/ at 100%:
+ // statements 832/845, branches 456/488, functions 100%, lines 776/789.
+ // What is left uncovered is the one-line command guard at the bottom of
+ // each gate and the branches for a tool that cannot be started at all.
thresholds: {
- statements: 98.37,
- branches: 93.1,
+ statements: 98.46,
+ branches: 93.44,
functions: 100,
- lines: 98.25,
+ lines: 98.35,
},
},
},
diff --git a/vitest.mutation.config.ts b/vitest.mutation.config.ts
new file mode 100644
index 0000000..d5d2c15
--- /dev/null
+++ b/vitest.mutation.config.ts
@@ -0,0 +1,13 @@
+// The suites that exercise src/, which is all Stryker mutates. The gate suites
+// read the git index and the tool binaries, neither of which exists in
+// Stryker's sandbox, and none of them reaches src/.
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ test: {
+ include: ["test/model/**/*.test.ts", "test/canonical-json.test.ts"],
+ setupFiles: ["./test/setup.ts"],
+ restoreMocks: true,
+ unstubEnvs: true,
+ },
+});