diff --git a/build.sbt b/build.sbt index d151f85..dcf254e 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ name := "atom" ThisBuild / organization := "io.appthreat" -ThisBuild / version := "2.0.14" +ThisBuild / version := "2.0.15" ThisBuild / scalaVersion := "3.4.1" val chenVersion = "2.0.11" diff --git a/codemeta.json b/codemeta.json index 3e49c3c..69aedac 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.14", + "version": "2.0.15", "description": "Atom is a novel intermediate representation for next-generation code analysis.", "applicationCategory": "code-analysis", "keywords": [ diff --git a/src/main/scala/io/appthreat/atom/parsedeps/PythonDependencyParser.scala b/src/main/scala/io/appthreat/atom/parsedeps/PythonDependencyParser.scala index 88faffc..21a7112 100644 --- a/src/main/scala/io/appthreat/atom/parsedeps/PythonDependencyParser.scala +++ b/src/main/scala/io/appthreat/atom/parsedeps/PythonDependencyParser.scala @@ -14,6 +14,8 @@ import java.io.File as JFile object PythonDependencyParser extends XDependencyParser: implicit val engineContext: EngineContext = EngineContext() + private val SETUP_PY_FILE = ".*setup.py" + private val SETUP_REQUIRES_PATTERN = "(install_requires|extras_require|tests_require)" override def parse(cpg: Cpg): DependencySlice = DependencySlice( (parseSetupPy(cpg) ++ parseImports(cpg)) @@ -28,15 +30,18 @@ object PythonDependencyParser extends XDependencyParser: val requirementsPattern = """([\[\]/.\w_-]+)\s?((=>|<=|==|>=|=<|<|>|!=|~=).*)""".r def dataSourcesToRequires = (cpg.literal ++ cpg.identifier) - .where(_.file.name(".*setup.py")) - .where(_.argumentName("install_requires")) - .collectAll[CfgNode] + .where(_.file.name(SETUP_PY_FILE)) + .where(_.argumentName(SETUP_REQUIRES_PATTERN)) + .collectAll[CfgNode] ++ cpg.assignment.where(_.file.name(SETUP_PY_FILE)).where( + _.source.isCall.name(".listLiteral") + ).target.isIdentifier.code(".*(libs|requirements)").collectAll[CfgNode] - def installRequires = cpg.call.where(_.file.name(".*setup.py")).where(_.argumentName( - "install_requires" - )).argument.collectAll[Literal] + def installOrExtraRequires = + cpg.call.where(_.file.name(SETUP_PY_FILE)).where(_.argumentName( + SETUP_REQUIRES_PATTERN + )).argument.collectAll[Literal] - def setupCall = cpg.call("setup").where(_.file.name(".*setup.py")) + def setupCall = cpg.call("setup").where(_.file.name(SETUP_PY_FILE)) def findOriginalDeclaration(xs: Traversal[CfgNode]): Iterable[Literal] = xs.flatMap { @@ -45,7 +50,7 @@ object PythonDependencyParser extends XDependencyParser: case i: Identifier => findOriginalDeclaration( cpg.assignment.where(_.and( - _.file.name(".*setup.py"), + _.file.name(SETUP_PY_FILE), _.target.isIdentifier.nameExact(i.name) )).source ) @@ -56,7 +61,7 @@ object PythonDependencyParser extends XDependencyParser: .to(Iterable) val initialTraversal = if dataFlowEnabled then setupCall.reachableBy(dataSourcesToRequires) - else (dataSourcesToRequires ++ installRequires) + else (dataSourcesToRequires ++ installOrExtraRequires) findOriginalDeclaration(initialTraversal) .map(x => X2Cpg.stripQuotes(x.code)) .map { @@ -105,7 +110,7 @@ object PythonDependencyParser extends XDependencyParser: ).last.replaceFirst("\\.py", "")) .toSet cpg.imports - .whereNot(_.call.file.name(".*setup.py")) + .whereNot(_.call.file.name(SETUP_PY_FILE)) .filterNot { _.importedEntity match case Some(x) if x.startsWith(".") => true diff --git a/src/test/scala/io/appthreat/atom/PythonDependencyScannerTests.scala b/src/test/scala/io/appthreat/atom/PythonDependencyScannerTests.scala index 8bcc84b..e6457bf 100644 --- a/src/test/scala/io/appthreat/atom/PythonDependencyScannerTests.scala +++ b/src/test/scala/io/appthreat/atom/PythonDependencyScannerTests.scala @@ -7,11 +7,11 @@ import org.scalatest.wordspec.AnyWordSpec import java.io.File -class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = false) { +class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = false): - "dependencies from the `requests` library" should { - lazy val cpg = code( - """ + "dependencies from the `requests` library" should { + lazy val cpg = code( + """ |#!/usr/bin/env python |import os |import sys @@ -138,9 +138,9 @@ class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = fa |) | |""".stripMargin, - "setup.py" - ).moreCode( - """ + "setup.py" + ).moreCode( + """ |import os.path |import socket # noqa: F401 | @@ -196,36 +196,62 @@ class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = fa | raise InvalidSchema("Missing dependencies for SOCKS support.") | |""".stripMargin, - Seq("requests", "adapters.py").mkString(File.separator) - ) + Seq("requests", "adapters.py").mkString(File.separator) + ) - "have the modules scanned successfully" in { - val scanResult = PythonDependencyParser.parse(cpg) - scanResult.modules shouldBe List( - ModuleWithVersion("PackageC", "1.2.0.dev1+hg.5.b11e5e6f0b0b", "", ""), - ModuleWithVersion("PickyThing", "2.4c1", "<1.6,>1.9,!=1.9.6,<2.0a0", ""), - ModuleWithVersion("certifi", "", ">=2017.4.17", ""), - ModuleWithVersion("charset_normalizer", "", ">=2,<4", ""), - ModuleWithVersion("dbt-core", "", "~=1.7,<1.8", ""), - ModuleWithVersion("google-api-core[grpc]", "", ">= 1.34.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,!=2.10.*", ""), - ModuleWithVersion("idna", "", ">=2.5,<4", ""), - ModuleWithVersion("os", "", "", "os.path"), - ModuleWithVersion("packageA", "", ">=1.4.2,<1.9,!=1.5.*,!=1.6.*", ""), - ModuleWithVersion("packageB", "", ">=0.5.0,< 0.7.0", ""), - ModuleWithVersion("proto-plus", "", ">= 1.22.2, <2.0.0dev; python_version>='3.11',>= 1.22.0, <2.0.0dev", ""), - ModuleWithVersion("protobuf", "", ">=3.19.5,<5.0.0dev,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", ""), - ModuleWithVersion("re-wx", "", ">=0.0.2", ""), - ModuleWithVersion("socket", "", "", "socket"), - ModuleWithVersion("typing-extensions", "3.10.0.2", "", ""), - ModuleWithVersion("urllib3", "", ">=1.21.1,<3", "urllib3.poolmanager.proxy_from_url,urllib3.util.Timeout,urllib3.exceptions.LocationValueError,urllib3.contrib.socks.SOCKSProxyManager,urllib3.exceptions.HTTPError,urllib3.exceptions.SSLError,urllib3.exceptions.ProxyError,urllib3.exceptions.InvalidHeader,urllib3.exceptions.MaxRetryError,urllib3.exceptions.ConnectTimeoutError,urllib3.exceptions.ClosedPoolError,urllib3.exceptions.ProtocolError,urllib3.util.retry.Retry,urllib3.exceptions.ResponseError,urllib3.exceptions.ReadTimeoutError,urllib3.exceptions.NewConnectionError,urllib3.util.parse_url,urllib3.poolmanager.PoolManager"), - ModuleWithVersion("zope.interface", "", ">=5.1.0", "") - ) + "have the modules scanned successfully" in { + val scanResult = PythonDependencyParser.parse(cpg) + scanResult.modules shouldBe List( + ModuleWithVersion("PackageC", "1.2.0.dev1+hg.5.b11e5e6f0b0b", "", ""), + ModuleWithVersion("PickyThing", "2.4c1", "<1.6,>1.9,!=1.9.6,<2.0a0", ""), + ModuleWithVersion("PySocks", "", ">=1.5.6, !=1.5.7", ""), + ModuleWithVersion("certifi", "", ">=2017.4.17", ""), + ModuleWithVersion("charset_normalizer", "", ">=2,<4", ""), + ModuleWithVersion("dbt-core", "", "~=1.7,<1.8", ""), + ModuleWithVersion( + "google-api-core[grpc]", + "", + ">= 1.34.0, <3.0.0dev,!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,!=2.5.*,!=2.6.*,!=2.7.*,!=2.8.*,!=2.9.*,!=2.10.*", + "" + ), + ModuleWithVersion("idna", "", ">=2.5,<4", ""), + ModuleWithVersion("os", "", "", "os.path"), + ModuleWithVersion("packageA", "", ">=1.4.2,<1.9,!=1.5.*,!=1.6.*", ""), + ModuleWithVersion("packageB", "", ">=0.5.0,< 0.7.0", ""), + ModuleWithVersion( + "proto-plus", + "", + ">= 1.22.2, <2.0.0dev; python_version>='3.11',>= 1.22.0, <2.0.0dev", + "" + ), + ModuleWithVersion( + "protobuf", + "", + ">=3.19.5,<5.0.0dev,!=3.20.0,!=3.20.1,!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5", + "" + ), + ModuleWithVersion("pytest", "", ">=3", ""), + ModuleWithVersion("pytest-cov", "", "", ""), + ModuleWithVersion("pytest-httpbin", "2.0.0", "", ""), + ModuleWithVersion("pytest-mock", "", "", ""), + ModuleWithVersion("pytest-xdist", "", "", ""), + ModuleWithVersion("re-wx", "", ">=0.0.2", ""), + ModuleWithVersion("socket", "", "", "socket"), + ModuleWithVersion("typing-extensions", "3.10.0.2", "", ""), + ModuleWithVersion( + "urllib3", + "", + ">=1.21.1,<3", + "urllib3.poolmanager.proxy_from_url,urllib3.util.Timeout,urllib3.exceptions.LocationValueError,urllib3.contrib.socks.SOCKSProxyManager,urllib3.exceptions.HTTPError,urllib3.exceptions.SSLError,urllib3.exceptions.ProxyError,urllib3.exceptions.InvalidHeader,urllib3.exceptions.MaxRetryError,urllib3.exceptions.ConnectTimeoutError,urllib3.exceptions.ClosedPoolError,urllib3.exceptions.ProtocolError,urllib3.util.retry.Retry,urllib3.exceptions.ResponseError,urllib3.exceptions.ReadTimeoutError,urllib3.exceptions.NewConnectionError,urllib3.util.parse_url,urllib3.poolmanager.PoolManager" + ), + ModuleWithVersion("zope.interface", "", ">=5.1.0", "") + ) + } } - } "dependencies from the `impacket` library" should { lazy val cpg = code( - """ + """ |#!/usr/bin/env python |# $Id$ | @@ -268,7 +294,7 @@ class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = fa |) | |""".stripMargin, - "setup.py" + "setup.py" ) "have the modules scanned successfully" in { @@ -285,4 +311,314 @@ class PythonDependencyScannerTests extends PySrc2CpgFixture(withOssDataflow = fa } } -} + "dependencies from the `evadb` project" should { + lazy val cpg = code( + """ + |import io + |import os + | + |# to read contents of README file + |from pathlib import Path + |from typing import Dict + | + |from setuptools import find_packages, setup + |from setuptools.command.install import install + |from subprocess import check_call + | + |this_directory = Path(__file__).parent + |LONG_DESCRIPTION = (this_directory / "README.md").read_text() + | + |DESCRIPTION = "EvaDB AI-Relational Database System" + |NAME = "evadb" + |AUTHOR = "Georgia Tech Database Group" + |AUTHOR_EMAIL = "arulraj@gatech.edu" + |URL = "https://github.com/georgia-tech-db/eva" + | + |# Check Python version + |# import sys + |# if sys.version_info < (3, 8): + |# sys.exit("Python 3.8 or later is required.") + | + | + |def read(path, encoding="utf-8"): + | path = os.path.join(os.path.dirname(__file__), path) + | with io.open(path, encoding=encoding) as fp: + | return fp.read() + | + | + |# version.py defines the VERSION and VERSION_SHORT variables + |VERSION_DICT: Dict[str, str] = {} + |with open("evadb/version.py", "r") as version_file: + | exec(version_file.read(), VERSION_DICT) + | + |DOWNLOAD_URL = "https://github.com/georgia-tech-db/eva" + |LICENSE = "Apache License 2.0" + |VERSION = VERSION_DICT["VERSION"] + | + |minimal_requirements = [ + | "numpy>=1.19.5", + | "pandas>=2.1.0", # DataFrame.map is available after v2.1.0 + | "sqlalchemy>=2.0.0", + | "sqlalchemy-utils>=0.36.6", + | "lark>=1.0.0", + | "pyyaml>=5.1", + | "aenum>=2.2.0", + | "diskcache>=5.4.0", + | "retry>=0.9.2", + | "pydantic<2", # ray-project/ray#37019. + | "psutil", + | "thefuzz", + |] + | + |vision_libs = [ + | "torch>=1.10.0", + | "torchvision>=0.11.1", + | "transformers", # HUGGINGFACE + | "faiss-cpu", # DEFAULT VECTOR INDEX + | "opencv-python-headless>=4.6.0.66", + | "Pillow>=8.4.0", + | "eva-decord>=0.6.1", # VIDEO PROCESSING + | "ultralytics>=8.0.93", # OBJECT DETECTION + | "timm>=0.6.13", # HUGGINGFACE VISION TASKS + | "sentencepiece", # TRANSFORMERS + |] + | + |document_libs = [ + | "transformers", # HUGGINGFACE + | "langchain", # DATA LOADERS + | "faiss-cpu", # DEFAULT VECTOR INDEX + | "pymupdf<1.23.0", # pymupdf/PyMuPDF#2617 and pymupdf/PyMuPDF#2614 + | "pdfminer.six", + | "sentence-transformers", + | "protobuf", + | "bs4", + | "openai>=1.0", # CHATGPT + | "gpt4all", # PRIVATE GPT + | "sentencepiece", # TRANSFORMERS + |] + | + |function_libs = [ + | "facenet-pytorch>=2.5.2", # FACE DETECTION + | "pytube", # YOUTUBE QA APP + | "youtube-transcript-api", # YOUTUBE QA APP + | "boto3", # AWS + | "norfair>=2.2.0", # OBJECT TRACKING + | "kornia", # SIFT FEATURES + |] + | + |ray_libs = [ + | "ray>=1.13.0,<2.5.0", # BREAKING CHANGES IN 2.5.0 + |] + | + |notebook_libs = [ + | "ipython<8.13.0", + | "ipywidgets>=7.7.2", + | "matplotlib>=3.3.4", + | "nbmake>=1.2.1", + | "nest-asyncio>=1.5.6", + |] + | + |qdrant_libs = ["qdrant_client"] # cannot install on 3.11 due to grcpio + | + |pinecone_libs = ["pinecone-client"] + | + |chromadb_libs = ["chromadb"] + | + |weaviate_libs = ["weaviate-client"] + | + |milvus_libs = ["pymilvus>=2.3.0"] + | + | + |postgres_libs = [ + | "psycopg2", + |] + | + |ludwig_libs = ["ludwig[hyperopt,distributed]"] # MODEL TRAIN AND FINE TUNING + | + |sklearn_libs = ["scikit-learn"] + | + |xgboost_libs = ["flaml[automl]"] + | + |hackernews_libs = ["requests"] + | + |forecasting_libs = [ + | "statsforecast", # MODEL TRAIN AND FINE TUNING + | "neuralforecast", # MODEL TRAIN AND FINE TUNING + |] + | + |imagegen_libs = [ + | "replicate" + |] + | + |### NEEDED FOR DEVELOPER TESTING ONLY + | + |dev_libs = [ + | # TESTING PACKAGES + | "pytest>=6.1.2", + | "pytest-cov>=2.11.1", + | "mock", + | "coveralls>=3.0.1", + | "moto[s3]>=4.1.1", + | "pytest-testmon", + | # BENCHMARK PACKAGES + | "pytest-benchmark", + | # LINTING PACKAGES + | "codespell", + | "pylint", + | "black>=23.1.0", + | "isort>=5.10.1", + | "flake8>=3.9.1", + | # DISTRIBUTION PACKAGES + | "wheel>=0.37.1", + | "semantic_version", + | "PyGithub", + | "twine", + | "PyDriller", + |] + | + |INSTALL_REQUIRES = minimal_requirements + | + |EXTRA_REQUIRES = { + | "ray": ray_libs, + | "vision": vision_libs, + | "document": document_libs, + | "function": function_libs, + | "notebook": notebook_libs, + | "qdrant": qdrant_libs, + | "pinecone": pinecone_libs, + | "chromadb": chromadb_libs, + | "milvus": milvus_libs, + | "weaviate": weaviate_libs, + | "postgres": postgres_libs, + | "ludwig": ludwig_libs, + | "sklearn": sklearn_libs, + | "xgboost": xgboost_libs, + | "forecasting": forecasting_libs, + | "hackernews": hackernews_libs, + | # everything except ray, qdrant, ludwig and postgres. The first three fail on pyhton 3.11. + | "dev": dev_libs + vision_libs + document_libs + function_libs + notebook_libs + forecasting_libs + sklearn_libs + imagegen_libs + xgboost_libs + |} + | + |setup( + | name=NAME, + | version=VERSION, + | description=DESCRIPTION, + | long_description=LONG_DESCRIPTION, + | long_description_content_type="text/markdown", + | author=AUTHOR, + | author_email=AUTHOR_EMAIL, + | url=URL, + | download_url=DOWNLOAD_URL, + | license=LICENSE, + | classifiers=[ + | "Development Status :: 5 - Production/Stable", + | "License :: OSI Approved :: Apache Software License", + | "Programming Language :: Python :: 3.8", + | "Programming Language :: Python :: 3.9", + | "Programming Language :: Python :: 3.10", + | # "Programming Language :: Python :: 3.11", + | ], + | packages=find_packages(exclude=["tests", "tests.*"]), + | # https://python-packaging.readthedocs.io/en/latest/command-line-scripts.html#the-console-scripts-entry-point + | entry_points={ + | "console_scripts": [ + | "evadb_server=evadb.evadb_server:main", + | "evadb_client=evadb.evadb_cmd_client:main", + | ] + | }, + | python_requires=">=3.8", + | install_requires=INSTALL_REQUIRES, + | extras_require=EXTRA_REQUIRES, + | include_package_data=True, + | package_data={ + | "evadb": [ + | "evadb.yml", + | "parser/evadb.lark", + | "third_party/databases/**/requirements.txt", + | ] + | }, + |) + | + |""".stripMargin, + "setup.py" + ) + + "have the modules scanned successfully" in { + val scanResult = PythonDependencyParser.parse(cpg) + scanResult.modules shouldBe List( + ModuleWithVersion("Pillow", "", ">=8.4.0", ""), + ModuleWithVersion("PyDriller", "", "", ""), + ModuleWithVersion("PyGithub", "", "", ""), + ModuleWithVersion("aenum", "", ">=2.2.0", ""), + ModuleWithVersion("black", "", ">=23.1.0", ""), + ModuleWithVersion("boto3", "", "", ""), + ModuleWithVersion("bs4", "", "", ""), + ModuleWithVersion("chromadb", "", "", ""), + ModuleWithVersion("codespell", "", "", ""), + ModuleWithVersion("coveralls", "", ">=3.0.1", ""), + ModuleWithVersion("diskcache", "", ">=5.4.0", ""), + ModuleWithVersion("eva-decord", "", ">=0.6.1", ""), + ModuleWithVersion("facenet-pytorch", "", ">=2.5.2", ""), + ModuleWithVersion("faiss-cpu", "", "", ""), + ModuleWithVersion("flake8", "", ">=3.9.1", ""), + ModuleWithVersion("flaml[automl]", "", "", ""), + ModuleWithVersion("gpt4all", "", "", ""), + ModuleWithVersion("ipython", "", "<8.13.0", ""), + ModuleWithVersion("ipywidgets", "", ">=7.7.2", ""), + ModuleWithVersion("isort", "", ">=5.10.1", ""), + ModuleWithVersion("kornia", "", "", ""), + ModuleWithVersion("langchain", "", "", ""), + ModuleWithVersion("lark", "", ">=1.0.0", ""), + ModuleWithVersion("ludwig[hyperopt,distributed]", "", "", ""), + ModuleWithVersion("matplotlib", "", ">=3.3.4", ""), + ModuleWithVersion("mock", "", "", ""), + ModuleWithVersion("moto[s3]", "", ">=4.1.1", ""), + ModuleWithVersion("nbmake", "", ">=1.2.1", ""), + ModuleWithVersion("nest-asyncio", "", ">=1.5.6", ""), + ModuleWithVersion("neuralforecast", "", "", ""), + ModuleWithVersion("norfair", "", ">=2.2.0", ""), + ModuleWithVersion("numpy", "", ">=1.19.5", ""), + ModuleWithVersion("openai", "", ">=1.0", ""), + ModuleWithVersion("opencv-python-headless", "", ">=4.6.0.66", ""), + ModuleWithVersion("pandas", "", ">=2.1.0", ""), + ModuleWithVersion("pdfminer.six", "", "", ""), + ModuleWithVersion("pinecone-client", "", "", ""), + ModuleWithVersion("protobuf", "", "", ""), + ModuleWithVersion("psutil", "", "", ""), + ModuleWithVersion("psycopg2", "", "", ""), + ModuleWithVersion("pydantic", "", "<2", ""), + ModuleWithVersion("pylint", "", "", ""), + ModuleWithVersion("pymilvus", "", ">=2.3.0", ""), + ModuleWithVersion("pymupdf", "", "<1.23.0", ""), + ModuleWithVersion("pytest", "", ">=6.1.2", ""), + ModuleWithVersion("pytest-benchmark", "", "", ""), + ModuleWithVersion("pytest-cov", "", ">=2.11.1", ""), + ModuleWithVersion("pytest-testmon", "", "", ""), + ModuleWithVersion("pytube", "", "", ""), + ModuleWithVersion("pyyaml", "", ">=5.1", ""), + ModuleWithVersion("qdrant_client", "", "", ""), + ModuleWithVersion("ray", "", ">=1.13.0,<2.5.0", ""), + ModuleWithVersion("replicate", "", "", ""), + ModuleWithVersion("requests", "", "", ""), + ModuleWithVersion("retry", "", ">=0.9.2", ""), + ModuleWithVersion("scikit-learn", "", "", ""), + ModuleWithVersion("semantic_version", "", "", ""), + ModuleWithVersion("sentence-transformers", "", "", ""), + ModuleWithVersion("sentencepiece", "", "", ""), + ModuleWithVersion("sqlalchemy", "", ">=2.0.0", ""), + ModuleWithVersion("sqlalchemy-utils", "", ">=0.36.6", ""), + ModuleWithVersion("statsforecast", "", "", ""), + ModuleWithVersion("thefuzz", "", "", ""), + ModuleWithVersion("timm", "", ">=0.6.13", ""), + ModuleWithVersion("torch", "", ">=1.10.0", ""), + ModuleWithVersion("torchvision", "", ">=0.11.1", ""), + ModuleWithVersion("transformers", "", "", ""), + ModuleWithVersion("twine", "", "", ""), + ModuleWithVersion("ultralytics", "", ">=8.0.93", ""), + ModuleWithVersion("weaviate-client", "", "", ""), + ModuleWithVersion("wheel", "", ">=0.37.1", ""), + ModuleWithVersion("youtube-transcript-api", "", "", "") + ) + } + } +end PythonDependencyScannerTests diff --git a/wrapper/nodejs/package-lock.json b/wrapper/nodejs/package-lock.json index 6063f8a..1c86928 100644 --- a/wrapper/nodejs/package-lock.json +++ b/wrapper/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@appthreat/atom", - "version": "2.0.14", + "version": "2.0.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@appthreat/atom", - "version": "2.0.14", + "version": "2.0.15", "license": "Apache-2.0", "dependencies": { "@babel/parser": "^7.24.7", diff --git a/wrapper/nodejs/package.json b/wrapper/nodejs/package.json index 0abfc8d..159f81c 100644 --- a/wrapper/nodejs/package.json +++ b/wrapper/nodejs/package.json @@ -1,6 +1,6 @@ { "name": "@appthreat/atom", - "version": "2.0.14", + "version": "2.0.15", "description": "Create atom (⚛) representation for your application, packages and libraries", "exports": "./index.js", "type": "module",