From 87d6665d7b4d1e92aaceca0b082c4543f5c2fa31 Mon Sep 17 00:00:00 2001 From: prabhu <7842+prabhu@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:10:43 +0000 Subject: [PATCH] Ruby support (#170) * Ruby frontend Signed-off-by: Prabhu Subramanian * Tag rails routes Signed-off-by: Prabhu Subramanian * Tag sinatra routes Signed-off-by: Prabhu Subramanian * Update typescript Signed-off-by: Prabhu Subramanian * Use Ruby 3.4.1 in CI Signed-off-by: Prabhu Subramanian --------- Signed-off-by: Prabhu Subramanian --- .github/workflows/containers.yml | 4 ++ .github/workflows/nodejstests.yml | 4 ++ .github/workflows/npm-release.yml | 4 ++ .github/workflows/pr.yml | 4 ++ .github/workflows/release.yml | 4 ++ .github/workflows/repotests.yml | 4 ++ README.md | 1 + build.sbt | 8 ++-- ci/Dockerfile | 38 +++++++++++++++---- ci/Dockerfile.sle | 5 ++- codemeta.json | 2 +- docs/docs/languages.md | 1 + project/build.properties | 2 +- project/plugins.sbt | 2 +- src/main/scala/io/appthreat/atom/Atom.scala | 12 +++++- .../atom/slicing/ReachableSlicing.scala | 2 +- wrapper/nodejs/build.sh | 8 +++- wrapper/nodejs/package-lock.json | 31 +++++++-------- wrapper/nodejs/package.json | 9 +++-- .../nodejs/plugins/rubyastgen/.bundle/config | 5 +++ wrapper/nodejs/plugins/rubyastgen/Gemfile | 9 +++++ .../nodejs/plugins/rubyastgen/Gemfile.lock | 33 ++++++++++++++++ wrapper/nodejs/plugins/rubyastgen/setup.sh | 6 +++ wrapper/nodejs/rbastgen.js | 37 ++++++++++++++++++ wrapper/nodejs/utils.mjs | 12 +++++- 25 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 wrapper/nodejs/plugins/rubyastgen/.bundle/config create mode 100644 wrapper/nodejs/plugins/rubyastgen/Gemfile create mode 100644 wrapper/nodejs/plugins/rubyastgen/Gemfile.lock create mode 100755 wrapper/nodejs/plugins/rubyastgen/setup.sh create mode 100755 wrapper/nodejs/rbastgen.js diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index 584f824..035b008 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -38,6 +38,10 @@ jobs: uses: actions/setup-node@v4 with: node-version: '22.x' + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - name: Delete `.rustup` directory run: rm -rf /home/runner/.rustup # to save disk space if: runner.os == 'Linux' diff --git a/.github/workflows/nodejstests.yml b/.github/workflows/nodejstests.yml index 20be141..be194f8 100644 --- a/.github/workflows/nodejstests.yml +++ b/.github/workflows/nodejstests.yml @@ -20,6 +20,10 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - uses: actions/checkout@v4 with: repository: 'ShiftLeftSecurity/shiftleft-java-example' diff --git a/.github/workflows/npm-release.yml b/.github/workflows/npm-release.yml index 2c39048..a430acb 100644 --- a/.github/workflows/npm-release.yml +++ b/.github/workflows/npm-release.yml @@ -22,6 +22,10 @@ jobs: with: node-version: '23.x' registry-url: https://registry.npmjs.org/ + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - uses: coursier/cache-action@v6 - name: Set up JDK uses: actions/setup-java@v4 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 2f5dac2..4ae4c31 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -13,6 +13,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - uses: actions/checkout@v4 with: repository: 'ShiftLeftSecurity/shiftleft-java-example' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 894ccee..f6bf5c6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -20,6 +20,10 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - name: Set up JDK uses: graalvm/setup-graalvm@v1 with: diff --git a/.github/workflows/repotests.yml b/.github/workflows/repotests.yml index 6ab2743..f5f663a 100644 --- a/.github/workflows/repotests.yml +++ b/.github/workflows/repotests.yml @@ -81,6 +81,10 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.12' + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.4.1' + bundler-cache: false - name: Install sbt run: brew install sbt if: runner.os == 'macOS' diff --git a/README.md b/README.md index 19e614e..30ea443 100644 --- a/README.md +++ b/README.md @@ -191,6 +191,7 @@ atom -o app.atom -l java --export-atom --export-dir --with-data-dep - TypeScript - Python - PHP (Requires PHP >= 7.0. Supports PHP 5.2 to 8.3) +- Ruby (Requires Ruby 3.4.0. Supports Ruby 1.8 - 3.4.0 syntax) ## Atom Specification diff --git a/build.sbt b/build.sbt index 2e5afaf..284b9e5 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,9 @@ name := "atom" ThisBuild / organization := "io.appthreat" -ThisBuild / version := "2.0.25" -ThisBuild / scalaVersion := "3.5.2" +ThisBuild / version := "2.1.0" +ThisBuild / scalaVersion := "3.6.2" -val chenVersion = "2.2.3" +val chenVersion = "2.3.0" lazy val atom = Projects.atom @@ -23,6 +23,7 @@ libraryDependencies ++= Seq( "io.appthreat" %% "jssrc2cpg" % Versions.chen, "io.appthreat" %% "jimple2cpg" % Versions.chen, "io.appthreat" %% "php2atom" % Versions.chen, + "io.appthreat" %% "ruby2atom" % Versions.chen, ("io.appthreat" %% "semanticcpg" % Versions.chen % Test).classifier("tests"), ("io.appthreat" %% "x2cpg" % Versions.chen % Test).classifier("tests"), ("io.appthreat" %% "pysrc2cpg" % Versions.chen % Test).classifier("tests"), @@ -106,7 +107,6 @@ Compile / packageDoc / publishArtifact := false wartremoverWarnings ++= Seq( Wart.NoNeedImport, Wart.ArrayEquals, - Wart.Any, Wart.FinalCaseClass, Wart.FinalVal, Wart.ToString, diff --git a/ci/Dockerfile b/ci/Dockerfile index 6485cd2..b55ee89 100644 --- a/ci/Dockerfile +++ b/ci/Dockerfile @@ -4,7 +4,7 @@ LABEL maintainer="appthreat" \ org.opencontainers.image.authors="Team AppThreat " \ org.opencontainers.image.source="https://github.com/appthreat/atom" \ org.opencontainers.image.url="https://github.com/appthreat/atom" \ - org.opencontainers.image.version="2.0.x" \ + org.opencontainers.image.version="2.1.x" \ org.opencontainers.image.vendor="appthreat" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.title="atom" \ @@ -12,6 +12,7 @@ LABEL maintainer="appthreat" \ org.opencontainers.docker.cmd="docker run --rm -v /tmp:/tmp -v $HOME:$HOME -v $(pwd):/app:rw -it ghcr.io/appthreat/atom atom -o /app/app.atom -l java /app" ARG MAVEN_VERSION=3.9.9 +ARG RUBY_VERSION=3.4.0 ENV MAVEN_VERSION=$MAVEN_VERSION \ MAVEN_HOME="/opt/maven/${MAVEN_VERSION}" \ @@ -21,9 +22,15 @@ ENV MAVEN_VERSION=$MAVEN_VERSION \ PYTHONUNBUFFERED=1 \ PYTHONIOENCODING="utf-8" \ CDXGEN_NO_BANNER=true \ - COMPOSER_ALLOW_SUPERUSER=1 + COMPOSER_ALLOW_SUPERUSER=1 \ + RUBY_VERSION=$RUBY_VERSION \ + MALLOC_CONF="dirty_decay_ms:2000,narenas:2,background_thread:true" \ + RUBY_CONFIGURE_OPTS="--with-jemalloc --enable-yjit" \ + RUBYOPT="--yjit" \ + RUBY_BUILD_BUILD_PATH="/tmp/rbenv" \ + RUBY_BUILD_HTTP_CLIENT=curl -ENV PATH=/opt/bin:/opt/vendor/bin:${PATH}:${MAVEN_HOME}/bin:/usr/local/bin/:/root/.local/bin:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools: +ENV PATH=/opt/bin:/opt/vendor/bin:${PATH}:${MAVEN_HOME}/bin:/usr/local/bin/:/root/.local/bin:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools:/root/.rbenv/bin: WORKDIR /opt @@ -43,15 +50,29 @@ RUN set -e; \ && microdnf install -y gcc git-core php php-cli php-curl php-zip php-bcmath php-json php-pear php-mbstring php-devel make \ python3.12 python3.12-devel python3.12-pip \ wget bash glibc-common glibc-all-langpacks java-21-openjdk-headless \ - pcre2 findutils which tar gzip zip unzip sudo nodejs \ + openssl-devel libffi-devel readline-devel libyaml zlib-devel ncurses ncurses-devel \ + pcre2 findutils which tar gzip zip unzip sudo nodejs rust \ + && microdnf install -y epel-release \ + && microdnf install --enablerepo=crb -y libyaml-devel jemalloc-devel \ + && git clone https://github.com/rbenv/rbenv.git --depth=1 ~/.rbenv \ + && echo 'export PATH="/root/.rbenv/bin:$PATH"' >> ~/.bashrc \ + && echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bashrc \ + && source ~/.bashrc \ + && mkdir -p "$(rbenv root)/plugins" \ + && git clone https://github.com/rbenv/ruby-build.git --depth=1 "$(rbenv root)/plugins/ruby-build" \ + && rbenv install ${RUBY_VERSION} \ + && rbenv global ${RUBY_VERSION} \ + && ruby --version \ + && which ruby \ + && rm -rf /root/.rbenv/cache $RUBY_BUILD_BUILD_PATH \ && alternatives --install /usr/bin/python3 python /usr/bin/python3.12 10 \ && alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 10 \ && python3 --version \ && node --version \ && python3 -m pip install --upgrade pip poetry atom-tools \ && curl -s "https://get.sdkman.io" | bash \ - && source "$HOME/.sdkman/bin/sdkman-init.sh" \ - && echo -e "sdkman_auto_answer=true\nsdkman_selfupdate_feature=false\nsdkman_auto_env=true\nsdkman_curl_connect_timeout=20\nsdkman_curl_max_time=0" >> $HOME/.sdkman/etc/config \ + && source "/root/.sdkman/bin/sdkman-init.sh" \ + && echo -e "sdkman_auto_answer=true\nsdkman_selfupdate_feature=false\nsdkman_auto_env=true\nsdkman_curl_connect_timeout=20\nsdkman_curl_max_time=0" >> /root/.sdkman/etc/config \ && sdk install maven $MAVEN_VERSION \ && sdk offline enable \ && mv /root/.sdkman/candidates/* /opt/ \ @@ -65,7 +86,7 @@ RUN set -e; \ && /opt/android-sdk-linux/cmdline-tools/latest/bin/sdkmanager 'platform-tools' --sdk_root=/opt/android-sdk-linux \ && /opt/android-sdk-linux/cmdline-tools/latest/bin/sdkmanager 'platforms;android-34' --sdk_root=/opt/android-sdk-linux \ && /opt/android-sdk-linux/cmdline-tools/latest/bin/sdkmanager 'build-tools;34.0.0' --sdk_root=/opt/android-sdk-linux \ - && sudo npm install -g @cyclonedx/cdxgen --omit=optional \ + && npm install -g @cyclonedx/cdxgen --omit=optional \ && php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" && php composer-setup.php \ && mv composer.phar /usr/local/bin/composer \ && curl -LO https://raw.githubusercontent.com/AppThreat/chen/main/platform/frontends/php2atom/composer.lock \ @@ -79,11 +100,12 @@ COPY ./wrapper . RUN unzip -q atom.zip \ && composer update --no-progress --prefer-dist --ignore-platform-reqs \ && cd /opt/nodejs && npm install --only=production && cd /opt \ - && sudo npm install -g /opt/nodejs \ + && npm install -g /opt/nodejs \ && rm -rf atom.zip composer.json composer.lock composer-setup.php /usr/local/bin/atom \ && /opt/bin/atom --help \ && which astgen \ && which phpastgen \ + && which rbastgen \ && microdnf clean all CMD ["/opt/bin/atom"] diff --git a/ci/Dockerfile.sle b/ci/Dockerfile.sle index 7d79ee0..44148e3 100644 --- a/ci/Dockerfile.sle +++ b/ci/Dockerfile.sle @@ -4,7 +4,7 @@ LABEL maintainer="appthreat" \ org.opencontainers.image.authors="Team AppThreat " \ org.opencontainers.image.source="https://github.com/appthreat/atom" \ org.opencontainers.image.url="https://github.com/appthreat/atom" \ - org.opencontainers.image.version="2.0.x" \ + org.opencontainers.image.version="2.1.x" \ org.opencontainers.image.vendor="appthreat" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.title="atom" \ @@ -37,7 +37,7 @@ RUN set -e; \ ;; \ *) echo >&2 "error: unsupported architecture: '$ARCH_NAME'"; exit 1 ;; \ esac; \ - zypper --non-interactive install -l --no-recommends php8 php8-cli php8-curl php8-zip php8-bcmath php8-pear php8-mbstring php8-devel \ + zypper --non-interactive install -l --no-recommends php8 php8-cli php8-curl php8-zip php8-bcmath php8-pear php8-mbstring php8-devel ruby ruby-devel \ && source /root/.nvm/nvm.sh \ && python3 --version \ && source /root/.nvm/nvm.sh \ @@ -72,6 +72,7 @@ RUN unzip -q atom.zip \ && /opt/bin/atom --help \ && which astgen \ && which phpastgen \ + && which rbastgen \ && zypper clean -a CMD ["/opt/bin/atom"] diff --git a/codemeta.json b/codemeta.json index dbc4908..ce33909 100644 --- a/codemeta.json +++ b/codemeta.json @@ -7,7 +7,7 @@ "downloadUrl": "https://github.com/AppThreat/atom", "issueTracker": "https://github.com/AppThreat/atom/issues", "name": "atom", - "version": "2.0.25", + "version": "2.1.0", "description": "Atom is a novel intermediate representation for next-generation code analysis.", "applicationCategory": "code-analysis", "keywords": [ diff --git a/docs/docs/languages.md b/docs/docs/languages.md index 28e105d..cd6a918 100644 --- a/docs/docs/languages.md +++ b/docs/docs/languages.md @@ -14,3 +14,4 @@ title: Languages supported - TypeScript - Python - PHP (Requires PHP >= 7.0. Supports PHP 5.2 to 8.3) +- Ruby (Requires Ruby 3.4.0. Supports Ruby 1.8 - 3.4.0 syntax) diff --git a/project/build.properties b/project/build.properties index db1723b..73df629 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.10.5 +sbt.version=1.10.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index 8576c75..368d92e 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2") addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.4") addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.3") -addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.2.4") +addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.2.5") diff --git a/src/main/scala/io/appthreat/atom/Atom.scala b/src/main/scala/io/appthreat/atom/Atom.scala index 45be6f3..ab1c80c 100644 --- a/src/main/scala/io/appthreat/atom/Atom.scala +++ b/src/main/scala/io/appthreat/atom/Atom.scala @@ -18,6 +18,7 @@ import io.appthreat.jssrc2cpg.passes.{ import io.appthreat.jssrc2cpg.{JsSrc2Cpg, Config as JSConfig} import io.appthreat.php2atom.passes.PhpSetKnownTypesPass import io.appthreat.php2atom.{Php2Atom, Config as PhpConfig} +import io.appthreat.ruby2atom.{Ruby2Atom, Config as RubyConfig} import io.appthreat.pysrc2cpg.{ DynamicTypeHintFullNamePass, Py2CpgOnFileSystem, @@ -208,7 +209,7 @@ object Atom: ) cmd("usages") .text("Extract local variable and parameter usages") - .action((_, *) => AtomUsagesConfig().withRemoveAtom(true)) + .action((_, *) => AtomUsagesConfig()) .children( opt[Int]("min-num-calls") .text(s"the minimum number of calls required for a usage slice - defaults to 1.") @@ -566,6 +567,15 @@ object Atom: new PhpSetKnownTypesPass(ag).createAndApply() ag } + case Languages.RUBYSRC | "RUBY" | "RB" | "JRUBY" => + new Ruby2Atom().createCpgWithOverlays( + RubyConfig() + .withInputPath(config.inputPath.pathAsString) + .withOutputPath(outputAtomFile) + .withIgnoredFilesRegex(".*(samples|examples|docs|tests).*") + ).map { ag => + ag + } case _ => Failure( new RuntimeException( s"No language frontend supported for language '$language'" diff --git a/src/main/scala/io/appthreat/atom/slicing/ReachableSlicing.scala b/src/main/scala/io/appthreat/atom/slicing/ReachableSlicing.scala index 1df118f..3c35219 100644 --- a/src/main/scala/io/appthreat/atom/slicing/ReachableSlicing.scala +++ b/src/main/scala/io/appthreat/atom/slicing/ReachableSlicing.scala @@ -88,7 +88,7 @@ object ReachableSlicing: atom.tag.name(CLI_SOURCE_TAG).call ).map(toSlice).toList end if - if language == Languages.PHP + if language == Languages.PHP || language == Languages.RUBYSRC then flowsList ++= atom.ret.where(_.tag.name(config.sinkTag)).reachableByFlows( atom.tag.name(config.sourceTag).parameter diff --git a/wrapper/nodejs/build.sh b/wrapper/nodejs/build.sh index 732e466..24c8959 100755 --- a/wrapper/nodejs/build.sh +++ b/wrapper/nodejs/build.sh @@ -13,6 +13,12 @@ php -r "unlink('composer-setup.php');" export COMPOSER_VENDOR_DIR=plugins php composer.phar require nikic/php-parser:4.18.0 --ignore-platform-reqs --optimize-autoloader -npm install +cd plugins/rubyastgen +bash setup.sh +cd ../.. + +rm plugins/bin/racc plugins/bin/ruby-parse plugins/bin/ruby-rewrite + +npm ci rm composer.phar composer.json composer.lock diff --git a/wrapper/nodejs/package-lock.json b/wrapper/nodejs/package-lock.json index ffa5dec..8153c72 100644 --- a/wrapper/nodejs/package-lock.json +++ b/wrapper/nodejs/package-lock.json @@ -1,22 +1,23 @@ { "name": "@appthreat/atom", - "version": "2.0.25", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@appthreat/atom", - "version": "2.0.25", + "version": "2.1.0", "license": "Apache-2.0", "dependencies": { - "@babel/parser": "^7.26.2", - "typescript": "^5.6.3", + "@babel/parser": "^7.26.3", + "typescript": "^5.7.2", "yargs": "^17.7.2" }, "bin": { "astgen": "astgen.js", "atom": "index.js", - "phpastgen": "phpastgen.js" + "phpastgen": "phpastgen.js", + "rbastgen": "rbastgen.js" }, "devDependencies": { "eslint": "8.57.0" @@ -53,12 +54,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -68,9 +69,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -1207,9 +1208,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/wrapper/nodejs/package.json b/wrapper/nodejs/package.json index e06c872..12c9ac8 100644 --- a/wrapper/nodejs/package.json +++ b/wrapper/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "@appthreat/atom", - "version": "2.0.25", + "version": "2.1.0", "description": "Create atom (⚛) representation for your application, packages and libraries", "exports": "./index.js", "type": "module", @@ -9,8 +9,8 @@ "lint": "eslint *.mjs *.js" }, "dependencies": { - "@babel/parser": "^7.26.2", - "typescript": "^5.6.3", + "@babel/parser": "^7.26.3", + "typescript": "^5.7.2", "yargs": "^17.7.2" }, "devDependencies": { @@ -19,7 +19,8 @@ "bin": { "atom": "index.js", "astgen": "astgen.js", - "phpastgen": "phpastgen.js" + "phpastgen": "phpastgen.js", + "rbastgen": "rbastgen.js" }, "engines": { "node": ">=16.0.0" diff --git a/wrapper/nodejs/plugins/rubyastgen/.bundle/config b/wrapper/nodejs/plugins/rubyastgen/.bundle/config new file mode 100644 index 0000000..2a12c99 --- /dev/null +++ b/wrapper/nodejs/plugins/rubyastgen/.bundle/config @@ -0,0 +1,5 @@ +--- +BUNDLE_BIN: "../bin" +BUNDLE_PATH: "bundle" +BUNDLE_DISABLE_SHARED_GEMS: "1" +BUNDLE_CACHE_ALL: "false" diff --git a/wrapper/nodejs/plugins/rubyastgen/Gemfile b/wrapper/nodejs/plugins/rubyastgen/Gemfile new file mode 100644 index 0000000..8e6a0f0 --- /dev/null +++ b/wrapper/nodejs/plugins/rubyastgen/Gemfile @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +source "https://rubygems.org" + +group :frontend do + gem "ruby_ast_gen", github: 'joernio/ruby_ast_gen', ref: 'v0.34.0' + gem "parser" + gem "ostruct" +end diff --git a/wrapper/nodejs/plugins/rubyastgen/Gemfile.lock b/wrapper/nodejs/plugins/rubyastgen/Gemfile.lock new file mode 100644 index 0000000..09b63f7 --- /dev/null +++ b/wrapper/nodejs/plugins/rubyastgen/Gemfile.lock @@ -0,0 +1,33 @@ +GIT + remote: https://github.com/joernio/ruby_ast_gen.git + revision: 1c6e88faec50a986d319e7fbcfe297ec01c48e5a + ref: v0.34.0 + specs: + ruby_ast_gen (0.34.0) + +GEM + remote: https://rubygems.org/ + specs: + ast (2.4.2) + ostruct (0.6.1) + parser (3.3.6.0) + ast (~> 2.4.1) + racc + racc (1.8.1) + racc (1.8.1-java) + +PLATFORMS + java + mswin64 + ruby + unknown + unknown + x86_64-darwin-23 + +DEPENDENCIES + ostruct + parser + ruby_ast_gen! + +BUNDLED WITH + 2.6.2 diff --git a/wrapper/nodejs/plugins/rubyastgen/setup.sh b/wrapper/nodejs/plugins/rubyastgen/setup.sh new file mode 100755 index 0000000..92ec902 --- /dev/null +++ b/wrapper/nodejs/plugins/rubyastgen/setup.sh @@ -0,0 +1,6 @@ +#! /usr/bin/env bash + +export GEM_HOME=. +bundle install --binstubs=../bin --no-cache --standalone=frontend +rm -rf bundle/ruby/3.4.0/bundler/gems/ruby_ast_gen-1c6e88faec50/.git* +rm -rf bundle/ruby/3.4.0/cache diff --git a/wrapper/nodejs/rbastgen.js b/wrapper/nodejs/rbastgen.js new file mode 100755 index 0000000..0be05b0 --- /dev/null +++ b/wrapper/nodejs/rbastgen.js @@ -0,0 +1,37 @@ +#!/usr/bin/env node + +import { dirname, join } from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { detectRuby } from "./utils.mjs"; + +let url = import.meta.url; +if (!url.startsWith("file://")) { + url = new URL(`file://${import.meta.url}`).toString(); +} +const dirName = import.meta ? dirname(fileURLToPath(url)) : __dirname; +export const PLUGINS_HOME = join(dirName, "plugins"); +const RUBY_ASTGEN_BIN = + process.env.RUBY_ASTGEN_BIN || join(PLUGINS_HOME, "bin", "ruby_ast_gen"); + +function main(argvs) { + if (!detectRuby()) { + console.warn("Ruby is not installed!"); + return false; + } + const cwd = process.env.ATOM_CWD || process.cwd(); + argvs.splice( + 0, + 0, + process.env.RUBY_ASTGEN_BIN || join(PLUGINS_HOME, "bin", "ruby_ast_gen") + ); + spawnSync(process.env.RUBY_CMD || "ruby", argvs, { + encoding: "utf-8", + cwd, + stdio: "inherit", + stderr: "inherit", + env: process.env, + timeout: process.env.ATOM_TIMEOUT || process.env.ASTGEN_TIMEOUT + }); +} +main(process.argv.slice(2)); diff --git a/wrapper/nodejs/utils.mjs b/wrapper/nodejs/utils.mjs index 0f659d0..0c0ad8c 100644 --- a/wrapper/nodejs/utils.mjs +++ b/wrapper/nodejs/utils.mjs @@ -88,7 +88,17 @@ export const detectJava = () => { }; export const detectPhp = () => { - let result = spawnSync(process.env.JAVA_CMD || "php", ["--version"], { + let result = spawnSync(process.env.PHP_CMD || "php", ["--version"], { + encoding: "utf-8" + }); + if (result.status !== 0 || result.error) { + return false; + } + return true; +}; + +export const detectRuby = () => { + let result = spawnSync(process.env.RUBY_CMD || "ruby", ["--version"], { encoding: "utf-8" }); if (result.status !== 0 || result.error) {