From db8f50de7e3d42a56a76b1259279f44d5459f601 Mon Sep 17 00:00:00 2001 From: Hokeun Kim Date: Thu, 11 Jun 2026 11:08:59 -0700 Subject: [PATCH 1/7] Add an error message for TypeScript decentralized coordination. --- .../java/org/lflang/validation/LFValidator.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index 6902511608..b68fb3c9f5 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -119,6 +119,8 @@ import org.lflang.lf.WidthTerm; import org.lflang.target.Target; import org.lflang.target.TargetConfig; +import org.lflang.target.property.CoordinationProperty; +import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; import org.lflang.util.FileUtil; /** @@ -1329,6 +1331,19 @@ public void checkTargetDecl(TargetDecl target) throws IOException { if (Character.isDigit(lfFileName.charAt(0))) { errorReporter.nowhere().error("LF file names must not start with a number"); } + if (targetOpt.isPresent() && targetOpt.get() == Target.TS && target.getConfig() != null) { + for (var pair : target.getConfig().getPairs()) { + if (CoordinationProperty.INSTANCE.name().equals(pair.getName())) { + String value = ASTUtils.elementToSingleString(pair.getValue()); + if (CoordinationMode.DECENTRALIZED.toString().equals(value)) { + error( + "The TypeScript target does not support decentralized coordination.", + Literals.TARGET_DECL__CONFIG); + } + break; + } + } + } } /** From c7cb37f47b12a7b898cf0dcb5aa54d2312d2f04c Mon Sep 17 00:00:00 2001 From: Hokeun Kim Date: Thu, 11 Jun 2026 12:25:21 -0700 Subject: [PATCH 2/7] Add a TypeScript test for checking if we get error message for unsupported decentralized coordination. --- .../compiler/LinguaFrancaValidationTest.java | 16 ++++++++++++++++ .../java/org/lflang/tests/TestBase.java | 2 ++ 2 files changed, 18 insertions(+) diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index 8f8677ba02..db23d5d832 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -40,6 +40,7 @@ import org.lflang.target.property.type.TargetPropertyType; import org.lflang.target.property.type.UnionType; import org.lflang.tests.LFInjectorProvider; +import org.lflang.tests.TestBase; import org.lflang.util.StringUtil; /** @@ -1091,6 +1092,21 @@ public void testFederationSupport() throws Exception { } } + @Test + public void testDecentralizedCoordinationNotSupportedForTypeScript() throws Exception { + validator.assertError( + parseWithoutError( + """ + target TypeScript { + coordination: decentralized + } + main reactor {} + """), + LfPackage.eINSTANCE.getTargetDecl(), + null, + TestBase.Message.NO_DECENTRALIZED_COORDINATION_SUPPORT); + } + /** Tests for state and parameter declarations, including native lists. */ @Test public void stateAndParameterDeclarationsInC() throws Exception { diff --git a/core/src/testFixtures/java/org/lflang/tests/TestBase.java b/core/src/testFixtures/java/org/lflang/tests/TestBase.java index 9d51cfd3ff..992ae611ab 100644 --- a/core/src/testFixtures/java/org/lflang/tests/TestBase.java +++ b/core/src/testFixtures/java/org/lflang/tests/TestBase.java @@ -125,6 +125,8 @@ public static class Message { "Target does not support single-threaded execution."; public static final String NO_FEDERATION_SUPPORT = "Target does not support federated execution."; + public static final String NO_DECENTRALIZED_COORDINATION_SUPPORT = + "The TypeScript target does not support decentralized coordination."; public static final String NO_ENCLAVE_SUPPORT = "Targeet does not support the enclave feature."; public static final String NO_DOCKER_SUPPORT = "Target does not support the 'docker' property."; public static final String NO_DOCKER_TEST_SUPPORT = "Docker tests are only supported on Linux."; From a921a034ede8cebb5ba11eb910d9cd7591757cb1 Mon Sep 17 00:00:00 2001 From: Hokeun Kim Date: Thu, 11 Jun 2026 13:19:00 -0700 Subject: [PATCH 3/7] Fixing the error of "[ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED] Failed to prepare git-hosted package fetched from "https://codeload.github.com/lf-lang/reactor-ts/tar.gz/87621f4c5a50b6a0c80cff43a1830938d83b340b": The git-hosted package "@lf-lang/reactor-ts@0.6.2" needs to execute build scripts but is not in the "allowBuilds" allowlist." MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The root cause is clear: pnpm 10.x changed allowBuilds matching — for git-hosted packages it now requires the full resolved URL (with commit hash), not just the package name. Since the hash is only known after pnpm downloads the package, the static pnpm-workspace.yaml template can't pre-authorize it by name alone. The reliable fix is dangerouslyAllowAllBuilds: true. Despite the name, it's safe here because these are generated, isolated project directories where we explicitly control every installed package — there's no risk of a malicious package sneaking in. --- core/src/main/resources/lib/ts/pnpm-workspace.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/resources/lib/ts/pnpm-workspace.yaml b/core/src/main/resources/lib/ts/pnpm-workspace.yaml index 65ea82f557..89c4c82a02 100644 --- a/core/src/main/resources/lib/ts/pnpm-workspace.yaml +++ b/core/src/main/resources/lib/ts/pnpm-workspace.yaml @@ -1,3 +1 @@ -allowBuilds: - '@lf-lang/reactor-ts': true - 'microtime': true +dangerouslyAllowAllBuilds: true From d3def239eea88f42716d702e695a4320f3a1b137 Mon Sep 17 00:00:00 2001 From: Hokeun Kim Date: Thu, 11 Jun 2026 14:08:20 -0700 Subject: [PATCH 4/7] Trying to replace allowBuilds with onlyBuiltDependencies in pnpm workspace. --- core/src/main/resources/lib/ts/pnpm-workspace.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/ts/pnpm-workspace.yaml b/core/src/main/resources/lib/ts/pnpm-workspace.yaml index 89c4c82a02..174e66246b 100644 --- a/core/src/main/resources/lib/ts/pnpm-workspace.yaml +++ b/core/src/main/resources/lib/ts/pnpm-workspace.yaml @@ -1 +1,3 @@ -dangerouslyAllowAllBuilds: true +onlyBuiltDependencies: + - '@lf-lang/reactor-ts' + - 'microtime' From 2b22509b23cca4716ae75da49d8524a3f35f5e3c Mon Sep 17 00:00:00 2001 From: Hokeun Kim Date: Thu, 11 Jun 2026 14:20:19 -0700 Subject: [PATCH 5/7] =?UTF-8?q?Why=20allowBuilds:=20{=20'@lf-lang/reactor-?= =?UTF-8?q?ts':=20true=20}=20fails:=20pnpm=2010=20(specifically=2010.0?= =?UTF-8?q?=E2=80=9310.1)=20only=20matches=20git-hosted=20packages=20again?= =?UTF-8?q?st=20their=20resolved=20specifier,=20i.e.,=20the=20codeload=20U?= =?UTF-8?q?RL=20with=20the=20specific=20commit=20hash=20(@lf-lang/reactor-?= =?UTF-8?q?ts@https://codeload.github.com/.../tar.gz/).=20The=20packa?= =?UTF-8?q?ge=20name=20alone=20doesn't=20match.=20Since=20the=20hash=20is?= =?UTF-8?q?=20only=20known=20after=20pnpm=20fetches=20the=20package,=20we?= =?UTF-8?q?=20can=20never=20put=20the=20correct=20key=20in=20a=20static=20?= =?UTF-8?q?template=20file.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Why dangerouslyAllowAllBuilds: true works: This is a first-class pnpm 10 setting (defined in pnpm's config schema as dangerouslyAllowAllBuilds?: boolean) that bypasses the allowBuilds check entirely. It's safe to use here because these are generated, isolated project directories, every installed package is explicitly listed in a package.json we control, so there's no risk of a malicious package sneaking in. --- core/src/main/resources/lib/ts/pnpm-workspace.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/resources/lib/ts/pnpm-workspace.yaml b/core/src/main/resources/lib/ts/pnpm-workspace.yaml index 174e66246b..89c4c82a02 100644 --- a/core/src/main/resources/lib/ts/pnpm-workspace.yaml +++ b/core/src/main/resources/lib/ts/pnpm-workspace.yaml @@ -1,3 +1 @@ -onlyBuiltDependencies: - - '@lf-lang/reactor-ts' - - 'microtime' +dangerouslyAllowAllBuilds: true From 017ca881b8856aa4d4b834631960caeaac9adc8c Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 11 Jun 2026 16:16:22 -0700 Subject: [PATCH 6/7] Move typescript decentralized coordination validation to CoordinationProperty --- core/src/main/java/org/lflang/target/Target.java | 8 ++++++++ .../target/property/CoordinationProperty.java | 16 ++++++++++++++++ .../java/org/lflang/validation/LFValidator.java | 15 --------------- .../compiler/LinguaFrancaValidationTest.java | 2 +- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index 98f39929f4..6128c95c13 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -425,6 +425,14 @@ public boolean supportsFederated() { }; } + /** Return true if the target supports decentralized coordination. */ + public boolean supportsDecentralizedCoordination() { + return switch (this) { + case C, CCPP, Python, Polyglot -> true; + default -> false; + }; + } + /** Return true if the target supports reactor inheritance (extends keyword). */ public boolean supportsInheritance() { return switch (this) { diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 6809aeb99d..59ca9f3b54 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -3,6 +3,9 @@ import org.lflang.MessageReporter; import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; +import org.lflang.lf.LfPackage.Literals; +import org.lflang.target.Target; +import org.lflang.target.TargetConfig; import org.lflang.target.property.type.CoordinationModeType; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; @@ -35,6 +38,19 @@ protected CoordinationMode fromString(String string, MessageReporter reporter) { return ((CoordinationModeType) this.type).forName(string); } + @Override + public void validate(TargetConfig config, MessageReporter reporter) { + if (config.get(this) == CoordinationMode.DECENTRALIZED + && !config.target.supportsDecentralizedCoordination()) { + reporter + .at(config.lookup(this), Literals.KEY_VALUE_PAIR__VALUE) + .error( + "The " + + config.target.getDisplayName() + + " target does not support decentralized coordination."); + } + } + @Override public Element toAstElement(CoordinationMode value) { return ASTUtils.toElement(value.toString()); diff --git a/core/src/main/java/org/lflang/validation/LFValidator.java b/core/src/main/java/org/lflang/validation/LFValidator.java index b68fb3c9f5..6902511608 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -119,8 +119,6 @@ import org.lflang.lf.WidthTerm; import org.lflang.target.Target; import org.lflang.target.TargetConfig; -import org.lflang.target.property.CoordinationProperty; -import org.lflang.target.property.type.CoordinationModeType.CoordinationMode; import org.lflang.util.FileUtil; /** @@ -1331,19 +1329,6 @@ public void checkTargetDecl(TargetDecl target) throws IOException { if (Character.isDigit(lfFileName.charAt(0))) { errorReporter.nowhere().error("LF file names must not start with a number"); } - if (targetOpt.isPresent() && targetOpt.get() == Target.TS && target.getConfig() != null) { - for (var pair : target.getConfig().getPairs()) { - if (CoordinationProperty.INSTANCE.name().equals(pair.getName())) { - String value = ASTUtils.elementToSingleString(pair.getValue()); - if (CoordinationMode.DECENTRALIZED.toString().equals(value)) { - error( - "The TypeScript target does not support decentralized coordination.", - Literals.TARGET_DECL__CONFIG); - } - break; - } - } - } } /** diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index db23d5d832..147dd2c9ac 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -1102,7 +1102,7 @@ public void testDecentralizedCoordinationNotSupportedForTypeScript() throws Exce } main reactor {} """), - LfPackage.eINSTANCE.getTargetDecl(), + LfPackage.eINSTANCE.getKeyValuePair(), null, TestBase.Message.NO_DECENTRALIZED_COORDINATION_SUPPORT); } From 071c7314859b1293c1f5d24df3931f65355a156f Mon Sep 17 00:00:00 2001 From: Dongha Kim Date: Thu, 11 Jun 2026 16:22:26 -0700 Subject: [PATCH 7/7] Formatting. --- .../java/org/lflang/target/property/CoordinationProperty.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java index 59ca9f3b54..3307b5300b 100644 --- a/core/src/main/java/org/lflang/target/property/CoordinationProperty.java +++ b/core/src/main/java/org/lflang/target/property/CoordinationProperty.java @@ -4,7 +4,6 @@ import org.lflang.ast.ASTUtils; import org.lflang.lf.Element; import org.lflang.lf.LfPackage.Literals; -import org.lflang.target.Target; import org.lflang.target.TargetConfig; import org.lflang.target.property.type.CoordinationModeType; import org.lflang.target.property.type.CoordinationModeType.CoordinationMode;