diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07dd27387..41099b87d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,23 +68,25 @@ jobs: # - run: opam pin add rescript-editor-analysis.dev . --no-action # - run: opam install . --deps-only --with-doc --with-test - - name: Build and test + - name: Build + run: opam exec -- make + + - name: Test run: opam exec -- make test - working-directory: analysis # Also avoids artifacts upload permission loss: # https://github.com/actions/upload-artifact/tree/ee69f02b3dfdecd58bb31b4d133da38ba6fe3700#permission-loss - name: Compress files run: | - cd analysis mkdir ${{matrix.artifact-folder}} mv rescript-editor-analysis.exe ${{matrix.artifact-folder}} + mv rescript-tools.exe ${{matrix.artifact-folder}} tar -cvf binary.tar ${{matrix.artifact-folder}} - uses: actions/upload-artifact@v3 with: name: ${{matrix.os}} - path: analysis/binary.tar + path: binary.tar package: needs: test @@ -106,37 +108,51 @@ jobs: uses: actions/download-artifact@v3 with: name: macos-latest - path: ./server/analysis_binaries + path: binaries - run: tar -xvf binary.tar - working-directory: ./server/analysis_binaries + working-directory: binaries - name: Download MacOS ARM binary uses: actions/download-artifact@v3 with: name: macos-arm - path: ./server/analysis_binaries + path: binaries - run: tar -xvf binary.tar - working-directory: ./server/analysis_binaries + working-directory: binaries - name: Download Linux binary uses: actions/download-artifact@v3 with: name: ubuntu-20.04 - path: ./server/analysis_binaries + path: binaries - run: tar -xvf binary.tar - working-directory: ./server/analysis_binaries + working-directory: binaries - name: Download Windows binary uses: actions/download-artifact@v3 with: name: windows-latest - path: ./server/analysis_binaries + path: binaries - run: tar -xvf binary.tar - working-directory: ./server/analysis_binaries + working-directory: binaries - name: Cleanup tar file run: rm binary.tar - working-directory: ./server/analysis_binaries + working-directory: binaries + + - name: Move binaries to folders + run: | + declare -a platforms=("darwin" "darwinarm64" "linux" "win32") + + for platform in "${platforms[@]}"; do + mkdir server/analysis_binaries/"$platform" + mv binaries/"$platform"/rescript-editor-analysis.exe server/analysis_binaries/"$platform" + done + + for platform in "${platforms[@]}"; do + mkdir tools/binaries/"$platform" + mv binaries/"$platform"/rescript-tools.exe tools/binaries/"$platform" + done - name: Store short commit SHA for filename id: vars @@ -221,9 +237,6 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Copy analysis binaries to tools folder - run: cp -r server/analysis_binaries/* tools/analysis_binaries - - name: Build @rescript/tools package working-directory: tools run: | diff --git a/.gitignore b/.gitignore index eec4dd08d..be3459b4b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,19 @@ out node_modules examples/*/lib + analysis/tests/lib analysis/tests/.bsb.lock -analysis/_build analysis/tests/.merlin -analysis/rescript-editor-analysis.exe -analysis/_opam + tools/node_modules tools/lib -tools/**/*.bs.js +tools/**/*.res.js +tools/tests/node_modules +tools/tests/lib + +rescript-editor-analysis.exe +rescript-tools.exe + +_opam/ +_build/ diff --git a/analysis/.ocamlformat b/.ocamlformat similarity index 100% rename from analysis/.ocamlformat rename to .ocamlformat diff --git a/.ocamlformat-ignore b/.ocamlformat-ignore new file mode 100644 index 000000000..a0940f84d --- /dev/null +++ b/.ocamlformat-ignore @@ -0,0 +1,2 @@ +analysis/vendor/compiler-libs-406/* +analysis/vendor/res_outcome_printer/* diff --git a/.vscode/settings.json b/.vscode/settings.json index 7cf99ab8c..c7e28bd31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,13 +1,13 @@ { - "editor.insertSpaces": false, - "tslint.enable": true, - "typescript.tsc.autoDetect": "off", - "typescript.preferences.quoteStyle": "single", - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - "ocaml.sandbox": { - "kind": "opam", - "switch": "4.14.0" - } + "editor.insertSpaces": false, + "tslint.enable": true, + "typescript.tsc.autoDetect": "off", + "typescript.preferences.quoteStyle": "single", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": true + }, + "ocaml.sandbox": { + "kind": "opam", + "switch": "${workspaceFolder:rescript-vscode}" + } } diff --git a/.vscodeignore b/.vscodeignore index aa75b64a6..a2ba46c12 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -8,3 +8,10 @@ contributing.md server/node_modules/.bin node_modules/.bin analysis/ +tools/ +scripts/ +dune-project +analysis.opam +tools.opam +.ocamlformat +.ocamlformat-ignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 72951128a..a6d9949cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,10 @@ - More cases of not emitting `_` when completing in expressions. https://github.com/rescript-lang/rescript-vscode/pull/890 +#### :house: Internal + +- Move `rescript-tools` to OCaml code and make `analysis` an library. https://github.com/rescript-lang/rescript-vscode/pull/855 + ## 1.34.0 #### :rocket: New Feature diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21824c676..1a7a0668c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,14 +10,21 @@ Thanks for your interest. Below is an informal spec of how the plugin's server c │ └── src │ └── extension.ts // Language Client entry point ├── analysis // Native binary powering hover, autocomplete, etc. -│ ├── src -│ └── rescript-editor-analysis.exe // Dev-time analysis binary +│ ├── src // Analysis library +│ ├── bin // Analysis binary ├── package.json // The extension manifest -└── server // Language Server. Usable standalone - ├── src - │ ├── server.ts // Language Server Module - │ ├── cli.ts // LSP CLI - └── analysis_binaries // Prod-time platform-specific analysis binaries +├── server // Language Server. Usable standalone +│ ├── src +│ │ ├── server.ts // Language Server Module +│ │ ├── cli.ts // LSP CLI +│ └── analysis_binaries // Prod-time platform-specific analysis binaries +│ ├── darwin +│ ├── linux +│ └── win32 +└── tools // ReScript Tools + ├── bin // OCaml Binary + ├── src // ReScript Tools library + └── binaries // Prod-time platform-specific binaries ├── darwin ├── linux └── win32 @@ -27,9 +34,11 @@ Thanks for your interest. Below is an informal spec of how the plugin's server c - Run `npm install` at the root. This will also install the npm modules for both the `client` and `server` folders. -## Analysis Binary +## OCaml Code + +This is needed for the `analysis` and `tools` folder, which is native code. -This is needed for the `analysis` folder, which is native code. +At the root: ```sh # If you haven't created the switch, do it. OPAM(https://opam.ocaml.org) @@ -38,14 +47,14 @@ opam switch 4.14.0 # can also create local switch with opam switch create . 4.14 # Install dev dependencies from OPAM opam install . --deps-only -# For IDE support, install the OCaml language server -opam install ocaml-lsp-server +# For IDE support, install the OCaml language server and OCaml Formatter +opam install ocaml-lsp-server ocamlformat ``` ## Build & Run - `npm run compile`. You don't need this if you're developing this repo in VSCode. The compilation happens automatically in the background. -- `cd analysis && make`. +- `make`. ## Test @@ -67,7 +76,7 @@ opam install ocaml-lsp-server image -- For the native analysis binary tests: `cd analysis && make test`. +- For the native analysis and tools binary tests: `make test`. ## Change the Grammar @@ -96,7 +105,7 @@ We call a few binaries and it's tricky to call them properly cross-platform. Her ## General Coding Guidance -- `server/` is a standalone folder that can be vendored by e.g. Vim and Sublime Text. Keep it light, don't add deps unless absolutely necessarily, and don't accidentally use a runtime dep from the top level `package.json`. +- `server/` is a standalone LSP server. Keep it light, don't add deps unless absolutely necessarily, and don't accidentally use a runtime dep from the top level `package.json`. - This codebase stayed alive by not trying to babysit long-living processes. Be fast, call a binary and shut down. ## Rough Description Of How The Plugin Works @@ -197,9 +206,8 @@ We're happy to gather more resources over time here, including more in-depth get _This below will automatically release the LSP package as well._ 1. Bump the version to an _even minor_ version number in `package.json` and `server/package.json` and their lockfiles. It's very important that it's an even minor like `1.8.0`, and not `1.7.0`. This is because even minors are reserved for actual releases, and uneven minors for pre-releases. Commit and push the version bump. -2. Make sure @ryyppy is aware of your changes. He needs to sync them over to the vim plugin. -3. Let CI build your version bump commit. -4. Tag the commit with the version number (e.g. `git tag 1.6.0`) and push the tag (e.g. `git push origin 1.6.0`). Another build will trigger, which should automatically: +2. Let CI build your version bump commit. +3. Tag the commit with the version number (e.g. `git tag 1.6.0`) and push the tag (e.g. `git push origin 1.6.0`). Another build will trigger, which should automatically: - create a `rescript-vscode-.vsix` file - publish that extension version to the VSCode marketplace - create an automatic release on GitHub @@ -214,4 +222,4 @@ For beta releases, ask folks to use the pre-release version installable from the ## Releasing the `@rescript/tools` package -The tools package is released by bumping the version in `tools/package.json`, running `npm i` in the `tools/` folder, and then pushing those changes with the commit message `publish tools`. +The tools package is released by bumping the version in `tools/package.json` and run `node scripts/updateVersion.js`, running `npm i` in the `tools/` folder, and then pushing those changes with the commit message `publish tools`. diff --git a/Makefile b/Makefile index dd56cd9b3..e693761a0 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,24 @@ SHELL = /bin/bash build: - make -C analysis build - -clean: - make -C analysis clean + dune build + cp _build/install/default/bin/rescript-editor-analysis rescript-editor-analysis.exe + cp _build/install/default/bin/rescript-tools rescript-tools.exe test: make -C analysis test + make -C tools/tests test + +clean: + dune clean + make -C analysis clean + make -C tools/tests clean format: - make -C analysis format + dune build @fmt --auto-promote checkformat: - make -C analysis checkformat + dune build @fmt .DEFAULT_GOAL := build diff --git a/analysis/rescript-vscode.opam b/analysis.opam similarity index 73% rename from analysis/rescript-vscode.opam rename to analysis.opam index 72c8e4dd3..8a6978820 100644 --- a/analysis/rescript-vscode.opam +++ b/analysis.opam @@ -1,15 +1,13 @@ # This file is generated by dune, edit dune-project instead opam-version: "2.0" -synopsis: "ReScript vscode support" -maintainer: ["Cristiano Calcagno"] -authors: ["Cristiano Calcagno"] +synopsis: "ReScript Analysis" +maintainer: ["ReScript Team"] +authors: ["ReScript Team"] homepage: "https://github.com/rescript-lang/rescript-vscode" bug-reports: "https://github.com/rescript-lang/rescript-vscode/issues" depends: [ "ocaml" {>= "4.10"} - "ocamlformat" {= "0.26.1"} "cppo" {= "1.6.9"} - "reanalyze" {= "2.23.0"} "dune" ] build: [ diff --git a/analysis/.ocamlformat-ignore b/analysis/.ocamlformat-ignore deleted file mode 100644 index 841c7c180..000000000 --- a/analysis/.ocamlformat-ignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/compiler-libs-406/* -vendor/res_outcome_printer/* diff --git a/analysis/.vscode/settings.json b/analysis/.vscode/settings.json deleted file mode 100644 index 290cb9031..000000000 --- a/analysis/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "editor.formatOnSave": false, - "git.ignoreLimitWarning": true, - "git.enabled": true, - "editor.codeLens": true, - "editor.tabSize": 2, - "workbench.settings.editor": "json", - "ocaml.sandbox": { - "kind": "global" - } -} diff --git a/analysis/.vscode/tasks.json b/analysis/.vscode/tasks.json deleted file mode 100644 index 462911f2c..000000000 --- a/analysis/.vscode/tasks.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - ] -} \ No newline at end of file diff --git a/analysis/Makefile b/analysis/Makefile index 069dbbbe4..a29bdbd81 100644 --- a/analysis/Makefile +++ b/analysis/Makefile @@ -1,41 +1,26 @@ SHELL = /bin/bash -build-analysis-binary: - rm -f rescript-editor-analysis.exe - dune build - cp _build/install/default/bin/rescript-editor-analysis rescript-editor-analysis.exe - build-tests: make -C tests build build-reanalyze: make -C reanalyze build -build: build-analysis-binary build-reanalyze build-tests +build: build-reanalyze build-tests dce: build-analysis-binary opam exec reanalyze.exe -- -dce-cmt _build -suppress vendor -format: - dune build @fmt --auto-promote - -test-analysis-binary: build-analysis-binary +test-analysis-binary: make -C tests test -test-reanalyze: build-analysis-binary +test-reanalyze: make -C reanalyze test test: test-analysis-binary test-reanalyze clean: - rm -f rescript-editor-analysis.exe - dune clean make -C tests clean make -C reanalyze clean -checkformat: - dune build @fmt - -.DEFAULT_GOAL := build - -.PHONY: build-analysis-binary build-reanalyze build-tests dce clean format test +.PHONY: build-reanalyze build-tests dce clean test diff --git a/analysis/README.md b/analysis/README.md index 73e453e26..2ce1bf5a2 100644 --- a/analysis/README.md +++ b/analysis/README.md @@ -1,4 +1,4 @@ -# Analysis Binary +# Analysis Library and Binary This subfolder builds a private command line binary used by the plugin to power a few functionalities such as jump to definition, hover and autocomplete. @@ -12,8 +12,13 @@ See main CONTRIBUTING.md's repo structure. Additionally, `examples/` is a conven ## Usage +At root: ```sh ./rescript-editor-analysis.exe --help + +# or + +dune exec -- rescript-editor-analysis --help ``` ## History diff --git a/analysis/bin/dune b/analysis/bin/dune new file mode 100644 index 000000000..94665f5d1 --- /dev/null +++ b/analysis/bin/dune @@ -0,0 +1,6 @@ +(executable + (public_name rescript-editor-analysis) + (package analysis) + (modes byte exe) + (name main) + (libraries analysis)) diff --git a/analysis/src/Cli.ml b/analysis/bin/main.ml similarity index 97% rename from analysis/src/Cli.ml rename to analysis/bin/main.ml index d2ed112cd..9d44434b4 100644 --- a/analysis/src/Cli.ml +++ b/analysis/bin/main.ml @@ -1,3 +1,5 @@ +open Analysis + let help = {| **Private CLI For rescript-vscode usage only** @@ -143,14 +145,6 @@ let main () = ~pos:(int_of_string line_start, int_of_string line_end) ~maxLength ~debug | [_; "codeLens"; path] -> Commands.codeLens ~path ~debug - | [_; "extractDocs"; path] -> - let () = - match Sys.getenv_opt "FROM_COMPILER" with - | Some "true" -> Cfg.isDocGenFromCompiler := true - | _ -> () - in - - DocExtraction.extractDocs ~path ~debug | [_; "codeAction"; path; startLine; startCol; endLine; endCol; currentFile] -> Commands.codeAction ~path diff --git a/analysis/dune b/analysis/dune index 5ce956be5..6b297d2e5 100644 --- a/analysis/dune +++ b/analysis/dune @@ -1,4 +1,4 @@ -(dirs src reanalyze vendor) +(dirs bin src reanalyze vendor) (env (dev diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index 3a91151cc..bfb9dc3c2 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -347,9 +347,6 @@ let test ~path = let currentFile = createCurrentFile () in signatureHelp ~path ~pos:(line, col) ~currentFile ~debug:true; Sys.remove currentFile - | "dex" -> - print_endline ("Documentation extraction " ^ path); - DocExtraction.extractDocs ~path ~debug:true | "int" -> print_endline ("Create Interface " ^ path); let cmiFile = diff --git a/analysis/src/dune b/analysis/src/dune index bc16552c3..c1bd828c1 100644 --- a/analysis/src/dune +++ b/analysis/src/dune @@ -1,9 +1,5 @@ -(executable - (public_name rescript-editor-analysis) - (modes byte exe) - ; The main module that will become the binary. - (name Cli) +(library + (name analysis) (flags (-w "+6+26+27+32+33+39")) - ; Depends on: (libraries unix str ext ml jsonlib syntax reanalyze)) diff --git a/analysis/tests/test.sh b/analysis/tests/test.sh index e511a49ec..71a43c26e 100755 --- a/analysis/tests/test.sh +++ b/analysis/tests/test.sh @@ -1,6 +1,6 @@ for file in src/*.{res,resi}; do output="$(dirname $file)/expected/$(basename $file).txt" - ../rescript-editor-analysis.exe test $file &> $output + ../../rescript-editor-analysis.exe test $file &> $output # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. if [ "$RUNNER_OS" == "Windows" ]; then perl -pi -e 's/\r\n/\n/g' -- $output @@ -9,7 +9,7 @@ done for file in not_compiled/*.{res,resi}; do output="$(dirname $file)/expected/$(basename $file).txt" - ../rescript-editor-analysis.exe test $file &> $output + ../../rescript-editor-analysis.exe test $file &> $output # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. if [ "$RUNNER_OS" == "Windows" ]; then perl -pi -e 's/\r\n/\n/g' -- $output diff --git a/analysis/dune-project b/dune-project similarity index 52% rename from analysis/dune-project rename to dune-project index 6d54204c8..e3e04789b 100644 --- a/analysis/dune-project +++ b/dune-project @@ -2,24 +2,31 @@ (generate_opam_files true) -(authors "Cristiano Calcagno") +(authors "ReScript Team") -(maintainers "Cristiano Calcagno") +(maintainers "ReScript Team") (homepage "https://github.com/rescript-lang/rescript-vscode") (bug_reports "https://github.com/rescript-lang/rescript-vscode/issues") (package - (name rescript-vscode) - (synopsis "ReScript vscode support") + (name analysis) + (synopsis "ReScript Analysis") (depends (ocaml (>= 4.10)) - (ocamlformat - (= 0.26.1)) (cppo (= 1.6.9)) - (reanalyze - (= 2.23.0)) + dune)) + +(package + (name tools) + (synopsis "ReScript Tools") + (depends + (ocaml + (>= 4.10)) + (cppo + (= 1.6.9)) + analysis dune)) diff --git a/package.json b/package.json index a65328a51..c20c78223 100644 --- a/package.json +++ b/package.json @@ -218,7 +218,7 @@ "vscode:prepublish": "npm run clean && npm run compile", "compile": "tsc -b", "watch": "tsc -b -w", - "postinstall": "cd server && npm i && cd ../client && npm i && cd ../analysis/tests && npm i && cd ../reanalyze/examples/deadcode && npm i && cd ../termination && npm i" + "postinstall": "cd server && npm i && cd ../client && npm i && cd ../tools && npm i && cd ../tools/tests && npm i && cd ../../analysis/tests && npm i && cd ../reanalyze/examples/deadcode && npm i && cd ../termination && npm i" }, "devDependencies": { "@types/node": "^14.14.41", diff --git a/scripts/updateVersion.js b/scripts/updateVersion.js new file mode 100644 index 000000000..3f9f69bc6 --- /dev/null +++ b/scripts/updateVersion.js @@ -0,0 +1,24 @@ +//@ts-check +// This file is used only in dev time +// Bump version in package.json and this script will update version in ml file +// and rescript.json + +const fs = require("fs"); +const path = require("path"); + +const toolsPkgDir = path.join(__dirname, "..", "tools"); + +const { version } = JSON.parse( + fs.readFileSync(path.join(toolsPkgDir, "package.json"), "utf8"), +); + +const rescriptJsonPath = path.join(toolsPkgDir, "rescript.json"); + +const rescriptJson = JSON.parse(fs.readFileSync(rescriptJsonPath, "utf8")); +rescriptJson.version = version; +fs.writeFileSync(rescriptJsonPath, JSON.stringify(rescriptJson, null, 2)); + +fs.writeFileSync( + path.join(toolsPkgDir, "bin", "version.ml"), + `let version = "${version}"`, +); diff --git a/server/src/constants.ts b/server/src/constants.ts index 8fc2a1214..fd6e29472 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -18,7 +18,6 @@ export let bscNativeReScriptPartialPath = path.join( export let analysisDevPath = path.join( path.dirname(__dirname), "..", - "analysis", "rescript-editor-analysis.exe" ); export let analysisProdPath = path.join( diff --git a/tools.opam b/tools.opam new file mode 100644 index 000000000..3dbdc6f1d --- /dev/null +++ b/tools.opam @@ -0,0 +1,27 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "ReScript Tools" +maintainer: ["ReScript Team"] +authors: ["ReScript Team"] +homepage: "https://github.com/rescript-lang/rescript-vscode" +bug-reports: "https://github.com/rescript-lang/rescript-vscode/issues" +depends: [ + "ocaml" {>= "4.10"} + "cppo" {= "1.6.9"} + "analysis" + "dune" +] +build: [ + ["dune" "subst"] {pinned} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] diff --git a/tools/bin/dune b/tools/bin/dune new file mode 100644 index 000000000..d498e0675 --- /dev/null +++ b/tools/bin/dune @@ -0,0 +1,9 @@ +(executable + (public_name rescript-tools) + (package tools) + (modes byte exe) + ; The main module that will become the binary. + (name main) + (libraries tools) + (flags + (-w "+6+26+27+32+33+39"))) diff --git a/tools/bin/main.ml b/tools/bin/main.ml new file mode 100644 index 000000000..f1dc157b1 --- /dev/null +++ b/tools/bin/main.ml @@ -0,0 +1,57 @@ +let docHelp = + {|ReScript Tools + +Output documentation to standard output + +Usage: rescript-tools doc + +Example: rescript-tools doc ./path/to/EntryPointLib.res|} + +let help = + {|ReScript Tools + +Usage: rescript-tools [command] + +Commands: + +doc Generate documentation +reanalyze Reanalyze +-v, --version Print version +-h, --help Print help|} + +let logAndExit = function + | Ok log -> + Printf.printf "%s\n" log; + exit 0 + | Error log -> + Printf.eprintf "%s\n" log; + exit 1 + +let version = Version.version + +let main () = + match Sys.argv |> Array.to_list |> List.tl with + | "doc" :: rest -> ( + match rest with + | ["-h"] | ["--help"] -> logAndExit (Ok docHelp) + | [path] -> + (* NOTE: Internal use to generate docs from compiler *) + let () = + match Sys.getenv_opt "FROM_COMPILER" with + | Some "true" -> Analysis.Cfg.isDocGenFromCompiler := true + | _ -> () + in + logAndExit (Tools.extractDocs ~path ~debug:false) + | _ -> logAndExit (Error docHelp)) + | "reanalyze" :: _ -> + let len = Array.length Sys.argv in + for i = 1 to len - 2 do + Sys.argv.(i) <- Sys.argv.(i + 1) + done; + Sys.argv.(len - 1) <- ""; + Reanalyze.cli () + | ["-h"] | ["--help"] -> logAndExit (Ok help) + | ["-v"] | ["--version"] -> logAndExit (Ok version) + | _ -> logAndExit (Error help) + +let () = main () diff --git a/tools/bin/version.ml b/tools/bin/version.ml new file mode 100644 index 000000000..36ca949bb --- /dev/null +++ b/tools/bin/version.ml @@ -0,0 +1 @@ +let version = "0.3.0" \ No newline at end of file diff --git a/tools/analysis_binaries/.gitkeep b/tools/binaries/.gitkeep similarity index 100% rename from tools/analysis_binaries/.gitkeep rename to tools/binaries/.gitkeep diff --git a/tools/src/RescriptTools.res b/tools/npm/RescriptTools.res similarity index 100% rename from tools/src/RescriptTools.res rename to tools/npm/RescriptTools.res diff --git a/tools/src/Tools_Docgen.res b/tools/npm/Tools_Docgen.res similarity index 100% rename from tools/src/Tools_Docgen.res rename to tools/npm/Tools_Docgen.res diff --git a/tools/src/Tools_Docgen.resi b/tools/npm/Tools_Docgen.resi similarity index 100% rename from tools/src/Tools_Docgen.resi rename to tools/npm/Tools_Docgen.resi diff --git a/tools/npm/cli.js b/tools/npm/cli.js new file mode 100755 index 000000000..7f3dc4312 --- /dev/null +++ b/tools/npm/cli.js @@ -0,0 +1,19 @@ +#!/usr/bin/env node +//@ts-check +"use strict"; + +const child_process = require("child_process"); +const path = require("path"); + +const platformArch = + process.arch === "x64" ? process.platform : process.platform + process.arch; + +const binPath = path.join(__dirname, "..", "binaries", platformArch, "rescript-tools.exe"); + +const args = process.argv.slice(2); + +const spawn = child_process.spawnSync(binPath, args, { stdio: "inherit" }); + +if (spawn.status != null) { + process.exit(spawn.status) +} diff --git a/tools/package-lock.json b/tools/package-lock.json index 4827c4dc8..c56dd869f 100644 --- a/tools/package-lock.json +++ b/tools/package-lock.json @@ -12,7 +12,7 @@ "rescript": "^11.0.0-rc.7" }, "bin": { - "rescript-tools": "src/Cli.bs.js" + "rescript-tools": "npm/cli.js" }, "engines": { "node": "*" diff --git a/tools/package.json b/tools/package.json index 749d31245..1cc59028f 100644 --- a/tools/package.json +++ b/tools/package.json @@ -5,7 +5,7 @@ "author": "ReScript Team", "license": "MIT", "bin": { - "rescript-tools": "./src/Cli.bs.js" + "rescript-tools": "npm/cli.js" }, "keywords": [ "ReScript", @@ -13,10 +13,10 @@ "Docgen" ], "files": [ - "src/Cli.bs.js", - "src/*.res", - "src/*.resi", - "analysis_binaries/", + "npm/cli.js", + "npm/*.res", + "npm/*.resi", + "binaries", "rescript.json", "README.md" ], diff --git a/tools/rescript.json b/tools/rescript.json index 3673429fe..8917b16ec 100644 --- a/tools/rescript.json +++ b/tools/rescript.json @@ -1,9 +1,9 @@ { "name": "@rescript/tools", - "version": "0.2.0", + "version": "0.3.0", "sources": [ { - "dir": "src" + "dir": "npm" } ], "suffix": ".bs.js", diff --git a/tools/src/Cli.res b/tools/src/Cli.res deleted file mode 100644 index 6e17a0851..000000000 --- a/tools/src/Cli.res +++ /dev/null @@ -1,92 +0,0 @@ -@@directive("#!/usr/bin/env node") - -@module("fs") external readFileSync: string => string = "readFileSync" -@variadic @module("path") external join: array => string = "join" -@module("path") external dirname: string => string = "dirname" -@val external __dirname: string = "__dirname" - -type processEnvOptions = {stdio?: string} -type spawnSyncResult = {status: Js.Null.t} - -@module("child_process") -external spawnSync: (string, array, option) => spawnSyncResult = - "spawnSync" - -@val @scope("process") -external exit: int => unit = "exit" - -@val -external process: {"arch": string, "platform": string, "argv": array} = "process" - -let argv = process["argv"] - -let args = argv->Js.Array2.slice(~start=2, ~end_=Js.Array2.length(argv)) - -let platformDir = - process["arch"] === "arm64" ? process["platform"] ++ process["arch"] : process["platform"] - -let analysisProdPath = join([ - dirname(__dirname), - "analysis_binaries", - platformDir, - "rescript-editor-analysis.exe", -]) - -let docHelp = `ReScript Tools - -Output documentation to standard output - -Usage: rescript-tools doc - -Example: rescript-tools doc ./path/to/EntryPointLib.res` - -let help = `ReScript Tools - -Usage: rescript-tools [command] - -Commands: - -doc Generate documentation -reanalyze Reanalyze --v, --version Print version --h, --help Print help` - -let logAndExit = (~log, ~code) => { - Js.log(log) - exit(code) -} - -switch args->Belt.List.fromArray { -| list{"doc", ...rest} => - switch rest { - | list{"-h" | "--help"} => logAndExit(~log=docHelp, ~code=0) - | list{filePath} => - let spawn = spawnSync(analysisProdPath, ["extractDocs", filePath], Some({stdio: "inherit"})) - - switch spawn.status->Js.Null.toOption { - | Some(code) => exit(code) - | None => () - } - | _ => logAndExit(~log=docHelp, ~code=1) - } -| list{"reanalyze", ...rest} => - let args = ["reanalyze"]->Js.Array2.concat(Belt.List.toArray(rest)) - let spawn = spawnSync(analysisProdPath, args, Some({stdio: "inherit"})) - - switch spawn.status->Js.Null.toOption { - | Some(code) => exit(code) - | None => () - } -| list{"-h" | "--help"} => logAndExit(~log=help, ~code=0) -| list{"-v" | "--version"} => - let packageJson = join([__dirname, "..", "package.json"]) - switch readFileSync(packageJson)->Js.Json.parseExn->Js.Json.decodeObject { - | None => logAndExit(~log="error: failed to find version in package.json", ~code=1) - | Some(dict) => - switch dict->Js.Dict.get("version") { - | Some(version) => logAndExit(~log=version, ~code=0) - | None => logAndExit(~log="error: failed to find version in package.json", ~code=1) - } - } -| _ => logAndExit(~log=help, ~code=1) -} diff --git a/tools/src/Cli.resi b/tools/src/Cli.resi deleted file mode 100644 index 8b1378917..000000000 --- a/tools/src/Cli.resi +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tools/src/dune b/tools/src/dune new file mode 100644 index 000000000..f124a3737 --- /dev/null +++ b/tools/src/dune @@ -0,0 +1,5 @@ +(library + (name tools) + (flags + (-w "+6+26+27+32+33+39")) + (libraries analysis)) diff --git a/analysis/src/DocExtraction.ml b/tools/src/tools.ml similarity index 62% rename from analysis/src/DocExtraction.ml rename to tools/src/tools.ml index 59320d94a..d0996ca77 100644 --- a/analysis/src/DocExtraction.ml +++ b/tools/src/tools.ml @@ -1,3 +1,5 @@ +open Analysis + type fieldDoc = { fieldName: string; docstrings: string list; @@ -143,8 +145,7 @@ let rec stringifyDocItem ?(indentation = 0) ~originalEnv (item : docItem) = match deprecated with | Some d -> Some (wrapInQuotes d) | None -> None ); - ( "signature", - Some (signature |> String.trim |> wrapInQuotes) ); + ("signature", Some (signature |> String.trim |> wrapInQuotes)); ("docstrings", Some (stringifyDocstrings docstring)); ] | Type {id; docstring; signature; name; deprecated; detail} -> @@ -254,113 +255,125 @@ let makeId modulePath ~identifier = let extractDocs ~path ~debug = if debug then Printf.printf "extracting docs for %s\n" path; - if - FindFiles.isImplementation path = false - && FindFiles.isInterface path = false - then ( - Printf.eprintf "error: failed to read %s, expected an .res or .resi file\n" - path; - exit 1); - let path = - if FindFiles.isImplementation path then - let pathAsResi = - (path |> Filename.dirname) ^ "/" - ^ (path |> Filename.basename |> Filename.chop_extension) - ^ ".resi" + let result = + match + FindFiles.isImplementation path = false + && FindFiles.isInterface path = false + with + | false -> ( + let path = + if FindFiles.isImplementation path then + let pathAsResi = + (path |> Filename.dirname) ^ "/" + ^ (path |> Filename.basename |> Filename.chop_extension) + ^ ".resi" + in + if Sys.file_exists pathAsResi then ( + if debug then + Printf.printf "preferring found resi file for impl: %s\n" + pathAsResi; + pathAsResi) + else path + else path in - if Sys.file_exists pathAsResi then ( - if debug then - Printf.printf "preferring found resi file for impl: %s\n" pathAsResi; - pathAsResi) - else path - else path - in - match Cmt.loadFullCmtFromPath ~path with - | None -> - Printf.eprintf - "error: failed to generate doc for %s, try to build the project\n" path; - exit 1 - | Some full -> - let file = full.file in - let structure = file.structure in - let open SharedTypes in - let env = QueryEnv.fromFile file in - let rec extractDocsForModule ?(modulePath = [env.file.moduleName]) - (structure : Module.structure) = - { - id = modulePath |> List.rev |> ident; - docstring = structure.docstring |> List.map String.trim; - name = structure.name; - deprecated = structure.deprecated; - items = - structure.items - |> List.filter_map (fun (item : Module.item) -> - match item.kind with - | Value typ -> - Some - (Value - { - id = modulePath |> makeId ~identifier:item.name; - docstring = item.docstring |> List.map String.trim; - signature = - "let " ^ item.name ^ ": " ^ Shared.typeToString typ; - name = item.name; - deprecated = item.deprecated; - }) - | Type (typ, _) -> - Some - (Type - { - id = modulePath |> makeId ~identifier:item.name; - docstring = item.docstring |> List.map String.trim; - signature = typ.decl |> Shared.declToString item.name; - name = item.name; - deprecated = item.deprecated; - detail = typeDetail typ ~full ~env; - }) - | Module (Ident p) -> - (* module Whatever = OtherModule *) - let aliasToModule = p |> pathIdentToString in - let id = - (modulePath |> List.rev |> List.hd) ^ "." ^ item.name - in - let items, internalDocstrings = - match - ProcessCmt.fileForModule ~package:full.package - aliasToModule - with - | None -> ([], []) - | Some file -> - let docs = - extractDocsForModule ~modulePath:[id] file.structure + match Cmt.loadFullCmtFromPath ~path with + | None -> + Error + (Printf.sprintf + "error: failed to generate doc for %s, try to build the project" + path) + | Some full -> + let file = full.file in + let structure = file.structure in + let open SharedTypes in + let env = QueryEnv.fromFile file in + let rec extractDocsForModule ?(modulePath = [env.file.moduleName]) + (structure : Module.structure) = + { + id = modulePath |> List.rev |> ident; + docstring = structure.docstring |> List.map String.trim; + name = structure.name; + deprecated = structure.deprecated; + items = + structure.items + |> List.filter_map (fun (item : Module.item) -> + match item.kind with + | Value typ -> + Some + (Value + { + id = modulePath |> makeId ~identifier:item.name; + docstring = item.docstring |> List.map String.trim; + signature = + "let " ^ item.name ^ ": " + ^ Shared.typeToString typ; + name = item.name; + deprecated = item.deprecated; + }) + | Type (typ, _) -> + Some + (Type + { + id = modulePath |> makeId ~identifier:item.name; + docstring = item.docstring |> List.map String.trim; + signature = + typ.decl |> Shared.declToString item.name; + name = item.name; + deprecated = item.deprecated; + detail = typeDetail typ ~full ~env; + }) + | Module (Ident p) -> + (* module Whatever = OtherModule *) + let aliasToModule = p |> pathIdentToString in + let id = + (modulePath |> List.rev |> List.hd) ^ "." ^ item.name + in + let items, internalDocstrings = + match + ProcessCmt.fileForModule ~package:full.package + aliasToModule + with + | None -> ([], []) + | Some file -> + let docs = + extractDocsForModule ~modulePath:[id] + file.structure + in + (docs.items, docs.docstring) in - (docs.items, docs.docstring) - in - Some - (ModuleAlias - { - id; - name = item.name; - items; - docstring = - item.docstring @ internalDocstrings - |> List.map String.trim; - }) - | Module (Structure m) -> - (* module Whatever = {} in res or module Whatever: {} in resi. *) - Some - (Module - (extractDocsForModule ~modulePath:(m.name :: modulePath) - m)) - | Module (Constraint (Structure _impl, Structure interface)) -> - (* module Whatever: { } = { }. Prefer the interface. *) - Some - (Module - (extractDocsForModule - ~modulePath:(interface.name :: modulePath) - interface)) - | _ -> None); - } - in - let docs = extractDocsForModule structure in - print_endline (stringifyDocsForModule ~originalEnv:env docs) + Some + (ModuleAlias + { + id; + name = item.name; + items; + docstring = + item.docstring @ internalDocstrings + |> List.map String.trim; + }) + | Module (Structure m) -> + (* module Whatever = {} in res or module Whatever: {} in resi. *) + Some + (Module + (extractDocsForModule + ~modulePath:(m.name :: modulePath) m)) + | Module + (Constraint (Structure _impl, Structure interface)) -> + (* module Whatever: { } = { }. Prefer the interface. *) + Some + (Module + (extractDocsForModule + ~modulePath:(interface.name :: modulePath) + interface)) + | _ -> None); + } + in + let docs = extractDocsForModule structure in + Ok (stringifyDocsForModule ~originalEnv:env docs)) + | true -> + Error + (Printf.sprintf + "error: failed to read %s, expected an .res or .resi file" path) + in + + result diff --git a/tools/tests/Makefile b/tools/tests/Makefile new file mode 100644 index 000000000..5084c67ab --- /dev/null +++ b/tools/tests/Makefile @@ -0,0 +1,17 @@ +SHELL = /bin/bash + +node_modules/.bin/rescript: + npm install + +build: node_modules/.bin/rescript + node_modules/.bin/rescript + +test: build + ./test.sh + +clean: + rm -r node_modules lib + +.DEFAULT_GOAL := test + +.PHONY: clean test diff --git a/tools/tests/package-lock.json b/tools/tests/package-lock.json new file mode 100644 index 000000000..41294271a --- /dev/null +++ b/tools/tests/package-lock.json @@ -0,0 +1,92 @@ +{ + "name": "docstrings-test", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "docstrings-test", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@rescript/react": "^0.12.0-alpha.3", + "rescript": "^11.0.0" + } + }, + "node_modules/@rescript/react": { + "version": "0.12.0-alpha.3", + "resolved": "https://registry.npmjs.org/@rescript/react/-/react-0.12.0-alpha.3.tgz", + "integrity": "sha512-/S1uj77RPDzuLg3Ofb8KKU3Vppqy97/vF6bBdBZ+saIO9bpHVlsmmJyJG8QXjGZKE+aMynrrR3Tj4+9+5OzLdw==", + "peerDependencies": { + "react": ">=18.0.0", + "react-dom": ">=18.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/rescript": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/rescript/-/rescript-11.0.0.tgz", + "integrity": "sha512-uIUwDZZmDUb7ymGkBiiGioxMg8hXh1mze/2k/qhYQcZGgi7PrLHQIW9AksM7gb9WnpjCAvFsA8U2VgC0nA468w==", + "hasInstallScript": true, + "bin": { + "bsc": "bsc", + "bstracing": "lib/bstracing", + "rescript": "rescript" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + } + } +} diff --git a/tools/tests/package.json b/tools/tests/package.json new file mode 100644 index 000000000..e8b109e4a --- /dev/null +++ b/tools/tests/package.json @@ -0,0 +1,18 @@ +{ + "name": "docstrings-test", + "version": "0.0.0", + "scripts": { + "res:build": "rescript", + "res:clean": "rescript clean", + "res:dev": "rescript -w" + }, + "keywords": [ + "rescript" + ], + "author": "", + "license": "MIT", + "dependencies": { + "@rescript/react": "^0.12.0-alpha.3", + "rescript": "^11.0.0" + } +} diff --git a/tools/tests/rescript.json b/tools/tests/rescript.json new file mode 100644 index 000000000..c7968f1bf --- /dev/null +++ b/tools/tests/rescript.json @@ -0,0 +1,13 @@ +{ + "name": "docstrings-test", + "sources": { + "dir": "src", + "subdirs": true + }, + "package-specs": { + "module": "commonjs", + "in-source": true + }, + "suffix": ".res.js", + "bs-dependencies": ["@rescript/react"] +} diff --git a/analysis/tests/src/DocExtraction2.res b/tools/tests/src/DocExtraction2.res similarity index 100% rename from analysis/tests/src/DocExtraction2.res rename to tools/tests/src/DocExtraction2.res diff --git a/analysis/tests/src/DocExtraction2.resi b/tools/tests/src/DocExtraction2.resi similarity index 100% rename from analysis/tests/src/DocExtraction2.resi rename to tools/tests/src/DocExtraction2.resi diff --git a/analysis/tests/src/DocExtractionRes.res b/tools/tests/src/DocExtractionRes.res similarity index 100% rename from analysis/tests/src/DocExtractionRes.res rename to tools/tests/src/DocExtractionRes.res diff --git a/tools/tests/src/expected/DocExtraction2.res.json b/tools/tests/src/expected/DocExtraction2.res.json new file mode 100644 index 000000000..06467b54c --- /dev/null +++ b/tools/tests/src/expected/DocExtraction2.res.json @@ -0,0 +1,41 @@ + +{ + "name": "DocExtraction2", + "docstrings": ["Module level doc here."], + "items": [ + { + "id": "DocExtraction2.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["Type t is pretty cool."] + }, + { + "id": "DocExtraction2.make", + "kind": "value", + "name": "make", + "signature": "let make: (. unit) => t", + "docstrings": ["Makerz of stuffz."] + }, + { + "id": "DocExtraction2.InnerModule", + "name": "InnerModule", + "kind": "module", + "docstrings": [], + "items": [ + { + "id": "DocExtraction2.InnerModule.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."] + }, + { + "id": "DocExtraction2.InnerModule.make", + "kind": "value", + "name": "make", + "signature": "let make: (. unit) => t", + "docstrings": ["Maker of tea."] + }] + }] +} diff --git a/tools/tests/src/expected/DocExtraction2.resi.json b/tools/tests/src/expected/DocExtraction2.resi.json new file mode 100644 index 000000000..06467b54c --- /dev/null +++ b/tools/tests/src/expected/DocExtraction2.resi.json @@ -0,0 +1,41 @@ + +{ + "name": "DocExtraction2", + "docstrings": ["Module level doc here."], + "items": [ + { + "id": "DocExtraction2.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["Type t is pretty cool."] + }, + { + "id": "DocExtraction2.make", + "kind": "value", + "name": "make", + "signature": "let make: (. unit) => t", + "docstrings": ["Makerz of stuffz."] + }, + { + "id": "DocExtraction2.InnerModule", + "name": "InnerModule", + "kind": "module", + "docstrings": [], + "items": [ + { + "id": "DocExtraction2.InnerModule.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["This type is also t."] + }, + { + "id": "DocExtraction2.InnerModule.make", + "kind": "value", + "name": "make", + "signature": "let make: (. unit) => t", + "docstrings": ["Maker of tea."] + }] + }] +} diff --git a/tools/tests/src/expected/DocExtractionRes.res.json b/tools/tests/src/expected/DocExtractionRes.res.json new file mode 100644 index 000000000..c31159024 --- /dev/null +++ b/tools/tests/src/expected/DocExtractionRes.res.json @@ -0,0 +1,184 @@ + +{ + "name": "DocExtractionRes", + "docstrings": ["Module level documentation goes here."], + "items": [ + { + "id": "DocExtractionRes.t", + "kind": "type", + "name": "t", + "signature": "type t = {name: string, online: bool}", + "docstrings": ["This type represents stuff."], + "detail": + { + "kind": "record", + "items": [{ + "name": "name", + "optional": false, + "docstrings": ["The name of the stuff."], + "signature": "string" + }, { + "name": "online", + "optional": false, + "docstrings": ["Whether stuff is online."], + "signature": "bool" + }] + } + }, + { + "id": "DocExtractionRes.make", + "kind": "value", + "name": "make", + "signature": "let make: (. string) => t", + "docstrings": ["Create stuff.\n\n```rescript example\nlet stuff = make(\"My name\")\n```"] + }, + { + "id": "DocExtractionRes.asOffline", + "kind": "value", + "name": "asOffline", + "signature": "let asOffline: (. t) => t", + "docstrings": ["Stuff goes offline."] + }, + { + "id": "DocExtractionRes.SomeConstant\\", + "kind": "value", + "name": "SomeConstant\\", + "signature": "let SomeConstant\\: int", + "docstrings": ["exotic identifier"] + }, + { + "id": "DocExtractionRes.SomeInnerModule", + "name": "SomeInnerModule", + "kind": "module", + "docstrings": ["Another module level docstring here."], + "items": [ + { + "id": "DocExtractionRes.SomeInnerModule.status", + "kind": "type", + "name": "status", + "signature": "type status = Started(t) | Stopped | Idle", + "docstrings": [], + "detail": + { + "kind": "variant", + "items": [ + { + "name": "Started", + "docstrings": ["If this is started or not"], + "signature": "Started(t)" + }, + { + "name": "Stopped", + "docstrings": ["Stopped?"], + "signature": "Stopped" + }, + { + "name": "Idle", + "docstrings": ["Now idle."], + "signature": "Idle" + }] + } + }, + { + "id": "DocExtractionRes.SomeInnerModule.validInputs", + "kind": "type", + "name": "validInputs", + "signature": "type validInputs = [\n | #\"needs-escaping\"\n | #something\n | #status(status)\n | #withPayload(int)\n]", + "docstrings": ["These are all the valid inputs."] + }, + { + "id": "DocExtractionRes.SomeInnerModule.callback", + "kind": "type", + "name": "callback", + "signature": "type callback = (. t, ~status: status) => unit", + "docstrings": [] + }] + }, + { + "id": "DocExtractionRes.AnotherModule", + "name": "AnotherModule", + "kind": "module", + "docstrings": ["Mighty fine module here too!"], + "items": [ + { + "id": "DocExtractionRes.LinkedModule", + "kind": "moduleAlias", + "name": "LinkedModule", + "docstrings": ["This links another module. Neat."], + "items": [] + }, + { + "id": "DocExtractionRes.AnotherModule.callback", + "kind": "type", + "name": "callback", + "signature": "type callback = (. SomeInnerModule.status) => unit", + "docstrings": ["Testing what this looks like."] + }, + { + "id": "DocExtractionRes.AnotherModule.isGoodStatus", + "kind": "value", + "name": "isGoodStatus", + "signature": "let isGoodStatus: (. SomeInnerModule.status) => bool", + "docstrings": [] + }, + { + "id": "DocExtractionRes.AnotherModule.someVariantWithInlineRecords", + "kind": "type", + "name": "someVariantWithInlineRecords", + "signature": "type someVariantWithInlineRecords =\n | SomeStuff({offline: bool, online?: bool})", + "docstrings": ["Trying how it looks with an inline record in a variant."], + "detail": + { + "kind": "variant", + "items": [ + { + "name": "SomeStuff", + "docstrings": ["This has inline records..."], + "signature": "SomeStuff({offline: bool, online?: bool})", + "payload": { + "kind": "inlineRecord", + "fields": [{ + "name": "offline", + "optional": false, + "docstrings": [], + "signature": "bool" + }, { + "name": "online", + "optional": true, + "docstrings": ["Is the user online?"], + "signature": "option" + }] + } + }] + } + }, + { + "id": "DocExtractionRes.AnotherModule.domRoot", + "kind": "type", + "name": "domRoot", + "signature": "type domRoot = (. unit) => ReactDOM.Client.Root.t", + "docstrings": ["Callback to get the DOM root..."] + }] + }, + { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported", + "name": "ModuleWithThingsThatShouldNotBeExported", + "kind": "module", + "docstrings": [], + "items": [ + { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.t", + "kind": "type", + "name": "t", + "signature": "type t", + "docstrings": ["The type t is stuff."] + }, + { + "id": "DocExtractionRes.ModuleWithThingsThatShouldNotBeExported.make", + "kind": "value", + "name": "make", + "signature": "let make: (. unit) => t", + "docstrings": ["The maker of stuff!"] + }] + }] +} diff --git a/tools/tests/test.sh b/tools/tests/test.sh new file mode 100755 index 000000000..4a002d8f1 --- /dev/null +++ b/tools/tests/test.sh @@ -0,0 +1,21 @@ +for file in src/*.{res,resi}; do + output="$(dirname $file)/expected/$(basename $file).json" + dune exec --no-print-directory -- rescript-tools doc $file > $output + # # CI. We use LF, and the CI OCaml fork prints CRLF. Convert. + if [ "$RUNNER_OS" == "Windows" ]; then + perl -pi -e 's/\r\n/\n/g' -- $output + fi +done + +warningYellow='\033[0;33m' +successGreen='\033[0;32m' +reset='\033[0m' + +diff=$(git ls-files --modified src/expected) +if [[ $diff = "" ]]; then + printf "${successGreen}✅ No unstaged tests difference.${reset}\n" +else + printf "${warningYellow}⚠️ There are unstaged differences in tests/! Did you break a test?\n${diff}\n${reset}" + git --no-pager diff src/expected + exit 1 +fi