Skip to content

Add local ParparVM-backed JavaScript builder gated to Enterprise tier#5050

Merged
shai-almog merged 4 commits into
masterfrom
local-javascript-builder-enterprise-gate
May 27, 2026
Merged

Add local ParparVM-backed JavaScript builder gated to Enterprise tier#5050
shai-almog merged 4 commits into
masterfrom
local-javascript-builder-enterprise-gate

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • New JavaScriptBuilder (in maven/codenameone-maven-plugin/src/main/java/com/codename1/builders/) mirrors IPhoneBuilder / AndroidGradleBuilder. It stages cn1-core + java-runtime + the user app, layers parparvm-java-api.jar on top to override stale java.* / com.codename1.impl.* stubs, compiles Ports/JavaScriptPort/src/main/java, generates a ParparVMBootstrap-based launcher, and runs ParparVM's ByteCodeTranslator javascript. Output is a zip containing worker.js / port.js / browser_bridge.js / index.html, attached as the project's webapp classifier.
  • Enterprise-tier gate runs before any build work: honors (in order) the javascript.userLevel build hint in codenameone_settings.properties, the codename1.userLevel system property, and the CN1_USER_LEVEL env var. Accepts numeric ranks or symbolic tier names (trial / free / pro / enterprise / midsizeenterprise / bigcorp). Anything below enterprise (rank 12000, matching the BuildDaemon scheme) prints a clear licensing error pointing to https://www.codenameone.com/pricing.html and returns false.
  • CN1BuildMojo.doJavaScriptLocalBuild dispatches the new local-javascript build target. Provided-scope deps aren't transitive, so child modules that only depend on a common library don't see codenameone-core / java-runtime on their compile classpath — for local-JS builds the mojo now explicitly bundles those into the staged jar so ParparVM's translator sees every referenced class.
  • Undocumented on purpose: no archetype build-script wiring, no IDE shortcut. Discoverable via mvn cn1:build -Dcodename1.platform=javascript -Dcodename1.buildTarget=local-javascript.

Test plan

  • Plugin compiles with local-dev-javase profile (mvn -pl codenameone-maven-plugin -Plocal-dev-javase install)
  • local-javascript build with no user level → prints ERROR: The local JavaScript build is licensed only to Enterprise and higher tier users... and exits non-zero
  • CN1_USER_LEVEL=Pro → same enterprise-required error, builder log shows user-level=Pro (rank=11000, required>=12000)
  • CN1_USER_LEVEL=Enterprise → full end-to-end build on scripts/hellocodenameone/javascript, produces hellocodenameone-javascript-1.0-SNAPSHOT.zip (~7.9 MB) with HelloCodenameOne-js/{worker.js,port.js,browser_bridge.js,index.html,sw.js} and all theme/assets — 10:18 wall time
  • Smoke-test the generated bundle in a browser before broader rollout (separate from this PR — the builder wraps existing translator output, so any rendering regressions would already affect the script-based build-javascript-port-hellocodenameone.sh flow)

🤖 Generated with Claude Code

shai-almog and others added 2 commits May 27, 2026 18:04
JavaScriptBuilder mirrors the IPhoneBuilder/AndroidGradleBuilder pattern
for the new ParparVM-based JS port, replacing the ad-hoc build script.
Gated at the Enterprise user-level threshold (rank >= 12000) via the
javascript.userLevel build hint or the CN1_USER_LEVEL env var; lower
or unknown tiers see a clear licensing error before any work runs.
CN1BuildMojo dispatches local-javascript builds to the new builder and
explicitly bundles codenameone-core/java-runtime into the staged jar
since their provided scope is non-transitive on child modules.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…DEFAULT_ENCODING)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 116 screenshots: 116 matched.

