├── .gitattributes ├── .github └── workflows │ └── ci_tests.yml ├── .gitignore ├── .node-version ├── .npm-version ├── .nvmrc ├── .prettierignore ├── LICENSE ├── README.md ├── flake.nix ├── meta ├── assets │ └── logo.png ├── build.sh ├── docker │ ├── .gitignore │ ├── Dockerfile.aarch64 │ ├── Dockerfile.x86_64 │ ├── build-environment-image │ │ ├── Dockerfile │ │ ├── README.md │ │ └── build.sh │ ├── build-image.sh │ └── wine-test-image │ │ ├── Dockerfile │ │ ├── README.md │ │ ├── build.sh │ │ └── sample.bat ├── examples │ ├── civet-example.civet │ ├── coffeescript-example.coffee │ ├── custom-repl.ts │ ├── environment-variables.js │ ├── git-info-to-yml.js │ ├── git-stuff.js │ ├── import-meta.js │ ├── importing-commonjs.js │ ├── importing-json.js │ ├── jsx-example.jsx │ ├── paths.js │ ├── script-args.js │ ├── show-globals.js │ ├── some-commonjs.js │ ├── some-json.json │ ├── tsx-example.tsx │ ├── typescript-example.ts │ └── using-stuff-from-npm.jsx ├── generated-docs │ ├── ChildProcess.md │ ├── README.md │ ├── __filename-and-__dirname.md │ ├── assert.md │ ├── basename.md │ ├── bytecode.md │ ├── cat.md │ ├── cd.md │ ├── chmod.md │ ├── console.md │ ├── csv.md │ ├── dirname.md │ ├── echo.md │ ├── encoding.md │ ├── engine.md │ ├── env.md │ ├── exec.md │ ├── exit.md │ ├── extname.md │ ├── filesystem.md │ ├── git-repo.md │ ├── glob.md │ ├── grep.md │ ├── help.md │ ├── inspect.md │ ├── interactive-prompt.md │ ├── intervals.md │ ├── is.md │ ├── jsx.md │ ├── libc.md │ ├── logger.md │ ├── ls.md │ ├── mkdir.md │ ├── mkdirp.md │ ├── modulesys.md │ ├── node-compat.md │ ├── open-url.md │ ├── others.md │ ├── parse-script-args.md │ ├── path.md │ ├── print.md │ ├── printf.md │ ├── pwd.md │ ├── quickjs-extensions.md │ ├── quickjs-globals.md │ ├── readlink.md │ ├── realpath.md │ ├── regexp-escape.md │ ├── sleep.md │ ├── start-repl.md │ ├── string-dedent.md │ ├── strings.md │ ├── toml.md │ ├── touch.md │ ├── types.md │ ├── which.md │ ├── whoami.md │ ├── yaml.md │ └── yavascript.md ├── how-to-deploy-a-new-version.txt ├── kame │ ├── kame-config.js │ ├── kame-module-stub.js │ ├── kame-nice-path-stub.js │ └── kame-ts-interface-checker-stub.js ├── ninja │ ├── bundles.ninja.js │ ├── bytecode.ninja.js │ ├── dts.ninja.js │ ├── generated-docs.ninja.js │ ├── npm.ninja.js │ ├── programs.ninja.js │ └── rules.ninja.js ├── npm │ ├── .gitignore │ ├── .npmignore │ ├── lib │ │ ├── binary-path.js │ │ ├── cli.js │ │ └── index.js │ └── package.json ├── root-dir.d.ts ├── root-dir.js ├── scripts │ ├── assemble-tgz.sh │ ├── ci.sh │ ├── lib │ │ ├── generated-doc-index.md │ │ ├── generated-doc-links.json5 │ │ ├── newline.txt │ │ └── walk.js │ ├── markdown-toc.js │ ├── md-links-from-json5.js │ ├── ninja-build.sh │ └── set-package-version.js ├── tests │ ├── fixtures │ │ ├── copy │ │ │ ├── .gitignore │ │ │ └── blah │ │ │ │ └── blah2 │ │ │ │ └── hi.txt │ │ ├── file_content │ │ │ ├── .gitignore │ │ │ ├── hello.txt │ │ │ └── hello2.txt │ │ ├── gitignoring │ │ │ ├── hi.txt │ │ │ └── subdir │ │ │ │ └── .gitignore │ │ ├── glob │ │ │ ├── cabana │ │ │ │ └── .gitkeep │ │ │ ├── hi.js │ │ │ ├── hi.something.js │ │ │ ├── hi.txt │ │ │ ├── hi │ │ │ │ ├── .yeah │ │ │ │ └── there.txt │ │ │ └── potato │ │ │ │ ├── banana │ │ │ │ ├── yo.js │ │ │ │ └── yo.txt │ │ │ │ └── eggplant │ │ ├── grep │ │ │ └── stuff.txt │ │ ├── logging │ │ │ ├── log-1.js │ │ │ ├── log-three.coffee │ │ │ └── log-two.ts │ │ ├── mkdir │ │ │ └── .gitignore │ │ ├── remove │ │ │ └── .gitignore │ │ ├── scripts │ │ │ ├── __filename-and-__dirname-2.js │ │ │ ├── __filename-and-__dirname.js │ │ │ ├── http-import-error.js │ │ │ ├── https-import-error.js │ │ │ ├── importing-from-npm-protocol.js │ │ │ ├── importing-json.js │ │ │ ├── npm-proto-import-error.js │ │ │ ├── requiring-with-npm-proto.js │ │ │ ├── some-civet.civet │ │ │ ├── some-coffeescript.coffee │ │ │ ├── some-json.json │ │ │ ├── some-jsx.jsx │ │ │ ├── some-tsx.tsx │ │ │ ├── some-typescript.ts │ │ │ ├── toplevel-await-and-export-together.js │ │ │ ├── toplevel-await.coffee │ │ │ ├── toplevel-await.js │ │ │ ├── toplevel-await.ts │ │ │ ├── toplevel-await.tsx │ │ │ ├── type-coercion-via-assert.ts │ │ │ └── type-coercion-via-is.ts │ │ ├── symlinks │ │ │ ├── dead-link │ │ │ ├── link-to-file │ │ │ ├── link-to-folder │ │ │ ├── some-file │ │ │ └── some-folder │ │ │ │ └── .gitkeep │ │ ├── which │ │ │ ├── bin1 │ │ │ │ ├── program │ │ │ │ ├── program1 │ │ │ │ └── something.bat │ │ │ ├── bin2 │ │ │ │ ├── program │ │ │ │ └── program3 │ │ │ └── usr │ │ │ │ └── bin3 │ │ │ │ ├── program │ │ │ │ ├── program2 │ │ │ │ └── something.exe │ │ └── worker │ │ │ ├── main.js │ │ │ └── worker.js │ ├── jest │ │ ├── babel-config.js │ │ ├── config.js │ │ ├── go-to-root.js │ │ └── snapshotSerializer.js │ ├── package-lock.json │ ├── package.json │ ├── src │ │ ├── __filename-and-__dirname.test.ts │ │ ├── __snapshots__ │ │ │ ├── determine-target.test.ts.snap │ │ │ ├── eval.test.ts.snap │ │ │ └── fixture-scripts.test.ts.snap │ │ ├── assert.test.ts │ │ ├── assert.type.test.ts │ │ ├── basename.test.ts │ │ ├── cat.test.ts │ │ ├── cd-and-pwd.test.ts │ │ ├── cjs-interop.test.ts │ │ ├── console.test.ts │ │ ├── csv.test.ts │ │ ├── determine-target.test.ts │ │ ├── dirname.test.ts │ │ ├── dts.test.ts │ │ ├── echo.test.ts │ │ ├── env.test.ts │ │ ├── error-handling.test.ts │ │ ├── esm-to-require.test.ts │ │ ├── eval.test.ts │ │ ├── exec.test.ts │ │ ├── exit.test.ts │ │ ├── extname.test.ts │ │ ├── filesystem.test.ts │ │ ├── fixture-scripts.test.ts │ │ ├── git-repo.test.ts │ │ ├── glob.test.ts │ │ ├── globals.test.ts │ │ ├── grep.test.ts │ │ ├── license.test.ts │ │ ├── logger.test.ts │ │ ├── ls.test.ts │ │ ├── mkdir.test.ts │ │ ├── others.test.ts │ │ ├── parse-script-args.test.ts │ │ ├── path.test.ts │ │ ├── preload.test.ts │ │ ├── printf.test.ts │ │ ├── readlink.test.ts │ │ ├── realpath.test.ts │ │ ├── repl.test.ts │ │ ├── sleep.test.ts │ │ ├── strings.test.ts │ │ ├── test-helpers.ts │ │ ├── to-argv.test.ts │ │ ├── toml.test.ts │ │ ├── which.test.ts │ │ ├── whoami.test.ts │ │ ├── win32-exe.test.ts │ │ └── worker.test.ts │ └── tsconfig.json └── type-tests │ ├── exec.type-test.ts │ ├── grep.type-test.ts │ └── tsconfig.json ├── package-lock.json ├── package.json ├── src ├── api │ ├── __filename-and-__dirname │ │ ├── __filename-and-__dirname.inc.d.ts │ │ ├── __filename-and-__dirname.ts │ │ └── index.ts │ ├── _install-api.ts │ ├── assert │ │ ├── assert.inc.d.ts │ │ ├── assert.ts │ │ └── index.ts │ ├── commands │ │ ├── _all.ts │ │ ├── _stubs.ts │ │ ├── basename │ │ │ ├── basename.inc.d.ts │ │ │ ├── basename.ts │ │ │ └── index.ts │ │ ├── cat │ │ │ ├── cat.inc.d.ts │ │ │ ├── cat.ts │ │ │ └── index.ts │ │ ├── cd │ │ │ ├── cd.inc.d.ts │ │ │ ├── cd.ts │ │ │ └── index.ts │ │ ├── chmod │ │ │ ├── chmod.inc.d.ts │ │ │ ├── chmod.ts │ │ │ └── index.ts │ │ ├── dirname │ │ │ ├── dirname.inc.d.ts │ │ │ ├── dirname.ts │ │ │ └── index.ts │ │ ├── echo │ │ │ ├── echo.inc.d.ts │ │ │ ├── echo.ts │ │ │ └── index.ts │ │ ├── exit │ │ │ ├── exit.inc.d.ts │ │ │ ├── exit.ts │ │ │ └── index.ts │ │ ├── extname │ │ │ ├── extname.inc.d.ts │ │ │ ├── extname.ts │ │ │ └── index.ts │ │ ├── ls │ │ │ ├── index.ts │ │ │ ├── ls.inc.d.ts │ │ │ └── ls.ts │ │ ├── mkdir │ │ │ ├── index.ts │ │ │ ├── mkdir.inc.d.ts │ │ │ ├── mkdir.ts │ │ │ ├── mkdirp.inc.d.ts │ │ │ └── mkdirp.ts │ │ ├── printf │ │ │ ├── index.ts │ │ │ ├── printf.inc.d.ts │ │ │ └── printf.ts │ │ ├── pwd │ │ │ ├── index.ts │ │ │ ├── note.txt │ │ │ ├── pwd.inc.d.ts │ │ │ └── pwd.ts │ │ ├── readlink │ │ │ ├── index.ts │ │ │ ├── readlink.inc.d.ts │ │ │ └── readlink.ts │ │ ├── realpath │ │ │ ├── index.ts │ │ │ ├── realpath.inc.d.ts │ │ │ └── realpath.ts │ │ ├── sleep │ │ │ ├── index.ts │ │ │ ├── sleep.inc.d.ts │ │ │ └── sleep.ts │ │ ├── touch │ │ │ ├── index.ts │ │ │ ├── touch.inc.d.ts │ │ │ └── touch.ts │ │ ├── which │ │ │ ├── index.ts │ │ │ ├── which.inc.d.ts │ │ │ └── which.ts │ │ └── whoami │ │ │ ├── index.ts │ │ │ ├── whoami.inc.d.ts │ │ │ └── whoami.ts │ ├── console │ │ ├── console.inc.d.ts │ │ ├── console.ts │ │ ├── index.ts │ │ └── print.inc.d.ts │ ├── csv │ │ ├── csv.inc.d.ts │ │ ├── csv.ts │ │ └── index.ts │ ├── env │ │ ├── env.inc.d.ts │ │ ├── env.ts │ │ └── index.ts │ ├── exec │ │ ├── ChildProcess.inc.d.ts │ │ ├── ChildProcess.ts │ │ ├── exec.inc.d.ts │ │ ├── exec.ts │ │ ├── index.ts │ │ └── to-argv.ts │ ├── filesystem │ │ ├── _getPathInfo.ts │ │ ├── copy.ts │ │ ├── exists.ts │ │ ├── filesystem.inc.d.ts │ │ ├── index.ts │ │ ├── isDir.ts │ │ ├── isExecutable.ts │ │ ├── isFile.ts │ │ ├── isLink.ts │ │ ├── isReadable.ts │ │ ├── isWritable.ts │ │ ├── readFile.ts │ │ ├── remove.ts │ │ ├── rename.ts │ │ └── writeFile.ts │ ├── git-repo │ │ ├── git-repo.inc.d.ts │ │ ├── git-repo.ts │ │ └── index.ts │ ├── glob │ │ ├── glob.inc.d.ts │ │ ├── glob.ts │ │ └── index.ts │ ├── grep │ │ ├── grep.inc.d.ts │ │ ├── grep.ts │ │ └── index.ts │ ├── help │ │ ├── help.inc.d.ts │ │ ├── help.ts │ │ └── index.ts │ ├── is │ │ ├── index.ts │ │ ├── is.inc.d.ts │ │ └── is.ts │ ├── jsx │ │ ├── index.ts │ │ ├── jsx.inc.d.ts │ │ └── jsx.ts │ ├── logger │ │ ├── index.ts │ │ ├── logger.inc.d.ts │ │ └── logger.ts │ ├── node-compat │ │ ├── index.ts │ │ ├── node-compat.inc.d.ts │ │ └── node-compat.ts │ ├── open-url │ │ ├── index.ts │ │ ├── open-url.inc.d.ts │ │ └── open-url.ts │ ├── others │ │ ├── index.ts │ │ ├── others.inc.d.ts │ │ └── others.ts │ ├── parse-script-args │ │ ├── index.ts │ │ ├── parse-script-args.inc.d.ts │ │ └── parse-script-args.ts │ ├── path │ │ ├── _win32Helpers.ts │ │ ├── index.ts │ │ ├── path.inc.d.ts │ │ └── path.ts │ ├── regexp-escape │ │ ├── index.ts │ │ ├── regexp-escape.inc.d.ts │ │ └── regexp-escape.ts │ ├── repl │ │ ├── generic-repl.js │ │ ├── history-file.ts │ │ ├── index.ts │ │ ├── interactive-prompt.inc.d.ts │ │ ├── interactive-prompt.ts │ │ ├── modified-qjs-repl.js │ │ ├── special.ts │ │ ├── start-repl.inc.d.ts │ │ └── start-repl.ts │ ├── shared │ │ └── make-inspect-log.ts │ ├── string-dedent │ │ ├── index.ts │ │ ├── string-dedent.inc.d.ts │ │ └── string-dedent.ts │ ├── strings │ │ ├── index.ts │ │ ├── strings.inc.d.ts │ │ └── strings.ts │ ├── toml │ │ ├── index.ts │ │ ├── toml.inc.d.ts │ │ └── toml.ts │ ├── types │ │ ├── index.ts │ │ ├── types.inc.d.ts │ │ └── types.ts │ ├── yaml │ │ ├── index.ts │ │ ├── yaml.inc.d.ts │ │ └── yaml.ts │ └── yavascript │ │ ├── index.ts │ │ ├── yavascript.inc.d.ts │ │ └── yavascript.ts ├── cjs-interop.ts ├── compilers.ts ├── config-dir.ts ├── determine-target.ts ├── error-with-properties.ts ├── esm-to-require.ts ├── extension-handlers │ ├── _load-all.ts │ ├── civet.ts │ ├── coffee.ts │ ├── empty.ts │ ├── js.ts │ ├── json.ts │ ├── jsx.ts │ ├── ts.ts │ └── tsx.ts ├── hardcoded │ ├── compile-time.js │ └── index.ts ├── has-colors.ts ├── index.ts ├── inspect-options.ts ├── kame-filetypes.d.ts ├── langs.ts ├── lazy-load.ts ├── license-text.ts ├── module-hooks.ts ├── module-protocols │ ├── _all.ts │ ├── http.ts │ ├── https.ts │ └── npm.ts ├── primordials.ts ├── print-error.ts ├── resizable-buffer.ts ├── targets │ ├── eval.ts │ ├── help.ts │ ├── invalid.ts │ ├── license.ts │ ├── print-types.ts │ ├── repl │ │ └── index.ts │ ├── run-file.ts │ └── version.ts └── templates │ ├── commands.d.ts.tmpl │ ├── quickjs-globals.inc.d.ts │ ├── yavascript-git.d.ts.tmpl │ └── yavascript.d.ts.tmpl ├── todo.md ├── tsconfig.json └── yavascript.d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | text eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/ci_tests.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: [opened, synchronize] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Build and test 17 | run: meta/scripts/ci.sh 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | dist 4 | bin 5 | .vscode 6 | yavascript-internal.js 7 | 8 | meta/tgz-release 9 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | v22.8.0 2 | -------------------------------------------------------------------------------- /.npm-version: -------------------------------------------------------------------------------- 1 | 10.8.2 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.8.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tgz-release 3 | yavascript-internal.js 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Lily Skye 4 | 5 | Permission is hereby granted, free of 6 | charge, to any person obtaining a copy of this software and associated 7 | documentation files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, copy, modify, merge, 9 | publish, distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to the 11 | following conditions: 12 | 13 | The above copyright notice and this permission notice 14 | (including the next paragraph) shall be included in all copies or substantial 15 | portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 20 | EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 4 | }; 5 | 6 | outputs = { self, nixpkgs }: 7 | let 8 | inherit (nixpkgs) lib; 9 | 10 | makePackages = (system: 11 | let 12 | pkgs = import nixpkgs { 13 | inherit system; 14 | }; 15 | in 16 | { 17 | default = pkgs.buildNpmPackage rec { 18 | pname = "yavascript"; 19 | version = 20 | let 21 | sha = builtins.substring 0 12 (self.rev or self.dirtyRev); 22 | dirty = lib.strings.optionalString (self ? dirtyRev) "-dirty"; 23 | in 24 | "git-${sha}${dirty}"; 25 | 26 | src = ./.; 27 | 28 | npmConfigHook = pkgs.importNpmLock.npmConfigHook; 29 | npmDeps = pkgs.importNpmLock { 30 | npmRoot = src; 31 | }; 32 | 33 | SKIP_FNM_USE = 1; 34 | SKIP_NPM_INSTALL = 1; 35 | YAVASCRIPT_VERSION = version; 36 | 37 | preBuild = '' 38 | patchShebangs meta 39 | ''; 40 | 41 | nativeBuildInputs = with pkgs; [ 42 | ninja 43 | ]; 44 | dontUseNinjaBuild = true; 45 | dontUseNinjaInstall = true; 46 | 47 | installPhase = '' 48 | mkdir -p $out/bin 49 | cp -r dist $out/ 50 | mv \ 51 | $out/dist/yavascript \ 52 | $out/dist/yavascript-bootstrap \ 53 | $out/bin/ 54 | ''; 55 | }; 56 | } 57 | ); 58 | in 59 | builtins.foldl' lib.recursiveUpdate { } (builtins.map 60 | (system: { 61 | devShells.${system} = makePackages system; 62 | packages.${system} = makePackages system; 63 | }) 64 | lib.systems.flakeExposed); 65 | } 66 | -------------------------------------------------------------------------------- /meta/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/assets/logo.png -------------------------------------------------------------------------------- /meta/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 5 | cd "$SCRIPT_DIR/.." # go to root 6 | 7 | # Use node 18 8 | if [[ "${SKIP_FNM_USE:-}" == "" ]]; then 9 | fnm use 10 | fi 11 | 12 | # grab JS dependencies from npm 13 | if [[ "${SKIP_NPM_INSTALL:-}" == "" ]]; then 14 | npm install 15 | fi 16 | 17 | meta/scripts/ninja-build.sh 18 | -------------------------------------------------------------------------------- /meta/docker/.gitignore: -------------------------------------------------------------------------------- 1 | yavascript* 2 | -------------------------------------------------------------------------------- /meta/docker/Dockerfile.aarch64: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/aarch64 scratch 2 | COPY --from=tarampampam/curl:7.78.0 /bin/curl /bin/curl 3 | COPY ./yavascript-aarch64 /bin/yavascript 4 | COPY ./empty /tmp 5 | 6 | ENTRYPOINT ["/bin/yavascript"] 7 | -------------------------------------------------------------------------------- /meta/docker/Dockerfile.x86_64: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 scratch 2 | COPY --from=tarampampam/curl:7.78.0 /bin/curl /bin/curl 3 | COPY ./yavascript-x86_64 /bin/yavascript 4 | COPY ./empty /tmp 5 | 6 | ENTRYPOINT ["/bin/yavascript"] 7 | -------------------------------------------------------------------------------- /meta/docker/build-environment-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22.8.0-bookworm 2 | 3 | RUN apt-get update && apt-get -y install ninja-build 4 | 5 | # the intent is that you volume-mount the repo here 6 | WORKDIR /opt/yavascript 7 | 8 | ENV SKIP_FNM_USE=1 9 | 10 | ENTRYPOINT /bin/bash 11 | -------------------------------------------------------------------------------- /meta/docker/build-environment-image/README.md: -------------------------------------------------------------------------------- 1 | this isn't used in CI or local dev (unless you wanna use it in local dev). it's mainly present just to document what a working build configuration for the project is, so that as things change in the future, there is a "known-good environment" to fall back to. 2 | -------------------------------------------------------------------------------- /meta/docker/build-environment-image/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 4 | cd "$SCRIPT_DIR" 5 | 6 | docker build -t suchipi/yavascript-build-environment . 7 | -------------------------------------------------------------------------------- /meta/docker/build-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 6 | cd "$SCRIPT_DIR" 7 | 8 | cp ../../dist/bin/x86_64-unknown-linux-static/yavascript ./yavascript-x86_64 9 | cp ../../dist/bin/aarch64-unknown-linux-static/yavascript ./yavascript-aarch64 10 | 11 | mkdir -p empty 12 | 13 | IMAGE_NAME="suchipi/yavascript" 14 | 15 | # override to "latest" or "v1.2.3" via env var 16 | TAG="${YS_DOCKER_TAG:-}" 17 | if [[ "$TAG" == "" ]]; then 18 | TAG="dev-unstable-$(date +%s)" 19 | fi 20 | 21 | docker build -f Dockerfile.x86_64 -t "${IMAGE_NAME}:${TAG}-x86_64" . 22 | docker build -f Dockerfile.aarch64 -t "${IMAGE_NAME}:${TAG}-aarch64" . 23 | 24 | # have to push them to be able to make a manifest list :( 25 | docker push "${IMAGE_NAME}:${TAG}-x86_64" 26 | docker push "${IMAGE_NAME}:${TAG}-aarch64" 27 | 28 | docker manifest create "${IMAGE_NAME}:${TAG}" \ 29 | --amend "${IMAGE_NAME}:${TAG}-x86_64" \ 30 | --amend "${IMAGE_NAME}:${TAG}-aarch64" 31 | 32 | docker manifest annotate --arch amd64 "${IMAGE_NAME}:${TAG}" "${IMAGE_NAME}:${TAG}-x86_64" 33 | docker manifest annotate --arch arm64 "${IMAGE_NAME}:${TAG}" "${IMAGE_NAME}:${TAG}-aarch64" 34 | 35 | docker manifest push "${IMAGE_NAME}:${TAG}" 36 | 37 | echo "Done building and pushing: ${IMAGE_NAME}:${TAG}" 38 | -------------------------------------------------------------------------------- /meta/docker/wine-test-image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM --platform=linux/amd64 ubuntu:22.04 2 | 3 | RUN dpkg --add-architecture i386 && \ 4 | apt-get update && apt-get install -y \ 5 | wine wine32 wine64 6 | 7 | RUN mkdir /wineprefix 8 | ENV WINEPREFIX=/wineprefix 9 | ENV WINEARCH=win64 10 | 11 | ADD sample.bat /opt/sample.bat 12 | 13 | # run wine once to make all those first-time error messages go away. 14 | # it fails to actually *run* sample.bat, but making it try is enough 15 | # to make the first-time error messages go away. 16 | RUN wine /opt/sample.bat || true 17 | -------------------------------------------------------------------------------- /meta/docker/wine-test-image/README.md: -------------------------------------------------------------------------------- 1 | this is used in src/win32-exe.test.ts to make sure the win32 exe works. it uses wine 2 | -------------------------------------------------------------------------------- /meta/docker/wine-test-image/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 4 | cd "$SCRIPT_DIR" 5 | 6 | docker build -t suchipi/yavascript-wine-test-image . 7 | -------------------------------------------------------------------------------- /meta/docker/wine-test-image/sample.bat: -------------------------------------------------------------------------------- 1 | echo hi 2 | -------------------------------------------------------------------------------- /meta/examples/civet-example.civet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | // YavaScript has builtin support for parsing and executing Civet files. 4 | 5 | // You can use import syntax... 6 | import * as std from 'quickjs:std' 7 | echo typeof std 8 | 9 | // or require if you prefer 10 | os := require 'quickjs:os' 11 | echo typeof os 12 | 13 | exec 'git status' 14 | 15 | files := ls() 16 | 17 | if files.length > 0 and isDir files[0] 18 | cd files[0] 19 | 20 | echo files[0] .stdout 31 | |> .trim() 32 | 33 | echo { branchName } 34 | 35 | echo GitRepo.findRoot(__dirname) 36 | 37 | echo """ 38 | hello 39 | there 40 | world 41 | """ 42 | 43 | function coolDestructuring(first: any, ...middles: Array, last: any): void 44 | echo { first, middles, last } 45 | 46 | coolDestructuring "one", "two", 3, "four", 5 47 | -------------------------------------------------------------------------------- /meta/examples/coffeescript-example.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | # YavaScript has builtin support for parsing and executing CoffeeScript files. 4 | 5 | # You can use import syntax... 6 | import * as std from 'quickjs:std' 7 | echo typeof std 8 | 9 | # or require if you prefer 10 | os = require 'quickjs:os' 11 | echo typeof os 12 | 13 | exec 'git status' 14 | 15 | files = ls() 16 | 17 | if isDir files[0] 18 | cd files[0] 19 | 20 | echo pwd() 21 | 22 | branchName = $ 'git rev-parse --abbrev-ref HEAD' 23 | .stdout 24 | .trim() 25 | 26 | echo { branchName } 27 | 28 | echo GitRepo.findRoot(__dirname) 29 | -------------------------------------------------------------------------------- /meta/examples/custom-repl.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | // Just defining some made-up stuff for demonstration purposes... 5 | const TOKEN_SEPARATOR = /[^\w]|_/g; 6 | function tokens(input: string) { 7 | return input.split(TOKEN_SEPARATOR).filter(Boolean); 8 | } 9 | 10 | // You can start the yavascript repl from your own file, 11 | // with your own stuff loaded, by calling `startRepl`: 12 | startRepl( 13 | // Variables to make available to the repl as globals. Optional 14 | { TOKEN_SEPARATOR, tokens }, 15 | // Which language repl input should be interpreted as, ie. typescript, coffeescript, jsx, etc. Defaults to "javascript". 16 | "typescript" 17 | ); 18 | -------------------------------------------------------------------------------- /meta/examples/environment-variables.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | echo(env); 5 | 6 | const isCI = "CI" in env; 7 | 8 | echo({ isCI }); 9 | -------------------------------------------------------------------------------- /meta/examples/git-info-to-yml.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | let isWorkingTreeDirty; 5 | try { 6 | exec(`git diff --quiet`); 7 | isWorkingTreeDirty = false; 8 | } catch (error) { 9 | isWorkingTreeDirty = true; 10 | } 11 | 12 | const branchName = $(`git rev-parse --abbrev-ref HEAD`).stdout.trim(); 13 | 14 | const gitInfo = { branchName, isWorkingTreeDirty }; 15 | echo(gitInfo); 16 | 17 | writeFile("git-info.yml", YAML.stringify(gitInfo)); 18 | -------------------------------------------------------------------------------- /meta/examples/git-stuff.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | exec(["git", "status"]); 5 | 6 | let branchName = $(["git", "rev-parse", "--abbrev-ref", "HEAD"]).stdout.trim(); 7 | 8 | echo({ branchName }); 9 | 10 | const repoRoot = GitRepo.findRoot(__dirname); 11 | echo(repoRoot); 12 | 13 | const yavascriptRepo = new GitRepo(repoRoot); 14 | 15 | // relative paths are resolved relative to pwd 16 | echo(GitRepo.findRoot("../quickjs")); 17 | cd(__dirname); 18 | echo(GitRepo.findRoot("../quickjs")); 19 | -------------------------------------------------------------------------------- /meta/examples/import-meta.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | console.log(import.meta.url); 5 | -------------------------------------------------------------------------------- /meta/examples/importing-commonjs.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | import * as stuff from "./some-commonjs"; 5 | echo(stuff); 6 | 7 | const stuff2 = require("./some-commonjs"); 8 | echo(stuff2); 9 | -------------------------------------------------------------------------------- /meta/examples/importing-json.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | import someJson from "./some-json.json"; 5 | 6 | echo(someJson); 7 | -------------------------------------------------------------------------------- /meta/examples/jsx-example.jsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | // JSX syntax gets compiled to expressions referencing `JSX.createElement` and 4 | // `JSX.Fragment`, which are both defined as a global. To change how JSX gets 5 | // compiled, change the values of `JSX.pragma` and `JSX.pragmaFrag`. 6 | // 7 | // Note that if you change `JSX.pragma` and/or `JSX.pragmaFrag`, you should 8 | // also update `types.JSX.Element` and `types.JSX.Fragment`. See the `JSX` section in 9 | // `yavascript --print-types` for more information. 10 | 11 | console.log(); // { $$typeof: Symbol(JSX.Element), type: "a", props: null, key: null } 12 | 13 | console.log(is(, types.JSX.Element)); // true 14 | console.log(is(2, types.JSX.Element)); // false 15 | 16 | console.log(is(<>, types.JSX.Fragment)); // true 17 | console.log(is(, types.JSX.Fragment)); // false 18 | console.log(is(2, types.JSX.Fragment)); // false 19 | -------------------------------------------------------------------------------- /meta/examples/paths.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | echo(new Path("/tmp", "/blaaa/")); 5 | echo(new Path(__dirname, "./git-stuff.js")); 6 | 7 | echo(new Path("C:\\something/whatever\\\\idk/lol\\")); 8 | echo(Path.splitToSegments("C:\\something/whatever\\\\idk/lol\\").join("\\")); 9 | 10 | echo(realpath(new Path(__dirname, "./git-stuff.js"))); 11 | 12 | echo(dirname("/tmp/hi/there.txt")); 13 | echo(basename("/tmp/hi/there.txt")); 14 | echo(extname("/tmp/hi/there.txt")); 15 | -------------------------------------------------------------------------------- /meta/examples/script-args.js: -------------------------------------------------------------------------------- 1 | const { flags, args, metadata } = parseScriptArgs( 2 | { 3 | // Note that while `-v` is also a command-line script for yavascript itself 4 | // (which prints the yavascript version), you can still use it in your own 5 | // scripts, because yavascript only prints its version when it's called with 6 | // `-v` with no other arguments. 7 | v: Boolean, 8 | verbose: Boolean, 9 | hello: String, 10 | input: Path, 11 | }, 12 | // This second argument is optional; in unspecified, it defaults to 13 | // `scriptArgs.slice(2)`. It's only shown here to demonstrate that it's 14 | // possible to pass different args here, if desired. 15 | scriptArgs.slice(2) 16 | ); 17 | 18 | console.log({ flags, args, metadata }); 19 | -------------------------------------------------------------------------------- /meta/examples/show-globals.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | // NOTE: only shows enumerable globals. all the yavascript APIs are enumerable. all builtin globals are non-enumerable, except console. 5 | console.log(globalThis); 6 | -------------------------------------------------------------------------------- /meta/examples/some-commonjs.js: -------------------------------------------------------------------------------- 1 | const hello = "there"; 2 | 3 | module.exports = { 4 | hello, 5 | }; 6 | -------------------------------------------------------------------------------- /meta/examples/some-json.json: -------------------------------------------------------------------------------- 1 | // comments are supported in json that gets imported using the import keyword 2 | { 3 | "hello": "there" 4 | } 5 | -------------------------------------------------------------------------------- /meta/examples/tsx-example.tsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | // JSX syntax gets compiled to expressions referencing `JSX.createElement` and 5 | // `JSX.Fragment`, which are both defined as a global. To change how JSX gets 6 | // compiled, change the values of `JSX.pragma` and `JSX.pragmaFrag`. 7 | // 8 | // Note that if you change `JSX.pragma` and/or `JSX.pragmaFrag`, you should 9 | // also update `types.JSX.Element` and `types.JSX.Fragment`. See the `JSX` section in 10 | // `yavascript --print-types` for more information. 11 | 12 | console.log(); // { $$typeof: Symbol(JSX.Element), type: "a", props: null, key: null } 13 | 14 | console.log(is(, types.JSX.Element)); // true 15 | console.log(is(2, types.JSX.Element)); // false 16 | 17 | console.log(is(<>, types.JSX.Fragment)); // true 18 | console.log(is(, types.JSX.Fragment)); // false 19 | console.log(is(2, types.JSX.Fragment)); // false 20 | -------------------------------------------------------------------------------- /meta/examples/typescript-example.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | // YavaScript has builtin support for parsing and executing TypeScript files. 5 | 6 | import * as std from "quickjs:std"; 7 | echo(typeof std); 8 | 9 | function look(path: Path) { 10 | echo(`path: ${path}`); 11 | ls(path); 12 | exec("git status"); 13 | } 14 | 15 | look(pwd()); 16 | -------------------------------------------------------------------------------- /meta/examples/using-stuff-from-npm.jsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | import * as preact from "npm:preact@^10.5.0"; 5 | 6 | JSX.createElement = preact.createElement; 7 | JSX.Fragment = preact.Fragment; 8 | 9 | echo(); 10 | -------------------------------------------------------------------------------- /meta/generated-docs/__filename-and-__dirname.md: -------------------------------------------------------------------------------- 1 | - [\_\_filename (string)](#__filename-string) 2 | - [\_\_dirname (string)](#__dirname-string) 3 | 4 | # \_\_filename (string) 5 | 6 | The absolute path to the currently-executing file (whether script or module). 7 | 8 | Behaves the same as in Node.js, except that it's also present within ES 9 | modules. 10 | 11 | Example: `/home/suchipi/some-folder/some-file.js` 12 | 13 | ```ts 14 | var __filename: string; 15 | ``` 16 | 17 | # \_\_dirname (string) 18 | 19 | The absolute path to the directory containing the currently-executing file. 20 | 21 | Behaves the same as in Node.js, except that it's also present within ES 22 | modules. 23 | 24 | Example: `/home/suchipi/some-folder` 25 | 26 | ```ts 27 | var __dirname: string; 28 | ``` 29 | -------------------------------------------------------------------------------- /meta/generated-docs/assert.md: -------------------------------------------------------------------------------- 1 | - [assert (function)](#assert-function) 2 | - [assert(...) (call signature)](#assert-call-signature) 3 | - [assert.type (function property)](#asserttype-function-property) 4 | 5 | # assert (function) 6 | 7 | ```ts 8 | const assert: { 9 | ( 10 | value: ValueType, 11 | message?: string 12 | ): asserts value is ValueType extends null | undefined | false | 0 | "" 13 | ? never 14 | : ValueType; 15 | type: | CoerceableToTypeValidator>( 16 | value: any, 17 | type: T, 18 | optionalMessage?: string 19 | ) => asserts value is UnwrapTypeFromCoerceableOrValidator; 20 | }; 21 | ``` 22 | 23 | ## assert(...) (call signature) 24 | 25 | Throws an error if `value` is not truthy. 26 | 27 | - `@param` _value_ — The value to test for truthiness 28 | - `@param` _message_ — An optional error message to use. If unspecified, "Assertion failed" will be used. 29 | 30 | ```ts 31 | (value: ValueType, message?: string): asserts value is ValueType extends null | undefined | false | 0 | "" ? never : ValueType; 32 | ``` 33 | 34 | ## assert.type (function property) 35 | 36 | Throws an error if its argument isn't the correct type. 37 | 38 | - `@param` _value_ — The value to test the type of 39 | - `@param` _type_ — The type that `value` should be, as either a `TypeValidator` (from the `types.*` namespace) or a value which can be coerced into a `TypeValidator` via the `types.coerce` function, like `String`, `Boolean`, etc. 40 | - `@param` _message_ — An optional error message to use. If unspecified, a generic-but-descriptive message will be used. 41 | 42 | ```ts 43 | type: | CoerceableToTypeValidator>(value: any, type: T, optionalMessage?: string) => asserts value is UnwrapTypeFromCoerceableOrValidator; 44 | ``` 45 | -------------------------------------------------------------------------------- /meta/generated-docs/basename.md: -------------------------------------------------------------------------------- 1 | - [basename (function)](#basename-function) 2 | 3 | # basename (function) 4 | 5 | Return the last component of a path string. 6 | 7 | Provides the same functionality as the unix binary of the same name. 8 | 9 | > Example: `basename("/home/suchipi/something")` returns `"something"`, the last part. 10 | 11 | ```ts 12 | declare function basename(path: string | Path): string; 13 | ``` 14 | -------------------------------------------------------------------------------- /meta/generated-docs/bytecode.md: -------------------------------------------------------------------------------- 1 | - ["quickjs:bytecode" (namespace)](#quickjsbytecode-namespace) 2 | - ["quickjs:bytecode".fromFile (exported function)](#quickjsbytecodefromfile-exported-function) 3 | - ["quickjs:bytecode".fromValue (exported function)](#quickjsbytecodefromvalue-exported-function) 4 | - ["quickjs:bytecode".toValue (exported function)](#quickjsbytecodetovalue-exported-function) 5 | 6 | # "quickjs:bytecode" (namespace) 7 | 8 | ```ts 9 | declare module "quickjs:bytecode" { 10 | export function fromFile( 11 | path: string, 12 | options?: { 13 | byteSwap?: boolean; 14 | sourceType?: "module" | "script"; 15 | encodedFileName?: string; 16 | } 17 | ): ArrayBuffer; 18 | export function fromValue( 19 | value: any, 20 | options?: { 21 | byteSwap?: boolean; 22 | } 23 | ): ArrayBuffer; 24 | export function toValue(bytecode: ArrayBuffer): any; 25 | } 26 | ``` 27 | 28 | ## "quickjs:bytecode".fromFile (exported function) 29 | 30 | Convert the module or script in the specified file into bytecode. 31 | 32 | When converted back to a value, it will be a function. 33 | 34 | ```ts 35 | function fromFile( 36 | path: string, 37 | options?: { 38 | byteSwap?: boolean; 39 | sourceType?: "module" | "script"; 40 | encodedFileName?: string; 41 | } 42 | ): ArrayBuffer; 43 | ``` 44 | 45 | ## "quickjs:bytecode".fromValue (exported function) 46 | 47 | Convert the provided value into bytecode. Doesn't work with all values. 48 | 49 | ```ts 50 | function fromValue( 51 | value: any, 52 | options?: { 53 | byteSwap?: boolean; 54 | } 55 | ): ArrayBuffer; 56 | ``` 57 | 58 | ## "quickjs:bytecode".toValue (exported function) 59 | 60 | Convert the provided bytecode into a value. 61 | 62 | ```ts 63 | function toValue(bytecode: ArrayBuffer): any; 64 | ``` 65 | -------------------------------------------------------------------------------- /meta/generated-docs/cd.md: -------------------------------------------------------------------------------- 1 | - [cd (function)](#cd-function) 2 | 3 | # cd (function) 4 | 5 | Changes the process's current working directory to the specified path. If no 6 | path is specified, moves to the user's home directory. 7 | 8 | Provides the same functionality as the shell builtin of the same name. 9 | 10 | ```ts 11 | declare function cd(path?: string | Path): void; 12 | ``` 13 | -------------------------------------------------------------------------------- /meta/generated-docs/csv.md: -------------------------------------------------------------------------------- 1 | - [CSV (object)](#csv-object) 2 | - [CSV.parse (method)](#csvparse-method) 3 | - [CSV.stringify (method)](#csvstringify-method) 4 | 5 | # CSV (object) 6 | 7 | Serializes or deserializes CSV data. 8 | 9 | The `CSV` object contains a `parse` function and a `stringify` function which 10 | can be used to parse strings of CSV (comma-separated values) data into 11 | arrays-of-arrays-of-strings and serialize arrays-of-arrays-of-strings into 12 | strings of CSV data. 13 | 14 | Its interface is similar to `JSON.parse` and `JSON.stringify`, but CSV does 15 | not support the spacing/replacer/reviver options that `JSON.parse` and 16 | `JSON.stringify` have. 17 | 18 | ```ts 19 | const CSV: { 20 | parse(input: string): Array>; 21 | stringify(input: Array>): string; 22 | }; 23 | ``` 24 | 25 | ## CSV.parse (method) 26 | 27 | Parse a CSV string into an Array of Arrays of strings. 28 | 29 | The outer array holds the rows, and the inner arrays hold the items in 30 | each row. 31 | 32 | ```ts 33 | parse(input: string): Array>; 34 | ``` 35 | 36 | ## CSV.stringify (method) 37 | 38 | Convert an Array of Arrays of strings into a CSV string. 39 | 40 | The outer array holds the rows, and the inner arrays hold the items in 41 | each row. 42 | 43 | ```ts 44 | stringify(input: Array>): string; 45 | ``` 46 | -------------------------------------------------------------------------------- /meta/generated-docs/dirname.md: -------------------------------------------------------------------------------- 1 | - [dirname (function)](#dirname-function) 2 | 3 | # dirname (function) 4 | 5 | Removes the final component from a path string. 6 | 7 | Provides the same functionality as the unix binary of the same name. 8 | 9 | > Example: `dirname("/home/suchipi/something")` returns 10 | > `"/home/suchipi"`, everything except the last part. 11 | 12 | ```ts 13 | declare function dirname(path: string | Path): Path; 14 | ``` 15 | -------------------------------------------------------------------------------- /meta/generated-docs/echo.md: -------------------------------------------------------------------------------- 1 | - [echo (value)](#echo-value) 2 | 3 | # echo (value) 4 | 5 | Print one or more values to stdout. 6 | 7 | Provides the same functionality as the shell builtin of the same name. 8 | 9 | > NOTE: This can print any value, not just strings. 10 | 11 | `echo` is functionally identical to `console.log`. 12 | 13 | ```ts 14 | const echo: typeof console.log; 15 | ``` 16 | -------------------------------------------------------------------------------- /meta/generated-docs/encoding.md: -------------------------------------------------------------------------------- 1 | - ["quickjs:encoding" (namespace)](#quickjsencoding-namespace) 2 | - ["quickjs:encoding".toUtf8 (exported function)](#quickjsencodingtoutf8-exported-function) 3 | - ["quickjs:encoding".fromUtf8 (exported function)](#quickjsencodingfromutf8-exported-function) 4 | 5 | # "quickjs:encoding" (namespace) 6 | 7 | ```ts 8 | declare module "quickjs:encoding" { 9 | export function toUtf8(input: ArrayBuffer): string; 10 | export function fromUtf8(input: string): ArrayBuffer; 11 | } 12 | ``` 13 | 14 | ## "quickjs:encoding".toUtf8 (exported function) 15 | 16 | ```ts 17 | function toUtf8(input: ArrayBuffer): string; 18 | ``` 19 | 20 | ## "quickjs:encoding".fromUtf8 (exported function) 21 | 22 | ```ts 23 | function fromUtf8(input: string): ArrayBuffer; 24 | ``` 25 | -------------------------------------------------------------------------------- /meta/generated-docs/env.md: -------------------------------------------------------------------------------- 1 | - [env (object)](#env-object) 2 | 3 | # env (object) 4 | 5 | An object representing the process's environment variables. You can read 6 | from it to read environment variables, write into it to set environment 7 | variables, and/or delete properties from it to unset environment variables. 8 | Any value you write will be coerced into a string. 9 | 10 | ```ts 11 | const env: { 12 | [key: string]: string | undefined; 13 | }; 14 | ``` 15 | -------------------------------------------------------------------------------- /meta/generated-docs/exit.md: -------------------------------------------------------------------------------- 1 | - [exit (function)](#exit-function) 2 | - [exit(...) (call signature)](#exit-call-signature) 3 | - [exit.code (number property)](#exitcode-number-property) 4 | 5 | # exit (function) 6 | 7 | Exit the yavascript process. 8 | 9 | Provides the same functionality as the shell builtin of the same name. 10 | 11 | If exit is called with an argument, that argument is used as the exit code. 12 | Otherwise, `exit.code` is used, which defaults to 0. 13 | 14 | `exit.code` will also be used as the exit status code for the yavascript 15 | process if the process exits normally. 16 | 17 | > Attempting to call `exit` or set `exit.code` within a Worker will fail and 18 | > throw an error. 19 | 20 | ```ts 21 | const exit: { 22 | (code?: number): never; 23 | code: number; 24 | }; 25 | ``` 26 | 27 | ## exit(...) (call signature) 28 | 29 | ```ts 30 | (code?: number): never; 31 | ``` 32 | 33 | ## exit.code (number property) 34 | 35 | ```ts 36 | code: number; 37 | ``` 38 | -------------------------------------------------------------------------------- /meta/generated-docs/extname.md: -------------------------------------------------------------------------------- 1 | - [extname (function)](#extname-function) 2 | - [ExtnameOptions (interface)](#extnameoptions-interface) 3 | - [ExtnameOptions.full (boolean property)](#extnameoptionsfull-boolean-property) 4 | 5 | # extname (function) 6 | 7 | Returns the file extension of the file at a given path. 8 | 9 | If the file has no extension (eg `Makefile`, etc), then `''` will be 10 | returned. 11 | 12 | - `@param` _pathOrFilename_ — The input path 13 | - `@param` _options_ — Options which affect the return value. See [ExtnameOptions](/meta/generated-docs/extname.md#extnameoptions-interface). 14 | 15 | ```ts 16 | declare function extname( 17 | pathOrFilename: string | Path, 18 | options?: ExtnameOptions 19 | ): string; 20 | ``` 21 | 22 | # ExtnameOptions (interface) 23 | 24 | Options for [extname](/meta/generated-docs/extname.md#extname-function) and [Path.prototype.extname](/meta/generated-docs/path.md#pathprototypeextname-method). 25 | 26 | ```ts 27 | declare interface ExtnameOptions { 28 | full?: boolean; 29 | } 30 | ``` 31 | 32 | ## ExtnameOptions.full (boolean property) 33 | 34 | Whether to get compound extensions, like `.d.ts` or `.test.js`, instead of 35 | just the final extension (`.ts` or `.js` in this example). 36 | 37 | ```ts 38 | full?: boolean; 39 | ``` 40 | -------------------------------------------------------------------------------- /meta/generated-docs/help.md: -------------------------------------------------------------------------------- 1 | - [help (function)](#help-function) 2 | 3 | # help (function) 4 | 5 | Prints a link to the YavaScript help docs for the currently-running version 6 | of YavaScript. 7 | 8 | For the latest help docs, see: 9 | https://github.com/suchipi/yavascript/blob/main/meta/generated-docs/README.md 10 | 11 | ```ts 12 | declare function help(): void; 13 | ``` 14 | -------------------------------------------------------------------------------- /meta/generated-docs/intervals.md: -------------------------------------------------------------------------------- 1 | - [Interval (type)](#interval-type) 2 | - [setInterval (function)](#setinterval-function) 3 | - [clearInterval (function)](#clearinterval-function) 4 | 5 | # Interval (type) 6 | 7 | ```ts 8 | declare type Interval = { 9 | [Symbol.toStringTag]: "Interval"; 10 | }; 11 | ``` 12 | 13 | # setInterval (function) 14 | 15 | ```ts 16 | declare function setInterval(func: (...args: any) => any, ms: number): Interval; 17 | ``` 18 | 19 | # clearInterval (function) 20 | 21 | ```ts 22 | declare function clearInterval(interval: Interval): void; 23 | ``` 24 | -------------------------------------------------------------------------------- /meta/generated-docs/logger.md: -------------------------------------------------------------------------------- 1 | - [logger (object)](#logger-object) 2 | - [logger.trace (function property)](#loggertrace-function-property) 3 | - [logger.info (function property)](#loggerinfo-function-property) 4 | 5 | # logger (object) 6 | 7 | The logger used internally by yavascript API functions such as [which](/meta/generated-docs/which.md#which-function), 8 | [exec](/meta/generated-docs/exec.md#exec-interface), [copy](/meta/generated-docs/filesystem.md#copy-function), [glob](/meta/generated-docs/glob.md#glob-function), and more. 9 | 10 | You can modify the properties on this object in order to configure the 11 | amount and style of log output from yavascript API functions. 12 | 13 | This object behaves similarly to the shell builtin `set -x`. 14 | 15 | ```ts 16 | const logger: { 17 | trace: (...args: Array) => void; 18 | info: (...args: Array) => void; 19 | }; 20 | ``` 21 | 22 | ## logger.trace (function property) 23 | 24 | This property is used as the default value for `trace` in yavascript API 25 | functions which receive `logging.trace` as an option, like [which](/meta/generated-docs/which.md#which-function), 26 | [exec](/meta/generated-docs/exec.md#exec-interface), [copy](/meta/generated-docs/filesystem.md#copy-function) and [glob](/meta/generated-docs/glob.md#glob-function). 27 | 28 | The default value of `logger.trace` is a no-op function. 29 | 30 | ```ts 31 | trace: (...args: Array) => void; 32 | ``` 33 | 34 | ## logger.info (function property) 35 | 36 | This property is used as the default value for `info` in yavascript API 37 | functions which receive `logging.info` as an option, like [exec](/meta/generated-docs/exec.md#exec-interface), 38 | [copy](/meta/generated-docs/filesystem.md#copy-function), and [glob](/meta/generated-docs/glob.md#glob-function). 39 | 40 | The default value of `logger.info` writes dimmed text to stdout. 41 | 42 | ```ts 43 | info: (...args: Array) => void; 44 | ``` 45 | -------------------------------------------------------------------------------- /meta/generated-docs/ls.md: -------------------------------------------------------------------------------- 1 | - [ls (function)](#ls-function) 2 | 3 | # ls (function) 4 | 5 | Returns the contents of a directory, as absolute paths. `.` and `..` are 6 | omitted. 7 | 8 | If `ls()` is called with no directory, the present working directory 9 | (`pwd()`) is used. 10 | 11 | ```ts 12 | declare function ls(dir?: string | Path): Array; 13 | ``` 14 | -------------------------------------------------------------------------------- /meta/generated-docs/mkdir.md: -------------------------------------------------------------------------------- 1 | - [mkdir (function)](#mkdir-function) 2 | 3 | # mkdir (function) 4 | 5 | Create a directory (folder). 6 | 7 | Provides the same functionality as the unix binary of the same name. 8 | 9 | ```ts 10 | declare function mkdir( 11 | path: string | Path, 12 | options?: { 13 | recursive?: boolean; 14 | mode?: number; 15 | logging?: { 16 | trace?: (...args: Array) => void; 17 | info?: (...args: Array) => void; 18 | }; 19 | } 20 | ): void; 21 | ``` 22 | -------------------------------------------------------------------------------- /meta/generated-docs/mkdirp.md: -------------------------------------------------------------------------------- 1 | - [mkdirp (function)](#mkdirp-function) 2 | 3 | # mkdirp (function) 4 | 5 | Create a directory (folder) and all parents, recursively 6 | 7 | Alias for `mkdir(path, { recursive: true })`. 8 | 9 | Provides the same functionality as `mkdir -p`. 10 | 11 | ```ts 12 | declare function mkdirp( 13 | path: string | Path, 14 | options?: { 15 | mode?: number; 16 | logging?: { 17 | trace?: (...args: Array) => void; 18 | info?: (...args: Array) => void; 19 | }; 20 | } 21 | ): void; 22 | ``` 23 | -------------------------------------------------------------------------------- /meta/generated-docs/open-url.md: -------------------------------------------------------------------------------- 1 | - [openUrl (function)](#openurl-function) 2 | 3 | # openUrl (function) 4 | 5 | Opens the resource at the given path or URL using the operating system's 6 | default application or handler. 7 | 8 | Examples: 9 | 10 | ```ts 11 | openUrl("/home/me/stuff/code.txt"); // opens code.txt in your default text editor 12 | openUrl("code.txt"); // same as above, using relative path 13 | openUrl("file:///home/me/stuff/code.txt"); // same as above, using file:// url 14 | 15 | openUrl("IMG_001.jpg"); // opens IMG_001.jpg in your default image viewer 16 | 17 | openUrl("https://example.com/"); // opens example.com in your default web browser 18 | ``` 19 | 20 | ```ts 21 | declare function openUrl(urlOrFilePath: string | Path): void; 22 | ``` 23 | -------------------------------------------------------------------------------- /meta/generated-docs/print.md: -------------------------------------------------------------------------------- 1 | - [print (function)](#print-function) 2 | 3 | # print (function) 4 | 5 | `print` is an alias for [console.log](/meta/generated-docs/console.md#consolelog-method), which prints values to stdout. 6 | 7 | Any value can be logged, not just strings. Non-string values will be 8 | formatted using [inspect](/meta/generated-docs/inspect.md#inspect-inspectfunction). 9 | 10 | ```ts 11 | declare function print(...args: any): void; 12 | ``` 13 | -------------------------------------------------------------------------------- /meta/generated-docs/printf.md: -------------------------------------------------------------------------------- 1 | - [printf (function)](#printf-function) 2 | 3 | # printf (function) 4 | 5 | Print data to stdout using C-style format specifiers. 6 | 7 | The same formats as the [standard C library 8 | printf](https://en.cppreference.com/w/c/io/fprintf) are supported. Integer 9 | format types (e.g. `%d`) truncate the Numbers or BigInts to 32 bits. Use the 10 | l modifier (e.g. `%ld`) to truncate to 64 bits. 11 | 12 | ```ts 13 | declare function printf(format: string, ...args: Array): void; 14 | ``` 15 | -------------------------------------------------------------------------------- /meta/generated-docs/pwd.md: -------------------------------------------------------------------------------- 1 | - [pwd (function)](#pwd-function) 2 | - [pwd(...) (call signature)](#pwd-call-signature) 3 | - [pwd.initial (Path property)](#pwdinitial-path-property) 4 | 5 | # pwd (function) 6 | 7 | Returns the process's current working directory. 8 | 9 | Provides the same functionality as the shell builtin of the same name. 10 | 11 | ```ts 12 | const pwd: { 13 | (): Path; 14 | readonly initial: Path; 15 | }; 16 | ``` 17 | 18 | ## pwd(...) (call signature) 19 | 20 | Returns the process's current working directory. 21 | 22 | Provides the same functionality as the shell builtin of the same name. 23 | 24 | ```ts 25 | (): Path; 26 | ``` 27 | 28 | ## pwd.initial (Path property) 29 | 30 | A frozen, read-only `Path` object containing what `pwd()` was when 31 | yavascript first started up. 32 | 33 | ```ts 34 | readonly initial: Path; 35 | ``` 36 | -------------------------------------------------------------------------------- /meta/generated-docs/quickjs-globals.md: -------------------------------------------------------------------------------- 1 | - [std (value)](#std-value) 2 | - [os (value)](#os-value) 3 | - [\_\_date_clock (function)](#__date_clock-function) 4 | 5 | # std (value) 6 | 7 | ```ts 8 | const std: typeof import("quickjs:std"); 9 | ``` 10 | 11 | # os (value) 12 | 13 | ```ts 14 | const os: typeof import("quickjs:os"); 15 | ``` 16 | 17 | # \_\_date_clock (function) 18 | 19 | Get the current unix timestamp with microsecond precision. 20 | 21 | ```ts 22 | declare function __date_clock(): number; 23 | ``` 24 | -------------------------------------------------------------------------------- /meta/generated-docs/readlink.md: -------------------------------------------------------------------------------- 1 | - [readlink (function)](#readlink-function) 2 | 3 | # readlink (function) 4 | 5 | Reads a symlink. 6 | 7 | Returns the target of the symlink, which may be absolute or relative. 8 | 9 | Provides the same functionality as the unix binary of the same name. 10 | 11 | ```ts 12 | declare function readlink(path: string | Path): Path; 13 | ``` 14 | -------------------------------------------------------------------------------- /meta/generated-docs/realpath.md: -------------------------------------------------------------------------------- 1 | - [realpath (function)](#realpath-function) 2 | 3 | # realpath (function) 4 | 5 | Get the absolute path given a relative path. Symlinks are also resolved. 6 | 7 | The path's target file/directory must exist. 8 | 9 | Provides the same functionality as the unix binary of the same name. 10 | 11 | > If you want to convert a relative path to an absolute path, but the path's 12 | > target might NOT exist, use [Path.normalize](/meta/generated-docs/path.md#pathnormalize-static-method). 13 | 14 | ```ts 15 | declare function realpath(path: string | Path): Path; 16 | ``` 17 | -------------------------------------------------------------------------------- /meta/generated-docs/regexp-escape.md: -------------------------------------------------------------------------------- 1 | - [RegExpConstructor (interface)](#regexpconstructor-interface) 2 | - [RegExpConstructor.escape (method)](#regexpconstructorescape-method) 3 | 4 | # RegExpConstructor (interface) 5 | 6 | ```ts 7 | interface RegExpConstructor { 8 | escape(str: any): string; 9 | } 10 | ``` 11 | 12 | ## RegExpConstructor.escape (method) 13 | 14 | The function `RegExp.escape` accepts an input string and prefixes with `\` 15 | those characters in that string which have a special meaning when appearing 16 | in a regular expression. 17 | 18 | The implementation is based on the stage 2 ECMAScript proposal of the same 19 | name: https://github.com/tc39/proposal-regex-escaping 20 | 21 | ```ts 22 | escape(str: any): string; 23 | ``` 24 | -------------------------------------------------------------------------------- /meta/generated-docs/start-repl.md: -------------------------------------------------------------------------------- 1 | - [startRepl (function)](#startrepl-function) 2 | - [startRepl(...) (call signature)](#startrepl-call-signature) 3 | - [startRepl.NOTHING (symbol property)](#startreplnothing-symbol-property) 4 | 5 | # startRepl (function) 6 | 7 | Launch the Yavascript REPL (read-eval-print-loop). 8 | 9 | - `@param` _context_ — Variables to make available as globals within the repl. 10 | - `@param` _lang_ — The language to use in the repl. Defaults to "javascript". 11 | 12 | ```ts 13 | const startRepl: { 14 | ( 15 | context?: { 16 | [key: string]: any; 17 | }, 18 | lang?: 19 | | "js" 20 | | "javascript" 21 | | "ts" 22 | | "typescript" 23 | | "jsx" 24 | | "tsx" 25 | | "coffee" 26 | | "coffeescript" 27 | | "civet" 28 | ): void; 29 | NOTHING: symbol; 30 | }; 31 | ``` 32 | 33 | ## startRepl(...) (call signature) 34 | 35 | ```ts 36 | (context?: { 37 | [key: string]: any; 38 | }, lang?: "js" | "javascript" | "ts" | "typescript" | "jsx" | "tsx" | "coffee" | "coffeescript" | "civet"): void; 39 | ``` 40 | 41 | ## startRepl.NOTHING (symbol property) 42 | 43 | A special value; when expressions result in this value, the repl will 44 | print nothing instead of printing this value. 45 | 46 | ```ts 47 | NOTHING: symbol; 48 | ``` 49 | -------------------------------------------------------------------------------- /meta/generated-docs/toml.md: -------------------------------------------------------------------------------- 1 | - [TOML (object)](#toml-object) 2 | - [TOML.parse (method)](#tomlparse-method) 3 | - [TOML.stringify (method)](#tomlstringify-method) 4 | 5 | # TOML (object) 6 | 7 | An object with a `parse` function and a `stringify` function which can be 8 | used to parse TOML document strings into objects and serialize objects into 9 | TOML document strings. 10 | 11 | Its interface is similar to `JSON.parse` and `JSON.stringify`, but 12 | `TOML.parse` and `TOML.stringify` do not support the spacing/replacer/reviver 13 | options that `JSON.parse` and `JSON.stringify` do. 14 | 15 | ```ts 16 | var TOML: { 17 | parse(data: string): { 18 | [key: string]: any; 19 | }; 20 | stringify(data: { [key: string]: any }): string; 21 | }; 22 | ``` 23 | 24 | ## TOML.parse (method) 25 | 26 | Parse a TOML document string (`data`) into an object. 27 | 28 | ```ts 29 | parse(data: string): { 30 | [key: string]: any; 31 | }; 32 | ``` 33 | 34 | ## TOML.stringify (method) 35 | 36 | Convert an object into a TOML document. 37 | 38 | ```ts 39 | stringify(data: { 40 | [key: string]: any; 41 | }): string; 42 | ``` 43 | -------------------------------------------------------------------------------- /meta/generated-docs/touch.md: -------------------------------------------------------------------------------- 1 | - [touch (function)](#touch-function) 2 | 3 | # touch (function) 4 | 5 | If the file at `path` exists, update its creation/modification timestamps. 6 | 7 | Otherwise, create an empty file at that path. 8 | 9 | - `@param` _path_ — The target path for the file. 10 | 11 | ```ts 12 | declare function touch(path: string | Path): void; 13 | ``` 14 | -------------------------------------------------------------------------------- /meta/generated-docs/whoami.md: -------------------------------------------------------------------------------- 1 | - [WhoAmIResult (interface)](#whoamiresult-interface) 2 | - [WhoAmIResult.name (string property)](#whoamiresultname-string-property) 3 | - [WhoAmIResult.uid (number property)](#whoamiresultuid-number-property) 4 | - [WhoAmIResult.gid (number property)](#whoamiresultgid-number-property) 5 | - [whoami (function)](#whoami-function) 6 | 7 | # WhoAmIResult (interface) 8 | 9 | The type of the return value of [whoami](/meta/generated-docs/whoami.md#whoami-function). 10 | 11 | ```ts 12 | declare interface WhoAmIResult { 13 | name: string; 14 | uid: number; 15 | gid: number; 16 | } 17 | ``` 18 | 19 | ## WhoAmIResult.name (string property) 20 | 21 | ```ts 22 | name: string; 23 | ``` 24 | 25 | ## WhoAmIResult.uid (number property) 26 | 27 | ```ts 28 | uid: number; 29 | ``` 30 | 31 | ## WhoAmIResult.gid (number property) 32 | 33 | ```ts 34 | gid: number; 35 | ``` 36 | 37 | # whoami (function) 38 | 39 | Get info about the user the yavascript process is executing as. 40 | 41 | Provides functionality similar to the unix binaries `whoami` and `id`. 42 | 43 | NOTE: Doesn't work on Windows; throws an error. 44 | 45 | ```ts 46 | declare function whoami(): WhoAmIResult; 47 | ``` 48 | -------------------------------------------------------------------------------- /meta/generated-docs/yaml.md: -------------------------------------------------------------------------------- 1 | - [YAML (object)](#yaml-object) 2 | - [YAML.parse (method)](#yamlparse-method) 3 | - [YAML.stringify (method)](#yamlstringify-method) 4 | 5 | # YAML (object) 6 | 7 | The `YAML` namespace contains functions which can serialize and deserialize 8 | YAML documents, following the same pattern as JavaScript's `JSON` builtin. 9 | 10 | ```ts 11 | const YAML: { 12 | parse( 13 | input: string, 14 | reviver?: (this: any, key: string, value: any) => any 15 | ): any; 16 | stringify( 17 | input: any, 18 | replacer?: 19 | | ((this: any, key: string, value: any) => any) 20 | | (number | string)[] 21 | | null, 22 | indent?: number 23 | ): string; 24 | }; 25 | ``` 26 | 27 | ## YAML.parse (method) 28 | 29 | Converts a YAML document string into a JavaScript value. It works the same 30 | way that `JSON.parse` does, but for YAML. 31 | 32 | ```ts 33 | parse(input: string, reviver?: (this: any, key: string, value: any) => any): any; 34 | ``` 35 | 36 | ## YAML.stringify (method) 37 | 38 | Converts a JavaScript value into a YAML document string. It works the same 39 | way that `JSON.stringify` does, but for YAML. 40 | 41 | ```ts 42 | stringify(input: any, replacer?: ((this: any, key: string, value: any) => any) | (number | string)[] | null, indent?: number): string; 43 | ``` 44 | -------------------------------------------------------------------------------- /meta/how-to-deploy-a-new-version.txt: -------------------------------------------------------------------------------- 1 | - build everything (meta/build.sh) with env var `YAVASCRIPT_VERSION` set to whatever (eg v0.0.8) 2 | - this will update the files in dist/bin/ 3 | - run meta/scripts/set-package-version.js to set the package.json version to the same version string 4 | - run npm publish in the meta/npm dir 5 | - commit the changes and push to github 6 | - make a release on github and create a tag from the latest commit with the version name as the tag name 7 | - run `env YAVASCRIPT_VERSION=whatever meta/scripts/assemble-tgz.sh` to make all the archives for each version in the meta/tgz-release folder and then upload all those as release artifacts on github 8 | - build docker images with meta/docker/build-image.sh with the env var `YS_DOCKER_TAG` set to the version string, and then again with it set to "latest" 9 | - note that this also pushes the images 10 | - use meta/scripts/set-package-version.js to change the version in package.json back to 0.0.0-git and commit and push that 11 | 12 | I think that's it -------------------------------------------------------------------------------- /meta/kame/kame-module-stub.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /meta/kame/kame-nice-path-stub.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Path: Path, 3 | }; 4 | -------------------------------------------------------------------------------- /meta/kame/kame-ts-interface-checker-stub.js: -------------------------------------------------------------------------------- 1 | const hasOwnProperty = Object.prototype.hasOwnProperty; 2 | 3 | const noop = () => {}; 4 | 5 | module.exports = { 6 | union: noop, 7 | lit: noop, 8 | iface: noop, 9 | array: noop, 10 | opt: noop, 11 | 12 | createCheckers(inputs) { 13 | const checkers = {}; 14 | 15 | for (let key in inputs) { 16 | if (hasOwnProperty.call(inputs, key)) { 17 | checkers[key] = { 18 | check() {}, 19 | strictCheck() {}, 20 | }; 21 | } 22 | } 23 | 24 | return checkers; 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /meta/ninja/bundles.ninja.js: -------------------------------------------------------------------------------- 1 | /// 2 | const { walkJsDeps } = require("../scripts/lib/walk"); 3 | 4 | const moduleFilenames = walkJsDeps("src/index.ts", { useKameResolver: true }); 5 | 6 | const index_arm64_js = build({ 7 | rule: "kame", 8 | inputs: "src/index.ts", 9 | implicitInputs: moduleFilenames, 10 | output: builddir("bundles/index-arm64.js"), 11 | ruleVariables: { 12 | YAVASCRIPT_ARCH: "arm64", 13 | }, 14 | }); 15 | 16 | build({ 17 | rule: "kame", 18 | inputs: "src/primordials.ts", 19 | implicitInputs: moduleFilenames, 20 | output: builddir("bundles/primordials-arm64.js"), 21 | ruleVariables: { 22 | YAVASCRIPT_ARCH: "arm64", 23 | }, 24 | }); 25 | 26 | const index_x86_64_js = build({ 27 | rule: "kame", 28 | inputs: "src/index.ts", 29 | implicitInputs: moduleFilenames, 30 | output: builddir("bundles/index-x86_64.js"), 31 | ruleVariables: { 32 | YAVASCRIPT_ARCH: "x86_64", 33 | }, 34 | }); 35 | 36 | build({ 37 | rule: "kame", 38 | inputs: "src/primordials.ts", 39 | implicitInputs: moduleFilenames, 40 | output: builddir("bundles/primordials-x86_64.js"), 41 | ruleVariables: { 42 | YAVASCRIPT_ARCH: "x86_64", 43 | }, 44 | }); 45 | 46 | if (process.arch === "arm64") { 47 | build({ 48 | rule: "copy", 49 | inputs: [index_arm64_js], 50 | output: builddir("bundles/index.js"), 51 | }); 52 | } else { 53 | build({ 54 | rule: "copy", 55 | inputs: [index_x86_64_js], 56 | output: builddir("bundles/index.js"), 57 | }); 58 | } 59 | 60 | // so you can click-to-position in stack traces 61 | build({ 62 | rule: "copy", 63 | inputs: [builddir("bundles/index.js")], 64 | output: "yavascript-internal.js", 65 | }); 66 | -------------------------------------------------------------------------------- /meta/ninja/bytecode.ninja.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | const index_arm64_bin = build({ 4 | rule: "to-bytecode", 5 | inputs: [builddir("bundles/index-arm64.js")], 6 | output: builddir("bytecode/index-arm64.bin"), 7 | }); 8 | 9 | const index_x86_64_bin = build({ 10 | rule: "to-bytecode", 11 | inputs: [builddir("bundles/index-x86_64.js")], 12 | output: builddir("bytecode/index-x86_64.bin"), 13 | }); 14 | 15 | if (process.arch === "arm64") { 16 | build({ 17 | rule: "copy", 18 | inputs: [index_arm64_bin], 19 | output: builddir("bytecode/index.bin"), 20 | }); 21 | } else { 22 | build({ 23 | rule: "copy", 24 | inputs: [index_x86_64_bin], 25 | output: builddir("bytecode/index.bin"), 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /meta/ninja/dts.ninja.js: -------------------------------------------------------------------------------- 1 | /// 2 | const path = require("path"); 3 | 4 | const includeFiles = glob("src/**/*.inc.d.ts"); 5 | 6 | const dtsFolderPaths = new Set(); 7 | includeFiles.forEach((match) => { 8 | dtsFolderPaths.add(path.dirname(match)); 9 | }); 10 | 11 | const includePaths = [ 12 | ...dtsFolderPaths, 13 | "src/templates", 14 | "node_modules/@suchipi/quickjs/build/dts", 15 | ]; 16 | 17 | const quickjsDtsFiles = glob("node_modules/@suchipi/quickjs/build/dts/*"); 18 | 19 | const dtsRaw = build({ 20 | rule: "macaroni", 21 | inputs: ["src/templates/yavascript.d.ts.tmpl"], 22 | output: builddir("dts/yavascript-raw.d.ts"), 23 | implicitInputs: [...includeFiles, ...quickjsDtsFiles], 24 | ruleVariables: { 25 | INCLUDE_PATHS: JSON.stringify(includePaths.join(",")), 26 | }, 27 | }); 28 | build({ 29 | rule: "prettier", 30 | inputs: [dtsRaw], 31 | output: builddir("yavascript.d.ts"), 32 | }); 33 | 34 | const dtsGitRaw = build({ 35 | rule: "macaroni", 36 | inputs: ["src/templates/yavascript-git.d.ts.tmpl"], 37 | output: builddir("dts/yavascript-git-raw.d.ts"), 38 | implicitInputs: [...includeFiles, ...quickjsDtsFiles], 39 | ruleVariables: { 40 | INCLUDE_PATHS: JSON.stringify(includePaths.join(",")), 41 | }, 42 | }); 43 | build({ 44 | rule: "prettier", 45 | inputs: [dtsGitRaw], 46 | output: "yavascript.d.ts", 47 | }); 48 | -------------------------------------------------------------------------------- /meta/ninja/npm.ninja.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | const quickjs = require("@suchipi/quickjs"); 4 | 5 | for (const platform of quickjs.platforms) { 6 | const programPath = `bin/${platform.name}/yavascript${platform.programSuffix}`; 7 | 8 | build({ 9 | rule: "copy", 10 | inputs: builddir(programPath), 11 | output: `meta/npm/${programPath}`, 12 | }); 13 | } 14 | 15 | build({ 16 | rule: "copy", 17 | inputs: builddir("yavascript.d.ts"), 18 | output: "meta/npm/yavascript.d.ts", 19 | }); 20 | 21 | build({ 22 | rule: "copy", 23 | inputs: ["README.md"], 24 | output: "meta/npm/README.md", 25 | }); 26 | 27 | for (const filename of [ 28 | "index-x86_64.js", 29 | "index-arm64.js", 30 | "primordials-x86_64.js", 31 | "primordials-arm64.js", 32 | ]) { 33 | build({ 34 | rule: "copy", 35 | inputs: [builddir(`bundles/${filename}`)], 36 | output: `meta/npm/dist/${filename}`, 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /meta/npm/.gitignore: -------------------------------------------------------------------------------- 1 | yavascript.d.ts 2 | bin 3 | README.md 4 | -------------------------------------------------------------------------------- /meta/npm/.npmignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/npm/.npmignore -------------------------------------------------------------------------------- /meta/npm/lib/binary-path.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | var binDir = path.resolve(__dirname, "..", "bin"); 4 | 5 | function getBinaryPath(platformAndArch) { 6 | switch (platformAndArch) { 7 | case "darwin-arm64": { 8 | return path.join(binDir, "aarch64-apple-darwin", "yavascript"); 9 | } 10 | case "darwin-x64": { 11 | return path.join(binDir, "x86_64-apple-darwin", "yavascript"); 12 | } 13 | case "linux-arm64": { 14 | return path.join(binDir, "aarch64-unknown-linux-static", "yavascript"); 15 | } 16 | case "linux-x64": { 17 | return path.join(binDir, "x86_64-unknown-linux-static", "yavascript"); 18 | } 19 | case "win32-x64": { 20 | return path.join(binDir, "x86_64-pc-windows-static", "yavascript.exe"); 21 | } 22 | default: { 23 | throw new Error("Unsupported platform: " + platformAndArch); 24 | } 25 | } 26 | } 27 | 28 | var binaryPath = getBinaryPath(process.platform + "-" + process.arch); 29 | 30 | module.exports = { 31 | getBinaryPath: getBinaryPath, 32 | binaryPath: binaryPath, 33 | }; 34 | -------------------------------------------------------------------------------- /meta/npm/lib/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var child_process = require("child_process"); 3 | var binaryPath = require("./binary-path").binaryPath; 4 | 5 | try { 6 | child_process.execFileSync(binaryPath, process.argv.slice(2), { 7 | cwd: process.cwd(), 8 | stdio: "inherit", 9 | }); 10 | } catch (err) { 11 | process.exitCode = 1; 12 | } 13 | -------------------------------------------------------------------------------- /meta/npm/lib/index.js: -------------------------------------------------------------------------------- 1 | var getBinaryPath = require("./binary-path").getBinaryPath; 2 | var binaryPath = require("./binary-path").binaryPath; 3 | var version = require("../package.json").version; 4 | 5 | module.exports = { 6 | getBinaryPath, 7 | binaryPath, 8 | version, 9 | }; 10 | -------------------------------------------------------------------------------- /meta/npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yavascript", 3 | "version": "0.0.0-git", 4 | "main": "lib/index.js", 5 | "bin": "lib/cli.js", 6 | "types": "yavascript.d.ts", 7 | "author": "Lily Skye ", 8 | "license": "MIT", 9 | "repository": "suchipi/yavascript" 10 | } 11 | -------------------------------------------------------------------------------- /meta/root-dir.d.ts: -------------------------------------------------------------------------------- 1 | declare var rootDir: import("path-less-traveled").PathMarker; 2 | export = rootDir; 3 | -------------------------------------------------------------------------------- /meta/root-dir.js: -------------------------------------------------------------------------------- 1 | const { pathMarker } = require("path-less-traveled"); 2 | 3 | module.exports = pathMarker(__dirname, ".."); 4 | -------------------------------------------------------------------------------- /meta/scripts/assemble-tgz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euo pipefail 4 | 5 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 6 | cd "$SCRIPT_DIR/../.." # go to root 7 | ROOTDIR="$PWD" 8 | 9 | VERSION=`node -e 'console.log(require("./src/hardcoded/compile-time.js").version)'` 10 | 11 | if test -e meta/tgz-release; then 12 | rm -rf meta/tgz-release 13 | fi 14 | mkdir -p meta/tgz-release 15 | cd meta/tgz-release 16 | 17 | TARGETS=( 18 | aarch64-apple-darwin 19 | aarch64-unknown-linux-gnu 20 | aarch64-unknown-linux-musl 21 | aarch64-unknown-linux-static 22 | x86_64-apple-darwin 23 | x86_64-pc-windows-static 24 | x86_64-unknown-linux-gnu 25 | x86_64-unknown-linux-musl 26 | x86_64-unknown-linux-static 27 | ) 28 | for TARGET in "${TARGETS[@]}"; do 29 | mkdir -p "./$TARGET/yavascript-$VERSION" 30 | 31 | cp "$ROOTDIR"/dist/bin/"$TARGET"/* "./$TARGET/yavascript-$VERSION" 32 | cp "$ROOTDIR"/dist/yavascript.d.ts "./$TARGET/yavascript-$VERSION/" 33 | 34 | pushd "$TARGET" > /dev/null 35 | tar -czvf "../yavascript-$VERSION-$TARGET.tar.gz" "yavascript-$VERSION/" 36 | popd > /dev/null 37 | done 38 | -------------------------------------------------------------------------------- /meta/scripts/ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | # install ninja 5 | sudo apt-get install -y ninja-build 6 | 7 | export NVM_DIR="$HOME/.nvm" 8 | # this is really chatty... 9 | echo "+ source "$NVM_DIR/nvm.sh" --no-use" 10 | set +x 11 | source "$NVM_DIR/nvm.sh" --no-use 12 | set -x 13 | 14 | nvm install 15 | nvm use 16 | 17 | env SKIP_FNM_USE=1 meta/build.sh 18 | 19 | # commented out until I can get it working locally 20 | # meta/docker/wine-test-image/build.sh 21 | 22 | pushd meta/tests 23 | npm install 24 | popd 25 | 26 | npm test 27 | npm run typecheck 28 | -------------------------------------------------------------------------------- /meta/scripts/lib/newline.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /meta/scripts/lib/walk.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { walk } = require("resolve-everything"); 3 | const rootDir = require("../../root-dir"); 4 | 5 | // walk the JS/TS import/require graph, starting at the given entrypoint, 6 | // and return all the files that were part of it. It only goes one-file-deep 7 | // into node_modules. 8 | function walkJsDeps(entrypoint, { useKameResolver = false } = {}) { 9 | const entrypointAbs = path.isAbsolute(entrypoint) 10 | ? entrypoint 11 | : rootDir(entrypoint); 12 | 13 | const walkOptions = { 14 | skip: /node_modules/g, 15 | }; 16 | if (useKameResolver) { 17 | walkOptions.resolver = require("../../kame/kame-config").resolve; 18 | } 19 | 20 | const { errors, modules } = walk(entrypointAbs, walkOptions); 21 | 22 | if (errors.length > 0) { 23 | throw Object.assign(new Error("module traversal errors occurred"), { 24 | errors, 25 | }); 26 | } 27 | 28 | return Array.from(modules.keys()).map((filename) => { 29 | // our kame resolver adds "query params" to the end of filenames sometimes 30 | const withoutTrailingQueryParam = filename.replace(/\?.*$/, ""); 31 | // these don't strictly-speaking need to be relative paths, but it makes 32 | // the build.ninja file easier to read 33 | return rootDir.relative(withoutTrailingQueryParam); 34 | }); 35 | } 36 | 37 | module.exports = { walkJsDeps }; 38 | -------------------------------------------------------------------------------- /meta/scripts/markdown-toc.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const { parseArgv, Path } = require("clef-parse"); 3 | const { mdtocs } = require("mdtocs"); 4 | 5 | const argv = parseArgv(process.argv.slice(2), { 6 | input: Path, 7 | output: Path, 8 | }); 9 | 10 | if (!argv.options.input || !argv.options.output) { 11 | throw new Error("You have to specify --input [path] and --output [path]"); 12 | } 13 | 14 | const inputPath = argv.options.input; 15 | const outputPath = argv.options.output; 16 | 17 | const inputContent = fs.readFileSync(inputPath.toString(), "utf-8"); 18 | 19 | const toc = mdtocs(inputContent); 20 | 21 | fs.writeFileSync(outputPath.toString(), toc); 22 | -------------------------------------------------------------------------------- /meta/scripts/md-links-from-json5.js: -------------------------------------------------------------------------------- 1 | const fs = require("node:fs"); 2 | const JSON5 = require("json5"); 3 | 4 | const inputPath = process.argv[2]; 5 | const outputPath = process.argv[3]; 6 | 7 | const docLinksStr = fs.readFileSync(inputPath, "utf-8"); 8 | const docLinks = JSON5.parse(docLinksStr); 9 | 10 | const writeStream = fs.createWriteStream(outputPath, "utf-8"); 11 | 12 | writeStream.write("\n"); 13 | 14 | for (const [name, url] of Object.entries(docLinks)) { 15 | writeStream.write(`[\`${name}\`]: ${url}\n`); 16 | } 17 | 18 | writeStream.close(); 19 | -------------------------------------------------------------------------------- /meta/scripts/ninja-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -exuo pipefail 4 | shopt -s globstar 5 | 6 | SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd) 7 | cd "$SCRIPT_DIR/../.." # go to root 8 | 9 | # this file needs to exist for the module resolve step in bundles.ninja.js 10 | # to work 11 | mkdir -p dist 12 | if [[ ! -e dist/yavascript.d.ts ]]; then 13 | touch dist/yavascript.d.ts 14 | fi 15 | 16 | env BUILDDIR=dist npx --no-install shinobi \ 17 | ./meta/ninja/**/*.ninja.js \ 18 | -o dist/build.ninja 19 | 20 | ninja -f dist/build.ninja 21 | -------------------------------------------------------------------------------- /meta/scripts/set-package-version.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | function main(newVersion) { 5 | cd(GitRepo.findRoot(__dirname)); 6 | 7 | const currentVersion = readJson("./package.json").version; 8 | console.log(`current version: ${currentVersion}`); 9 | 10 | console.log(`new version: ${newVersion}`); 11 | 12 | const pkgJsonFiles = ["./package.json", "./meta/npm/package.json"]; 13 | 14 | for (const pkgJsonFile of pkgJsonFiles) { 15 | const pkg = readJson(pkgJsonFile); 16 | pkg.version = newVersion; 17 | writeJson(pkgJsonFile, pkg); 18 | console.log(`updated ${pkgJsonFile}`); 19 | } 20 | 21 | // update package-lock.json 22 | exec("npm install"); 23 | } 24 | 25 | function readJson(filepath) { 26 | return JSON.parse(readFile(filepath)); 27 | } 28 | 29 | function writeJson(filepath, data) { 30 | writeFile(filepath, JSON.stringify(data, null, 2) + "\n"); 31 | } 32 | 33 | function readArgv() { 34 | const { args } = parseScriptArgs(); 35 | 36 | const newVersion = args[0]; 37 | if (!newVersion) { 38 | throw new Error("Please specify the new version."); 39 | } 40 | 41 | return [newVersion]; 42 | } 43 | 44 | main(...readArgv()); 45 | -------------------------------------------------------------------------------- /meta/tests/fixtures/copy/.gitignore: -------------------------------------------------------------------------------- 1 | blah_copy 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/copy/blah/blah2/hi.txt: -------------------------------------------------------------------------------- 1 | yeah hi there 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/file_content/.gitignore: -------------------------------------------------------------------------------- 1 | written.txt 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/file_content/hello.txt: -------------------------------------------------------------------------------- 1 | hello, world!!! :D 2 | あ -------------------------------------------------------------------------------- /meta/tests/fixtures/file_content/hello2.txt: -------------------------------------------------------------------------------- 1 | trailing newline incoming 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/gitignoring/hi.txt: -------------------------------------------------------------------------------- 1 | unignored 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/gitignoring/subdir/.gitignore: -------------------------------------------------------------------------------- 1 | hi.txt 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/cabana/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/cabana/.gitkeep -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/hi.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/hi.js -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/hi.something.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/hi.something.js -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/hi.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/hi.txt -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/hi/.yeah: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/hi/.yeah -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/hi/there.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/hi/there.txt -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/potato/banana/yo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/potato/banana/yo.js -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/potato/banana/yo.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/potato/banana/yo.txt -------------------------------------------------------------------------------- /meta/tests/fixtures/glob/potato/eggplant: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/glob/potato/eggplant -------------------------------------------------------------------------------- /meta/tests/fixtures/grep/stuff.txt: -------------------------------------------------------------------------------- 1 | blah bla 2 | one two bl 3 | rah rah bb 4 | twot 5 | -------------------------------------------------------------------------------- /meta/tests/fixtures/logging/log-1.js: -------------------------------------------------------------------------------- 1 | console.log("1"); 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/logging/log-three.coffee: -------------------------------------------------------------------------------- 1 | console.log "three" 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/logging/log-two.ts: -------------------------------------------------------------------------------- 1 | type Something = 5; 2 | 3 | console.log("two"); 4 | -------------------------------------------------------------------------------- /meta/tests/fixtures/mkdir/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /meta/tests/fixtures/remove/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/__filename-and-__dirname-2.js: -------------------------------------------------------------------------------- 1 | export default { 2 | __filename, 3 | __dirname, 4 | }; 5 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/__filename-and-__dirname.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | echo({ __filename, __dirname }); 5 | 6 | import resultsFromOtherModule from "./__filename-and-__dirname-2.js"; 7 | 8 | echo(resultsFromOtherModule); 9 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/http-import-error.js: -------------------------------------------------------------------------------- 1 | import something from "http://suchipi.com/there-is-nothing-at-this-path"; 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/https-import-error.js: -------------------------------------------------------------------------------- 1 | import something from "https://suchipi.com/there-is-nothing-at-this-path"; 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/importing-from-npm-protocol.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | import * as pheno from "npm:pheno@0.12.0"; 5 | 6 | console.log(pheno); 7 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/importing-json.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | import someJson from "./some-json.json"; 5 | 6 | echo(someJson); 7 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/npm-proto-import-error.js: -------------------------------------------------------------------------------- 1 | import something from "npm:@suchipi/this-package-does-not-exist"; 2 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/requiring-with-npm-proto.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | const pheno = require("npm:pheno@0.12.0"); 5 | 6 | console.log(pheno); 7 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-civet.civet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | import * as std from 'quickjs:std' 4 | echo typeof std 5 | 6 | os := require 'quickjs:os' 7 | echo typeof os 8 | 9 | "potato" 10 | |> isDir 11 | |> echo 12 | 13 | someEl := 14 | <.hi +disabled> 15 | hi 16 | 17 | echo someEl 18 | 19 | type Something = string 20 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-coffeescript.coffee: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | import * as std from 'quickjs:std' 4 | echo typeof std 5 | 6 | os = require 'quickjs:os' 7 | echo typeof os 8 | 9 | echo isDir "potato" 10 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-json.json: -------------------------------------------------------------------------------- 1 | // comments are supported in json that gets imported using the import keyword 2 | { 3 | "hello": "there" 4 | } 5 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-jsx.jsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | 3 | // JSX syntax gets compiled to expressions referencing `JSX.createElement` and 4 | // `JSX.Fragment`, which are both defined as a global. To change how JSX gets 5 | // compiled, change the values of `JSX.pragma` and `JSX.pragmaFrag`. 6 | // 7 | // Note that if you change `JSX.pragma` and/or `JSX.pragmaFrag`, you should 8 | // also update `types.JSX.Element` and `types.JSX.Fragment`. See the `JSX` section in 9 | // `yavascript --print-types` for more information. 10 | 11 | console.log(); // { $$typeof: Symbol(JSX.Element), type: "a", props: null, key: null } 12 | 13 | console.log(is(, types.JSX.Element)); // true 14 | console.log(is(2, types.JSX.Element)); // false 15 | 16 | console.log(is(<>, types.JSX.Fragment)); // true 17 | console.log(is(, types.JSX.Fragment)); // false 18 | console.log(is(2, types.JSX.Fragment)); // false 19 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-tsx.tsx: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | // JSX syntax gets compiled to expressions referencing `JSX.createElement` and 5 | // `JSX.Fragment`, which are both defined as a global. To change how JSX gets 6 | // compiled, change the values of `JSX.pragma` and `JSX.pragmaFrag`. 7 | // 8 | // Note that if you change `JSX.pragma` and/or `JSX.pragmaFrag`, you should 9 | // also update `types.JSX.Element` and `types.JSX.Fragment`. See the `JSX` section in 10 | // `yavascript --print-types` for more information. 11 | 12 | console.log(); // { $$typeof: Symbol(JSX.Element), type: "a", props: null, key: null } 13 | 14 | console.log(is(, types.JSX.Element)); // true 15 | console.log(is(2, types.JSX.Element)); // false 16 | 17 | console.log(is(<>, types.JSX.Fragment)); // true 18 | console.log(is(, types.JSX.Fragment)); // false 19 | console.log(is(2, types.JSX.Fragment)); // false 20 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/some-typescript.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env yavascript 2 | /// 3 | 4 | declare var something: any; 5 | echo(typeof something); 6 | 7 | import * as std from "quickjs:std"; 8 | echo(typeof std); 9 | 10 | function look(path: Path) { 11 | echo(`path: ${path}`); 12 | echo(realpath(path)); 13 | } 14 | 15 | look(pwd()); 16 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/toplevel-await-and-export-together.js: -------------------------------------------------------------------------------- 1 | // this errors 2 | await (2 + 2); 3 | export const five = 5; 4 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/toplevel-await.coffee: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std" 2 | 3 | four = await new Promise((resolve) -> resolve 4) 4 | console.log four, std.open 5 | 6 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/toplevel-await.js: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | const four = await new Promise((resolve) => resolve(4)); 4 | console.log(four, std.open); 5 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/toplevel-await.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | await Promise.reject(new Error("nope!")); 4 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/toplevel-await.tsx: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | type Something = { yeah: string | number }; 4 | 5 | const someElement = await ; 6 | console.log(someElement); 7 | console.log(std.open); 8 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/type-coercion-via-assert.ts: -------------------------------------------------------------------------------- 1 | const logThrowMessage = (val, type) => { 2 | try { 3 | assert.type(val, type); 4 | } catch (err: any) { 5 | console.log(err.message); 6 | return; 7 | } 8 | console.log( 9 | "no error message from", 10 | val, 11 | is(type, Function) ? type.name : type 12 | ); 13 | }; 14 | 15 | logThrowMessage("hi", string); 16 | logThrowMessage(null, string); // throws 17 | logThrowMessage(24, string); // throws 18 | 19 | logThrowMessage("hi", "hi"); 20 | logThrowMessage("yes", "hi"); // throws 21 | logThrowMessage("something", number); // throws 22 | 23 | logThrowMessage(42, number); 24 | -------------------------------------------------------------------------------- /meta/tests/fixtures/scripts/type-coercion-via-is.ts: -------------------------------------------------------------------------------- 1 | const logIs = (val, type) => console.log(is(val, type)); 2 | 3 | logIs("hi", string); // true 4 | logIs(null, string); // false 5 | logIs(24, string); // false 6 | 7 | logIs("hi", "hi"); // true 8 | logIs("yes", "hi"); // false 9 | logIs("something", number); // false 10 | 11 | logIs(42, number); // true 12 | -------------------------------------------------------------------------------- /meta/tests/fixtures/symlinks/dead-link: -------------------------------------------------------------------------------- 1 | ./nowhere-real -------------------------------------------------------------------------------- /meta/tests/fixtures/symlinks/link-to-file: -------------------------------------------------------------------------------- 1 | ./some-file -------------------------------------------------------------------------------- /meta/tests/fixtures/symlinks/link-to-folder: -------------------------------------------------------------------------------- 1 | ./some-folder -------------------------------------------------------------------------------- /meta/tests/fixtures/symlinks/some-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/symlinks/some-file -------------------------------------------------------------------------------- /meta/tests/fixtures/symlinks/some-folder/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/symlinks/some-folder/.gitkeep -------------------------------------------------------------------------------- /meta/tests/fixtures/which/bin1/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/bin1/program -------------------------------------------------------------------------------- /meta/tests/fixtures/which/bin1/program1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/bin1/program1 -------------------------------------------------------------------------------- /meta/tests/fixtures/which/bin1/something.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/bin1/something.bat -------------------------------------------------------------------------------- /meta/tests/fixtures/which/bin2/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/bin2/program -------------------------------------------------------------------------------- /meta/tests/fixtures/which/bin2/program3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/bin2/program3 -------------------------------------------------------------------------------- /meta/tests/fixtures/which/usr/bin3/program: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/usr/bin3/program -------------------------------------------------------------------------------- /meta/tests/fixtures/which/usr/bin3/program2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/usr/bin3/program2 -------------------------------------------------------------------------------- /meta/tests/fixtures/which/usr/bin3/something.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/suchipi/yavascript/aef22cbb36acead0341d4df91ae3b476281fb910/meta/tests/fixtures/which/usr/bin3/something.exe -------------------------------------------------------------------------------- /meta/tests/fixtures/worker/main.js: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | 3 | console.log("in main"); 4 | const w = new os.Worker("./worker.js"); 5 | 6 | setTimeout(() => { 7 | console.log("in main, sending try-to-exit"); 8 | w.postMessage("try-to-exit"); 9 | }, 10); 10 | -------------------------------------------------------------------------------- /meta/tests/fixtures/worker/worker.js: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as os from "quickjs:os"; 3 | 4 | console.log("in worker"); 5 | 6 | os.Worker.parent.onmessage = (event) => { 7 | console.log("in worker, received:", inspect(event)); 8 | if (event.data === "try-to-exit") { 9 | std.exit(1); 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /meta/tests/jest/babel-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | babelrc: false, 3 | presets: [ 4 | ["@babel/preset-env", { targets: { node: "current" } }], 5 | "@babel/preset-typescript", 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /meta/tests/jest/config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const babelConfig = require("./babel-config"); 3 | const rootDir = require("../../root-dir"); 4 | 5 | /** @type {import('jest').Config} */ 6 | const config = { 7 | rootDir: rootDir(), 8 | setupFiles: [require.resolve("./go-to-root")], 9 | transform: { 10 | "\\.[jt]sx?$": [require.resolve("babel-jest"), babelConfig], 11 | }, 12 | watchPathIgnorePatterns: ["node_modules", "/meta/tests/fixtures"], 13 | snapshotSerializers: [path.join(__dirname, "snapshotSerializer.js")], 14 | testPathIgnorePatterns: [ 15 | "/node_modules/", 16 | "/dist", 17 | "/meta/generated-docs/", 18 | ], 19 | }; 20 | 21 | module.exports = config; 22 | -------------------------------------------------------------------------------- /meta/tests/jest/go-to-root.js: -------------------------------------------------------------------------------- 1 | const rootDir = require("../../root-dir"); 2 | 3 | process.chdir(rootDir()); 4 | -------------------------------------------------------------------------------- /meta/tests/jest/snapshotSerializer.js: -------------------------------------------------------------------------------- 1 | const kame = require("kame"); 2 | const runtime = new kame.Runtime(); 3 | const { cleanResult } = runtime.load(require.resolve("../src/test-helpers.ts")); 4 | 5 | const hasOwnProperty = Object.prototype.hasOwnProperty; 6 | const cleaned = new WeakMap(); 7 | 8 | module.exports = { 9 | test: (val) => 10 | typeof val === "object" && 11 | val != null && 12 | typeof val.stdout === "string" && 13 | typeof val.stderr === "string" && 14 | hasOwnProperty.call(val, "code") && 15 | hasOwnProperty.call(val, "error") && 16 | !cleaned.has(val), 17 | print: (val, serialize) => { 18 | const cleanedResult = cleanResult(val); 19 | cleaned.set(cleanedResult, true); 20 | return serialize(cleanedResult); 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /meta/tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yavascript-tests", 3 | "private": true, 4 | "scripts": { 5 | "test": "jest --config=./jest/config.js" 6 | }, 7 | "dependencies": { 8 | "first-base": "^1.5.2", 9 | "jest": "^29.7.0" 10 | }, 11 | "devDependencies": { 12 | "@babel/core": "^7.26.0", 13 | "@babel/preset-env": "^7.26.0", 14 | "@babel/preset-typescript": "^7.26.0", 15 | "@types/jest": "^29.5.14", 16 | "babel-jest": "^29.7.0" 17 | }, 18 | "prettier": {} 19 | } 20 | -------------------------------------------------------------------------------- /meta/tests/src/__filename-and-__dirname.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("__filename and __dirname", async () => { 4 | const result = await evaluate( 5 | ` 6 | echo(__filename); 7 | echo(__dirname); 8 | `, 9 | { cwd: __dirname } 10 | ); 11 | expect(result).toMatchInlineSnapshot(` 12 | { 13 | "code": 0, 14 | "error": false, 15 | "stderr": "", 16 | "stdout": "/meta/tests/src/ 17 | /meta/tests/src 18 | ", 19 | } 20 | `); 21 | }); 22 | -------------------------------------------------------------------------------- /meta/tests/src/assert.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("assert - truthy value", async () => { 4 | const result = await evaluate(` 5 | assert(2 + 2 === 4); 6 | `); 7 | expect(result).toMatchInlineSnapshot(` 8 | { 9 | "code": 0, 10 | "error": false, 11 | "stderr": "", 12 | "stdout": "", 13 | } 14 | `); 15 | }); 16 | 17 | test("assert - falsy value", async () => { 18 | const result = await evaluate(` 19 | assert(2 + 2 === 5); 20 | `); 21 | expect(result).toMatchInlineSnapshot(` 22 | { 23 | "code": 1, 24 | "error": false, 25 | "stderr": "Error: Assertion failed (value = false) 26 | at somewhere 27 | { 28 | value: false 29 | } 30 | ", 31 | "stdout": "", 32 | } 33 | `); 34 | }); 35 | -------------------------------------------------------------------------------- /meta/tests/src/basename.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("basename", async () => { 4 | const result = await evaluate(`basename("/hi/there/yeah")`); 5 | expect(result).toMatchInlineSnapshot(` 6 | { 7 | "code": 0, 8 | "error": false, 9 | "stderr": "", 10 | "stdout": "yeah 11 | ", 12 | } 13 | `); 14 | }); 15 | 16 | test("basename (windows-style path)", async () => { 17 | const result = await evaluate(`basename("C:\\\\Users\\\\Suchipi")`); 18 | expect(result).toMatchInlineSnapshot(` 19 | { 20 | "code": 0, 21 | "error": false, 22 | "stderr": "", 23 | "stdout": "Suchipi 24 | ", 25 | } 26 | `); 27 | }); 28 | -------------------------------------------------------------------------------- /meta/tests/src/csv.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("CSV", async () => { 4 | const result = await evaluate( 5 | ` 6 | const table = [ 7 | ["a", "b", "c"], 8 | ["d", "e", "f"] 9 | ]; 10 | 11 | const csv = CSV.stringify(table); 12 | const reparsed = CSV.parse(csv); 13 | 14 | console.log({ 15 | table, 16 | csv, 17 | reparsed 18 | }) 19 | ` 20 | ); 21 | expect(result).toMatchInlineSnapshot(` 22 | { 23 | "code": 0, 24 | "error": false, 25 | "stderr": "", 26 | "stdout": "{ 27 | table: [ 28 | [ 29 | "a" 30 | "b" 31 | "c" 32 | ] 33 | [ 34 | "d" 35 | "e" 36 | "f" 37 | ] 38 | ] 39 | csv: "a,b,c\\r\\nd,e,f" 40 | reparsed: [ 41 | [ 42 | "a" 43 | "b" 44 | "c" 45 | ] 46 | [ 47 | "d" 48 | "e" 49 | "f" 50 | ] 51 | ] 52 | } 53 | ", 54 | } 55 | `); 56 | }); 57 | -------------------------------------------------------------------------------- /meta/tests/src/dirname.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("dirname", async () => { 4 | const result = await evaluate(`dirname("/hi/there/yeah")`); 5 | expect(result).toMatchInlineSnapshot(` 6 | { 7 | "code": 0, 8 | "error": false, 9 | "stderr": "", 10 | "stdout": "Path { /hi/there } 11 | ", 12 | } 13 | `); 14 | }); 15 | 16 | test("dirname (folder in root dir)", async () => { 17 | const result = await evaluate(`dirname("/hi")`); 18 | expect(result).toMatchInlineSnapshot(` 19 | { 20 | "code": 0, 21 | "error": false, 22 | "stderr": "", 23 | "stdout": "Path { / } 24 | ", 25 | } 26 | `); 27 | }); 28 | 29 | test("dirname (windows-style path)", async () => { 30 | const result = await evaluate(`dirname("C:\\\\Users\\\\Suchipi")`); 31 | expect(result).toMatchInlineSnapshot(` 32 | { 33 | "code": 0, 34 | "error": false, 35 | "stderr": "", 36 | "stdout": "Path { C:\\Users } 37 | ", 38 | } 39 | `); 40 | }); 41 | -------------------------------------------------------------------------------- /meta/tests/src/dts.test.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import ts from "typescript"; 3 | import { rootDir } from "./test-helpers"; 4 | 5 | const dtsPath = rootDir("yavascript.d.ts"); 6 | 7 | describe("yavascript.d.ts", () => { 8 | it("is considered a global script rather than a module", async () => { 9 | const content = await fs.promises.readFile(dtsPath, "utf-8"); 10 | const sourceFile = ts.createSourceFile( 11 | "yavascript.d.ts", 12 | content, 13 | ts.ScriptTarget.ES2020 14 | ); 15 | 16 | // @ts-ignore this function is there, but it isn't in the type defs 17 | const isModule = ts.isFileProbablyExternalModule(sourceFile); 18 | 19 | // Could just do `expect(isModule).toBeFalsy()`, but all the stuff below 20 | // will give a more actionable error message 21 | if (!isModule) { 22 | return; 23 | } 24 | 25 | const lines = content.split("\n"); 26 | const exportingLineIndex = lines.findIndex((line) => 27 | line.startsWith("export") 28 | ); 29 | const exportingLine = 30 | exportingLineIndex === -1 ? null : lines[exportingLineIndex]; 31 | if (exportingLine != null) { 32 | const lineNumber = exportingLineIndex + 1; 33 | const actual = `Line ${lineNumber}: ${exportingLine}`; 34 | const expected = `Line ${lineNumber}: ${exportingLine.replace( 35 | /^export/, 36 | "declare" 37 | )}`; 38 | expect(actual).toBe(expected); 39 | } else { 40 | // We can't give a very actionable error message, but this test needs to 41 | // still fail. 42 | expect(isModule).toBeFalsy(); 43 | } 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /meta/tests/src/echo.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("echo string", async () => { 4 | const result = await evaluate(`echo("hi");`); 5 | expect(result).toMatchInlineSnapshot(` 6 | { 7 | "code": 0, 8 | "error": false, 9 | "stderr": "", 10 | "stdout": "hi 11 | ", 12 | } 13 | `); 14 | }); 15 | 16 | test("echo object", async () => { 17 | const result = await evaluate(`echo({ hi: true });`); 18 | expect(result).toMatchInlineSnapshot(` 19 | { 20 | "code": 0, 21 | "error": false, 22 | "stderr": "", 23 | "stdout": "{ 24 | hi: true 25 | } 26 | ", 27 | } 28 | `); 29 | }); 30 | 31 | test("echo multiple", async () => { 32 | const result = await evaluate(`echo("hi", { hi: true }, "hi again");`); 33 | expect(result).toMatchInlineSnapshot(` 34 | { 35 | "code": 0, 36 | "error": false, 37 | "stderr": "", 38 | "stdout": "hi { 39 | hi: true 40 | } hi again 41 | ", 42 | } 43 | `); 44 | }); 45 | -------------------------------------------------------------------------------- /meta/tests/src/error-handling.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("prints thrown errors to stderr", async () => { 4 | const result = await evaluate(`blahhhh`); 5 | expect(result).toMatchInlineSnapshot(` 6 | { 7 | "code": 1, 8 | "error": false, 9 | "stderr": "ReferenceError: 'blahhhh' is not defined 10 | at somewhere 11 | ", 12 | "stdout": "", 13 | } 14 | `); 15 | }); 16 | 17 | test("prints thrown non-errors to stderr", async () => { 18 | const result = await evaluate(`throw "nope"`); 19 | expect(result).toMatchInlineSnapshot(` 20 | { 21 | "code": 1, 22 | "error": false, 23 | "stderr": "Non-error value was thrown: "nope" 24 | ", 25 | "stdout": "", 26 | } 27 | `); 28 | }); 29 | 30 | test("prints extra error properties to stderr", async () => { 31 | const result = await evaluate( 32 | `e = new Error('hi'); e.something = true; e.somethingElse = false; throw e;` 33 | ); 34 | expect(result).toMatchInlineSnapshot(` 35 | { 36 | "code": 1, 37 | "error": false, 38 | "stderr": "Error: hi 39 | at somewhere 40 | { 41 | something: true 42 | somethingElse: false 43 | } 44 | ", 45 | "stdout": "", 46 | } 47 | `); 48 | }); 49 | -------------------------------------------------------------------------------- /meta/tests/src/extname.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("extname", async () => { 4 | const script = ` 5 | echo(extname("something.js")); 6 | echo(extname("/tmp/somewhere/something.js")); 7 | 8 | echo(extname("something.test.js")); 9 | echo(extname("/tmp/somewhere/something.test.js")); 10 | 11 | echo(extname("something.test.js", { full: true })); 12 | echo(extname("/tmp/somewhere/something.test.js", { full: true })); 13 | 14 | echo(extname("something.test.js", { full: false })); 15 | echo(extname("/tmp/somewhere/something.test.js", { full: false })); 16 | 17 | echo(extname("Makefile")); 18 | echo(extname("Makefile", { full: false })); 19 | echo(extname("Makefile", { full: true })); 20 | `; 21 | 22 | const result = await evaluate(script); 23 | expect(result).toMatchInlineSnapshot(` 24 | { 25 | "code": 0, 26 | "error": false, 27 | "stderr": "", 28 | "stdout": ".js 29 | .js 30 | .js 31 | .js 32 | .test.js 33 | .test.js 34 | .js 35 | .js 36 | 37 | 38 | 39 | ", 40 | } 41 | `); 42 | }); 43 | 44 | test("extname (windows-style path)", async () => { 45 | const script = ` 46 | echo(extname("E:\\\\somewhere\\\\something.js")); 47 | echo(extname("E:\\\\somewhere\\\\something.test.js")); 48 | echo(extname("E:\\\\somewhere\\\\something.test.js", { full: true })); 49 | echo(extname("E:\\\\somewhere\\\\something.test.js", { full: false })); 50 | `; 51 | 52 | const result = await evaluate(script); 53 | expect(result).toMatchInlineSnapshot(` 54 | { 55 | "code": 0, 56 | "error": false, 57 | "stderr": "", 58 | "stdout": ".js 59 | .js 60 | .test.js 61 | .js 62 | ", 63 | } 64 | `); 65 | }); 66 | -------------------------------------------------------------------------------- /meta/tests/src/fixture-scripts.test.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import { spawn } from "first-base"; 4 | import { binaryPath, cleanResult, rootDir } from "./test-helpers"; 5 | 6 | const scriptsDir = rootDir("meta/tests/fixtures/scripts"); 7 | 8 | const scripts = fs.readdirSync(scriptsDir); 9 | for (const script of scripts) { 10 | test(script, async () => { 11 | const run = spawn(binaryPath, [script], { cwd: scriptsDir }); 12 | await run.completion; 13 | expect(cleanResult(run.result)).toMatchSnapshot(); 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /meta/tests/src/others.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("global constructor aliases", async () => { 4 | const result = await evaluate( 5 | ` 6 | assert(bigint === BigInt); 7 | assert(boolean === Boolean); 8 | assert(number === Number); 9 | assert(string === String); 10 | assert(symbol === Symbol); 11 | ` 12 | ); 13 | expect(result).toMatchInlineSnapshot(` 14 | { 15 | "code": 0, 16 | "error": false, 17 | "stderr": "", 18 | "stdout": "", 19 | } 20 | `); 21 | }); 22 | -------------------------------------------------------------------------------- /meta/tests/src/parse-script-args.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate, binaryPath, cleanResult } from "./test-helpers"; 2 | 3 | test("parseScriptArgs", async () => { 4 | const result = await evaluate(` 5 | parseScriptArgs({ 6 | somePath: Path, 7 | someNumber: Number, 8 | someBool: Boolean, 9 | anotherBool: Boolean, 10 | someString: String, 11 | }, [ 12 | "--some-path", 13 | "blah", 14 | "--some-number", 15 | "32", 16 | "--some-bool", 17 | "--some-string", 18 | "hi", 19 | "--unexpected-flag-1", 20 | "73", 21 | "--unexpected-flag-2", 22 | "--", 23 | "yeah hi", 24 | ]) 25 | `); 26 | expect(result).toMatchInlineSnapshot(` 27 | { 28 | "code": 0, 29 | "error": false, 30 | "stderr": "", 31 | "stdout": "{ 32 | flags: { 33 | somePath: Path { /blah } 34 | someNumber: 32 35 | someBool: true 36 | someString: "hi" 37 | unexpectedFlag1: 73 38 | unexpectedFlag2: true 39 | } 40 | args: [ 41 | "yeah hi" 42 | ] 43 | metadata: { 44 | keys: { 45 | --some-path: "somePath" 46 | --some-number: "someNumber" 47 | --some-bool: "someBool" 48 | --some-string: "someString" 49 | --unexpected-flag-1: "unexpectedFlag1" 50 | --unexpected-flag-2: "unexpectedFlag2" 51 | } 52 | hints: { 53 | somePath: "path" 54 | someNumber: "number" 55 | someBool: "boolean" 56 | someString: "string" 57 | } 58 | guesses: { 59 | unexpectedFlag1: "number" 60 | unexpectedFlag2: "boolean" 61 | } 62 | } 63 | } 64 | ", 65 | } 66 | `); 67 | }); 68 | -------------------------------------------------------------------------------- /meta/tests/src/printf.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("printf", async () => { 4 | const result = await evaluate( 5 | ` 6 | printf("bla %s blah %03d yeah 0x%04x", "hi", 9, 100); 7 | ` 8 | ); 9 | expect(result).toMatchInlineSnapshot(` 10 | { 11 | "code": 0, 12 | "error": false, 13 | "stderr": "", 14 | "stdout": "bla hi blah 009 yeah 0x0064", 15 | } 16 | `); 17 | }); 18 | -------------------------------------------------------------------------------- /meta/tests/src/readlink.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate, rootDir } from "./test-helpers"; 2 | 3 | const symlinksFixturesDir = rootDir("meta/tests/fixtures/symlinks"); 4 | 5 | test("readlink", async () => { 6 | const result = await evaluate( 7 | `[readlink("dead-link"), readlink("link-to-file"), readlink("link-to-folder")]`, 8 | { cwd: symlinksFixturesDir } 9 | ); 10 | expect(result).toMatchInlineSnapshot(` 11 | { 12 | "code": 0, 13 | "error": false, 14 | "stderr": "", 15 | "stdout": "[ 16 | Path { ./nowhere-real } 17 | Path { ./some-file } 18 | Path { ./some-folder } 19 | ] 20 | ", 21 | } 22 | `); 23 | }); 24 | -------------------------------------------------------------------------------- /meta/tests/src/repl.test.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from "first-base"; 2 | import { binaryPath } from "./test-helpers"; 3 | 4 | describe("repl", () => { 5 | test("basic run", async () => { 6 | const run = spawn(binaryPath); 7 | await run.outputContains("> "); 8 | run.write("2 + 2\n"); 9 | await run.outputContains("4"); 10 | run.kill("SIGINT"); // Ctrl-C 11 | await run.outputContains("Press Ctrl-C again"); 12 | run.kill("SIGINT"); 13 | await run.completion; 14 | expect(run.result).toMatchInlineSnapshot(` 15 | { 16 | "code": 0, 17 | "error": false, 18 | "stderr": "", 19 | "stdout": "> 2 + 2 20 | 4 21 | > 22 | (Press Ctrl-C again to quit) 23 | > 24 | ", 25 | } 26 | `); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /meta/tests/src/sleep.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("sleep", async () => { 4 | const result = await evaluate( 5 | ` 6 | sleep(10); 7 | sleep.sync(10); 8 | sleep.async(10).then(() => console.log('hi')); 9 | ` 10 | ); 11 | expect(result).toMatchInlineSnapshot(` 12 | { 13 | "code": 0, 14 | "error": false, 15 | "stderr": "", 16 | "stdout": "Promise {} 17 | hi 18 | ", 19 | } 20 | `); 21 | }); 22 | -------------------------------------------------------------------------------- /meta/tests/src/toml.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("TOML.parse", async () => { 4 | const result = await evaluate( 5 | ` 6 | const doc = \` 7 | ayo = 99 8 | 9 | [something] 10 | yeah = 4 11 | 12 | [something.mhm] 13 | yes=99 14 | \`; 15 | const obj = TOML.parse(doc); 16 | console.log(obj); 17 | ` 18 | ); 19 | expect(result).toMatchInlineSnapshot(` 20 | { 21 | "code": 0, 22 | "error": false, 23 | "stderr": "", 24 | "stdout": "{ 25 | ayo: 99 26 | something: { 27 | yeah: 4 28 | mhm: { 29 | yes: 99 30 | } 31 | } 32 | } 33 | ", 34 | } 35 | `); 36 | }); 37 | 38 | test("TOML.stringify", async () => { 39 | const result = await evaluate( 40 | ` 41 | const obj = { 42 | ayo: 99, 43 | something: { 44 | yeah: 4, 45 | mhm: { 46 | yes: 99 47 | } 48 | } 49 | }; 50 | const doc = TOML.stringify(obj); 51 | console.log(doc); 52 | ` 53 | ); 54 | expect(result).toMatchInlineSnapshot(` 55 | { 56 | "code": 0, 57 | "error": false, 58 | "stderr": "", 59 | "stdout": "ayo = 99 60 | 61 | [something] 62 | yeah = 4 63 | 64 | [something.mhm] 65 | yes = 99 66 | 67 | ", 68 | } 69 | `); 70 | }); 71 | -------------------------------------------------------------------------------- /meta/tests/src/whoami.test.ts: -------------------------------------------------------------------------------- 1 | import { evaluate } from "./test-helpers"; 2 | 3 | test("whoami", async () => { 4 | const result = await evaluate(` 5 | const result = whoami(); 6 | // We avoid printing the actual values since they will vary from system to 7 | // system and therefore won't result in a stable snapshot 8 | console.log(Object.keys(result)); 9 | console.log("name:", typeof result.name); 10 | console.log("uid:", typeof result.uid); 11 | console.log("gid:", typeof result.gid); 12 | `); 13 | expect(result).toMatchInlineSnapshot(` 14 | { 15 | "code": 0, 16 | "error": false, 17 | "stderr": "", 18 | "stdout": "[ 19 | "name" 20 | "uid" 21 | "gid" 22 | ] 23 | name: string 24 | uid: number 25 | gid: number 26 | ", 27 | } 28 | `); 29 | }); 30 | -------------------------------------------------------------------------------- /meta/tests/src/win32-exe.test.ts: -------------------------------------------------------------------------------- 1 | import { cleanResult, rootDir } from "./test-helpers"; 2 | import { spawn } from "first-base"; 3 | 4 | // skipping this for now until I can get a reliable wine-in-docker working 5 | test.skip("win32 exe smoke test (via docker)", async () => { 6 | const hasDocker = await getHasDocker(); 7 | if (!hasDocker) { 8 | throw new Error("You must install docker to run this test."); 9 | } 10 | 11 | const run = spawn("docker", [ 12 | `run`, 13 | `--rm`, 14 | `-v`, 15 | rootDir() + ":" + rootDir(), 16 | `-w`, 17 | rootDir(), 18 | `--platform`, 19 | `linux/amd64`, 20 | `suchipi/yavascript-wine-test-image`, 21 | `wine`, 22 | `bin/x86_64-pc-windows-static/yavascript.exe`, 23 | `-e`, 24 | `echo('hi');`, 25 | ]); 26 | await run.completion; 27 | 28 | let result = { ...run.result }; 29 | if (result.code === 0) { 30 | // wine prints a bunch of noise into stderr 31 | result.stderr = ""; 32 | } 33 | 34 | expect(cleanResult(result)).toMatchInlineSnapshot(` 35 | { 36 | "code": 1, 37 | "error": false, 38 | "stderr": "<3>WSL (1) ERROR: ConfigInitializeEntry:1554: Failed to mount (null) at /dev as devtmpfs 1 39 | ", 40 | "stdout": "", 41 | } 42 | `); 43 | }); 44 | 45 | async function getHasDocker() { 46 | const run = spawn("which", ["docker"]); 47 | await run.completion; 48 | if (run.result.code === 0) { 49 | return true; 50 | } else { 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /meta/tests/src/worker.test.ts: -------------------------------------------------------------------------------- 1 | import { runYavascript, cleanResult, rootDir } from "./test-helpers"; 2 | 3 | const workerFixturesDir = rootDir.concat("meta/tests/fixtures/worker"); 4 | 5 | // TODO: Change to use yavascript `exit` instead of quickjs `std.exit`, once 6 | // workers get the yavascript globals 7 | test("worker cannot call std.exit", async () => { 8 | const result = await runYavascript([workerFixturesDir("main.js")]); 9 | 10 | // Note that the Error in the worker doesn't cause the main thread to exit 11 | // with a nonzero status code. 12 | expect(cleanResult(result)).toMatchInlineSnapshot(` 13 | { 14 | "code": 0, 15 | "error": false, 16 | "stderr": "Error: std.exit can only be called from the main thread 17 | at somewhere 18 | 19 | ", 20 | "stdout": "in main 21 | in worker 22 | in main, sending try-to-exit 23 | in worker, received: { 24 | data: "try-to-exit" 25 | } 26 | ", 27 | } 28 | `); 29 | }); 30 | -------------------------------------------------------------------------------- /meta/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../tsconfig.json"], 3 | "files": [], 4 | "include": ["./**/*.ts"], 5 | "exclude": ["./fixtures/**/*"] 6 | } 7 | -------------------------------------------------------------------------------- /meta/type-tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "files": [], 4 | "include": ["../../yavascript.d.ts", "./**/*.ts"], 5 | "exclude": [] 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yavascript", 3 | "version": "0.0.0-git", 4 | "main": "dist/index.js", 5 | "author": "Lily Skye ", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "@danielx/civet": "^0.9.0", 9 | "@iarna/toml": "^2.2.5", 10 | "@suchipi/dtsmd": "^1.0.0", 11 | "@suchipi/macaroni": "^0.3.0", 12 | "@suchipi/marked-terminal": "^5.2.0", 13 | "@suchipi/print": "^2.5.0", 14 | "@suchipi/quickjs": "^0.10.2", 15 | "@suchipi/shinobi": "^1.0.1", 16 | "@types/coffeescript": "^2.5.7", 17 | "@types/minimatch": "^5.1.2", 18 | "@types/node": "^22.10.1", 19 | "@types/papaparse": "^5.3.15", 20 | "a-mimir": "^1.0.1", 21 | "chalk": "^4.1.2", 22 | "clef-parse": "^0.6.0", 23 | "coffeescript": "^2.7.0", 24 | "globby": "^11.1.0", 25 | "json5": "^2.2.3", 26 | "kame": "^1.15.0", 27 | "kleur": "^4.1.5", 28 | "mark-applier": "^0.5.2", 29 | "marked": "^5.1.2", 30 | "mdtocs": "^1.0.4", 31 | "minimatch": "^5.1.0", 32 | "papaparse": "^5.4.1", 33 | "path-less-traveled": "^2.1.0", 34 | "pheno": "^0.12.0", 35 | "prettier": "^2.8.8", 36 | "resolve-everything": "^0.1.2", 37 | "string-dedent": "^3.0.1", 38 | "strip-ansi": "^6.0.1", 39 | "sucrase": "^3.35.0", 40 | "tmp": "^0.2.3", 41 | "typescript": "^5.7.2", 42 | "typescript-assert-utils": "^1.1.0", 43 | "wrap-ansi": "^7.0.0", 44 | "yaml": "^2.6.1" 45 | }, 46 | "scripts": { 47 | "build": "meta/build.sh", 48 | "test": "cd meta/tests && npm run test --", 49 | "typecheck": "tsc --noEmit --skipLibCheck" 50 | }, 51 | "prettier": {} 52 | } 53 | -------------------------------------------------------------------------------- /src/api/__filename-and-__dirname/__filename-and-__dirname.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The absolute path to the currently-executing file (whether script or module). 3 | * 4 | * Behaves the same as in Node.js, except that it's also present within ES 5 | * modules. 6 | * 7 | * Example: `/home/suchipi/some-folder/some-file.js` 8 | */ 9 | declare var __filename: string; 10 | 11 | /** 12 | * The absolute path to the directory containing the currently-executing file. 13 | * 14 | * Behaves the same as in Node.js, except that it's also present within ES 15 | * modules. 16 | * 17 | * Example: `/home/suchipi/some-folder` 18 | */ 19 | declare var __dirname: string; 20 | -------------------------------------------------------------------------------- /src/api/__filename-and-__dirname/__filename-and-__dirname.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import * as engine from "quickjs:engine"; 3 | import { dirname } from "../commands/dirname"; 4 | 5 | // Not public API; exported for __filename, which *is* a public API 6 | export function get__filename(depth: number): string { 7 | let ret = engine.getFileNameFromStack(depth); 8 | try { 9 | ret = os.realpath(ret); 10 | } catch (err) { 11 | // ignored 12 | } 13 | 14 | return ret; 15 | } 16 | 17 | // Not public API; exported for __dirname, which *is* a public API 18 | export function get__dirname(depth: number): string { 19 | let filename = engine.getFileNameFromStack(depth); 20 | try { 21 | filename = os.realpath(filename); 22 | } catch (err) { 23 | // ignored 24 | } 25 | 26 | const ret = dirname(filename); 27 | return ret.toString(); 28 | } 29 | -------------------------------------------------------------------------------- /src/api/__filename-and-__dirname/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./__filename-and-__dirname"; 2 | -------------------------------------------------------------------------------- /src/api/assert/assert.inc.d.ts: -------------------------------------------------------------------------------- 1 | declare const assert: { 2 | /** 3 | * Throws an error if `value` is not truthy. 4 | * 5 | * @param value - The value to test for truthiness 6 | * @param message - An optional error message to use. If unspecified, "Assertion failed" will be used. 7 | */ 8 | ( 9 | value: ValueType, 10 | message?: string 11 | ): asserts value is ValueType extends null | undefined | false | 0 | "" 12 | ? never 13 | : ValueType; 14 | 15 | /** 16 | * Throws an error if its argument isn't the correct type. 17 | * 18 | * @param value - The value to test the type of 19 | * @param type - The type that `value` should be, as either a `TypeValidator` (from the `types.*` namespace) or a value which can be coerced into a `TypeValidator` via the `types.coerce` function, like `String`, `Boolean`, etc. 20 | * @param message - An optional error message to use. If unspecified, a generic-but-descriptive message will be used. 21 | */ 22 | type: | CoerceableToTypeValidator>( 23 | value: any, 24 | type: T, 25 | optionalMessage?: string 26 | ) => asserts value is UnwrapTypeFromCoerceableOrValidator; 27 | }; 28 | -------------------------------------------------------------------------------- /src/api/assert/assert.ts: -------------------------------------------------------------------------------- 1 | import { assertType as phenoAssertType } from "pheno"; 2 | import { makeErrorWithProperties } from "../../error-with-properties"; 3 | import { 4 | TypeValidator, 5 | CoerceableToTypeValidator, 6 | UnwrapTypeFromCoerceableOrValidator, 7 | types, 8 | } from "../types"; 9 | 10 | function assert( 11 | value: ValueType, 12 | message?: string 13 | ): asserts value is ValueType extends null | undefined | false | 0 | "" 14 | ? never 15 | : ValueType { 16 | if (value) return; 17 | 18 | const errMsg = message || "Assertion failed"; 19 | throw makeErrorWithProperties(errMsg, { value }); 20 | } 21 | 22 | const assertType = | CoerceableToTypeValidator>( 23 | value: any, 24 | type: T, 25 | optionalMessage?: string 26 | ): asserts value is UnwrapTypeFromCoerceableOrValidator => { 27 | const validator = types.coerce(type); 28 | if (optionalMessage != null) { 29 | if (!validator(value)) { 30 | throw new TypeError(optionalMessage); 31 | } 32 | } else { 33 | phenoAssertType(value, validator); 34 | } 35 | }; 36 | 37 | const assert_: typeof assert & { type: typeof assertType } = Object.assign( 38 | assert, 39 | { type: assertType } 40 | ); 41 | 42 | export { assert_ as assert }; 43 | -------------------------------------------------------------------------------- /src/api/assert/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./assert"; 2 | -------------------------------------------------------------------------------- /src/api/commands/_all.ts: -------------------------------------------------------------------------------- 1 | // This file has an underscore at the beginning of its name so that it is at 2 | // the top of the list in the text editor's sidebar 3 | import { makeGetterPropertyDescriptorMap } from "../../lazy-load"; 4 | 5 | export default makeGetterPropertyDescriptorMap({ 6 | basename: () => 7 | (require("./basename") as typeof import("./basename")).basename, 8 | cat: () => (require("./cat") as typeof import("./cat")).cat, 9 | cd: () => (require("./cd") as typeof import("./cd")).cd, 10 | chmod: () => (require("./chmod") as typeof import("./chmod")).chmod, 11 | dirname: () => (require("./dirname") as typeof import("./dirname")).dirname, 12 | echo: () => (require("./echo") as typeof import("./echo")).echo, 13 | exit: () => (require("./exit") as typeof import("./exit")).exit, 14 | extname: () => (require("./extname") as typeof import("./extname")).extname, 15 | ls: () => (require("./ls") as typeof import("./ls")).ls, 16 | mkdir: () => (require("./mkdir") as typeof import("./mkdir")).mkdir, 17 | mkdirp: () => (require("./mkdir") as typeof import("./mkdir")).mkdirp, 18 | printf: () => (require("./printf") as typeof import("./printf")).printf, 19 | pwd: () => (require("./pwd") as typeof import("./pwd")).pwd, 20 | readlink: () => 21 | (require("./readlink") as typeof import("./readlink")).readlink, 22 | realpath: () => 23 | (require("./realpath") as typeof import("./realpath")).realpath, 24 | sleep: () => (require("./sleep") as typeof import("./sleep")).sleep, 25 | touch: () => (require("./touch") as typeof import("./touch")).touch, 26 | which: () => (require("./which") as typeof import("./which")).which, 27 | whoami: () => (require("./whoami") as typeof import("./whoami")).whoami, 28 | }); 29 | -------------------------------------------------------------------------------- /src/api/commands/_stubs.ts: -------------------------------------------------------------------------------- 1 | import { makeGetterPropertyDescriptorMap } from "../../lazy-load"; 2 | 3 | export default makeGetterPropertyDescriptorMap( 4 | { 5 | ensureDir() { 6 | throw new ReferenceError("'ensureDir' has been renamed to 'mkdirp'."); 7 | }, 8 | cp() { 9 | throw new ReferenceError("'cp' is not defined. Did you mean 'copy'?"); 10 | }, 11 | mv() { 12 | throw new ReferenceError("'mv' is not defined. Did you mean 'rename'?"); 13 | }, 14 | ren() { 15 | throw new ReferenceError("'ren' is not defined. Did you mean 'rename'?"); 16 | }, 17 | rm() { 18 | throw new ReferenceError("'rm' is not defined. Did you mean 'remove'?"); 19 | }, 20 | grep() { 21 | throw new ReferenceError( 22 | "'grep' is not defined. Maybe you want 'grepFile', 'grepString', or 'String.prototype.grep'?" 23 | ); 24 | }, 25 | man() { 26 | throw new ReferenceError("'man' is not defined. Did you mean 'help'?"); 27 | }, 28 | cwd() { 29 | throw new ReferenceError("'cwd' is not defined. Did you mean 'pwd'?"); 30 | }, 31 | where() { 32 | throw new ReferenceError("'where' is not defined. Did you mean 'which'?"); 33 | }, 34 | id() { 35 | throw new ReferenceError( 36 | "'id' is not defined. Maybe you want to use 'whoami()'?" 37 | ); 38 | }, 39 | openURL() { 40 | throw new ReferenceError( 41 | "'openURL' is not defined. Did you mean 'openUrl'?" 42 | ); 43 | }, 44 | }, 45 | false 46 | ); 47 | -------------------------------------------------------------------------------- /src/api/commands/basename/basename.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Return the last component of a path string. 3 | * 4 | * Provides the same functionality as the unix binary of the same name. 5 | * 6 | * > Example: `basename("/home/suchipi/something")` returns `"something"`, the last part. 7 | */ 8 | declare function basename(path: string | Path): string; 9 | -------------------------------------------------------------------------------- /src/api/commands/basename/basename.ts: -------------------------------------------------------------------------------- 1 | import { Path } from "../../path"; 2 | import { assert } from "../../assert"; 3 | import { is } from "../../is"; 4 | import { types } from "../../types"; 5 | 6 | export function basename(path: string | Path): string { 7 | if (is(path, types.Path)) { 8 | path = path.toString(); 9 | } 10 | 11 | assert.type( 12 | path, 13 | String, 14 | "'path' argument must be either a string or a Path object" 15 | ); 16 | 17 | const parts = Path.splitToSegments(path); 18 | return parts[parts.length - 1]; 19 | } 20 | -------------------------------------------------------------------------------- /src/api/commands/basename/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./basename"; 2 | -------------------------------------------------------------------------------- /src/api/commands/cat/cat.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Reads the contents of one or more files from disk as either one UTF-8 string 3 | * or one ArrayBuffer. 4 | * 5 | * Provides the same functionality as the unix binary of the same name. 6 | * 7 | * > Example: If you have a file called `hi.txt` in the current working 8 | * > directory, and it contains the text "hello", running `cat("hi.txt")` 9 | * > returns `"hello"`. 10 | */ 11 | declare const cat: { 12 | /** 13 | * Read the contents of one or more files from disk, as one UTF-8 string. 14 | */ 15 | (paths: string | Path | Array): string; 16 | 17 | /** 18 | * Read the contents of one or more files from disk, as one UTF-8 string. 19 | */ 20 | (paths: string | Path | Array, options: {}): string; 21 | 22 | /** 23 | * Read the contents of one or more files from disk, as one UTF-8 string. 24 | */ 25 | ( 26 | paths: string | Path | Array, 27 | options: { binary: false } 28 | ): string; 29 | 30 | /** 31 | * Read the contents of one or more files from disk, as one ArrayBuffer. 32 | */ 33 | ( 34 | paths: string | Path | Array, 35 | options: { binary: true } 36 | ): ArrayBuffer; 37 | }; 38 | -------------------------------------------------------------------------------- /src/api/commands/cat/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cat"; 2 | -------------------------------------------------------------------------------- /src/api/commands/cd/cd.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Changes the process's current working directory to the specified path. If no 3 | * path is specified, moves to the user's home directory. 4 | * 5 | * Provides the same functionality as the shell builtin of the same name. 6 | */ 7 | declare function cd(path?: string | Path): void; 8 | -------------------------------------------------------------------------------- /src/api/commands/cd/cd.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { env } from "../../env"; 3 | import { assert } from "../../assert"; 4 | import { is } from "../../is"; 5 | import type { Path } from "../../path"; 6 | import { appendSlashIfWindowsDriveLetter } from "../../path/_win32Helpers"; 7 | import { types } from "../../types"; 8 | 9 | export function cd(path?: string | Path): void { 10 | if (path == null) { 11 | path = env.HOME; 12 | } 13 | if (path == null) { 14 | throw new Error( 15 | "Please either specify a path (as the first argument) or set the HOME environment variable" 16 | ); 17 | } 18 | 19 | if (is(path, types.Path)) { 20 | path = path.toString(); 21 | } 22 | 23 | assert.type( 24 | path, 25 | String, 26 | "'path' argument must be either a string or a Path object" 27 | ); 28 | 29 | path = appendSlashIfWindowsDriveLetter(path); 30 | 31 | os.chdir(path); 32 | } 33 | -------------------------------------------------------------------------------- /src/api/commands/cd/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./cd"; 2 | -------------------------------------------------------------------------------- /src/api/commands/chmod/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./chmod"; 2 | -------------------------------------------------------------------------------- /src/api/commands/dirname/dirname.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Removes the final component from a path string. 3 | * 4 | * Provides the same functionality as the unix binary of the same name. 5 | * 6 | * > Example: `dirname("/home/suchipi/something")` returns 7 | * > `"/home/suchipi"`, everything except the last part. 8 | */ 9 | declare function dirname(path: string | Path): Path; 10 | -------------------------------------------------------------------------------- /src/api/commands/dirname/dirname.ts: -------------------------------------------------------------------------------- 1 | import { Path } from "../../path"; 2 | import { is } from "../../is"; 3 | import { types } from "../../types"; 4 | 5 | export function dirname(path: string | Path): Path { 6 | let pathObj: Path; 7 | 8 | if (is(path, types.Path)) { 9 | pathObj = path; 10 | } else if (is(path, types.string)) { 11 | pathObj = new Path(path); 12 | } else { 13 | throw new TypeError( 14 | "'path' argument must be either a string or a Path object" 15 | ); 16 | } 17 | 18 | return pathObj.dirname(); 19 | } 20 | -------------------------------------------------------------------------------- /src/api/commands/dirname/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./dirname"; 2 | -------------------------------------------------------------------------------- /src/api/commands/echo/echo.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Print one or more values to stdout. 3 | * 4 | * Provides the same functionality as the shell builtin of the same name. 5 | * 6 | * > NOTE: This can print any value, not just strings. 7 | * 8 | * `echo` is functionally identical to `console.log`. 9 | */ 10 | declare const echo: typeof console.log; 11 | -------------------------------------------------------------------------------- /src/api/commands/echo/echo.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { makeInspectLog } from "../../shared/make-inspect-log"; 3 | 4 | export const echo = makeInspectLog(std.out); 5 | -------------------------------------------------------------------------------- /src/api/commands/echo/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./echo"; 2 | -------------------------------------------------------------------------------- /src/api/commands/exit/exit.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Exit the yavascript process. 3 | * 4 | * Provides the same functionality as the shell builtin of the same name. 5 | * 6 | * If exit is called with an argument, that argument is used as the exit code. 7 | * Otherwise, `exit.code` is used, which defaults to 0. 8 | * 9 | * `exit.code` will also be used as the exit status code for the yavascript 10 | * process if the process exits normally. 11 | * 12 | * > Attempting to call `exit` or set `exit.code` within a Worker will fail and 13 | * > throw an error. 14 | */ 15 | declare const exit: { 16 | (code?: number): never; 17 | code: number; 18 | }; 19 | -------------------------------------------------------------------------------- /src/api/commands/exit/exit.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | function exit(code?: number) { 4 | std.exit(code); 5 | } 6 | 7 | Object.defineProperty(exit, "code", { 8 | get() { 9 | return std.getExitCode(); 10 | }, 11 | set(newValue: number) { 12 | std.setExitCode(newValue); 13 | }, 14 | }); 15 | 16 | const exit_: typeof exit & { 17 | code: number; 18 | } = exit as any; 19 | 20 | export { exit_ as exit }; 21 | -------------------------------------------------------------------------------- /src/api/commands/exit/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./exit"; 2 | -------------------------------------------------------------------------------- /src/api/commands/extname/extname.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the file extension of the file at a given path. 3 | * 4 | * If the file has no extension (eg `Makefile`, etc), then `''` will be 5 | * returned. 6 | * 7 | * @param pathOrFilename The input path 8 | * @param options Options which affect the return value. See {@link ExtnameOptions}. 9 | */ 10 | declare function extname( 11 | pathOrFilename: string | Path, 12 | options?: ExtnameOptions 13 | ): string; 14 | 15 | /** 16 | * Options for {@link extname} and {@link Path.prototype.extname}. 17 | */ 18 | declare interface ExtnameOptions { 19 | /** 20 | * Whether to get compound extensions, like `.d.ts` or `.test.js`, instead of 21 | * just the final extension (`.ts` or `.js` in this example). 22 | */ 23 | full?: boolean; 24 | } 25 | -------------------------------------------------------------------------------- /src/api/commands/extname/extname.ts: -------------------------------------------------------------------------------- 1 | import { basename } from "../basename"; 2 | import { is } from "../../is"; 3 | import { assert } from "../../assert"; 4 | import type { Path } from "../../path"; 5 | import { types } from "../../types"; 6 | 7 | export function extname( 8 | pathOrFilename: string | Path, 9 | options: { full?: boolean } = {} 10 | ): string { 11 | if (is(pathOrFilename, types.Path)) { 12 | pathOrFilename = pathOrFilename.toString(); 13 | } 14 | 15 | assert.type( 16 | pathOrFilename, 17 | String, 18 | "'pathOrFilename' argument must be either a string or a Path object" 19 | ); 20 | 21 | const filename = basename(pathOrFilename); 22 | const parts = filename.split("."); 23 | 24 | if (parts.length === 1) { 25 | return ""; 26 | } 27 | 28 | assert.type( 29 | options, 30 | Object, 31 | "'options' argument must be either an object or undefined" 32 | ); 33 | 34 | if (options.full) { 35 | return "." + parts.slice(1).join("."); 36 | } else { 37 | return "." + parts[parts.length - 1]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/api/commands/extname/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./extname"; 2 | -------------------------------------------------------------------------------- /src/api/commands/ls/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ls"; 2 | -------------------------------------------------------------------------------- /src/api/commands/ls/ls.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the contents of a directory, as absolute paths. `.` and `..` are 3 | * omitted. 4 | * 5 | * If `ls()` is called with no directory, the present working directory 6 | * (`pwd()`) is used. 7 | */ 8 | declare function ls(dir?: string | Path): Array; 9 | -------------------------------------------------------------------------------- /src/api/commands/ls/ls.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { pwd } from "../pwd/pwd"; 3 | import { Path } from "../../path"; 4 | import { isDir } from "../../filesystem"; 5 | import { is } from "../../is"; 6 | import { assert } from "../../assert"; 7 | import { appendSlashIfWindowsDriveLetter } from "../../path/_win32Helpers"; 8 | import { types } from "../../types"; 9 | 10 | export function ls(dir: string | Path = pwd()): Array { 11 | if (is(dir, types.Path)) { 12 | dir = dir.toString(); 13 | } 14 | 15 | assert.type( 16 | dir, 17 | String, 18 | "'dir' argument must be either a string or a Path object" 19 | ); 20 | 21 | dir = appendSlashIfWindowsDriveLetter(dir); 22 | 23 | if (!isDir(dir)) { 24 | throw new Error(`Not a directory: ${dir}`); 25 | } 26 | 27 | const parent = os.realpath(dir); 28 | 29 | let children = os 30 | .readdir(dir) 31 | .filter((child) => child !== "." && child !== "..") 32 | .map((child) => { 33 | return new Path(parent, child); 34 | }); 35 | 36 | return children; 37 | } 38 | -------------------------------------------------------------------------------- /src/api/commands/mkdir/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./mkdir"; 2 | export * from "./mkdirp"; 3 | -------------------------------------------------------------------------------- /src/api/commands/mkdir/mkdir.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a directory (folder). 3 | * 4 | * Provides the same functionality as the unix binary of the same name. 5 | */ 6 | declare function mkdir( 7 | path: string | Path, 8 | options?: { 9 | recursive?: boolean; 10 | mode?: number; 11 | logging?: { 12 | trace?: (...args: Array) => void; 13 | info?: (...args: Array) => void; 14 | }; 15 | } 16 | ): void; 17 | -------------------------------------------------------------------------------- /src/api/commands/mkdir/mkdirp.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Create a directory (folder) and all parents, recursively 3 | * 4 | * Alias for `mkdir(path, { recursive: true })`. 5 | * 6 | * Provides the same functionality as `mkdir -p`. 7 | */ 8 | declare function mkdirp( 9 | path: string | Path, 10 | options?: { 11 | mode?: number; 12 | logging?: { 13 | trace?: (...args: Array) => void; 14 | info?: (...args: Array) => void; 15 | }; 16 | } 17 | ): void; 18 | -------------------------------------------------------------------------------- /src/api/commands/mkdir/mkdirp.ts: -------------------------------------------------------------------------------- 1 | import { mkdir } from "./mkdir"; 2 | import type { Path } from "../../path"; 3 | 4 | export function mkdirp( 5 | path: string | Path, 6 | options?: { 7 | mode?: number; 8 | logging?: { 9 | trace?: (...args: Array) => void; 10 | info?: (...args: Array) => void; 11 | }; 12 | } 13 | ): void { 14 | mkdir(path, { ...options, recursive: true }); 15 | } 16 | -------------------------------------------------------------------------------- /src/api/commands/printf/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./printf"; 2 | -------------------------------------------------------------------------------- /src/api/commands/printf/printf.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Print data to stdout using C-style format specifiers. 3 | * 4 | * The same formats as the [standard C library 5 | * printf](https://en.cppreference.com/w/c/io/fprintf) are supported. Integer 6 | * format types (e.g. `%d`) truncate the Numbers or BigInts to 32 bits. Use the 7 | * l modifier (e.g. `%ld`) to truncate to 64 bits. 8 | */ 9 | declare function printf(format: string, ...args: Array): void; 10 | -------------------------------------------------------------------------------- /src/api/commands/printf/printf.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { assert } from "../../assert"; 3 | 4 | export function printf(format: string, ...args: Array): void { 5 | assert.type(format, String, "'format' argument must be a string"); 6 | 7 | std.out.printf(format, ...args); 8 | } 9 | -------------------------------------------------------------------------------- /src/api/commands/pwd/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./pwd"; 2 | -------------------------------------------------------------------------------- /src/api/commands/pwd/note.txt: -------------------------------------------------------------------------------- 1 | test is in src/api/commands/cd/cd-and-pwd.test.ts 2 | -------------------------------------------------------------------------------- /src/api/commands/pwd/pwd.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the process's current working directory. 3 | * 4 | * Provides the same functionality as the shell builtin of the same name. 5 | */ 6 | declare const pwd: { 7 | /** 8 | * Returns the process's current working directory. 9 | * 10 | * Provides the same functionality as the shell builtin of the same name. 11 | */ 12 | (): Path; 13 | 14 | /** 15 | * A frozen, read-only `Path` object containing what `pwd()` was when 16 | * yavascript first started up. 17 | */ 18 | readonly initial: Path; 19 | }; 20 | -------------------------------------------------------------------------------- /src/api/commands/pwd/pwd.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../../path"; 3 | 4 | export function pwd(): Path { 5 | return new Path(os.getcwd()); 6 | } 7 | 8 | const initialPwd = pwd(); 9 | Object.freeze(initialPwd); 10 | Object.freeze(initialPwd.segments); 11 | 12 | Object.defineProperty(pwd, "initial", { 13 | configurable: false, 14 | writable: false, 15 | enumerable: true, 16 | 17 | value: initialPwd, 18 | }); 19 | -------------------------------------------------------------------------------- /src/api/commands/readlink/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./readlink"; 2 | -------------------------------------------------------------------------------- /src/api/commands/readlink/readlink.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Reads a symlink. 3 | * 4 | * Returns the target of the symlink, which may be absolute or relative. 5 | * 6 | * Provides the same functionality as the unix binary of the same name. 7 | */ 8 | declare function readlink(path: string | Path): Path; 9 | -------------------------------------------------------------------------------- /src/api/commands/readlink/readlink.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { is } from "../../is"; 3 | import { assert } from "../../assert"; 4 | import { Path } from "../../path"; 5 | import { types } from "../../types"; 6 | 7 | export function readlink(path: string | Path): Path { 8 | if (is(path, types.Path)) { 9 | path = path.toString(); 10 | } 11 | 12 | assert.type( 13 | path, 14 | String, 15 | "'path' argument must be either a string or a Path object" 16 | ); 17 | 18 | if (os.readlink == null) { 19 | throw new Error( 20 | `readlink is not yet supported in platform '${os.platform}'` 21 | ); 22 | } else { 23 | return new Path(os.readlink(path)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/api/commands/realpath/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./realpath"; 2 | -------------------------------------------------------------------------------- /src/api/commands/realpath/realpath.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Get the absolute path given a relative path. Symlinks are also resolved. 3 | * 4 | * The path's target file/directory must exist. 5 | * 6 | * Provides the same functionality as the unix binary of the same name. 7 | * 8 | * > If you want to convert a relative path to an absolute path, but the path's 9 | * > target might NOT exist, use {@link Path.normalize}. 10 | */ 11 | declare function realpath(path: string | Path): Path; 12 | -------------------------------------------------------------------------------- /src/api/commands/realpath/realpath.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { is } from "../../is"; 3 | import { assert } from "../../assert"; 4 | import { Path } from "../../path"; 5 | import { appendSlashIfWindowsDriveLetter } from "../../path/_win32Helpers"; 6 | import { types } from "../../types"; 7 | 8 | export function realpath(path: string | Path): Path { 9 | if (is(path, types.Path)) { 10 | path = path.toString(); 11 | } 12 | 13 | assert.type( 14 | path, 15 | String, 16 | "'path' argument must be either a string or a Path object" 17 | ); 18 | 19 | path = appendSlashIfWindowsDriveLetter(path); 20 | 21 | const result = os.realpath(path); 22 | return new Path(result); 23 | } 24 | -------------------------------------------------------------------------------- /src/api/commands/sleep/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./sleep"; 2 | -------------------------------------------------------------------------------- /src/api/commands/sleep/sleep.ts: -------------------------------------------------------------------------------- 1 | import * as aMimir from "a-mimir"; 2 | 3 | function sleep(milliseconds: number) { 4 | aMimir.sleep.sync(milliseconds); 5 | } 6 | 7 | const sleep_ = Object.assign(sleep, { 8 | sync: aMimir.sleep.sync, 9 | async: aMimir.sleep.async, 10 | }); 11 | 12 | export { sleep_ as sleep }; 13 | -------------------------------------------------------------------------------- /src/api/commands/touch/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./touch"; 2 | -------------------------------------------------------------------------------- /src/api/commands/touch/touch.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * If the file at `path` exists, update its creation/modification timestamps. 3 | * 4 | * Otherwise, create an empty file at that path. 5 | * 6 | * @param path The target path for the file. 7 | */ 8 | declare function touch(path: string | Path): void; 9 | -------------------------------------------------------------------------------- /src/api/commands/touch/touch.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as os from "quickjs:os"; 3 | import { is } from "../../is"; 4 | import { assert } from "../../assert"; 5 | import type { Path } from "../../path"; 6 | import { appendSlashIfWindowsDriveLetter } from "../../path/_win32Helpers"; 7 | import { types } from "../../types"; 8 | 9 | // cause everytime we touch, I get this feeling 10 | export function touch(path: string | Path) { 11 | if (is(path, types.Path)) { 12 | path = path.toString(); 13 | } 14 | 15 | assert.type( 16 | path, 17 | String, 18 | "'path' argument must be either a string or a Path object" 19 | ); 20 | 21 | path = appendSlashIfWindowsDriveLetter(path); 22 | 23 | let exists = false; 24 | try { 25 | os.access(path, os.F_OK); 26 | exists = true; 27 | } catch (err) { 28 | // ignored 29 | } 30 | 31 | if (!exists) { 32 | const file = std.open(path, "w"); 33 | file.close(); 34 | } else { 35 | os.utimes(path, Date.now(), Date.now()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/api/commands/which/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./which"; 2 | -------------------------------------------------------------------------------- /src/api/commands/whoami/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./whoami"; 2 | -------------------------------------------------------------------------------- /src/api/commands/whoami/whoami.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** The type of the return value of {@link whoami}. */ 2 | declare interface WhoAmIResult { 3 | name: string; 4 | uid: number; 5 | gid: number; 6 | } 7 | 8 | /** 9 | * Get info about the user the yavascript process is executing as. 10 | * 11 | * Provides functionality similar to the unix binaries `whoami` and `id`. 12 | * 13 | * NOTE: Doesn't work on Windows; throws an error. 14 | */ 15 | declare function whoami(): WhoAmIResult; 16 | -------------------------------------------------------------------------------- /src/api/commands/whoami/whoami.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | export interface WhoAmIResult { 4 | name: string; 5 | uid: number; 6 | gid: number; 7 | } 8 | 9 | export function whoami(): WhoAmIResult { 10 | const passwdEntry = std.getpwuid(std.geteuid()); 11 | 12 | return { 13 | name: passwdEntry.name, 14 | uid: passwdEntry.uid, 15 | gid: passwdEntry.gid, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/api/console/console.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { makeInspectLog } from "../shared/make-inspect-log"; 3 | import { NOTHING } from "../repl/special"; 4 | 5 | export function clear() { 6 | std.out.puts("\u001b[2J\u001b[0;0H"); // Clear screen 7 | std.out.puts("\u001b[3J"); // Clear scrollback 8 | return NOTHING; 9 | } 10 | 11 | // To overwrite the quickjs console object 12 | export const console = { 13 | log: makeInspectLog(std.out), 14 | info: makeInspectLog(std.out), 15 | warn: makeInspectLog(std.err), 16 | error: makeInspectLog(std.err), 17 | clear, 18 | }; 19 | 20 | // To overwrite the quickjs globalThis.print 21 | export const print = makeInspectLog(std.out); 22 | -------------------------------------------------------------------------------- /src/api/console/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./console"; 2 | -------------------------------------------------------------------------------- /src/api/console/print.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * `print` is an alias for {@link console.log}, which prints values to stdout. 3 | * 4 | * Any value can be logged, not just strings. Non-string values will be 5 | * formatted using {@link inspect}. 6 | */ 7 | declare function print(...args: any): void; 8 | -------------------------------------------------------------------------------- /src/api/csv/csv.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Serializes or deserializes CSV data. 3 | * 4 | * The `CSV` object contains a `parse` function and a `stringify` function which 5 | * can be used to parse strings of CSV (comma-separated values) data into 6 | * arrays-of-arrays-of-strings and serialize arrays-of-arrays-of-strings into 7 | * strings of CSV data. 8 | * 9 | * Its interface is similar to `JSON.parse` and `JSON.stringify`, but CSV does 10 | * not support the spacing/replacer/reviver options that `JSON.parse` and 11 | * `JSON.stringify` have. 12 | */ 13 | declare const CSV: { 14 | /** 15 | * Parse a CSV string into an Array of Arrays of strings. 16 | * 17 | * The outer array holds the rows, and the inner arrays hold the items in 18 | * each row. 19 | */ 20 | parse(input: string): Array>; 21 | 22 | /** 23 | * Convert an Array of Arrays of strings into a CSV string. 24 | * 25 | * The outer array holds the rows, and the inner arrays hold the items in 26 | * each row. 27 | */ 28 | stringify(input: Array>): string; 29 | }; 30 | -------------------------------------------------------------------------------- /src/api/csv/csv.ts: -------------------------------------------------------------------------------- 1 | import Papa from "papaparse"; 2 | import { assert } from "../assert"; 3 | import { types } from "../types"; 4 | 5 | export const CSV = { 6 | parse(input: string): Array> { 7 | assert.type(input, types.string, "'input' argument must be a string"); 8 | 9 | const { data, errors } = Papa.parse(input, { header: false }); 10 | if (errors.length > 0) { 11 | const messageParts = [ 12 | "CSV parse failed:", 13 | ...errors.map((error) => { 14 | return `Row ${(error.row ?? 0) + 1}: ${error.code}: ${error.message}`; 15 | }), 16 | ]; 17 | 18 | let message: string; 19 | if (messageParts.length <= 2) { 20 | message = messageParts.join(" "); 21 | } else { 22 | message = [ 23 | messageParts[0], 24 | ...messageParts.slice(1).map((part) => "- " + part), 25 | ].join("\n"); 26 | } 27 | 28 | throw new Error(message); 29 | } 30 | 31 | return data as any; 32 | }, 33 | stringify(input: Array>): string { 34 | assert.type( 35 | input, 36 | types.arrayOf(types.arrayOf(types.string)), 37 | "'input' argument must be an array of arrays of strings" 38 | ); 39 | 40 | return Papa.unparse(input); 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /src/api/csv/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./csv"; 2 | -------------------------------------------------------------------------------- /src/api/env/env.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An object representing the process's environment variables. You can read 3 | * from it to read environment variables, write into it to set environment 4 | * variables, and/or delete properties from it to unset environment variables. 5 | * Any value you write will be coerced into a string. 6 | */ 7 | declare const env: { [key: string]: string | undefined }; 8 | -------------------------------------------------------------------------------- /src/api/env/env.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | const _env = std.getenviron(); 4 | 5 | export const env = new Proxy(_env, { 6 | get(target, property, receiver) { 7 | if (typeof property === "symbol") return undefined; 8 | return std.getenv(property) || undefined; 9 | }, 10 | 11 | set(target, property, value, receiver) { 12 | if (typeof property === "symbol") return false; 13 | 14 | if (value == null) { 15 | delete _env[property]; 16 | std.unsetenv(property); 17 | } else { 18 | const strValue = String(value); 19 | _env[property] = strValue; 20 | std.setenv(property, strValue); 21 | } 22 | 23 | return true; 24 | }, 25 | 26 | deleteProperty(target, property) { 27 | if (typeof property === "symbol") return false; 28 | 29 | std.unsetenv(property); 30 | delete _env[property]; 31 | return true; 32 | }, 33 | 34 | ownKeys(target) { 35 | return Object.keys(std.getenviron()); 36 | }, 37 | 38 | has(target, property) { 39 | if (typeof property === "symbol") return false; 40 | 41 | const result = std.getenv(property); 42 | return typeof result !== "undefined"; 43 | }, 44 | }); 45 | -------------------------------------------------------------------------------- /src/api/env/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./env"; 2 | -------------------------------------------------------------------------------- /src/api/exec/index.ts: -------------------------------------------------------------------------------- 1 | export { exec, $ } from "./exec"; 2 | export { ChildProcess, ChildProcessOptions } from "./ChildProcess"; 3 | -------------------------------------------------------------------------------- /src/api/filesystem/_getPathInfo.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { exists } from "./exists"; 3 | import { isLink } from "./isLink"; 4 | import { isDir } from "./isDir"; 5 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 6 | 7 | /** internal use only */ 8 | export function _getPathInfo(path: string) { 9 | if (isLink(path)) { 10 | try { 11 | path = appendSlashIfWindowsDriveLetter(path); 12 | 13 | const linkedPath = os.realpath(path); 14 | if (!exists(linkedPath)) return "nonexistent"; 15 | if (isDir(linkedPath)) return "dir"; 16 | return "file"; 17 | } catch { 18 | return "nonexistent"; 19 | } 20 | } 21 | 22 | if (!exists(path)) return "nonexistent"; 23 | if (isDir(path)) return "dir"; 24 | return "file"; 25 | } 26 | -------------------------------------------------------------------------------- /src/api/filesystem/exists.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 7 | 8 | export function exists(path: string | Path): boolean { 9 | assert.type( 10 | path, 11 | types.or(types.string, types.Path), 12 | "'path' argument must be either a string or a Path object" 13 | ); 14 | 15 | if (is(path, types.Path)) { 16 | path = path.toString(); 17 | } 18 | 19 | path = appendSlashIfWindowsDriveLetter(path); 20 | 21 | try { 22 | os.access(path, os.F_OK); 23 | return true; 24 | } catch (err) { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/api/filesystem/index.ts: -------------------------------------------------------------------------------- 1 | export { exists } from "./exists"; 2 | export { isFile } from "./isFile"; 3 | export { isDir } from "./isDir"; 4 | export { isLink } from "./isLink"; 5 | export { readFile } from "./readFile"; 6 | export { remove } from "./remove"; 7 | export { writeFile } from "./writeFile"; 8 | export { copy, CopyOptions } from "./copy"; 9 | export { rename } from "./rename"; 10 | export { isExecutable } from "./isExecutable"; 11 | export { isReadable } from "./isReadable"; 12 | export { isWritable } from "./isWritable"; 13 | -------------------------------------------------------------------------------- /src/api/filesystem/isDir.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 7 | 8 | export function isDir(path: string | Path): boolean { 9 | assert.type( 10 | path, 11 | types.or(types.string, types.Path), 12 | "'path' argument must be either a string or a Path object" 13 | ); 14 | 15 | if (is(path, types.Path)) { 16 | path = path.toString(); 17 | } 18 | 19 | path = appendSlashIfWindowsDriveLetter(path); 20 | 21 | try { 22 | let stats: os.Stats; 23 | if (os.platform === "win32") { 24 | // no lstat on windows 25 | stats = os.stat(path); 26 | } else { 27 | stats = os.lstat(path); 28 | } 29 | 30 | if (Boolean((os.S_IFMT & stats.mode) === os.S_IFLNK)) { 31 | return isDir(os.realpath(path)); 32 | } 33 | 34 | return Boolean((os.S_IFMT & stats.mode) === os.S_IFDIR); 35 | } catch { 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/api/filesystem/isExecutable.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { assert } from "../assert"; 3 | import { types } from "../types"; 4 | import type { Path } from "../path"; 5 | 6 | export function isExecutable(path: Path | string) { 7 | assert.type( 8 | path, 9 | types.or(types.Path, types.string), 10 | "'path' argument must be either a string or a Path object" 11 | ); 12 | 13 | path = path.toString(); 14 | 15 | // Throws error if doesn't exist 16 | os.access(path, os.F_OK); 17 | 18 | try { 19 | os.access(path, os.X_OK); 20 | } catch (err) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /src/api/filesystem/isFile.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 7 | 8 | export function isFile(path: string | Path) { 9 | assert.type( 10 | path, 11 | types.or(types.string, types.Path), 12 | "'path' argument must be either a string or a Path object" 13 | ); 14 | 15 | if (is(path, types.Path)) { 16 | path = path.toString(); 17 | } 18 | 19 | path = appendSlashIfWindowsDriveLetter(path); 20 | 21 | try { 22 | const stats = os.stat(path); 23 | return (stats.mode & os.S_IFMT) == os.S_IFREG; 24 | } catch (err) { 25 | return false; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/api/filesystem/isLink.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 7 | 8 | export function isLink(path: string | Path): boolean { 9 | assert.type( 10 | path, 11 | types.or(types.string, types.Path), 12 | "'path' argument must be either a string or a Path object" 13 | ); 14 | 15 | if (is(path, types.Path)) { 16 | path = path.toString(); 17 | } 18 | 19 | path = appendSlashIfWindowsDriveLetter(path); 20 | 21 | try { 22 | let stats: os.Stats; 23 | if (os.platform === "win32") { 24 | // no lstat on windows 25 | stats = os.stat(path); 26 | } else { 27 | stats = os.lstat(path); 28 | } 29 | 30 | return Boolean((os.S_IFMT & stats.mode) === os.S_IFLNK); 31 | } catch { 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/api/filesystem/isReadable.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { assert } from "../assert"; 3 | import { types } from "../types"; 4 | import type { Path } from "../path"; 5 | 6 | export function isReadable(path: Path | string) { 7 | assert.type( 8 | path, 9 | types.or(types.Path, types.string), 10 | "'path' argument must be either a string or a Path object" 11 | ); 12 | 13 | path = path.toString(); 14 | 15 | // Throws error if doesn't exist 16 | os.access(path, os.F_OK); 17 | 18 | try { 19 | os.access(path, os.R_OK); 20 | } catch (err) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /src/api/filesystem/isWritable.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { assert } from "../assert"; 3 | import { types } from "../types"; 4 | import type { Path } from "../path"; 5 | 6 | export function isWritable(path: Path | string) { 7 | assert.type( 8 | path, 9 | types.or(types.Path, types.string), 10 | "'path' argument must be either a string or a Path object" 11 | ); 12 | 13 | path = path.toString(); 14 | 15 | try { 16 | os.access(path, os.W_OK); 17 | } catch (err) { 18 | return false; 19 | } 20 | 21 | return true; 22 | } 23 | -------------------------------------------------------------------------------- /src/api/filesystem/readFile.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as os from "quickjs:os"; 3 | import { Path } from "../path"; 4 | import { is } from "../is"; 5 | import { types } from "../types"; 6 | import { assert } from "../assert"; 7 | 8 | type ReadFile = { 9 | (path: string | Path): string; 10 | (path: string | Path, options: {}): string; 11 | (path: string | Path, options: { binary: false }): string; 12 | (path: string | Path, options: { binary: true }): ArrayBuffer; 13 | }; 14 | 15 | export const readFile: ReadFile = function readFile( 16 | path: string | Path, 17 | options: { binary?: boolean } = {} 18 | ): string | ArrayBuffer { 19 | assert.type( 20 | path, 21 | types.or(types.string, types.Path), 22 | "'path' argument must be either a string or a Path object" 23 | ); 24 | 25 | assert.type( 26 | options, 27 | types.or(types.undefined, types.anyObject), 28 | "when present, 'options' argument must be an object" 29 | ); 30 | 31 | assert.type( 32 | options.binary, 33 | types.or(types.undefined, types.boolean), 34 | "when present, 'binary' options must be a boolean" 35 | ); 36 | 37 | if (is(path, types.Path)) { 38 | path = path.toString(); 39 | } 40 | 41 | if (options.binary) { 42 | const stats = os.stat(path); 43 | const buffer = new ArrayBuffer(stats.size); 44 | const file = std.open(path, "rb"); 45 | try { 46 | file.read(buffer, 0, stats.size); 47 | } finally { 48 | file.close(); 49 | } 50 | return buffer; 51 | } else { 52 | return std.loadFile(path); 53 | } 54 | } as any; 55 | -------------------------------------------------------------------------------- /src/api/filesystem/remove.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 7 | import { isDir } from "./isDir"; 8 | 9 | export function remove(path: string | Path): void { 10 | assert.type( 11 | path, 12 | types.or(types.string, types.Path), 13 | "'path' argument must be either a string or a Path object" 14 | ); 15 | 16 | if (is(path, types.Path)) { 17 | path = path.toString(); 18 | } 19 | 20 | path = appendSlashIfWindowsDriveLetter(path); 21 | 22 | if (isDir(path)) { 23 | const children = os 24 | .readdir(path) 25 | .filter((child) => child !== "." && child !== "..") 26 | .map((child) => path + "/" + child); 27 | 28 | for (const child of children) { 29 | remove(child); 30 | } 31 | } 32 | 33 | os.remove(path); 34 | } 35 | -------------------------------------------------------------------------------- /src/api/filesystem/rename.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "../path"; 3 | import { types } from "../types"; 4 | import { assert } from "../assert"; 5 | import { appendSlashIfWindowsDriveLetter } from "../path/_win32Helpers"; 6 | 7 | export function rename(from: string | Path, to: string | Path): void { 8 | assert.type( 9 | from, 10 | types.or(types.string, types.Path), 11 | "'from' argument must be either a string or a Path object" 12 | ); 13 | 14 | assert.type( 15 | to, 16 | types.or(types.string, types.Path), 17 | "'to' argument must be either a string or a Path object" 18 | ); 19 | 20 | from = Path.normalize(from).toString(); 21 | to = Path.normalize(to).toString(); 22 | 23 | from = appendSlashIfWindowsDriveLetter(from); 24 | to = appendSlashIfWindowsDriveLetter(to); 25 | 26 | try { 27 | os.rename(from, to); 28 | } catch (err) { 29 | Object.assign(err as any, { 30 | operation: "rename", 31 | from, 32 | to, 33 | }); 34 | throw err; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/api/filesystem/writeFile.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { Path } from "../path"; 3 | import { is } from "../is"; 4 | import { types } from "../types"; 5 | import { assert } from "../assert"; 6 | 7 | export function writeFile( 8 | path: string | Path, 9 | data: string | ArrayBuffer 10 | ): void { 11 | assert.type( 12 | path, 13 | types.or(types.string, types.Path), 14 | "'path' argument must be either a string or a Path object" 15 | ); 16 | 17 | assert.type( 18 | data, 19 | types.or(types.string, types.ArrayBuffer), 20 | "'data' argument must be either a string or an ArrayBuffer" 21 | ); 22 | 23 | if (is(path, types.Path)) { 24 | path = path.toString(); 25 | } 26 | 27 | const file = std.open(path, "w"); 28 | try { 29 | if (typeof data === "string") { 30 | file.puts(data); 31 | } else { 32 | file.write(data, 0, data.byteLength); 33 | } 34 | } finally { 35 | file.close(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/api/git-repo/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./git-repo"; 2 | -------------------------------------------------------------------------------- /src/api/glob/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./glob"; 2 | -------------------------------------------------------------------------------- /src/api/grep/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./grep"; 2 | -------------------------------------------------------------------------------- /src/api/help/help.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Prints a link to the YavaScript help docs for the currently-running version 3 | * of YavaScript. 4 | * 5 | * For the latest help docs, see: 6 | * https://github.com/suchipi/yavascript/blob/main/meta/generated-docs/README.md 7 | */ 8 | declare function help(): void; 9 | -------------------------------------------------------------------------------- /src/api/help/help.ts: -------------------------------------------------------------------------------- 1 | import { hasColors } from "../../has-colors"; 2 | import { blue, underline } from "../strings"; 3 | import { yavascript } from "../yavascript"; 4 | 5 | const docsUrlForRef = (ref: string) => { 6 | return `https://github.com/suchipi/yavascript/blob/${ref}/meta/generated-docs/README.md`; 7 | }; 8 | 9 | export function help() { 10 | let url; 11 | 12 | const ver = yavascript.version; 13 | 14 | let matches: RegExpMatchArray | null = null; 15 | if ((matches = ver.match(/^git-([A-Fa-f0-9]+)(?:-dirty)?$/))) { 16 | const sha = matches[1]; 17 | url = docsUrlForRef(sha); 18 | } else if ((matches = ver.match(/^(v[0-9.]+)/))) { 19 | const version = matches[1]; 20 | url = docsUrlForRef(version); 21 | } else { 22 | // idk 23 | url = docsUrlForRef("main"); 24 | } 25 | 26 | if (hasColors()) { 27 | url = underline(blue(url)); 28 | } 29 | console.log("\nPlease see: " + url + "\n"); 30 | } 31 | -------------------------------------------------------------------------------- /src/api/help/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./help"; 2 | -------------------------------------------------------------------------------- /src/api/is/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./is"; 2 | -------------------------------------------------------------------------------- /src/api/is/is.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TypeValidator, 3 | CoerceableToTypeValidator, 4 | UnwrapTypeFromCoerceableOrValidator, 5 | types, 6 | } from "../types"; 7 | 8 | export const is = | CoerceableToTypeValidator>( 9 | value: any, 10 | type: T 11 | ): value is UnwrapTypeFromCoerceableOrValidator => { 12 | return types.coerce(type)(value); 13 | }; 14 | -------------------------------------------------------------------------------- /src/api/jsx/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./jsx"; 2 | -------------------------------------------------------------------------------- /src/api/jsx/jsx.ts: -------------------------------------------------------------------------------- 1 | const Fragment = Symbol("JSX.Fragment"); 2 | const Element = Symbol("JSX.Element"); 3 | 4 | export const JSX = { 5 | pragma: "JSX.createElement", 6 | pragmaFrag: "JSX.Fragment", 7 | 8 | Fragment, 9 | Element, 10 | 11 | createElement(type: any, props: any, ...children: any) { 12 | if (children.length > 0) { 13 | props = props ?? {}; 14 | props.children = children; 15 | } 16 | 17 | let key = null; 18 | if (props != null) { 19 | key = props.key ?? null; 20 | } 21 | 22 | return { $$typeof: Element, type, props, key }; 23 | }, 24 | }; 25 | 26 | export namespace JSX { 27 | export interface Element< 28 | Props = { [key: string | symbol | number]: any }, 29 | Type = any 30 | > { 31 | $$typeof: typeof Element; 32 | type: Type; 33 | props: Props; 34 | key: string | number | null; 35 | } 36 | 37 | export type Fragment = Element<{}, typeof Fragment>; 38 | } 39 | -------------------------------------------------------------------------------- /src/api/logger/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./logger"; 2 | -------------------------------------------------------------------------------- /src/api/logger/logger.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The logger used internally by yavascript API functions such as {@link which}, 3 | * {@link exec}, {@link copy}, {@link glob}, and more. 4 | * 5 | * You can modify the properties on this object in order to configure the 6 | * amount and style of log output from yavascript API functions. 7 | * 8 | * This object behaves similarly to the shell builtin `set -x`. 9 | */ 10 | declare const logger: { 11 | /** 12 | * This property is used as the default value for `trace` in yavascript API 13 | * functions which receive `logging.trace` as an option, like {@link which}, 14 | * {@link exec}, {@link copy} and {@link glob}. 15 | * 16 | * The default value of `logger.trace` is a no-op function. 17 | */ 18 | trace: (...args: Array) => void; 19 | 20 | /** 21 | * This property is used as the default value for `info` in yavascript API 22 | * functions which receive `logging.info` as an option, like {@link exec}, 23 | * {@link copy}, and {@link glob}. 24 | * 25 | * The default value of `logger.info` writes dimmed text to stdout. 26 | */ 27 | info: (...args: Array) => void; 28 | }; 29 | -------------------------------------------------------------------------------- /src/api/logger/logger.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { assert } from "../assert"; 3 | import { inspectManyToParts } from "../shared/make-inspect-log"; 4 | import { types } from "../types"; 5 | import { dim } from "../strings"; 6 | 7 | type LoggerFunction = (...args: Array) => void; 8 | 9 | const noop = () => {}; 10 | 11 | let _info: LoggerFunction = (...args: Array) => { 12 | const parts = inspectManyToParts(args); 13 | const len = parts.length; 14 | for (let i = 0; i < len; i++) { 15 | std.err.puts(dim(parts[i])); 16 | } 17 | std.err.puts("\n"); 18 | }; 19 | let _trace: LoggerFunction = noop; 20 | 21 | export const logger = { 22 | get info() { 23 | return _info; 24 | }, 25 | set info(newValue: LoggerFunction) { 26 | assert.type( 27 | newValue, 28 | types.anyFunction, 29 | "'logger.info' must be a function" 30 | ); 31 | _info = newValue; 32 | }, 33 | get trace() { 34 | return _trace; 35 | }, 36 | set trace(newValue: LoggerFunction) { 37 | assert.type( 38 | newValue, 39 | types.anyFunction, 40 | "'logger.trace' must be a function" 41 | ); 42 | _trace = newValue; 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /src/api/node-compat/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./node-compat"; 2 | -------------------------------------------------------------------------------- /src/api/node-compat/node-compat.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * For compatibility with Node.js scripts, the global object is accessible via 3 | * the global variable named "global". 4 | */ 5 | declare var global: typeof globalThis; 6 | 7 | /** 8 | * A `process` global is provided for rudimentary compatibility with Node.js 9 | * scripts. It contains a subset of the properties found on the Node.js 10 | * `process` global, which each forward to their corresponding yavascript API. 11 | * 12 | * For instance, `process.env` is a getter that returns {@link env}, and 13 | * `process.argv` is a getter that returns {@link scriptArgs}. 14 | * 15 | * If you are writing yavascript-specific code, you should use yavascript's APIs 16 | * instead of `process`. 17 | */ 18 | declare var process: { 19 | version: string; 20 | versions: { 21 | node: string; 22 | yavascript: string; 23 | unicode: string; 24 | }; 25 | arch: string; 26 | /** Same as the global {@link env}. */ 27 | readonly env: { [key: string]: string | undefined }; 28 | /** Same as the global {@link scriptArgs}. */ 29 | readonly argv: Array; 30 | /** Same as `scriptArgs[0]`. */ 31 | readonly argv0: string; 32 | /** 33 | * Shortcut for `os.realpath(os.execPath())`, using the QuickJS {@link os} 34 | * module. 35 | */ 36 | readonly execPath: string; 37 | /** 38 | * Uses `std.getExitCode()` and `std.setExitCode()` from the QuickJS 39 | * {@link std} module. 40 | */ 41 | exitCode: number; 42 | /** 43 | * Uses `std.exit()` from the QuickJS {@link std} module. 44 | */ 45 | exit(code?: number | null | undefined): void; 46 | }; 47 | -------------------------------------------------------------------------------- /src/api/node-compat/node-compat.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as os from "quickjs:os"; 3 | import { version as ysVersion, arch as ysArch } from "../../hardcoded"; 4 | 5 | export function installNodeCompat(global: any) { 6 | Object.defineProperty(global, "global", { 7 | configurable: true, 8 | writable: true, 9 | enumerable: false, 10 | value: global, 11 | }); 12 | 13 | const process = { 14 | // This version supports approximately the same syntax features as we do 15 | version: "v16.19.0", 16 | versions: { 17 | node: "16.19.0", 18 | yavascript: ysVersion, 19 | unicode: "14.0", 20 | }, 21 | arch: ysArch === "x86_64" ? "x64" : ysArch, 22 | get env() { 23 | return (require("../env") as typeof import("../env")).env; 24 | }, 25 | get argv() { 26 | return scriptArgs; 27 | }, 28 | get argv0() { 29 | return scriptArgs[0]; 30 | }, 31 | get execPath() { 32 | return os.realpath(os.execPath()); 33 | }, 34 | get exitCode() { 35 | return std.getExitCode(); 36 | }, 37 | set exitCode(value: number) { 38 | std.setExitCode(value); 39 | }, 40 | exit(code?: number | null | undefined) { 41 | // TODO: process.on("exit", ...) 42 | 43 | if (code != null) { 44 | std.exit(code); 45 | } else { 46 | std.exit(); 47 | } 48 | }, 49 | }; 50 | 51 | Object.defineProperty(global, "process", { 52 | configurable: true, 53 | writable: true, 54 | enumerable: false, 55 | value: process, 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /src/api/open-url/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./open-url"; 2 | -------------------------------------------------------------------------------- /src/api/open-url/open-url.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Opens the resource at the given path or URL using the operating system's 3 | * default application or handler. 4 | * 5 | * Examples: 6 | * 7 | * ```ts 8 | * openUrl("/home/me/stuff/code.txt"); // opens code.txt in your default text editor 9 | * openUrl("code.txt"); // same as above, using relative path 10 | * openUrl("file:///home/me/stuff/code.txt"); // same as above, using file:// url 11 | * 12 | * openUrl("IMG_001.jpg"); // opens IMG_001.jpg in your default image viewer 13 | * 14 | * openUrl("https://example.com/") // opens example.com in your default web browser 15 | * ``` 16 | */ 17 | declare function openUrl(urlOrFilePath: string | Path): void; 18 | -------------------------------------------------------------------------------- /src/api/open-url/open-url.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { exec } from "../exec"; 3 | import type { Path } from "../path"; 4 | 5 | export function openUrl(urlOrFilePath: string | Path): void { 6 | switch (os.platform) { 7 | case "darwin": { 8 | exec(["open", urlOrFilePath], { block: false }); 9 | break; 10 | } 11 | case "win32": { 12 | exec(["rundll32.exe", "url.dll,OpenURL", urlOrFilePath], { 13 | block: false, 14 | }); 15 | break; 16 | } 17 | default: { 18 | exec(["xdg-open", urlOrFilePath], { block: false }); 19 | break; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/api/others/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./others"; 2 | -------------------------------------------------------------------------------- /src/api/parse-script-args/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./parse-script-args"; 2 | -------------------------------------------------------------------------------- /src/api/path/_win32Helpers.ts: -------------------------------------------------------------------------------- 1 | import { Path } from "../path"; 2 | 3 | const WIN32_DRIVE_LETTER_REGEXP = /^[A-Za-z]:$/; 4 | 5 | export function appendSlashIfWindowsDriveLetter(pathString: string): string { 6 | if (WIN32_DRIVE_LETTER_REGEXP.test(pathString)) { 7 | return pathString + Path.OS_SEGMENT_SEPARATOR; 8 | } else { 9 | return pathString; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/api/path/index.ts: -------------------------------------------------------------------------------- 1 | export { Path } from "./path"; 2 | -------------------------------------------------------------------------------- /src/api/regexp-escape/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./regexp-escape"; 2 | -------------------------------------------------------------------------------- /src/api/regexp-escape/regexp-escape.inc.d.ts: -------------------------------------------------------------------------------- 1 | interface RegExpConstructor { 2 | /** 3 | * The function `RegExp.escape` accepts an input string and prefixes with `\` 4 | * those characters in that string which have a special meaning when appearing 5 | * in a regular expression. 6 | * 7 | * The implementation is based on the stage 2 ECMAScript proposal of the same 8 | * name: https://github.com/tc39/proposal-regex-escaping 9 | */ 10 | escape(str: any): string; 11 | } 12 | -------------------------------------------------------------------------------- /src/api/regexp-escape/regexp-escape.ts: -------------------------------------------------------------------------------- 1 | // See https://github.com/tc39/proposal-regex-escaping 2 | export function escape(s: any): string { 3 | return String(s).replace(/[\\^$*+?.()|[\]{}]/g, "\\$&"); 4 | } 5 | 6 | export function install(_RegExp: any) { 7 | _RegExp.escape = escape; 8 | } 9 | -------------------------------------------------------------------------------- /src/api/repl/history-file.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { readFile } from "../../api/filesystem"; 3 | import { Path } from "../../api/path"; 4 | import { getConfigDir } from "../../config-dir"; 5 | import { touch } from "../../api/commands/touch"; 6 | import { mkdir } from "../commands/mkdir"; 7 | 8 | const noop = () => {}; 9 | 10 | export class HistoryFile { 11 | path: Path | null; 12 | 13 | constructor(filename: string) { 14 | const configDir = getConfigDir(); 15 | if (!configDir) { 16 | this.path = null; 17 | return; 18 | } 19 | 20 | mkdir(configDir, { recursive: true, logging: { info: noop } }); 21 | 22 | const path = new Path(configDir, filename); 23 | // create it if it doesn't exist 24 | touch(path); 25 | 26 | this.path = path; 27 | } 28 | 29 | load() { 30 | if (this.path == null) return []; 31 | 32 | const content = readFile(this.path).trimEnd(); 33 | const lines = content.split("\n"); 34 | return lines; 35 | } 36 | 37 | fileForAppend: FILE | null = null; 38 | 39 | append(line: string) { 40 | if (this.path == null) return; 41 | 42 | if (this.fileForAppend == null) { 43 | this.fileForAppend = std.open(this.path?.toString(), "a"); 44 | } 45 | 46 | this.fileForAppend.puts(line + "\n"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/api/repl/index.ts: -------------------------------------------------------------------------------- 1 | export { startRepl } from "./start-repl"; 2 | export { InteractivePrompt } from "./interactive-prompt"; 3 | -------------------------------------------------------------------------------- /src/api/repl/interactive-prompt.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This API is a work-in-progress and is subject to change at any time. 3 | */ 4 | interface InteractivePrompt { 5 | prompt?: () => string; 6 | printInput?: (input: string) => void; 7 | historyFileName?: string; 8 | getCompletions?: ( 9 | line: string, 10 | pos: number 11 | ) => { 12 | // TODO refactor these to have better key names 13 | tab: Array; 14 | pos: number; 15 | ctx: { [key: string | number | symbol]: any }; 16 | }; 17 | 18 | handleInput: (input: string) => void; 19 | start(): void; 20 | } 21 | 22 | /** 23 | * This API is a work-in-progress and is subject to change at any time. 24 | */ 25 | interface InteractivePromptConstructor { 26 | new ( 27 | handleInput: (input: string) => void, 28 | options?: { 29 | prompt?: () => string; 30 | printInput?: (input: string) => void; 31 | historyFileName?: string; 32 | getCompletions?: ( 33 | line: string, 34 | pos: number 35 | ) => { 36 | // TODO refactor these to have better key names 37 | tab: Array; 38 | pos: number; 39 | ctx: { [key: string | number | symbol]: any }; 40 | }; 41 | } 42 | ): InteractivePrompt; 43 | 44 | prototype: InteractivePrompt; 45 | } 46 | 47 | /** 48 | * This API is a work-in-progress and is subject to change at any time. 49 | */ 50 | declare var InteractivePrompt: InteractivePromptConstructor; 51 | -------------------------------------------------------------------------------- /src/api/repl/special.ts: -------------------------------------------------------------------------------- 1 | export const NOTHING = Symbol("NOTHING"); 2 | -------------------------------------------------------------------------------- /src/api/repl/start-repl.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Launch the Yavascript REPL (read-eval-print-loop). 3 | * 4 | * @param context Variables to make available as globals within the repl. 5 | * @param lang The language to use in the repl. Defaults to "javascript". 6 | */ 7 | declare const startRepl: { 8 | ( 9 | context?: { [key: string]: any }, 10 | lang?: 11 | | "js" 12 | | "javascript" 13 | | "ts" 14 | | "typescript" 15 | | "jsx" 16 | | "tsx" 17 | | "coffee" 18 | | "coffeescript" 19 | | "civet" 20 | ): void; 21 | 22 | /** 23 | * A special value; when expressions result in this value, the repl will 24 | * print nothing instead of printing this value. 25 | */ 26 | NOTHING: symbol; 27 | }; 28 | -------------------------------------------------------------------------------- /src/api/repl/start-repl.ts: -------------------------------------------------------------------------------- 1 | import replTarget from "../../targets/repl"; 2 | import { LANGS } from "../../langs"; 3 | import { NOTHING } from "./special"; 4 | 5 | const validLangs = Array.from(LANGS); 6 | 7 | // TODO merge with InteractivePrompt in a sensible way 8 | function startRepl( 9 | context: { [key: string]: any } = {}, 10 | lang: string = "javascript" 11 | ) { 12 | if (!LANGS.has(lang)) { 13 | throw new Error( 14 | `Invalid lang: '${lang}'. Valid langs are: ${validLangs 15 | .slice(0, -1) 16 | .join(", ")} or ${validLangs[validLangs.length - 1]}` 17 | ); 18 | } 19 | 20 | // TODO create actual QuickJS context and run stuff inside it 21 | Object.assign(globalThis, context); 22 | replTarget(lang); 23 | } 24 | 25 | Object.assign(startRepl, { NOTHING }); 26 | 27 | export { startRepl }; 28 | -------------------------------------------------------------------------------- /src/api/shared/make-inspect-log.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as inspectOptions from "../../inspect-options"; 3 | 4 | export function inspectManyToParts(args: Array): Array { 5 | const out: Array = []; 6 | 7 | for (let i = 0; i < args.length; i++) { 8 | if (i !== 0) { 9 | out.push(" "); 10 | } 11 | const arg = args[i]; 12 | 13 | let str: string; 14 | if (typeof arg === "string") { 15 | str = arg; 16 | } else { 17 | try { 18 | str = inspect(arg, inspectOptions.forPrint()); 19 | } catch (err) { 20 | try { 21 | std.err.puts((err as any).message + "\n"); 22 | } catch (err) { 23 | // I give up 24 | } 25 | str = String(arg); 26 | } 27 | } 28 | 29 | out.push(str); 30 | } 31 | 32 | return out; 33 | } 34 | 35 | export function inspectManyToFile(args: Array, file: FILE): void { 36 | for (let i = 0; i < args.length; i++) { 37 | if (i !== 0) { 38 | file.puts(" "); 39 | } 40 | const arg = args[i]; 41 | 42 | let str: string; 43 | if (typeof arg === "string") { 44 | str = arg; 45 | } else { 46 | try { 47 | str = inspect(arg, inspectOptions.forPrint()); 48 | } catch (err) { 49 | try { 50 | std.err.puts((err as any).message + "\n"); 51 | } catch (err) { 52 | // I give up 53 | } 54 | str = String(arg); 55 | } 56 | } 57 | 58 | file.puts(str); 59 | } 60 | } 61 | 62 | export const makeInspectLog = 63 | (file: FILE) => 64 | (...args: Array) => { 65 | inspectManyToFile(args, file); 66 | file.puts("\n"); 67 | }; 68 | -------------------------------------------------------------------------------- /src/api/string-dedent/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./string-dedent"; 2 | -------------------------------------------------------------------------------- /src/api/string-dedent/string-dedent.inc.d.ts: -------------------------------------------------------------------------------- 1 | interface StringConstructor { 2 | /** 3 | * The function `String.dedent` can be used to remove leading indentation from 4 | * a string. It is commonly used as a tagged template function, but you can 5 | * also call it and pass in a string. 6 | * 7 | * Note that the first line of the string must be empty. 8 | * 9 | * `String.dedent` is the default export from the npm package `string-dedent`. 10 | * See its readme on npm for more info: 11 | * https://www.npmjs.com/package/string-dedent 12 | */ 13 | dedent: { 14 | /** 15 | * Removes leading minimum indentation from the string `input`. 16 | * The first line of `input` MUST be empty. 17 | * 18 | * For more info, see: https://www.npmjs.com/package/string-dedent#usage 19 | */ 20 | (input: string): string; 21 | 22 | /** 23 | * Removes leading minimum indentation from the tagged template literal. 24 | * The first line of the template literal MUST be empty. 25 | * 26 | * For more info, see: https://www.npmjs.com/package/string-dedent#usage 27 | */ 28 | ( 29 | strings: readonly string[] | ArrayLike, 30 | ...substitutions: unknown[] 31 | ): string; 32 | 33 | /** 34 | * Wrap another template tag function such that tagged literals 35 | * become dedented before being passed to the wrapped function. 36 | * 37 | * For more info, see: https://www.npmjs.com/package/string-dedent#usage 38 | */ 39 | < 40 | Func extends ( 41 | strings: readonly string[] | ArrayLike, 42 | ...substitutions: any[] 43 | ) => string 44 | >( 45 | input: Func 46 | ): Func; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /src/api/string-dedent/string-dedent.ts: -------------------------------------------------------------------------------- 1 | import dedent from "string-dedent"; 2 | 3 | export function install(stringConstructor: StringConstructor) { 4 | // @ts-ignore 5 | stringConstructor.dedent = dedent; 6 | } 7 | -------------------------------------------------------------------------------- /src/api/strings/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./strings"; 2 | -------------------------------------------------------------------------------- /src/api/strings/strings.ts: -------------------------------------------------------------------------------- 1 | import stripAnsiFromString from "strip-ansi"; 2 | import kleur from "kleur"; 3 | import type { Path } from "../path"; 4 | 5 | kleur.enabled = true; 6 | 7 | import { assert } from "../assert"; 8 | import { types } from "../types"; 9 | 10 | function stripAnsi(input: string | number | Path) { 11 | if (typeof input === "string") { 12 | return stripAnsiFromString(input); 13 | } else { 14 | return stripAnsiFromString(String(input)); 15 | } 16 | } 17 | 18 | export { stripAnsi }; 19 | 20 | export const quote = (str: string | number | Path) => { 21 | assert.type( 22 | str, 23 | types.or(types.string, types.number, types.Path), 24 | "'str' argument must be a string, number, or Path" 25 | ); 26 | if (typeof str !== "string") { 27 | str = str.toString(); 28 | } 29 | return JSON.stringify(str); 30 | }; 31 | 32 | const { 33 | bgBlack, 34 | bgBlue, 35 | bgCyan, 36 | bgGreen, 37 | bgMagenta, 38 | bgRed, 39 | bgWhite, 40 | bgYellow, 41 | black, 42 | blue, 43 | bold, 44 | cyan, 45 | dim, 46 | gray, 47 | green, 48 | grey, 49 | hidden, 50 | inverse, 51 | italic, 52 | magenta, 53 | red, 54 | reset, 55 | strikethrough, 56 | underline, 57 | white, 58 | yellow, 59 | } = kleur; 60 | 61 | export { 62 | bgBlack, 63 | bgBlue, 64 | bgCyan, 65 | bgGreen, 66 | bgMagenta, 67 | bgRed, 68 | bgWhite, 69 | bgYellow, 70 | black, 71 | blue, 72 | bold, 73 | cyan, 74 | dim, 75 | gray, 76 | green, 77 | grey, 78 | hidden, 79 | inverse, 80 | italic, 81 | magenta, 82 | red, 83 | reset, 84 | strikethrough, 85 | underline, 86 | white, 87 | yellow, 88 | }; 89 | -------------------------------------------------------------------------------- /src/api/toml/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./toml"; 2 | -------------------------------------------------------------------------------- /src/api/toml/toml.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * An object with a `parse` function and a `stringify` function which can be 3 | * used to parse TOML document strings into objects and serialize objects into 4 | * TOML document strings. 5 | * 6 | * Its interface is similar to `JSON.parse` and `JSON.stringify`, but 7 | * `TOML.parse` and `TOML.stringify` do not support the spacing/replacer/reviver 8 | * options that `JSON.parse` and `JSON.stringify` do. 9 | */ 10 | declare var TOML: { 11 | /** 12 | * Parse a TOML document string (`data`) into an object. 13 | */ 14 | parse(data: string): { [key: string]: any }; 15 | /** 16 | * Convert an object into a TOML document. 17 | */ 18 | stringify(data: { [key: string]: any }): string; 19 | }; 20 | -------------------------------------------------------------------------------- /src/api/toml/toml.ts: -------------------------------------------------------------------------------- 1 | import iarnaTOML from "@iarna/toml"; 2 | 3 | export const TOML = { 4 | parse(data: string): { [key: string]: any } { 5 | return iarnaTOML.parse(data); 6 | }, 7 | stringify(data: { [key: string]: any }): string { 8 | return iarnaTOML.stringify(data); 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /src/api/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | -------------------------------------------------------------------------------- /src/api/yaml/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./yaml"; 2 | -------------------------------------------------------------------------------- /src/api/yaml/yaml.inc.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * The `YAML` namespace contains functions which can serialize and deserialize 3 | * YAML documents, following the same pattern as JavaScript's `JSON` builtin. 4 | */ 5 | declare const YAML: { 6 | /** 7 | * Converts a YAML document string into a JavaScript value. It works the same 8 | * way that `JSON.parse` does, but for YAML. 9 | */ 10 | parse( 11 | input: string, 12 | reviver?: (this: any, key: string, value: any) => any 13 | ): any; 14 | 15 | /** 16 | * Converts a JavaScript value into a YAML document string. It works the same 17 | * way that `JSON.stringify` does, but for YAML. 18 | */ 19 | stringify( 20 | input: any, 21 | replacer?: 22 | | ((this: any, key: string, value: any) => any) 23 | | (number | string)[] 24 | | null, 25 | indent?: number 26 | ): string; 27 | }; 28 | -------------------------------------------------------------------------------- /src/api/yaml/yaml.ts: -------------------------------------------------------------------------------- 1 | import { parse, stringify } from "yaml"; 2 | import { assert } from "../assert"; 3 | import { types } from "../types"; 4 | 5 | const reviverType = types.or(types.undefined, types.null, types.anyFunction); 6 | const replacerType = types.or( 7 | types.undefined, 8 | types.null, 9 | types.anyFunction, 10 | types.arrayOf(types.or(types.number, types.string)) 11 | ); 12 | const indentType = types.or(types.undefined, types.number); 13 | 14 | export const YAML = Object.assign(Object.create(null) as {}, { 15 | parse( 16 | input: string, 17 | reviver?: (this: any, key: string, value: any) => any 18 | ): any { 19 | assert.type(input, types.string, "'input' argument must be a string"); 20 | assert.type( 21 | reviver, 22 | reviverType, 23 | "when present, 'reviver' argument must be a function" 24 | ); 25 | 26 | return parse(input, reviver as any); 27 | }, 28 | stringify( 29 | input: any, 30 | replacer?: 31 | | ((this: any, key: string, value: any) => any) 32 | | (number | string)[] 33 | | null, 34 | indent?: number 35 | ): string { 36 | assert.type( 37 | replacer, 38 | replacerType, 39 | "when present, 'replacer' argument must be either a function or an Array of strings/numbers" 40 | ); 41 | assert.type( 42 | indent, 43 | indentType, 44 | "when present, 'indent' argument must be a number" 45 | ); 46 | 47 | return stringify(input, replacer, indent); 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /src/api/yavascript/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./yavascript"; 2 | -------------------------------------------------------------------------------- /src/api/yavascript/yavascript.ts: -------------------------------------------------------------------------------- 1 | import { version, arch } from "../../hardcoded"; 2 | import compilers from "../../compilers"; 3 | 4 | export const yavascript = { 5 | version, 6 | arch, 7 | ecmaVersion: "ES2020", 8 | compilers, 9 | }; 10 | -------------------------------------------------------------------------------- /src/config-dir.ts: -------------------------------------------------------------------------------- 1 | import * as os from "quickjs:os"; 2 | import { Path } from "./api/path"; 3 | import { env } from "./api/env"; 4 | 5 | export const getConfigDir = (): Path | null => { 6 | const { HOME, APPDATA, XDG_CONFIG_HOME } = env; 7 | 8 | if (os.platform === "win32") { 9 | if (APPDATA) { 10 | return new Path(APPDATA, "yavascript"); 11 | } else { 12 | return null; 13 | } 14 | } else if (os.platform === "darwin") { 15 | if (HOME) { 16 | return new Path(HOME, "Library", "Application Support", "yavascript"); 17 | } else { 18 | return null; 19 | } 20 | } 21 | 22 | if (XDG_CONFIG_HOME) { 23 | return new Path(XDG_CONFIG_HOME, "yavascript"); 24 | } 25 | 26 | if (HOME) { 27 | return new Path(HOME, ".config", "yavascript"); 28 | } else { 29 | return null; 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/error-with-properties.ts: -------------------------------------------------------------------------------- 1 | import * as inspectOptions from "./inspect-options"; 2 | 3 | const MAX_ERROR_MESSAGE_LENGTH = 1000 - 3; // minus 3 for ellipsis 4 | 5 | export function makeErrorWithProperties< 6 | Properties extends { [key: string]: any }, 7 | ErrConstructor extends { new (message: string): any } 8 | >( 9 | message: string, 10 | properties: Properties, 11 | // @ts-ignore could be instantiated with different subtype 12 | errorConstructor: ErrConstructor = Error 13 | ): Properties & ErrConstructor extends { new (message: string): infer Err } 14 | ? Err 15 | : never { 16 | let errorMessage = message; 17 | const entries = Object.entries(properties); 18 | if (entries.length > 0) { 19 | errorMessage += " ("; 20 | for (let i = 0; i < entries.length; i++) { 21 | const [key, value] = entries[i]; 22 | errorMessage += key; 23 | errorMessage += " = "; 24 | errorMessage += inspect(value, inspectOptions.forError()).replace( 25 | /\n+/g, 26 | " " 27 | ); 28 | if (i !== entries.length - 1) { 29 | errorMessage += ", "; 30 | } 31 | } 32 | errorMessage += ")"; 33 | } 34 | 35 | if (errorMessage.length > MAX_ERROR_MESSAGE_LENGTH) { 36 | errorMessage = errorMessage.slice(0, MAX_ERROR_MESSAGE_LENGTH) + "..."; 37 | } 38 | 39 | const err = new errorConstructor(errorMessage); 40 | return Object.assign(err, properties); 41 | } 42 | -------------------------------------------------------------------------------- /src/extension-handlers/_load-all.ts: -------------------------------------------------------------------------------- 1 | // This file has an underscore at the beginning of its name so that it is at 2 | // the top of the list in the text editor's sidebar 3 | import { ModuleDelegate } from "quickjs:engine"; 4 | 5 | import "./civet"; 6 | import "./coffee"; 7 | import "./empty"; 8 | import "./js"; 9 | import "./json"; 10 | import "./jsx"; 11 | import "./ts"; 12 | import "./tsx"; 13 | 14 | ModuleDelegate.searchExtensions = [ 15 | ".civet", 16 | ".ts", 17 | ".tsx", 18 | ".coffee", 19 | ".jsx", 20 | ".js", 21 | ]; 22 | -------------------------------------------------------------------------------- /src/extension-handlers/civet.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".civet"] = (filename: string, content: string) => { 5 | const compiled = compilers.civet(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-handlers/coffee.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".coffee"] = (filename: string, content: string) => { 5 | const compiled = compilers.coffee(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-handlers/empty.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[""] = (filename: string, content: string) => { 5 | return compilers.autodetect(content, { filename }); 6 | }; 7 | -------------------------------------------------------------------------------- /src/extension-handlers/js.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".js"] = (filename: string, content: string) => { 5 | const compiled = compilers.js(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-handlers/json.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { ModuleDelegate } from "quickjs:engine"; 3 | 4 | const template = (data: any) => 5 | `const data = ${JSON.stringify(data, null, 2)}; 6 | export default data; 7 | 8 | /* to make 'require' of json behave like in node */ 9 | export const __isCjsModule = true; 10 | export const __cjsExports = data; 11 | `; 12 | 13 | ModuleDelegate.compilers[".json"] = (filename: string, content: string) => { 14 | const data = std.parseExtJSON(content); 15 | return template(data); 16 | }; 17 | -------------------------------------------------------------------------------- /src/extension-handlers/jsx.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".jsx"] = (filename: string, content: string) => { 5 | const compiled = compilers.jsx(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-handlers/ts.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".ts"] = (filename: string, content: string) => { 5 | const compiled = compilers.ts(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/extension-handlers/tsx.ts: -------------------------------------------------------------------------------- 1 | import { ModuleDelegate } from "quickjs:engine"; 2 | import compilers from "../compilers"; 3 | 4 | ModuleDelegate.compilers[".tsx"] = (filename: string, content: string) => { 5 | const compiled = compilers.tsx(content, { filename }); 6 | return compiled; 7 | }; 8 | -------------------------------------------------------------------------------- /src/hardcoded/compile-time.js: -------------------------------------------------------------------------------- 1 | const child_process = require("child_process"); 2 | 3 | function run(cmd) { 4 | return child_process.execSync(cmd, { encoding: "utf-8" }).trim(); 5 | } 6 | 7 | // If you change the version string format, update help.ts and 8 | // yavascript.inc.d.ts 9 | function getVersion() { 10 | if (process.env.YAVASCRIPT_VERSION) { 11 | if (!/^v|^git-/.test(process.env.YAVASCRIPT_VERSION)) { 12 | throw new Error( 13 | `env var YAVASCRIPT_VERSION must start with 'v' or 'git-'!` 14 | ); 15 | } 16 | return process.env.YAVASCRIPT_VERSION; 17 | } 18 | 19 | let dirty = ""; 20 | try { 21 | run("git diff --quiet ."); 22 | } catch (err) { 23 | dirty = "-dirty"; 24 | } 25 | 26 | try { 27 | const gitTags = run("git tag --points-at HEAD") 28 | .split(/\s+/g) 29 | .filter(Boolean); 30 | 31 | if (gitTags.length > 0) { 32 | return gitTags[0] + dirty; 33 | } 34 | } catch (err) { 35 | // ignored 36 | } 37 | 38 | try { 39 | const SHA = run("git rev-parse HEAD"); 40 | return "git-" + SHA.slice(0, 12) + dirty; 41 | } catch (err) { 42 | // ignored 43 | } 44 | 45 | return "unknown"; 46 | } 47 | 48 | function getArch() { 49 | if (process.env.YAVASCRIPT_ARCH) { 50 | return process.env.YAVASCRIPT_ARCH; 51 | } 52 | 53 | try { 54 | return run("uname -m"); 55 | } catch (err) { 56 | return "unknown"; 57 | } 58 | } 59 | 60 | module.exports = { 61 | version: getVersion(), 62 | arch: getArch(), 63 | }; 64 | 65 | const wellKnownArchitectures = new Set(["arm64", "x86_64"]); 66 | 67 | if (!wellKnownArchitectures.has(module.exports.arch)) { 68 | console.warn( 69 | `WARNING: yavascript.arch will be set to '${module.exports.arch}', which may not be desirable. Generally, it should be either 'arm64' or 'x86_64'. Feel free to ignore this message if compiling for a different architecture.` 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /src/hardcoded/index.ts: -------------------------------------------------------------------------------- 1 | import * as values from "./compile-time?evalAtBuildTime"; 2 | 3 | export const version: string = values.version; 4 | export const arch: string = values.arch; 5 | -------------------------------------------------------------------------------- /src/has-colors.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import * as os from "quickjs:os"; 3 | 4 | // See https://bixense.com/clicolors/ 5 | export function hasColors(): boolean { 6 | const CLICOLOR = std.getenv("CLICOLOR"); 7 | const CLICOLOR_FORCE = std.getenv("CLICOLOR_FORCE"); 8 | 9 | if (CLICOLOR_FORCE != null && CLICOLOR_FORCE !== "0") { 10 | return true; 11 | } 12 | 13 | if (CLICOLOR === "0") { 14 | return false; 15 | } 16 | 17 | return os.isatty(std.out.fileno()); 18 | } 19 | -------------------------------------------------------------------------------- /src/inspect-options.ts: -------------------------------------------------------------------------------- 1 | let hasColors: () => boolean; 2 | 3 | // defer check for `yavascript` global until first time `hasColors` is called 4 | const __hasColorsInitialValue = (): boolean => { 5 | // @ts-ignore checking global that isn't in project types 6 | if (typeof yavascript !== "undefined") { 7 | hasColors = (require("./has-colors") as typeof import("./has-colors")) 8 | .hasColors; 9 | } else { 10 | hasColors = () => require("kleur").enabled; 11 | } 12 | 13 | return hasColors(); 14 | }; 15 | 16 | hasColors = __hasColorsInitialValue; 17 | 18 | export const forPrint: () => InspectOptions = () => ({ 19 | maxDepth: 8, 20 | noAmp: true, 21 | colours: hasColors(), 22 | indent: " ", 23 | noSource: true, 24 | }); 25 | 26 | export const forError: () => InspectOptions = () => ({ 27 | maxDepth: 1, 28 | noAmp: true, 29 | colours: false, 30 | indent: "", 31 | noSource: true, 32 | }); 33 | -------------------------------------------------------------------------------- /src/kame-filetypes.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.md" { 2 | const content: string; 3 | export = content; 4 | } 5 | 6 | declare module "*.txt" { 7 | const content: string; 8 | export = content; 9 | } 10 | 11 | declare module "*?contentString" { 12 | const content: string; 13 | export = content; 14 | } 15 | 16 | declare module "*?evalAtBuildTime" { 17 | const result: any; 18 | export = result; 19 | } 20 | -------------------------------------------------------------------------------- /src/langs.ts: -------------------------------------------------------------------------------- 1 | export const LANGS = new Set([ 2 | "js", 3 | "javascript", 4 | "ts", 5 | "typescript", 6 | "jsx", 7 | "tsx", 8 | "coffee", 9 | "coffeescript", 10 | "civet", 11 | ]); 12 | 13 | export function langToCompiler(lang: string) { 14 | const compilers: typeof import("./compilers").default = 15 | require("./compilers").default; 16 | 17 | switch (lang) { 18 | case "js": 19 | case "javascript": { 20 | return compilers.js; 21 | } 22 | case "ts": 23 | case "typescript": { 24 | return compilers.ts; 25 | } 26 | case "jsx": { 27 | return compilers.jsx; 28 | } 29 | case "tsx": { 30 | return compilers.tsx; 31 | } 32 | case "coffee": 33 | case "coffeescript": { 34 | return compilers.coffee; 35 | } 36 | case "civet": 37 | return compilers.civet; 38 | default: { 39 | throw new Error(`No compiler for lang: ${lang}`); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/lazy-load.ts: -------------------------------------------------------------------------------- 1 | const EMPTY = Symbol("EMPTY"); 2 | 3 | export function memoize(fn: () => T): () => T { 4 | let _value: T | typeof EMPTY = EMPTY; 5 | 6 | return () => { 7 | if (_value === EMPTY) { 8 | _value = fn(); 9 | } 10 | 11 | return _value; 12 | }; 13 | } 14 | 15 | export function makeGetterPropertyDescriptorMap< 16 | Input extends { [key: string]: () => any } 17 | >( 18 | input: Input, 19 | enumerable: boolean = true 20 | ): { [k in keyof Input]: PropertyDescriptor } { 21 | const entries: Array<[string, PropertyDescriptor]> = []; 22 | 23 | for (const [key, getterFn] of Object.entries(input)) { 24 | entries.push([ 25 | key, 26 | { 27 | get: memoize(getterFn), 28 | configurable: true, 29 | enumerable: enumerable, 30 | }, 31 | ]); 32 | } 33 | 34 | return Object.fromEntries(entries) as any; 35 | } 36 | -------------------------------------------------------------------------------- /src/module-protocols/_all.ts: -------------------------------------------------------------------------------- 1 | // This file has an underscore at the beginning of its name so that it is at 2 | // the top of the list in the text editor's sidebar 3 | import * as http from "./http"; 4 | import * as https from "./https"; 5 | import * as npm from "./npm"; 6 | 7 | export { http, https, npm }; 8 | -------------------------------------------------------------------------------- /src/module-protocols/http.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import compilers from "../compilers"; 3 | import { makeErrorWithProperties } from "../error-with-properties"; 4 | 5 | const HTTP_RE = /^http:\/\//i; 6 | 7 | export function handlesModulePath(modulePath: string) { 8 | return HTTP_RE.test(modulePath); 9 | } 10 | 11 | export function normalizeModulePath(modulePath: string) { 12 | return modulePath; 13 | } 14 | 15 | export function readModule(modulePath: string) { 16 | const { status, response, responseHeaders } = std.urlGet(modulePath, { 17 | full: true, 18 | }); 19 | if (status < 200 || status > 299) { 20 | const err = makeErrorWithProperties(`Failed to load module`, { 21 | httpStatusCode: status, 22 | url: modulePath, 23 | }); 24 | err.httpResponseHeaders = responseHeaders; 25 | err.httpResponseBody = response; 26 | throw err; 27 | } 28 | 29 | return compilers.autodetect(response, { filename: modulePath }); 30 | } 31 | -------------------------------------------------------------------------------- /src/module-protocols/https.ts: -------------------------------------------------------------------------------- 1 | import * as http from "./http"; 2 | 3 | const HTTPS_RE = /^https:\/\//i; 4 | 5 | export function handlesModulePath(modulePath: string) { 6 | return HTTPS_RE.test(modulePath); 7 | } 8 | 9 | export function normalizeModulePath(modulePath: string) { 10 | return modulePath; 11 | } 12 | 13 | export function readModule(modulePath: string) { 14 | return http.readModule(modulePath); 15 | } 16 | -------------------------------------------------------------------------------- /src/module-protocols/npm.ts: -------------------------------------------------------------------------------- 1 | import * as https from "./https"; 2 | 3 | const NPM_PROTO_RE = /^npm:/i; 4 | const SKYPACK_URL = "https://cdn.skypack.dev"; 5 | // HACK: looks like all of skypack's sub-import paths start with /-/. 6 | // Rely on that to identify sub-modules from skypack. 7 | const SKYPACK_SUBMODULE_RE = /^\/\-\//; 8 | 9 | export function handlesModulePath(modulePath: string) { 10 | return ( 11 | modulePath.startsWith(SKYPACK_URL) || 12 | NPM_PROTO_RE.test(modulePath) || 13 | SKYPACK_SUBMODULE_RE.test(modulePath) 14 | ); 15 | } 16 | 17 | export function normalizeModulePath(modulePath: string) { 18 | if (NPM_PROTO_RE.test(modulePath)) { 19 | return modulePath.replace(NPM_PROTO_RE, SKYPACK_URL + "/"); 20 | } 21 | 22 | if (SKYPACK_SUBMODULE_RE.test(modulePath)) { 23 | return SKYPACK_URL + modulePath; 24 | } 25 | 26 | return modulePath; 27 | } 28 | 29 | export function readModule(modulePath: string) { 30 | return https.readModule(modulePath); 31 | } 32 | -------------------------------------------------------------------------------- /src/primordials.ts: -------------------------------------------------------------------------------- 1 | // This file loads all the globals and etc 2 | 3 | import installApi from "./api/_install-api"; 4 | installApi(globalThis); 5 | 6 | import "./extension-handlers/_load-all"; 7 | -------------------------------------------------------------------------------- /src/print-error.ts: -------------------------------------------------------------------------------- 1 | import * as inspectOptions from "./inspect-options"; 2 | 3 | const normalProps = new Set(["name", "message", "stack"]); 4 | 5 | export default function printError(error: any, file: FILE) { 6 | if ( 7 | typeof error === "object" && 8 | error != null && 9 | typeof error.name === "string" && 10 | typeof error.message === "string" && 11 | typeof error.stack === "string" 12 | ) { 13 | file.puts(error.name); 14 | file.puts(": "); 15 | file.puts(error.message); 16 | file.puts("\n"); 17 | file.puts( 18 | error.stack 19 | .split("\n") 20 | .map((line: string) => line.replace(/^\s+/, " ")) 21 | .join("\n") 22 | .replace(/\s+$/, "") 23 | ); 24 | 25 | let extraProps: Array = []; 26 | try { 27 | extraProps = Object.getOwnPropertyNames(error).filter( 28 | (name) => !normalProps.has(name) 29 | ); 30 | } catch (err) { 31 | // ignored 32 | } 33 | 34 | if (extraProps.length > 0) { 35 | const propsObj = {}; 36 | for (const key of extraProps) { 37 | propsObj[key] = error[key]; 38 | } 39 | file.puts("\n"); 40 | file.puts(inspect(propsObj, inspectOptions.forPrint())); 41 | } 42 | 43 | file.puts("\n"); 44 | } else { 45 | file.puts("Non-error value was thrown: "); 46 | file.puts(inspect(error, inspectOptions.forPrint())); 47 | file.puts("\n"); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/resizable-buffer.ts: -------------------------------------------------------------------------------- 1 | export class ResizableBuffer { 2 | buffer: ArrayBuffer; 3 | 4 | constructor(byteLength: number) { 5 | this.buffer = new ArrayBuffer(byteLength); 6 | } 7 | 8 | resizeTo(byteLength: number) { 9 | this.resizeBy(byteLength - this.buffer.byteLength); 10 | } 11 | 12 | resizeBy(bytes: number) { 13 | if (bytes === 0) { 14 | return; 15 | } 16 | 17 | if (bytes < 0) { 18 | this.buffer = this.buffer.slice(0, -bytes); 19 | } else { 20 | const newBuffer = new ArrayBuffer(this.buffer.byteLength + bytes); 21 | new Uint8Array(newBuffer).set(new Uint8Array(this.buffer)); 22 | this.buffer = newBuffer; 23 | } 24 | 25 | return this.buffer; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/targets/eval.ts: -------------------------------------------------------------------------------- 1 | import * as engine from "quickjs:engine"; 2 | import * as os from "quickjs:os"; 3 | import * as esmToRequire from "../esm-to-require"; 4 | import { NOTHING } from "../api/repl/special"; 5 | import { langToCompiler } from "../langs"; 6 | 7 | export default function evalTarget(inputCode: string, lang: string) { 8 | let codeToRun: string | null = null; 9 | 10 | const compiler = langToCompiler(lang); 11 | codeToRun = compiler(inputCode, { expression: true }); 12 | 13 | const transformedCode = esmToRequire.transform(codeToRun); 14 | const filename = 15 | os.getcwd() + (os.platform === "win32" ? "\\" : "/") + ""; 16 | 17 | const result = engine.evalScript(transformedCode, { 18 | backtraceBarrier: true, 19 | filename, 20 | }); 21 | if (typeof result !== "undefined" && result !== NOTHING) { 22 | console.log(result); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/targets/invalid.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | export default function invalidTarget(message: string) { 4 | std.err.puts(message + "\n"); 5 | std.err.puts(`For more info, run '${scriptArgs[0]} --help'.\n`); 6 | } 7 | -------------------------------------------------------------------------------- /src/targets/license.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import license from "../license-text"; 3 | 4 | export default function licenseTarget() { 5 | std.out.puts(license); 6 | std.exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /src/targets/print-types.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | 3 | // @ts-ignore cannot find module 4 | import dtsText from "../../dist/yavascript.d.ts?contentString"; 5 | 6 | export default function printTypesTarget() { 7 | std.out.puts(dtsText); 8 | std.exit(0); 9 | } 10 | -------------------------------------------------------------------------------- /src/targets/repl/index.ts: -------------------------------------------------------------------------------- 1 | export default function replTarget(lang: string) { 2 | require("../../api/repl/modified-qjs-repl").startRepl(lang); 3 | } 4 | -------------------------------------------------------------------------------- /src/targets/version.ts: -------------------------------------------------------------------------------- 1 | import * as std from "quickjs:std"; 2 | import { version } from "../hardcoded"; 3 | 4 | export default function versionTarget() { 5 | std.out.puts(version); 6 | std.exit(0); 7 | } 8 | -------------------------------------------------------------------------------- /src/templates/commands.d.ts.tmpl: -------------------------------------------------------------------------------- 1 | #INCLUDE("basename.inc.d.ts") 2 | #INCLUDE("cat.inc.d.ts") 3 | #INCLUDE("cd.inc.d.ts") 4 | #INCLUDE("chmod.inc.d.ts") 5 | #INCLUDE("dirname.inc.d.ts") 6 | #INCLUDE("echo.inc.d.ts") 7 | #INCLUDE("exit.inc.d.ts") 8 | #INCLUDE("extname.inc.d.ts") 9 | #INCLUDE("ls.inc.d.ts") 10 | #INCLUDE("mkdir.inc.d.ts") 11 | #INCLUDE("mkdirp.inc.d.ts") 12 | #INCLUDE("printf.inc.d.ts") 13 | #INCLUDE("pwd.inc.d.ts") 14 | #INCLUDE("readlink.inc.d.ts") 15 | #INCLUDE("realpath.inc.d.ts") 16 | #INCLUDE("sleep.inc.d.ts") 17 | #INCLUDE("touch.inc.d.ts") 18 | #INCLUDE("which.inc.d.ts") 19 | #INCLUDE("whoami.inc.d.ts") 20 | -------------------------------------------------------------------------------- /src/templates/quickjs-globals.inc.d.ts: -------------------------------------------------------------------------------- 1 | declare const std: typeof import("quickjs:std"); 2 | declare const os: typeof import("quickjs:os"); 3 | 4 | // undocumented from quickjs, but it's there 5 | /** Get the current unix timestamp with microsecond precision. */ 6 | declare function __date_clock(): number; 7 | -------------------------------------------------------------------------------- /src/templates/yavascript-git.d.ts.tmpl: -------------------------------------------------------------------------------- 1 | // NOTE: This copy of yavascript.d.ts reflects what is in git. 2 | // APIs may differ from what you have installed. 3 | // Run `yavascript --print-types > yavascript.d.ts` to get the types 4 | // corresponding to your specific `yavascript` binary. 5 | 6 | #INCLUDE("yavascript.d.ts.tmpl") -------------------------------------------------------------------------------- /src/templates/yavascript.d.ts.tmpl: -------------------------------------------------------------------------------- 1 | // =============== 2 | // --------------- 3 | // YavaScript APIs 4 | // --------------- 5 | // =============== 6 | #INCLUDE("help.inc.d.ts") 7 | #INCLUDE("yavascript.inc.d.ts") 8 | #INCLUDE("env.inc.d.ts") 9 | #INCLUDE("parse-script-args.inc.d.ts") 10 | #INCLUDE("filesystem.inc.d.ts") 11 | #INCLUDE("path.inc.d.ts") 12 | #INCLUDE("__filename-and-__dirname.inc.d.ts") 13 | #INCLUDE("commands.d.ts.tmpl") 14 | #INCLUDE("exec.inc.d.ts") 15 | #INCLUDE("ChildProcess.inc.d.ts") 16 | #INCLUDE("glob.inc.d.ts") 17 | #INCLUDE("console.inc.d.ts") 18 | #INCLUDE("print.inc.d.ts") 19 | #INCLUDE("strings.inc.d.ts") 20 | #INCLUDE("grep.inc.d.ts") 21 | #INCLUDE("types.inc.d.ts") 22 | #INCLUDE("is.inc.d.ts") 23 | #INCLUDE("assert.inc.d.ts") 24 | #INCLUDE("interactive-prompt.inc.d.ts") 25 | #INCLUDE("start-repl.inc.d.ts") 26 | #INCLUDE("git-repo.inc.d.ts") 27 | #INCLUDE("logger.inc.d.ts") 28 | #INCLUDE("jsx.inc.d.ts") 29 | #INCLUDE("yaml.inc.d.ts") 30 | #INCLUDE("csv.inc.d.ts") 31 | #INCLUDE("toml.inc.d.ts") 32 | #INCLUDE("regexp-escape.inc.d.ts") 33 | #INCLUDE("string-dedent.inc.d.ts") 34 | #INCLUDE("open-url.inc.d.ts") 35 | #INCLUDE("others.inc.d.ts") 36 | #INCLUDE("node-compat.inc.d.ts") 37 | 38 | // ========================================== 39 | // ------------------------------------------ 40 | // QuickJS APIs, which YavaScript builds upon 41 | // ------------------------------------------ 42 | // ========================================== 43 | #INCLUDE("quickjs.d.ts") 44 | #INCLUDE("quickjs-inspect.d.ts") 45 | #INCLUDE("quickjs-intervals.d.ts") 46 | #INCLUDE("quickjs-libc.d.ts") 47 | #INCLUDE("quickjs-modulesys.d.ts") 48 | #INCLUDE("quickjs-engine.d.ts") 49 | #INCLUDE("quickjs-bytecode.d.ts") 50 | #INCLUDE("quickjs-context.d.ts") 51 | #INCLUDE("quickjs-encoding.d.ts") 52 | 53 | #INCLUDE("quickjs-globals.inc.d.ts") 54 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*.ts", "node_modules/@suchipi/quickjs/build/dts/*.d.ts"], 3 | "exclude": [ 4 | "**/*.inc.d.ts", 5 | "meta/examples", 6 | "./yavascript.d.ts", 7 | "meta/tests/**/*", 8 | "meta/type-tests/**/*" 9 | ], 10 | 11 | "compilerOptions": { 12 | "declaration": true, 13 | "lib": ["es2022"], 14 | "target": "es2020", 15 | "module": "es2022", 16 | "outDir": "dist", 17 | "skipLibCheck": true, 18 | 19 | "strict": true, 20 | "noImplicitAny": false, 21 | "strictNullChecks": true, 22 | "strictFunctionTypes": true, 23 | "strictPropertyInitialization": true, 24 | "noImplicitThis": true, 25 | "alwaysStrict": true, 26 | "noUnusedLocals": false, 27 | "noUnusedParameters": false, 28 | "noImplicitReturns": true, 29 | "noFallthroughCasesInSwitch": true, 30 | "downlevelIteration": true, 31 | 32 | "moduleResolution": "node", 33 | "esModuleInterop": true, 34 | "resolveJsonModule": true 35 | } 36 | } 37 | --------------------------------------------------------------------------------