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
-- 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