Native Android coverage

  • 📊 Line coverage: 12.40% (7184/57937 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.11% (36124/357193), branch 4.28% (1447/33834), complexity 5.30% (1720/32479), method 9.21% (1401/15204), class 15.04% (318/2114)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 12.40% (7184/57937 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.11% (36124/357193), branch 4.28% (1447/33834), complexity 5.30% (1720/32479), method 9.21% (1401/15204), class 15.04% (318/2114)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1303.000 ms
Base64 CN1 encode 367.000 ms
Base64 encode ratio (CN1/native) 0.282x (71.8% faster)
Base64 native decode 1101.000 ms
Base64 CN1 decode 371.000 ms
Base64 decode ratio (CN1/native) 0.337x (66.3% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 47 screenshots: 47 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Compared 116 screenshots: 116 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 212 seconds

Build and Run Timing

Metric Duration
Simulator Boot 67000 ms
Simulator Boot (Run) 1000 ms
App Install 12000 ms
App Launch 3000 ms
Test Execution 361000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 855.000 ms
Base64 CN1 encode 1719.000 ms
Base64 encode ratio (CN1/native) 2.011x (101.1% slower)
Base64 native decode 667.000 ms
Base64 CN1 decode 1244.000 ms
Base64 decode ratio (CN1/native) 1.865x (86.5% slower)
Base64 SIMD encode 500.000 ms
Base64 encode ratio (SIMD/native) 0.585x (41.5% faster)
Base64 encode ratio (SIMD/CN1) 0.291x (70.9% faster)
Base64 SIMD decode 667.000 ms
Base64 decode ratio (SIMD/native) 1.000x (0.0% slower)
Base64 decode ratio (SIMD/CN1) 0.536x (46.4% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 71.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.155x (84.5% faster)
Image applyMask (SIMD off) 228.000 ms
Image applyMask (SIMD on) 214.000 ms
Image applyMask ratio (SIMD on/off) 0.939x (6.1% faster)
Image modifyAlpha (SIMD off) 178.000 ms
Image modifyAlpha (SIMD on) 173.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.972x (2.8% faster)
Image modifyAlpha removeColor (SIMD off) 277.000 ms
Image modifyAlpha removeColor (SIMD on) 229.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.827x (17.3% faster)
Image PNG encode (SIMD off) 1983.000 ms
Image PNG encode (SIMD on) 1176.000 ms
Image PNG encode ratio (SIMD on/off) 0.593x (40.7% faster)
Image JPEG encode 703.000 ms

buildTarget is a @parameter(required = true), so the defensive
`buildTarget != null` in the local-JS check was misleading SpotBugs
into flagging the existing isLocalBuildTarget(buildTarget) call as a
potential null dereference.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

iOS Metal screenshot updates

Compared 114 screenshots: 113 matched, 1 updated.

  • BrowserComponent — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    BrowserComponent
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as BrowserComponent.png in workflow artifacts.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 318 seconds

Build and Run Timing

Metric Duration
Simulator Boot 100000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 13000 ms
Test Execution 322000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 617.000 ms
Base64 CN1 encode 1220.000 ms
Base64 encode ratio (CN1/native) 1.977x (97.7% slower)
Base64 native decode 284.000 ms
Base64 CN1 decode 1164.000 ms
Base64 decode ratio (CN1/native) 4.099x (309.9% slower)
Base64 SIMD encode 649.000 ms
Base64 encode ratio (SIMD/native) 1.052x (5.2% slower)
Base64 encode ratio (SIMD/CN1) 0.532x (46.8% faster)
Base64 SIMD decode 679.000 ms
Base64 decode ratio (SIMD/native) 2.391x (139.1% slower)
Base64 decode ratio (SIMD/CN1) 0.583x (41.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 132.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.076x (92.4% faster)
Image applyMask (SIMD off) 229.000 ms
Image applyMask (SIMD on) 156.000 ms
Image applyMask ratio (SIMD on/off) 0.681x (31.9% faster)
Image modifyAlpha (SIMD off) 198.000 ms
Image modifyAlpha (SIMD on) 158.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.798x (20.2% faster)
Image modifyAlpha removeColor (SIMD off) 197.000 ms
Image modifyAlpha removeColor (SIMD on) 126.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.640x (36.0% faster)
Image PNG encode (SIMD off) 1364.000 ms
Image PNG encode (SIMD on) 1079.000 ms
Image PNG encode ratio (SIMD on/off) 0.791x (20.9% faster)
Image JPEG encode 716.000 ms

Picker.startEditingAsync() never returns control on the JS port — the
lightweight popup never settles into the findButtonByText scan state
the cancel/done scenario expects, so the inner UITimer callbacks never
fire fail()/done() and the JS screenshot suite hangs for the full
browser-lifetime budget (TOP_BLOCKER=unknown|none|none) on this single
test.

The suite-level skip in Cn1ssDeviceRunner.shouldForceTimeoutInHtml5
doesn't catch this because it sees an unexpected platform name on the
JS port. CN.getPlatformName() reliably reports "HTML5" here, so
self-skip from runTest() and call done() to advance the suite.

Re-applies the fix from e0cd604 that was reverted in e3dd0c9
alongside unrelated diag cleanup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog merged commit b91f667 into master May 27, 2026
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant