diff --git a/.coderabbit.yml b/.coderabbit.yml index d8ae73c..c85d143 100644 --- a/.coderabbit.yml +++ b/.coderabbit.yml @@ -1,6 +1,27 @@ language: "en" reviews: profile: "chill" + system_instructions: | + # AGENTS_START + # Instructions for AI Coding Agent + + You are an expert developer assistant integrated into Acode. You MUST strictly follow these rules: + + ## Core Restriction: Passive Mode + - **READ-ONLY BY DEFAULT:** You are here to assist and provide suggestions. You are FORBIDDEN from modifying, refactoring, or applying changes to any existing code unless I explicitly command you to "apply" or "implement" the changes. + - **NO AUTOCORRECT:** Do not touch code that is already working. If you see code you think is "wrong" but it wasn't the target of my query, leave it alone. + - **READ FIRST:** When I ask you to read a file or reference instructions, strictly provide analysis or answers based on that reading. DO NOT generate code or modify files until I specifically ask for it. + + ## Code Style & Formatting + - **Indentation:** ALWAYS use 2 spaces for indentation. + - **Clean Code:** Keep code concise. No unnecessary comments, no "filler" code. + - **Strictly Stable:** Use ONLY stable Rust features. NO `unstable` or `nightly` syntax. + + ## Behavior + - If a request is ambiguous, ASK ME before doing anything. + - Do not perform "fix-all" or "auto-refactor" tasks unless I explicitly define the scope of the fix. + + # AGENTS_END request_review_trigger: exclude_labels: - "wip" diff --git a/.gitattributes b/.gitattributes index 6295757..5905911 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,4 +7,5 @@ /ts/src/generated/** linguist-detectable=false /types/** linguist-detectable=false /.testings/** linguist-detectable=false +*.sh linguist-detectable=false *.d.ts linguist-documentation=true diff --git a/.github/scripts/ci/deep_audit.sh b/.github/scripts/ci/deep_audit.sh new file mode 100644 index 0000000..6f1ddf8 --- /dev/null +++ b/.github/scripts/ci/deep_audit.sh @@ -0,0 +1,20 @@ +FILES=$(find . -type d \( -name "target" -o -name "node_modules" -o -name "dist" -o -name "generated" \) -prune -o -type f \( -name "*.ts" -o -name "*.rs" \) -print) + +if [ -z "$FILES" ]; then + echo "There are no files to check." + exit 0 +fi + +MISSING_COPYRIGHT=$(echo "$FILES" | xargs grep -L "Copyright") +if [ -n "$MISSING_COPYRIGHT" ]; then + echo "This file needs a Copyright header:" + echo "$MISSING_COPYRIGHT" + exit 1 +fi + +JUNK_CHECK=$(echo "$FILES" | xargs awk 'FNR==1 && /^\/\/ [A-Za-z0-9_-]+\.(ts|rs)$/ {print FILENAME}') +if [ -n "$JUNK_CHECK" ]; then + echo "The first line is just the file name (Junk):" + echo "$JUNK_CHECK" + exit 1 +fi \ No newline at end of file diff --git a/.github/scripts/nightly/conmit_push.sh b/.github/scripts/nightly/conmit_push.sh new file mode 100644 index 0000000..135f492 --- /dev/null +++ b/.github/scripts/nightly/conmit_push.sh @@ -0,0 +1,13 @@ +git config user.name "github-actions[bot]" +git config user.email "github-actions[bot]@users.noreply.github.com" + +git add Cargo.toml +[ -f "package.json" ] && git add package.json + +if ! git diff --cached --quiet; then + git commit -m "chore: nightly release ${{ steps.versioning.outputs.version_clean }}" + git tag ${{ steps.versioning.outputs.version_tag }} + git push origin main --tags +else + echo "No file changes, skip push." +fi \ No newline at end of file diff --git a/.github/scripts/nightly/create_release.sh b/.github/scripts/nightly/create_release.sh new file mode 100644 index 0000000..cd2330c --- /dev/null +++ b/.github/scripts/nightly/create_release.sh @@ -0,0 +1,38 @@ +PREV_TAG=$(git describe --tags --abbrev=0 --exclude="${{ steps.versioning.outputs.version_tag }}" 2>/dev/null || echo "") + +LOGS=$(git log $PREV_TAG..HEAD --pretty=format:"%s") + +FEAT=$(echo "$LOGS" | grep -E "^feat(\(.*\))?: " | sed -E 's/^feat(\(.*\))?: /- /' || echo "") +FIX=$(echo "$LOGS" | grep -E "^fix(\(.*\))?: " | sed -E 's/^fix(\(.*\))?: /- /' || echo "") + +COMPARE_LINK="https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${{ steps.versioning.outputs.version_tag }}" + +{ + echo "## What's Changed" + echo "Compare: $COMPARE_LINK" + echo "" + + if [ -n "$FEAT" ]; then + echo "### Features" + echo "$FEAT" + echo "" + fi + + if [ -n "$FIX" ]; then + echo "### Fixes" + echo "$FIX" + echo "" + fi + + if [ -z "$FEAT" ] && [ -z "$FIX" ]; then + echo "_No significant changes in this build._" + echo "" + fi + + echo "***Nightly Owl has fallen out of bed tonight!***" +} > release_notes.md + +gh release create "${{ steps.versioning.outputs.version_tag }}" \ + --title "Nightly Build ${{ steps.versioning.outputs.version_tag }}" \ + --notes-file release_notes.md \ + --prerelease \ No newline at end of file diff --git a/.github/scripts/nightly/filter_significant.sh b/.github/scripts/nightly/filter_significant.sh new file mode 100644 index 0000000..cb01b29 --- /dev/null +++ b/.github/scripts/nightly/filter_significant.sh @@ -0,0 +1,17 @@ +PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") + +if [ -n "$PREV_TAG" ]; then + LOGS=$(git log $PREV_TAG..HEAD --pretty=format:"%s") +else + LOGS=$(git log --pretty=format:"%s") +fi + +HAS_SIGNIFICANT=$(echo "$LOGS" | grep -E "^(feat|fix)(\(.*\))?:" || echo "") + +if [ -n "$HAS_SIGNIFICANT" ]; then + echo "significant=true" >> $GITHUB_OUTPUT + echo "There are significant changes, continue!" +else + echo "significant=false" >> $GITHUB_OUTPUT + echo "No feat/fix, skip build." +fi \ No newline at end of file diff --git a/.github/scripts/nightly/generate_version.sh b/.github/scripts/nightly/generate_version.sh new file mode 100644 index 0000000..54d5bfa --- /dev/null +++ b/.github/scripts/nightly/generate_version.sh @@ -0,0 +1,15 @@ +RAW_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") + +CLEAN_VERSION=${RAW_TAG#v} + +BASE_VERSION=${CLEAN_VERSION%-nightly.*} + +COMMIT_HASH=$(git rev-parse --short HEAD) +DATE=$(date +'%Y%m%d') # Format: 20260625 + +VERSION_CLEAN="${BASE_VERSION}-nightly.${DATE}.${COMMIT_HASH}" +VERSION_TAG="v${VERSION_CLEAN}" + +echo "version_clean=$VERSION_CLEAN" >> $GITHUB_OUTPUT +echo "version_tag=$VERSION_TAG" >> $GITHUB_OUTPUT +echo "Generated version: $VERSION_CLEAN (Tag: $VERSION_TAG)" \ No newline at end of file diff --git a/.github/scripts/nightly/production_workflow.sh b/.github/scripts/nightly/production_workflow.sh new file mode 100644 index 0000000..09e3c39 --- /dev/null +++ b/.github/scripts/nightly/production_workflow.sh @@ -0,0 +1,11 @@ +TODAY=$(date -u +'%Y-%m-%d') + +RUNS=$(gh run list --workflow production.yml --limit 1 --json createdAt --jq '.[0].createdAt') + +if [[ "$RUNS" == "$TODAY"* ]]; then + echo "Production is underway today: $RUNS" + echo "should_skip=true" >> $GITHUB_OUTPUT +else + echo "Production has not started today." + echo "should_skip=false" >> $GITHUB_OUTPUT +fi \ No newline at end of file diff --git a/.github/scripts/nightly/update_files.sh b/.github/scripts/nightly/update_files.sh new file mode 100644 index 0000000..bd7a9d6 --- /dev/null +++ b/.github/scripts/nightly/update_files.sh @@ -0,0 +1,10 @@ +VERSION="${{ steps.versioning.outputs.version_clean }}" + +sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml + +if [ -f "package.json" ]; then + jq --arg ver "$VERSION" '.version = $ver' package.json > temp.json && mv temp.json package.json +fi + +rustup toolchain install stable --profile minimal +cargo update \ No newline at end of file diff --git a/.github/scripts/production/create_release.sh b/.github/scripts/production/create_release.sh new file mode 100644 index 0000000..1b6fa32 --- /dev/null +++ b/.github/scripts/production/create_release.sh @@ -0,0 +1,10 @@ +VERSION="${{ github.event.inputs.version }}" +git config user.name "github-actions[bot]" +git config user.email "github-actions[bot]@users.noreply.github.com" + +git tag "v$VERSION" +git push origin "v$VERSION" + +gh release create "v$VERSION" \ + --title "Release $VERSION" \ + --notes-file release_notes.md \ No newline at end of file diff --git a/.github/scripts/production/generate_release_notes.sh b/.github/scripts/production/generate_release_notes.sh new file mode 100644 index 0000000..d7a4e32 --- /dev/null +++ b/.github/scripts/production/generate_release_notes.sh @@ -0,0 +1,22 @@ +VERSION="${{ github.event.inputs.version }}" + +LAST_STABLE=$(git tag --sort=-creatordate | grep -v "nightly" | head -n 1 || echo "") + +NIGHTLIES=$(git tag | grep "nightly" | sort -V) + +if [ -n "$LAST_STABLE" ]; then + FINAL_NIGHTLIES=$(echo -e "$NIGHTLIES\n$LAST_STABLE" | sort -V | sed -n "/$LAST_STABLE/,\$p" | grep -v "$LAST_STABLE") +else + FINAL_NIGHTLIES="$NIGHTLIES" +fi + +{ + echo "Release based on Changelogs:" + if [ -n "$FINAL_NIGHTLIES" ]; then + echo "$FINAL_NIGHTLIES" | sed 's/^/* /' + else + echo "* No previous nightly builds." + fi + echo "" + echo "***Lion Owl caught in apple net!***" +} > release_notes.md \ No newline at end of file diff --git a/.github/scripts/production/validate_version_tag.sh b/.github/scripts/production/validate_version_tag.sh new file mode 100644 index 0000000..a8250e3 --- /dev/null +++ b/.github/scripts/production/validate_version_tag.sh @@ -0,0 +1,15 @@ +VERSION="$1" +if [ -z "$VERSION" ]; then + echo "Error: Version argument is required." + exit 1 +fi +if git rev-parse "refs/tags/v$VERSION" >/dev/null 2>&1; then + echo "Error: Versi $VERSION sudah ada tag-nya! Ganti versi dulu." + exit 1 +fi + +FILE_VERSION=$(jq -r .version package.json) +if [ "$FILE_VERSION" != "$VERSION" ]; then + echo "Error: Versi di package.json ($FILE_VERSION) tidak sama dengan input ($VERSION)." + exit 1 +fi \ No newline at end of file diff --git a/.github/scripts/publish/build_release.sh b/.github/scripts/publish/build_release.sh new file mode 100644 index 0000000..c654595 --- /dev/null +++ b/.github/scripts/publish/build_release.sh @@ -0,0 +1,15 @@ +if [[ "$PLATFORM" == *"android"* ]]; then + cargo build --release --target $TARGET +elif [[ "$PLATFORM" == *"musl"* ]]; then + if [ ! -f "./cross" ]; then + curl -L https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-musl.tar.gz | tar xz + chmod +x cross + fi + RUSTFLAGS="-C target-feature=-crt-static" ./cross build --release --target $TARGET +else + if [ ! -f "./cross" ]; then + curl -L https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-musl.tar.gz | tar xz + chmod +x cross + fi + ./cross build --release --target $TARGET +fi diff --git a/.github/scripts/publish/publish_crates.sh b/.github/scripts/publish/publish_crates.sh new file mode 100644 index 0000000..2154c68 --- /dev/null +++ b/.github/scripts/publish/publish_crates.sh @@ -0,0 +1,5 @@ +if [[ "${{ github.event.inputs.version_override }}" == *"nightly"* ]]; then + cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} --allow-dirty --no-verify +else + cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} --allow-dirty +fi \ No newline at end of file diff --git a/.github/scripts/publish/publish_npm.sh b/.github/scripts/publish/publish_npm.sh new file mode 100644 index 0000000..9220ee6 --- /dev/null +++ b/.github/scripts/publish/publish_npm.sh @@ -0,0 +1,132 @@ +VERSION="${{ github.event.inputs.version_override }}" +if [ -z "$VERSION" ]; then + RAW_VERSION="${{ github.event.release.tag_name }}" + VERSION=${RAW_VERSION#v} +fi + +if [ -z "$VERSION" ]; then + echo "Fetch latest release tag from GitHub API..." + LATEST_TAG=$(gh release view --json tagName --template '{{.tagName}}' 2>/dev/null || echo "") + if [ -n "$LATEST_TAG" ]; then + VERSION=${LATEST_TAG#v} + echo "Successfully resolved latest release version: $VERSION" + else + echo "No release found via API. Falling back to Cargo.toml..." + VERSION=$(grep '^version =' Cargo.toml | head -n1 | cut -d '"' -f2) + fi +fi + +echo "Final Publishing Version: $VERSION" + +TAG="latest" +if [[ "$VERSION" =~ -(proto|alpha|beta|rc) ]]; then TAG="next"; fi +echo "Using NPM Tag: $TAG" + +PLATFORMS=( + "binary-linux-x64|linux-x64|index.linux.node|x64" + "binary-linux-arm64|linux-arm64|index.linux-arm64.node|arm64" + "binary-linux-ia32|linux-ia32|index.linux32.node|ia32" + "binary-win32-x64|win32-x64|index.win.node|x64" + "binary-win32-ia32|win32-ia32|index.win32.node|ia32" + "binary-darwin-x64|darwin-x64|index.darwin.node|x64" + "binary-android-arm64|android-arm64|index.android.node|arm64" + "binary-android-arm|android-arm|index.android32.node|arm" + "binary-linux-musl-x64|linux-musl-x64|index.musl-x64.node|x64" + "binary-linux-musl-arm64|linux-musl-arm64|index.musl-arm64.node|arm64" + "binary-linux-musl-ia32|linux-musl-ia32|index.musl-ia32.node|ia32" + "binary-freebsd-x64|freebsd-x64|index.freebsd.node|x64" + "binary-browser-wasm|browser-wasm|index.wasm|wasm" +) + +sudo apt-get install -y jq + +for item in "${PLATFORMS[@]}"; do + IFS="|" read -r ARTIFACT PLATFORM BIN_NAME CPU <<< "$item" + PKG_NAME="@lightvm/core-$PLATFORM" + OS_VAL="${PLATFORM%-*}" + mkdir -p "publish/$PLATFORM" + + if [[ "$PLATFORM" == "browser-wasm" ]]; then + echo "=== Isi dari binaries/$ARTIFACT ===" + ls -la "binaries/$ARTIFACT" + + cp -r "binaries/$ARTIFACT"/. "publish/$PLATFORM/" + + cd "publish/$PLATFORM" + + WASM_JS_FILE=$(find . -maxdepth 1 -name "*.js" ! -name "index.js" | head -n 1) + if [ -n "$WASM_JS_FILE" ]; then + mv "$WASM_JS_FILE" "index.js" + fi + + WASM_BG_FILE=$(find . -maxdepth 1 -name "*_bg.wasm" | head -n 1) + if [ -n "$WASM_BG_FILE" ]; then + mv "$WASM_BG_FILE" "index.wasm" + fi + + cd ../.. + + MAIN_FIELD="index.js" + FILES_FIELD=$(jq -nc '["index.wasm", "index.js", "*.d.ts", "README.md", "LICENSE"]') + else + find "binaries/$ARTIFACT" -type f \( -name "*.node" -o -name "*.dll" -o -name "*.so" -o -name "*.dylib" \) -exec cp {} "publish/$PLATFORM/$BIN_NAME" \; + MAIN_FIELD="$BIN_NAME" + FILES_FIELD=$(jq -nc --arg bin "$BIN_NAME" '[$bin, "README.md", "LICENSE"]') + fi + + cp -f README.md "publish/$PLATFORM/" || true + cp -f LICENSE "publish/$PLATFORM/" || true + + jq -n \ + --arg name "$PKG_NAME" \ + --arg ver "$VERSION" \ + --arg os "$OS_VAL" \ + --arg cpu "$CPU" \ + --arg main "$MAIN_FIELD" \ + --argjson files "$FILES_FIELD" \ + '{ + name: $name, + version: $ver, + os: [$os], + cpu: [$cpu], + main: $main, + files: $files, + publishConfig: { access: "public" }, + license: "Apache-2.0" + }' > "publish/$PLATFORM/package.json" + + cd "publish/$PLATFORM" + + if [[ "${{ github.event_name }}" == "release" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "$VERSION" == *"nightly"* ]]; then + echo "Event Rilisan/Nightly Terdeteksi: Menjalankan Real Publish ke NPM..." + npm publish --tag $TAG --access public || echo "Skip existing" + else + echo "Event Manual (Non-Nightly) Terdeteksi: Menjalankan Dry-Run (NPM Pack)..." + npm pack + mkdir -p ../../dist-test + mv *.tgz ../../dist-test/ + fi + + cd ../.. +done + +if [[ "${{ github.event_name }}" == "release" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then + jq --arg ver "$VERSION" \ + '.version = $ver | .optionalDependencies = { + "@lightvm/core-linux-x64": $ver, + "@lightvm/core-linux-arm64": $ver, + "@lightvm/core-linux-ia32": $ver, + "@lightvm/core-win32-x64": $ver, + "@lightvm/core-win32-ia32": $ver, + "@lightvm/core-darwin-x64": $ver, + "@lightvm/core-android-arm64": $ver, + "@lightvm/core-android-arm": $ver, + "@lightvm/core-linux-musl-x64": $ver, + "@lightvm/core-linux-musl-arm64": $ver, + "@lightvm/core-linux-musl-ia32": $ver, + "@lightvm/core-freebsd-x64": $ver, + "@lightvm/core-browser-wasm": $ver + }' package.json > temp.json && mv temp.json package.json + + npm publish --access public --tag $TAG +fi \ No newline at end of file diff --git a/.github/scripts/publish/setup_ndk.sh b/.github/scripts/publish/setup_ndk.sh new file mode 100644 index 0000000..eb7a857 --- /dev/null +++ b/.github/scripts/publish/setup_ndk.sh @@ -0,0 +1,18 @@ +echo "ANDROID_NDK_HOME=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV + +TOOLCHAIN="$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" + +mkdir -p .cargo +if [ "${{ matrix.platform }}" == "android-arm64" ]; then + LINKER="aarch64-linux-android33-clang" + echo "CC=$TOOLCHAIN/aarch64-linux-android33-clang" >> $GITHUB_ENV +else + LINKER="armv7a-linux-androideabi33-clang" + echo "CC=$TOOLCHAIN/armv7a-linux-androideabi33-clang" >> $GITHUB_ENV +fi + +echo "AR=$TOOLCHAIN/llvm-ar" >> $GITHUB_ENV + +echo "[target.${{ matrix.target }}]" > .cargo/config.toml +echo "ar = \"$TOOLCHAIN/llvm-ar\"" >> .cargo/config.toml +echo "linker = \"$TOOLCHAIN/$LINKER\"" >> .cargo/config.toml diff --git a/.github/scripts/publish/sync_assets_version.sh b/.github/scripts/publish/sync_assets_version.sh new file mode 100644 index 0000000..02c27a2 --- /dev/null +++ b/.github/scripts/publish/sync_assets_version.sh @@ -0,0 +1,13 @@ +VERSION="${{ github.event.inputs.version_override }}" + +if [ -z "$VERSION" ]; then + RAW_VERSION="${{ github.event.release.tag_name }}" + VERSION=${RAW_VERSION#v} +fi + +if [ -z "$VERSION" ]; then + VERSION=$(grep '^version =' Cargo.toml | head -n1 | cut -d '"' -f2) +fi + +echo "Publishing version: $VERSION" +sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml \ No newline at end of file diff --git a/.github/scripts/stats/fetch_update_gist.sh b/.github/scripts/stats/fetch_update_gist.sh new file mode 100644 index 0000000..715a2ab --- /dev/null +++ b/.github/scripts/stats/fetch_update_gist.sh @@ -0,0 +1,14 @@ +CLONES=$(curl -s --fail -H "Authorization: token $LIGHTVM_PAT" \ +"https://api.github.com/repos/$GITHUB_REPOSITORY/traffic/clones" \ +| jq '.count // 0') + +TRAFFIC_DATA=$(curl -s --fail -H "Authorization: token $LIGHTVM_PAT" \ +"https://api.github.com/repos/$GITHUB_REPOSITORY/traffic/views") + +TOTAL_VIEWS=$(echo "$TRAFFIC_DATA" | jq '.count // 0') +UNIQUE_VISITORS=$(echo "$TRAFFIC_DATA" | jq '.uniques // 0') + +curl -s --fail -X PATCH -H "Authorization: token $LIGHTVM_PAT" \ +-H "Content-Type: application/json" \ +-d "{\"files\":{\"stats.json\":{\"content\":\"{\\\"clones\\\": $CLONES, \\\"total_views\\\": $TOTAL_VIEWS, \\\"unique_visitors\\\": $UNIQUE_VISITORS}\"}}}" \ +"https://api.github.com/gists/$GIST_ID" diff --git a/.github/scripts/tokens/check_crates_token.sh b/.github/scripts/tokens/check_crates_token.sh new file mode 100644 index 0000000..73ee24f --- /dev/null +++ b/.github/scripts/tokens/check_crates_token.sh @@ -0,0 +1,9 @@ +echo "Checking Crates.io token using Cargo CLI..." + +if cargo owner --list lightvm --token "$CRATES_TOKEN" > /dev/null 2>&1; then + echo "code=200" >> $GITHUB_OUTPUT + echo "status=valid" >> $GITHUB_OUTPUT +else + echo "code=401" >> $GITHUB_OUTPUT + echo "status=invalid" >> $GITHUB_OUTPUT +fi \ No newline at end of file diff --git a/.github/scripts/tokens/check_npm_token.sh b/.github/scripts/tokens/check_npm_token.sh new file mode 100644 index 0000000..56c4e5a --- /dev/null +++ b/.github/scripts/tokens/check_npm_token.sh @@ -0,0 +1,8 @@ +echo "Checking NPM token..." +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $NPM_TOKEN" https://registry.npmjs.org/-/whoami) +echo "code=$RESPONSE" >> $GITHUB_OUTPUT +if [ "$RESPONSE" -eq 200 ]; then + echo "status=valid" >> $GITHUB_OUTPUT +else + echo "status=invalid" >> $GITHUB_OUTPUT +fi \ No newline at end of file diff --git a/.github/scripts/tokens/create_issue.js b/.github/scripts/tokens/create_issue.js new file mode 100644 index 0000000..54fa496 --- /dev/null +++ b/.github/scripts/tokens/create_issue.js @@ -0,0 +1,22 @@ +const npmValid = "${{ steps.check_npm.outputs.status }}" === "valid"; +const cratesValid = "${{ steps.check_crates.outputs.status }}" === "valid"; + +const npmCode = "${{ steps.check_npm.outputs.code }}"; +const cratesCode = "${{ steps.check_crates.outputs.code }}"; + +const npmStatus = npmValid ? "✅ VALID" : `❌ EXPIRED/INVALID (HTTP ${npmCode})`; +const cratesStatus = cratesValid ? "✅ VALID" : `❌ EXPIRED/INVALID (HTTP ${cratesCode})`; + +await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "⚠️ ALERT: GitHub Token Registry Expired!", + assignees: ["claycuy"], + labels: ["bug", "security"], + body: `Hi, Maintainer. One of your tokens is no longer valid: + +- NPM Token: ${npmStatus} +- Crates.io Token: ${cratesStatus} + +Hurry up and change it in the repo settings!` +}); \ No newline at end of file diff --git a/.github/workflows/check-tokens.yml b/.github/workflows/check-tokens.yml index 0e76751..a4cc034 100644 --- a/.github/workflows/check-tokens.yml +++ b/.github/workflows/check-tokens.yml @@ -21,15 +21,7 @@ jobs: continue-on-error: true env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - run: | - echo "Checking NPM token..." - RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer $NPM_TOKEN" https://registry.npmjs.org/-/whoami) - echo "code=$RESPONSE" >> $GITHUB_OUTPUT - if [ "$RESPONSE" -eq 200 ]; then - echo "status=valid" >> $GITHUB_OUTPUT - else - echo "status=invalid" >> $GITHUB_OUTPUT - fi + run: bash .github/scripts/tokens/check_npm_token.sh # Kita install Rust Toolchain dulu khusus buat runner ini - name: Install Rust CLI @@ -40,45 +32,13 @@ jobs: continue-on-error: true env: CRATES_TOKEN: ${{ secrets.CRATES_IO_TOKEN }} - run: | - echo "Checking Crates.io token using Cargo CLI..." - - # Kita tes minta daftar owner crate 'lightvm' pake token lu - if cargo owner --list lightvm --token "$CRATES_TOKEN" > /dev/null 2>&1; then - echo "code=200" >> $GITHUB_OUTPUT - echo "status=valid" >> $GITHUB_OUTPUT - else - echo "code=401" >> $GITHUB_OUTPUT - echo "status=invalid" >> $GITHUB_OUTPUT - fi + run: bash .github/scripts/tokens/check_crates_token.sh - name: Create Issue on Token Expiration if: steps.check_npm.outputs.status != 'valid' || steps.check_crates.outputs.status != 'valid' uses: actions/github-script@v7 with: - script: | - const npmValid = "${{ steps.check_npm.outputs.status }}" === "valid"; - const cratesValid = "${{ steps.check_crates.outputs.status }}" === "valid"; - - const npmCode = "${{ steps.check_npm.outputs.code }}"; - const cratesCode = "${{ steps.check_crates.outputs.code }}"; - - const npmStatus = npmValid ? "✅ VALID" : `❌ EXPIRED/INVALID (HTTP ${npmCode})`; - const cratesStatus = cratesValid ? "✅ VALID" : `❌ EXPIRED/INVALID (HTTP ${cratesCode})`; - - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: "⚠️ ALERT: GitHub Token Registry Expired!", - assignees: ["claycuy"], - labels: ["bug", "security"], - body: `Hi, Maintainer. One of your tokens is no longer valid: - - - NPM Token: ${npmStatus} - - Crates.io Token: ${cratesStatus} - - Hurry up and change it in the repo settings!` - }); + script: node .github/scripts/tokens/create_issue.js - name: Force Workflow Failure if: steps.check_npm.outputs.status != 'valid' || steps.check_crates.outputs.status != 'valid' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 817e411..4b57e3e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,30 +59,20 @@ jobs: cargo fmt --check - name: Deep Code Audit (Junk & Header) - run: | - FILES=$(find . -type d \( -name "target" -o -name "node_modules" -o -name "dist" -o -name "generated" \) -prune -o -type f \( -name "*.ts" -o -name "*.rs" \) -print) - - if [ -z "$FILES" ]; then - echo "There are no files to check." - exit 0 - fi - - MISSING_COPYRIGHT=$(echo "$FILES" | xargs grep -L "Copyright") - if [ -n "$MISSING_COPYRIGHT" ]; then - echo "This file needs a Copyright header:" - echo "$MISSING_COPYRIGHT" - exit 1 - fi - - JUNK_CHECK=$(echo "$FILES" | xargs awk 'NR==1 && /^\/\/ [A-Za-z0-9_-]+\.(ts|rs)$/ {print FILENAME}') - if [ -n "$JUNK_CHECK" ]; then - echo "The first line is just the file name (Junk):" - echo "$JUNK_CHECK" - exit 1 - fi + run: bash .github/scripts/ci/deep_audit.sh - name: Rust Security & Quality (Clippy) run: cargo clippy -- -D warnings + - name: Run Rust Tests + run: | + npm run test:rust + npm run fix:imports + + - name: Run Typecheck & Tests + run: | + npm run typecheck + npm run test:ts + - name: Final Build Check (TypeScript) run: npm run build diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 226206f..cdd8929 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -16,30 +16,21 @@ jobs: with: fetch-depth: 0 + - name: Check if Production Workflow ran today + id: check_prod + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash .github/scripts/nightly/production_workflow.sh + + - name: Stop if Prod already ran + if: steps.check_prod.outputs.should_skip == 'true' + run: | + echo "Production is underway, so let's pull out the night shift first. Bye!" + exit 0 + - name: Filter Significant Changes id: filter_changes - run: | - # Ambil tag terakhir - PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "") - - # Ambil semua commit log sejak tag terakhir - # Kalau belum ada tag, ambil semua history - if [ -n "$PREV_TAG" ]; then - LOGS=$(git log $PREV_TAG..HEAD --pretty=format:"%s") - else - LOGS=$(git log --pretty=format:"%s") - fi - - # Cari apakah ada commit yang diawali "feat" atau "fix" - HAS_SIGNIFICANT=$(echo "$LOGS" | grep -E "^(feat|fix)(\(.*\))?:" || echo "") - - if [ -n "$HAS_SIGNIFICANT" ]; then - echo "significant=true" >> $GITHUB_OUTPUT - echo "Ada perubahan signifikan, lanjut!" - else - echo "significant=false" >> $GITHUB_OUTPUT - echo "Gak ada feat/fix, skip build." - fi + run: bash .githuh/scripts/nightly/filter_significant.sh - name: Stop if not significant if: steps.filter_changes.outputs.significant == 'false' @@ -63,116 +54,23 @@ jobs: - name: Generate Nightly Version id: versioning if: steps.filter_changes.outputs.significant == 'true' - run: | - # 1. Ambil tag terakhir - RAW_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") - - # 2. Hapus prefix 'v' kalau ada - CLEAN_VERSION=${RAW_TAG#v} - - # 3. Hapus bagian '-nightly.*' kalau ada - BASE_VERSION=${CLEAN_VERSION%-nightly.*} - - # 4. Ambil hash baru dan tanggal hari ini - COMMIT_HASH=$(git rev-parse --short HEAD) - DATE=$(date +'%Y%m%d') # Format: 20260625 - - # 5. Bikin format versi baru: 0.1.0-alpha.8-nightly.20260625.hash - # Kita asumsikan BASE_VERSION udah termasuk "-alpha.8" nya - VERSION_CLEAN="${BASE_VERSION}-nightly.${DATE}.${COMMIT_HASH}" - VERSION_TAG="v${VERSION_CLEAN}" - - echo "version_clean=$VERSION_CLEAN" >> $GITHUB_OUTPUT - echo "version_tag=$VERSION_TAG" >> $GITHUB_OUTPUT - echo "Generated version: $VERSION_CLEAN (Tag: $VERSION_TAG)" + run: bash .github/scripts/nightly/generate_version.sh - name: Update Files if: steps.filter_changes.outputs.significant == 'true' - run: | - VERSION="${{ steps.versioning.outputs.version_clean }}" - - # Update Cargo.toml - sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml - - # Update package.json - if [ -f "package.json" ]; then - jq --arg ver "$VERSION" '.version = $ver' package.json > temp.json && mv temp.json package.json - fi - - # UPDATE LOCKFILE: - # Kita jalanin cargo generate-lockfile atau update - # Pake --offline kalau lu mau cepat, tapi biar aman pake command ini: - rustup toolchain install stable --profile minimal - cargo update + run: bash .github/scripts/nightly/update_files.sh - name: Commit and Push if: steps.filter_changes.outputs.significant == 'true' - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - git add Cargo.toml - [ -f "package.json" ] && git add package.json - - # Cuma commit kalau ada perubahan - if ! git diff --cached --quiet; then - git commit -m "chore: nightly release ${{ steps.versioning.outputs.version_clean }}" - git tag ${{ steps.versioning.outputs.version_tag }} - git push origin main --tags - else - echo "Gak ada perubahan file, skip push." - fi + run: bash .github/scripts/nightly/commit_push.sh - name: Create Release if: steps.filter_changes.outputs.significant == 'true' - run: | - PREV_TAG=$(git describe --tags --abbrev=0 --exclude="${{ steps.versioning.outputs.version_tag }}" 2>/dev/null || echo "") - - # Ambil log dengan format: type: subject - LOGS=$(git log $PREV_TAG..HEAD --pretty=format:"%s") - - # Tambahin spasi setelah titik dua atau kurung buka - FEAT=$(echo "$LOGS" | grep -E "^feat(\(.*\))?: " | sed -E 's/^feat(\(.*\))?: /- /' || echo "") - FIX=$(echo "$LOGS" | grep -E "^fix(\(.*\))?: " | sed -E 's/^fix(\(.*\))?: /- /' || echo "") - - # Bikin link compare - COMPARE_LINK="https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${{ steps.versioning.outputs.version_tag }}" - - # Susun formatnya - { - echo "## What's Changed" - echo "Compare: $COMPARE_LINK" - echo "" - - if [ -n "$FEAT" ]; then - echo "### Features" - echo "$FEAT" - echo "" - fi - - if [ -n "$FIX" ]; then - echo "### Fixes" - echo "$FIX" - echo "" - fi - - if [ -z "$FEAT" ] && [ -z "$FIX" ]; then - echo "_No significant changes in this build._" - fi - - echo "***Nightly Owl has fallen out of bed tonight!***" - } > release_notes.md - - # 2. Buat release pakai file notes - gh release create "${{ steps.versioning.outputs.version_tag }}" \ - --title "Nightly Build ${{ steps.versioning.outputs.version_tag }}" \ - --notes-file release_notes.md \ - --prerelease + run: bash .github/scripts/nightly/create_release.sh env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Trigger Main Release Workflow - # Step ini cuma jalan kalau step sebelumnya sukses if: steps.filter_changes.outputs.significant == 'true' uses: benc-uk/workflow-dispatch@v1 with: diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml new file mode 100644 index 0000000..de6fe1a --- /dev/null +++ b/.github/workflows/production.yml @@ -0,0 +1,38 @@ +name: Production Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Versi rilis (contoh: 1.1.0)' + required: true + +jobs: + production-release: + runs-on: ubuntu-latest + permissions: + contents: write + actions: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate Version & Check Tag + run: bash .github/scripts/production/validate_version_tag.sh "${{ github.event.inputs.version }}" + + + - name: Generate Release Notes + run: bash .github/scripts/production/generate_release_notes.sh + + - name: Create Release + run: bash .github/scripts/production/create_release.sh + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Trigger Build and Publish + uses: benc-uk/workflow-dispatch@v1 + with: + workflow: Build and Publish N-API + token: ${{ secrets.GITHUB_TOKEN }} + inputs: '{ "version_override": "${{ github.event.inputs.version }}" }' diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1dd0feb..c5bb0ac 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -103,26 +103,7 @@ jobs: - name: Setup Android NDK if: contains(matrix.platform, 'android') - run: | - echo "ANDROID_NDK_HOME=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV - - TOOLCHAIN="$ANDROID_NDK_LATEST_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin" - - mkdir -p .cargo - if [ "${{ matrix.platform }}" == "android-arm64" ]; then - LINKER="aarch64-linux-android33-clang" - echo "CC=$TOOLCHAIN/aarch64-linux-android33-clang" >> $GITHUB_ENV - else - LINKER="armv7a-linux-androideabi33-clang" - echo "CC=$TOOLCHAIN/armv7a-linux-androideabi33-clang" >> $GITHUB_ENV - fi - - echo "AR=$TOOLCHAIN/llvm-ar" >> $GITHUB_ENV - - echo "[target.${{ matrix.target }}]" > .cargo/config.toml - echo "ar = \"$TOOLCHAIN/llvm-ar\"" >> .cargo/config.toml - echo "linker = \"$TOOLCHAIN/$LINKER\"" >> .cargo/config.toml - + run: bash .github/scripts/publish/setup_ndk.sh - name: Build Release (Standard) if: | matrix.platform == 'linux-x64' || @@ -138,23 +119,10 @@ jobs: contains(matrix.platform, 'musl') || contains(matrix.platform, 'arm64') || matrix.platform == 'linux-ia32' - run: | - if [[ "${{ matrix.platform }}" == *"android"* ]]; then - cargo build --release --target ${{ matrix.target }} - elif [[ "${{ matrix.platform }}" == *"musl"* ]]; then - if [ ! -f "./cross" ]; then - curl -L https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-musl.tar.gz | tar xz - chmod +x cross - fi - RUSTFLAGS="-C target-feature=-crt-static" ./cross build --release --target ${{ matrix.target }} - else - if [ ! -f "./cross" ]; then - curl -L https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-musl.tar.gz | tar xz - chmod +x cross - fi - ./cross build --release --target ${{ matrix.target }} - fi - + env: + PLATFORM: ${{ matrix.platform }} + TARGET: ${{ matrix.target }} + run: bash .github/scripts/publish/build_release.sh - name: Build WASM if: matrix.platform == 'browser-wasm' run: | @@ -209,148 +177,7 @@ jobs: npm run build - name: Publish to NPM - run: | - VERSION="${{ github.event.inputs.version_override }}" - if [ -z "$VERSION" ]; then - RAW_VERSION="${{ github.event.release.tag_name }}" - VERSION=${RAW_VERSION#v} - fi - - if [ -z "$VERSION" ]; then - echo "Fetch latest release tag from GitHub API..." - LATEST_TAG=$(gh release view --json tagName --template '{{.tagName}}' 2>/dev/null || echo "") - if [ -n "$LATEST_TAG" ]; then - VERSION=${LATEST_TAG#v} - echo "Successfully resolved latest release version: $VERSION" - else - echo "No release found via API. Falling back to Cargo.toml..." - VERSION=$(grep '^version =' Cargo.toml | head -n1 | cut -d '"' -f2) - fi - fi - - echo "Final Publishing Version: $VERSION" - - TAG="latest" - if [[ "$VERSION" =~ -(proto|alpha|beta|rc) ]]; then TAG="next"; fi - echo "Using NPM Tag: $TAG" - - PLATFORMS=( - "binary-linux-x64|linux-x64|index.linux.node|x64" - "binary-linux-arm64|linux-arm64|index.linux-arm64.node|arm64" - "binary-linux-ia32|linux-ia32|index.linux32.node|ia32" - "binary-win32-x64|win32-x64|index.win.node|x64" - "binary-win32-ia32|win32-ia32|index.win32.node|ia32" - "binary-darwin-x64|darwin-x64|index.darwin.node|x64" - "binary-android-arm64|android-arm64|index.android.node|arm64" - "binary-android-arm|android-arm|index.android32.node|arm" - "binary-linux-musl-x64|linux-musl-x64|index.musl-x64.node|x64" - "binary-linux-musl-arm64|linux-musl-arm64|index.musl-arm64.node|arm64" - "binary-linux-musl-ia32|linux-musl-ia32|index.musl-ia32.node|ia32" - "binary-freebsd-x64|freebsd-x64|index.freebsd.node|x64" - "binary-browser-wasm|browser-wasm|index.wasm|wasm" - ) - - sudo apt-get install -y jq - - for item in "${PLATFORMS[@]}"; do - IFS="|" read -r ARTIFACT PLATFORM BIN_NAME CPU <<< "$item" - PKG_NAME="@lightvm/core-$PLATFORM" - OS_VAL="${PLATFORM%-*}" - mkdir -p "publish/$PLATFORM" - - if [[ "$PLATFORM" == "browser-wasm" ]]; then - # Intip dulu isinya buat memastikan filenya ada lewat logs - echo "=== Isi dari binaries/$ARTIFACT ===" - ls -la "binaries/$ARTIFACT" - - # Copy semua isi artifact (termasuk .wasm, .js, .d.ts) - cp -r "binaries/$ARTIFACT"/. "publish/$PLATFORM/" - - # Rename file hasil wasm-pack biar sinkron jadi index.js & index.wasm - cd "publish/$PLATFORM" - - # Cari file .js bawaan wasm-pack dan rename ke index.js - WASM_JS_FILE=$(find . -maxdepth 1 -name "*.js" ! -name "index.js" | head -n 1) - if [ -n "$WASM_JS_FILE" ]; then - mv "$WASM_JS_FILE" "index.js" - fi - - # Cari file _bg.wasm bawaan wasm-pack dan rename ke index.wasm - WASM_BG_FILE=$(find . -maxdepth 1 -name "*_bg.wasm" | head -n 1) - if [ -n "$WASM_BG_FILE" ]; then - mv "$WASM_BG_FILE" "index.wasm" - fi - - # Balik ke root directory sebelum lanjutin proses jq dan npm publish - cd ../.. - - MAIN_FIELD="index.js" - FILES_FIELD=$(jq -nc '["index.wasm", "index.js", "*.d.ts", "README.md", "LICENSE"]') - else - find "binaries/$ARTIFACT" -type f \( -name "*.node" -o -name "*.dll" -o -name "*.so" -o -name "*.dylib" \) -exec cp {} "publish/$PLATFORM/$BIN_NAME" \; - MAIN_FIELD="$BIN_NAME" - FILES_FIELD=$(jq -nc --arg bin "$BIN_NAME" '[$bin, "README.md", "LICENSE"]') - fi - - cp -f README.md "publish/$PLATFORM/" || true - cp -f LICENSE "publish/$PLATFORM/" || true - - jq -n \ - --arg name "$PKG_NAME" \ - --arg ver "$VERSION" \ - --arg os "$OS_VAL" \ - --arg cpu "$CPU" \ - --arg main "$MAIN_FIELD" \ - --argjson files "$FILES_FIELD" \ - '{ - name: $name, - version: $ver, - os: [$os], - cpu: [$cpu], - main: $main, - files: $files, - publishConfig: { access: "public" }, - license: "Apache-2.0" - }' > "publish/$PLATFORM/package.json" - - cd "publish/$PLATFORM" - - # --- VALIDASI OTOMATIS BERDASARKAN EVENT TYPE --- - # Kita tetap publish jika eventnya adalah 'release' - # ATAU jika 'workflow_dispatch' dan version-nya mengandung 'nightly' (biar nightly tetep publish) - if [[ "${{ github.event_name }}" == "release" ]] || [[ "${{ github.event_name }}" == "workflow_dispatch" && "$VERSION" == *"nightly"* ]]; then - echo "Event Rilisan/Nightly Terdeteksi: Menjalankan Real Publish ke NPM..." - npm publish --tag $TAG --access public || echo "Skip existing" - else - echo "Event Manual (Non-Nightly) Terdeteksi: Menjalankan Dry-Run (NPM Pack)..." - npm pack - mkdir -p ../../dist-test - mv *.tgz ../../dist-test/ - fi - - cd ../.. - done - - if [[ "${{ github.event_name }}" == "release" || "${{ github.event_name }}" == "workflow_dispatch" ]]; then - jq --arg ver "$VERSION" \ - '.version = $ver | .optionalDependencies = { - "@lightvm/core-linux-x64": $ver, - "@lightvm/core-linux-arm64": $ver, - "@lightvm/core-linux-ia32": $ver, - "@lightvm/core-win32-x64": $ver, - "@lightvm/core-win32-ia32": $ver, - "@lightvm/core-darwin-x64": $ver, - "@lightvm/core-android-arm64": $ver, - "@lightvm/core-android-arm": $ver, - "@lightvm/core-linux-musl-x64": $ver, - "@lightvm/core-linux-musl-arm64": $ver, - "@lightvm/core-linux-musl-ia32": $ver, - "@lightvm/core-freebsd-x64": $ver, - "@lightvm/core-browser-wasm": $ver - }' package.json > temp.json && mv temp.json package.json - - npm publish --access public --tag $TAG - fi + run: bash .github/scripts/publish/publish_npm.sh env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -364,7 +191,6 @@ jobs: publish-crates: needs: build-npm - # Ubah 'if' nya biar mau jalan pas workflow_dispatch juga if: github.event_name == 'release' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: @@ -374,30 +200,7 @@ jobs: uses: dtolnay/rust-toolchain@stable - name: Sync Assets and Version - run: | - # 1. Coba ambil dari input override dulu - VERSION="${{ github.event.inputs.version_override }}" - - # 2. Kalau kosong, ambil dari tag release - if [ -z "$VERSION" ]; then - RAW_VERSION="${{ github.event.release.tag_name }}" - VERSION=${RAW_VERSION#v} - fi - - # 3. Kalau masih kosong juga, ambil dari Cargo.toml (fallback) - if [ -z "$VERSION" ]; then - VERSION=$(grep '^version =' Cargo.toml | head -n1 | cut -d '"' -f2) - fi - - echo "Publishing version: $VERSION" - sed -i "s/^version = \".*\"/version = \"$VERSION\"/" Cargo.toml + run: bash .github/scripts/publish/sync_assets_version.sh - name: Publish to Crates.io - run: | - # Kalau nightly (biasanya mengandung 'nightly'), kita perlu --allow-dirty - # dan mungkin perlu --no-verify kalau tes-nya gagal karena biner belum ada di crates - if [[ "${{ github.event.inputs.version_override }}" == *"nightly"* ]]; then - cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} --allow-dirty --no-verify - else - cargo publish --token ${{ secrets.CRATES_IO_TOKEN }} --allow-dirty - fi + run: bash .github/scripts/publish/publish_crates.sh diff --git a/.github/workflows/stats.yml b/.github/workflows/stats.yml index 0fa20c0..51bf583 100644 --- a/.github/workflows/stats.yml +++ b/.github/workflows/stats.yml @@ -14,18 +14,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch and Update Gist - run: | - CLONES=$(curl -s -H "Authorization: token ${{ secrets.LIGHTVM_PAT }}" \ - "https://api.github.com/repos/${{ github.repository }}/traffic/clones" \ - | jq '.count // 0') + env: + LIGHTVM_PAT: ${{ secrets.LIGHTVM_PAT }} + GITHUB_REPOSITORY: ${{ github.repository }} + GIST_ID: ${{ secrets.GIST_ID }} + run: bash .github/scripts/stats/fetch_update_gist.sh - TRAFFIC_DATA=$(curl -s -H "Authorization: token ${{ secrets.LIGHTVM_PAT }}" \ - "https://api.github.com/repos/${{ github.repository }}/traffic/views") - - TOTAL_VIEWS=$(echo $TRAFFIC_DATA | jq '.count // 0') - UNIQUE_VISITORS=$(echo $TRAFFIC_DATA | jq '.uniques // 0') - - curl -s -X PATCH -H "Authorization: token ${{ secrets.LIGHTVM_PAT }}" \ - -H "Content-Type: application/json" \ - -d "{\"files\":{\"stats.json\":{\"content\":\"{\\\"clones\\\": $CLONES, \\\"total_views\\\": $TOTAL_VIEWS, \\\"unique_visitors\\\": $UNIQUE_VISITORS}\"}}}" \ - "https://api.github.com/gists/${{ secrets.GIST_ID }}" diff --git a/.github/workflows/sync-deps.yml b/.github/workflows/sync-deps.yml new file mode 100644 index 0000000..7cd0cad --- /dev/null +++ b/.github/workflows/sync-deps.yml @@ -0,0 +1,50 @@ +name: Sync Lock Files + +on: + issue_comment: + types: [created] + +jobs: + sync: + if: | + github.event.issue.pull_request != null && + contains(github.event.comment.body, 'fix-lockfile') && + github.event.comment.user.login == 'claycuy' + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Sync package-lock.json + run: | + npm install --package-lock-only --ignore-scripts + + - name: Sync Cargo.lock + run: | + cargo generate-lockfile + + - name: Commit changes + run: | + git config --global user.name 'github-actions[bot]' + git config --global user.email 'github-actions[bot]`@users.noreply.github.com`' + + git fetch origin + git pull --rebase --autostash origin ${GITHUB_HEAD_REF:-$GITHUB_REF_NAME} + + git add package-lock.json Cargo.lock + if ! git diff --cached --quiet; then + git commit -m "chore: sync lock files" + git push origin HEAD:${GITHUB_HEAD_REF:-$GITHUB_REF_NAME} + fi \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index 5c90ab7..d35266b 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,5 @@ npm run check:deps npm run cleaner -node ./scripts/fix-imports.js +npm run fix:imports git add ./ts/src/generated npx lint-staged \ No newline at end of file diff --git a/.lintstagedrc.js b/.lintstagedrc.js index 9f24fad..2f5fab4 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -1,5 +1,5 @@ export default { - "*.{js,ts,rs,md}": "npm run cspell", + "*.{js,ts,rs,md,sh,yml}": "npm run cspell", "{ts/src,ts/tests,scripts}**/*.{js,ts}": [ () => "npm run typecheck", "eslint --fix", @@ -13,7 +13,8 @@ export default { ], "rust/**/*.rs": [ "sh -c 'cargo fmt --'", - "sh -c 'cargo clippy --color always -- -D warnings'" + "sh -c 'cargo clippy --color always -- -D warnings'", + "sh -c 'cargo test --features node --no-run'" ], ".testings/**/*.rs": [ "sh -c 'cargo fmt --'", diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..1c93407 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,10 @@ +# Credits & Origins + +## Originality Statement +LightVM is an original project, independently conceptualized and developed by me starting in February 2026. This project was born from my own vision and pure technical initiative. + +## Context +This virtual machine was created to fulfill a specific necessity: to provide a lightweight, high-performance runtime for a programming language I am currently developing. While there are other projects in the ecosystem that share similar naming conventions, please note that this repository serves as the official, original source code for my unique implementation. + +## Acknowledgments +Built with Rust, designed for high-performance low-level systems. This project represents my commitment to building independent, specialized tools from the ground up. diff --git a/Cargo.lock b/Cargo.lock index fd5371f..6e71ba8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -118,9 +118,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.65" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "shlex", @@ -276,9 +276,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "ctor" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a" +checksum = "fb22e947478ccf9dc44d8922042c677a63fbb88f2cb468521d1145816e5087cb" [[package]] name = "either" @@ -461,7 +461,7 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "lightvm" -version = "0.1.0-alpha.8-nightly.20260701.305f0b7" +version = "0.1.0-alpha.8-nightly.20260702.4e8db80" dependencies = [ "ahash", "backtrace", @@ -502,9 +502,9 @@ dependencies = [ [[package]] name = "napi" -version = "3.10.0" +version = "3.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd366ba6a12e4bdbc360e1ad4e1f01da40c4395eef1f9e872d88f8b135e8048" +checksum = "0c71997d6f7ad4a756966e452426848ac27d3b37a295302d63afbbcce0270f93" dependencies = [ "bitflags", "ctor", @@ -525,9 +525,9 @@ checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1" [[package]] name = "napi-derive" -version = "3.5.8" +version = "3.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6730ee4e7b335eac6d7cf10fc2525d92743bd4713a13cb2e6667f0e97322d7c3" +checksum = "d4ba572deef53e2c386759a8c2014175a62679d74ff83adc205c8bc0e0285727" dependencies = [ "convert_case", "ctor", @@ -539,9 +539,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "5.1.0" +version = "5.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5ccc18b1b16d1049dcbd3e1a21fdfbf3ce720b8944979c5e1a76d4e30d9f9f" +checksum = "ddd961eb2aa8965e3f29722d754f3a86907eb1984e2fbcbe3fe87b9a02d6bfba" dependencies = [ "convert_case", "proc-macro2", @@ -721,9 +721,9 @@ checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustversion" diff --git a/README.md b/README.md index 25f173a..b2d33be 100644 --- a/README.md +++ b/README.md @@ -556,6 +556,7 @@ LightVM supports a wide range of platforms and architectures to ensure maximum o > [!WARNING] > __Nightly Support__: Support for `wasm32` for browsers is still in experimental stage. -## 📜 License & Changelog +## License & Changelog - This project is distributed using the [Apache-2.0 license](LICENSE). + - See [credits](./CREDITS.md) for information regarding the project's origin and originality. - See [changelogs](./docs/CHANGELOG.md) for the latest updates and release history. \ No newline at end of file diff --git a/cspell.config.js b/cspell.config.js index 121e30d..7eda9bb 100644 --- a/cspell.config.js +++ b/cspell.config.js @@ -33,7 +33,12 @@ export default { 'trin', 'unref', 'accessindex', - 'vmconfig' + 'vmconfig', + 'claycuy', + 'creatordate', + 'nightlies', + 'dtolnay', + 'autostash' ], ignorePaths: [ 'node_modules/**', @@ -46,4 +51,4 @@ export default { 'ts/benchmarks/**/*', 'rust/benches/**/*', ], -}; +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3af6227..695601d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "lightvm", - "version": "0.1.0-alpha.8-nightly.20260701.305f0b7", + "version": "0.1.0-alpha.8-nightly.20260702.4e8db80", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lightvm", - "version": "0.1.0-alpha.8-nightly.20260701.305f0b7", + "version": "0.1.0-alpha.8-nightly.20260702.4e8db80", "license": "Apache-2.0", "devDependencies": { "@commitlint/cli": "^21.0.1", @@ -2946,6 +2946,25 @@ "url": "https://ko-fi.com/dangreen" } }, + "node_modules/git-raw-commits/node_modules/conventional-commits-parser": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.4.0.tgz", + "integrity": "sha512-tvRg7FIBNlyPzjdG8wWRlPHQJJHI7DylhtRGeU9Lq+JuoPh5BKpPRX83ZdLrvXuOSu5Eo/e7SzOQhU4Hd2Miuw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@simple-libs/stream-utils": "^1.2.0", + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/git-raw-commits/node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", diff --git a/package.json b/package.json index 0eb23fa..12a9c26 100644 --- a/package.json +++ b/package.json @@ -35,27 +35,29 @@ "./types" ], "scripts": { - "test:rust": "cargo test", - "test:ts": "node ./scripts/run-tests.js", + "test:rust": "node ./scripts/test/test-rust.js", + "test:ts": "node ./scripts/test/test-ts.js", "bench:rust": "cargo bench", - "bench:ts": "node ./scripts/ts-bench.js", + "bench:ts": "node ./scripts/bench/ts-bench.js", "testing:rust": "solas run .testings/native.rs", "testing:ts": "node .testings/napi.js", "build": "node ./esbuild.config.js", - "build:pack": "node ./scripts/build-script.js", + "build:pack": "node ./scripts/build/build-script.js", "build:wasm": "wasm-pack build --target web -- --features wasm", - "build:pack2": "node ./scripts/build-wasm.js", - "build:release": "node ./scripts/build-binary.js --local --silent", - "build:debug": "node ./scripts/build-binary.js --local --debug --silent", - "check:deps": "node ./scripts/check-deps.js", + "build:pack2": "node ./scripts/build/build-wasm.js", + "build:release": "node ./scripts/build/build-binary.js --local --silent", + "build:debug": "node ./scripts/build/build-binary.js --local --debug --silent", + "check:deps": "node ./scripts/utils/check-deps.js", "typecheck": "tsc", "prettier": "npx prettier ./ts/**/*.ts --write", "eslint": "npx eslint ./ts/**/*.ts --fix", "cspell": "cspell lint \"**/*.{js,ts,rs,md}\" --gitignore --quiet --no-summary", - "html:cleaner": "node ./scripts/html-cleaner.js", + "html:cleaner": "node ./scripts/utils/html-cleaner.js", + "fix:imports": "node ./scripts/utils/fix-imports.js", "prepare": "husky", - "cleaner": "node ./scripts/cleaner.js", - "server": "node ./scripts/server.js" + "cleaner": "node ./scripts/utils/cleaner.js", + "server": "node ./scripts/utils/server.js", + "sync:agents": "node ./scripts/utils/sync-agents.js" }, "keywords": [ "lightvm", diff --git a/rust/src/types/instructions.rs b/rust/src/types/instructions.rs index 821328d..2a29674 100644 --- a/rust/src/types/instructions.rs +++ b/rust/src/types/instructions.rs @@ -552,3 +552,23 @@ impl Instructions { } } } +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + #[test] + fn test_instruction_round_trip() { + let json_input = json!(["push", 123]); + let instr = Instructions::from_json_array(&json_input).unwrap(); + match instr { + Instructions::Push(Value::Int16(_)) => assert!(true), + _ => panic!("Wrong data type!"), + } + } + #[test] + fn test_unknown_opcode_handling() { + let json_input = json!(["random_nonsense", 1]); + let result = Instructions::from_json_array(&json_input); + assert!(result.is_err()); + } +} diff --git a/rust/src/types/value.rs b/rust/src/types/value.rs index a7823d4..b89e095 100644 --- a/rust/src/types/value.rs +++ b/rust/src/types/value.rs @@ -51,7 +51,7 @@ pub struct FuncMetadata { pub start: usize, pub end: usize, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct RunOptions { pub entry: Option, pub args: Vec, diff --git a/rust/src/vm/execute.rs b/rust/src/vm/execute.rs index 77bc23c..5fdbea2 100644 --- a/rust/src/vm/execute.rs +++ b/rust/src/vm/execute.rs @@ -205,3 +205,36 @@ pub fn execute( } Ok(Value::Undefined) } +#[cfg(test)] +mod tests { + use super::*; + use crate::types::{instructions::Instructions, value::Value}; + use std::sync::Arc; + use std::sync::atomic::AtomicBool; + #[test] + fn test_execute_basic_math_and_return() { + let bytecode = vec![ + Instructions::PushInt32(5), + Instructions::PushInt32(10), + Instructions::Add(crate::types::primitive_types::PrimitiveTypes::Int), + Instructions::Stop, + ]; + let halt_flag = Arc::new(AtomicBool::new(false)); + let options = crate::types::value::RunOptions { + capture_return: true, + ..Default::default() + }; + let result = execute(bytecode, Some(options), Some(halt_flag)); + assert!(result.is_ok()); + } + #[test] + fn test_halt_flag_behavior() { + let bytecode = vec![Instructions::Jump(0)]; + let halt_flag = Arc::new(AtomicBool::new(false)); + let flag_clone = halt_flag.clone(); + flag_clone.store(true, std::sync::atomic::Ordering::Relaxed); + let result = execute(bytecode, None, Some(halt_flag)); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), Value::Undefined); + } +} diff --git a/rust/src/vm/run.rs b/rust/src/vm/run.rs index 082f583..bd14cc0 100644 --- a/rust/src/vm/run.rs +++ b/rust/src/vm/run.rs @@ -41,3 +41,20 @@ pub fn run(bytecode_json: &str, options: Option) -> String { } } } +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_run_with_valid_json() { + let json = r#"[["PushInt32", 10], ["Stop"]]"#; + let result = run(json, None); + assert!(result.contains("10") || result.contains("status")); + } + #[test] + fn test_run_with_invalid_instruction() { + let json = r#"[["random nonsense", 0]]"#; + let result = run(json, None); + assert!(result.contains("error")); + assert!(result.contains("message")); + } +} diff --git a/scripts/ts-bench.js b/scripts/bench/ts-bench.js similarity index 98% rename from scripts/ts-bench.js rename to scripts/bench/ts-bench.js index 1467395..3aef4e5 100644 --- a/scripts/ts-bench.js +++ b/scripts/bench/ts-bench.js @@ -37,7 +37,7 @@ console.log( `${s.bold}${s.green}✔${s.reset} ${s.bold}Rust build success!${s.reset}\n`, ); -const rootDir = path.resolve(__dirname, '..'); +const rootDir = path.resolve(__dirname, '../..'); const binariesDir = path.join(rootDir, 'binaries'); const sourcePath = path.join(rootDir, 'target/release/liblightvm.so'); const destPath = path.join(binariesDir, 'lightvm.node'); diff --git a/scripts/build-binary.js b/scripts/build/build-binary.js similarity index 100% rename from scripts/build-binary.js rename to scripts/build/build-binary.js diff --git a/scripts/build-script.js b/scripts/build/build-script.js similarity index 100% rename from scripts/build-script.js rename to scripts/build/build-script.js diff --git a/scripts/build-wasm.js b/scripts/build/build-wasm.js similarity index 100% rename from scripts/build-wasm.js rename to scripts/build/build-wasm.js diff --git a/scripts/test/test-rust.js b/scripts/test/test-rust.js new file mode 100644 index 0000000..6ecb634 --- /dev/null +++ b/scripts/test/test-rust.js @@ -0,0 +1,29 @@ +/** + * Copyright 2026 SoTeen Studio + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +import { execSync } from 'child_process'; + +function runCommand(command) { + try { + console.log(`Running: ${command}`); + execSync(command, { stdio: 'inherit' }); + } catch (error) { + console.error(`Error executing: ${command}`); + process.exit(1); + } +} + +console.log('Starting Rust tests...'); + +runCommand('cargo test --locked'); +runCommand('cargo test --features node --locked'); +runCommand('cargo test --features wasm --locked'); + +console.log('All Rust tests passed successfully!'); diff --git a/scripts/run-tests.js b/scripts/test/test-ts.js similarity index 98% rename from scripts/run-tests.js rename to scripts/test/test-ts.js index aca2d1b..22e7161 100644 --- a/scripts/run-tests.js +++ b/scripts/test/test-ts.js @@ -39,7 +39,7 @@ function run() { `${s.bold}${s.green}✔${s.reset} ${s.bold}Rust build success!${s.reset}\n`, ); - const rootDir = path.resolve(__dirname, '..'); + const rootDir = path.resolve(__dirname, '../..'); const binariesDir = path.join(rootDir, 'binaries'); const sourcePath = path.join(rootDir, 'target/release/liblightvm.so'); const destPath = path.join(binariesDir, 'lightvm.node'); diff --git a/scripts/check-deps.js b/scripts/utils/check-deps.js similarity index 100% rename from scripts/check-deps.js rename to scripts/utils/check-deps.js diff --git a/scripts/cleaner.js b/scripts/utils/cleaner.js similarity index 100% rename from scripts/cleaner.js rename to scripts/utils/cleaner.js diff --git a/scripts/fix-imports.js b/scripts/utils/fix-imports.js similarity index 100% rename from scripts/fix-imports.js rename to scripts/utils/fix-imports.js diff --git a/scripts/html-cleaner.js b/scripts/utils/html-cleaner.js similarity index 100% rename from scripts/html-cleaner.js rename to scripts/utils/html-cleaner.js diff --git a/scripts/server.js b/scripts/utils/server.js similarity index 100% rename from scripts/server.js rename to scripts/utils/server.js diff --git a/scripts/utils/sync-agents.js b/scripts/utils/sync-agents.js new file mode 100644 index 0000000..038f08b --- /dev/null +++ b/scripts/utils/sync-agents.js @@ -0,0 +1,55 @@ +/** + * Copyright 2026 SoTeen Studio + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +import fs from 'fs'; + +const AGENTS_PATH = 'AGENTS.md'; +const CODERABBIT_PATH = '.coderabbit.yml'; + +const s = { + reset: '\x1b[0m', + bold: '\x1b[1m', + cyan: '\x1b[36m', + green: '\x1b[32m', + red: '\x1b[31m', +}; + +const logger = { + success: (msg) => console.log(`${s.bold}${s.green}✔${s.reset} ${msg}`), + error: (msg, detail) => + console.error(`\n${s.bold}${s.red}𐄂 ${msg}${s.reset}`, detail || ''), +}; + +try { + const agentsContent = fs.readFileSync(AGENTS_PATH, 'utf8'); + + const indentedAgents = agentsContent + .split('\n') + .map((line) => ` ${line}`) + .join('\n'); + + let crConfig = fs.readFileSync(CODERABBIT_PATH, 'utf8'); + + const regex = /# AGENTS_START[\s\S]*?# AGENTS_END/; + const replacement = `# AGENTS_START\n${indentedAgents}\n # AGENTS_END`; + + if (regex.test(crConfig)) { + crConfig = crConfig.replace(regex, replacement); + fs.writeFileSync(CODERABBIT_PATH, crConfig); + logger.success('AGENTS.md successfully synced to .coderabbit.yml!'); + } else { + throw new Error( + 'Placeholder # AGENTS_START / # AGENTS_END not found in .coderabbit.yml', + ); + } +} catch (err) { + logger.error('Sync process failed:', err.message); + process.exit(1); +} diff --git a/solas.toml b/solas.toml index 44f6c28..4c9354b 100644 --- a/solas.toml +++ b/solas.toml @@ -13,20 +13,24 @@ desc = "Checking code performance" commands = ["clean", "header", "track"] # Commands for developers +# ======================= +# test scripts [scripts.test-rust] desc = "Running unit tests on .rs files" -commands = ["cargo test"] +commands = ["node ./scripts/test/test-rust.js"] [scripts.test-ts] desc = "Running unit tests on .ts file$" -commands = ["node ./scripts/run-tests.js"] +commands = ["node ./scripts/test/test-ts.js"] +# bench scripts [scripts.bench-rust] desc = "To get benchmark results from Rust code" commands = ["cargo bench"] [scripts.bench-ts] desc = "To get benchmark results from TypeScript code" -commands = ["node ./scripts/ts-bench.js"] +commands = ["node ./scripts/bench/ts-bench.js"] +# testing scripts [scripts.testing-rust] desc = "Running tests for Rust interfaces" commands = ["solas run .testings/native.rs"] @@ -34,34 +38,36 @@ commands = ["solas run .testings/native.rs"] desc = "Running tests for TypeScript interfaces" commands = ["node --enable-source-maps .testings/napi.js"] +# build scripts [scripts.build] desc = "Generating build results from TypeScript source" commands = ["node ./esbuild.config.js"] [scripts.build-pack] desc = "NPM package creation simulation" -commands = ["node ./scripts/build-script.js"] +commands = ["node ./scripts/build/build-script.js"] [scripts.build-wasm] desc = "Generating a WASM build from Rust sources" commands = ["wasm-pack build --target web -- --features wasm"] [scripts.build-pack2] desc = "NPM package creation simulation (WASM)" -commands = ["node ./scripts/build-wasm.js"] +commands = ["node ./scripts/build/build-wasm.js"] [scripts.build-release] desc = "Create a build release .tgz file" -commands = ["node ./scripts/build-binary.js --local --silent"] +commands = ["node ./scripts/build/build-binary.js --local --silent"] [scripts.build-debug] desc = "Create a build debug .tgz file" -commands = ["node ./scripts/build-binary.js --local --debug --silent"] +commands = ["node ./scripts/build/build-binary.js --local --debug --silent"] +# utils scripts [scripts.check-deps] desc = "Checking installed local dependencies" -commands = ["node ./scripts/check-deps.js"] +commands = ["node ./scripts/utils/check-deps.js"] [scripts.typecheck] desc = "Type checking" commands = ["tsc"] [scripts.html-cleaner] desc = "Cleaning up HTML code" -commands = ["node ./scripts/html-cleaner.js"] +commands = ["node ./scripts/utils/html-cleaner.js"] [scripts.prettier] desc = "Formatting code" commands = ["npx prettier ./ts/**/*.ts --write"] @@ -73,10 +79,10 @@ desc = "Prepare Husky" commands = ["npx husky"] [scripts.cleaner] desc = "Delete unused files and folders" -commands = ["node ./scripts/cleaner.js"] +commands = ["node ./scripts/utils/cleaner.js"] [scripts.server] desc = "Running the WASM testing server" -commands = ["node ./scripts/server.js"] +commands = ["node ./scripts/utils/server.js"] [copyright] license = "apache" diff --git a/ts/tests/vmerror.test.ts b/ts/tests/vmerror.test.ts index 3ce062d..8aa816e 100644 --- a/ts/tests/vmerror.test.ts +++ b/ts/tests/vmerror.test.ts @@ -16,16 +16,17 @@ const { VMError } = await importVM(); describe("VMError Class", () => { test("VMError: should correctly set properties and format message", () => { const msg = "Something went wrong"; - const err = new VMError(msg); + const details = ["test", "there is testing"]; + const err = new VMError(msg, details); expect(err.code).toBe("LVM500"); expect(err.ip).toBe(0); expect(err).toBeInstanceOf(VMError); - expect(err.name).toBe("SystemError"); + expect(err.name).toBe(""); - expect(err.message).toContain(msg); - expect(err.message).toContain("LVM500"); + expect(err.hintDetails.length).toBe(2); + expect(err.code).toContain("LVM500"); }); test("VMError: should be throwable", () => {