From a4dec944bc821d114bfd82debb72d60bd04f836d Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Mon, 11 Feb 2019 17:41:13 -0500 Subject: [PATCH] web design (#1728) --- .github/CONTRIBUTING.md | 98 ----- .github/PULL_REQUEST_TEMPLATE.md | 2 +- Docs.md | 440 +-------------------- README.md | 86 +--- Roadmap.md | 61 --- tools/format.ts | 2 +- website/README.md | 32 -- website/all_benchmark.html | 44 --- website/app.js | 4 +- website/benchmarks.html | 137 +++++++ website/index.html | 220 +++-------- website/manifest.json | 13 - website/manual.html | 40 ++ website/manual.md | 656 +++++++++++++++++++++++++++++++ website/schematic_v0.2.png | Bin 0 -> 58275 bytes website/showdown_toc.js | 142 +++++++ website/style.css | 97 +++-- website/style_guide.html | 40 ++ website/style_guide.md | 264 +++++++++++++ website/welcome.js | 1 + 20 files changed, 1407 insertions(+), 972 deletions(-) delete mode 100644 .github/CONTRIBUTING.md delete mode 100644 Roadmap.md delete mode 100644 website/README.md delete mode 100644 website/all_benchmark.html create mode 100644 website/benchmarks.html delete mode 100644 website/manifest.json create mode 100644 website/manual.html create mode 100644 website/manual.md create mode 100644 website/schematic_v0.2.png create mode 100644 website/showdown_toc.js create mode 100644 website/style_guide.html create mode 100644 website/style_guide.md create mode 100644 website/welcome.js diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index dac3f372b5..0000000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1,98 +0,0 @@ -# Contributing To Deno - -Check [the roadmap](https://github.com/denoland/deno/blob/master/Roadmap.md) -before contributing. - -Please don't make [the benchmarks](https://denoland.github.io/deno/) worse. - -Ask for help in the issues or on the -[chat room](https://gitter.im/denolife/Lobby). - -Progress towards future releases is tracked -[here](https://github.com/denoland/deno/milestones). - -Docs are [here](https://github.com/denoland/deno/blob/master/Docs.md). - -## Submitting a pull request - -Before submitting, please make sure the following is done: - -1. There are tests that cover the changes. -2. Ensure `./tools/test.py` passes. -3. Format your code with `PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run`. - -4. Make sure `./tools/lint.py` passes. - -## Changes to `third_party` - -Changes to `third_party` including any changes in the `package.json` will impact -the [denoland/deno_third_party](https://github.com/denoland/deno_third_party) -repository as well. - -## Adding Ops (aka bindings) - -We are very concerned about making mistakes when adding new APIs. When adding an -Op to Deno, the counterpart interfaces on other platforms should be researched. -Please list how this functionality is done in Go, Node, Rust, and Python. - -As an example, see how `deno.rename()` was proposed and added in -[PR #671](https://github.com/denoland/deno/pull/671). - -## Documenting APIs - -It is important to document public APIs and we want to do that inline with the -code. This helps ensure that code and documentation are tightly coupled -together. - -### Utilize JSDoc - -All publicly exposed APIs and types, both via the `deno` module as well as the -global/`window` namespace should have JSDoc documentation. This documentation is -parsed and available to the TypeScript compiler, and therefore easy to provide -further downstream. JSDoc blocks come just prior to the statement they apply to -and are denoted by a leading `/**` before terminating with a `*/`. For example: - -```ts -/** A simple JSDoc comment */ -export const FOO = "foo"; -``` - -### JSDoc style guide - -- It is important that documentation is easily human readable, but there is also - a need to provide additional styling information to ensure generated - documentation is more rich text. Therefore JSDoc should generally follow - markdown markup to enrich the text. -- While markdown supports HTML tags, it is forbidden in JSDoc blocks. -- Code string literals should be braced with the back-tick (\`) instead of - quotes. For example: - ```ts - /** Import something from the `deno` module. */ - ``` -- Do not document function arguments unless they are non-obvious of their intent - (though if they are non-obvious intent, the API should be considered anyways). - Therefore `@param` should generally not be used. -- Vertical spacing should be minimized whenever possible. Therefore single line - comments should be written as: - ```ts - /** This is a good single line JSDoc */ - ``` - And not: - ```ts - /** - * This is a bad single line JSDoc - */ - ``` -- Code examples should not utilise the triple-back tick (\`\`\`) notation or - tags. They should just be marked by indentation, which requires a break before - the block and 6 additional spaces for each line of the example. This is 4 more - than the first column of the comment. For example: - ```ts - /** A straight forward comment and an example: - * - * import { foo } from "deno"; - * foo("bar"); - */ - ``` -- Code examples should not contain additional comments. It is already inside a - comment. If it needs further comments is not a good example. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 427ca16c93..6b5df61827 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,3 +1,3 @@ diff --git a/Docs.md b/Docs.md index e0d732bc30..f038b411a1 100644 --- a/Docs.md +++ b/Docs.md @@ -1,439 +1 @@ -# Deno Documentation - -## Disclaimer - -A word of caution: Deno is very much under development. We encourage brave early -adopters, but expect bugs large and small. The API is subject to change without -notice. - -[Bug reports](https://github.com/denoland/deno/issues) do help! - -## Install - -Deno works on OSX, Linux, and Windows. Deno is a single binary executable. It -has no external dependencies. - -[deno_install](https://github.com/denoland/deno_install) provides convenience -scripts to download and install the binary. - -Using Shell: - -``` -curl -fL https://deno.land/x/install/install.sh | sh -``` - -Or using PowerShell: - -```powershell -iex (iwr https://deno.land/x/install/install.ps1) -``` - -_Note: Depending on your security settings, you may have to run -`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded -scripts to be executed._ - -With [Scoop](https://scoop.sh/): - -``` -scoop install deno -``` - -Deno can also be installed manually, by downloading a tarball or zip file at -[github.com/denoland/deno/releases](https://github.com/denoland/deno/releases). -These packages contain just a single executable file. You will have to set the -executable bit on Mac and Linux. - -Try it: - -``` -> deno https://deno.land/thumb.ts -``` - -## API Reference - -To get an exact reference of deno's runtime API, run the following in the -command line: - -``` -> deno --types -``` - -Or see the [doc website](https://deno.land/typedoc/index.html). - -If you are embedding deno in a Rust program, see -[the rust docs](https://deno.land/rustdoc/deno/index.html). - -## Build Instructions - -### Prerequisites: - -To ensure reproducible builds, deno has most of its dependencies in a git -submodule. However, you need to install separately: - -1. [Rust](https://www.rust-lang.org/en-US/install.html) >= 1.31.1 -2. [Node](https://nodejs.org/) -3. Python 2. - [Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578). - -Extra steps for Mac users: - -1. [XCode](https://developer.apple.com/xcode/) -2. Openssl 1.1: `brew install openssl@1.1` (TODO: shouldn't be necessary) - -Extra steps for Windows users: - -1. Add `python.exe` to `PATH` (e.g. `set PATH=%PATH%;C:\Python27\python.exe`) -2. Get [VS Community 2017](https://www.visualstudio.com/downloads/) with - `Desktop development with C++` toolkit and make sure to select the following - required tools listed below along with all C++ tools. - - Windows 10 SDK >= 10.0.17134 - - Visual C++ ATL for x86 and x64 - - Visual C++ MFC for x86 and x64 - - C++ profiling tools -3. Enable `Debugging Tools for Windows`. Go to `Control Panel` → `Programs` → - `Programs and Features` → Select - `Windows Software Development Kit - Windows 10` → `Change` → `Change` → Check - `Debugging Tools For Windows` → `Change` -> `Finish`. - -### Build: - - # Fetch deps. - git clone --recurse-submodules https://github.com/denoland/deno.git - cd deno - ./tools/setup.py - - # You may need to ensure that sccache is running. - # (TODO it's unclear if this is necessary or not.) - # prebuilt/mac/sccache --start-server - - # Build. - ./tools/build.py - - # Run. - ./target/debug/deno tests/002_hello.ts - - # Test. - ./tools/test.py - - # Format code. - PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run - - -Other useful commands: - - # Call ninja manually. - ./third_party/depot_tools/ninja -C target/debug - - # Build a release binary. - DENO_BUILD_MODE=release ./tools/build.py :deno - - # List executable targets. - ./third_party/depot_tools/gn ls target/debug //:* --as=output --type=executable - - # List build configuration. - ./third_party/depot_tools/gn args target/debug/ --list - - # Edit build configuration. - ./third_party/depot_tools/gn args target/debug/ - - # Describe a target. - ./third_party/depot_tools/gn desc target/debug/ :deno - ./third_party/depot_tools/gn help - - # Update third_party modules - git submodule update - -Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`, -`DENO_DIR`. - -## Tutorial - -### An implementation of the unix "cat" program - -In this program each command-line argument is assumed to be a filename, the file -is opened, and printed to stdout. - -```ts -import * as deno from "deno"; - -(async () => { - for (let i = 1; i < deno.args.length; i++) { - let filename = deno.args[i]; - let file = await deno.open(filename); - await deno.copy(deno.stdout, file); - file.close(); - } -})(); -``` - -The `copy()` function here actually makes no more than the necessary kernel -> -userspace -> kernel copies. That is, the same memory from which data is read -from the file, is written to stdout. This illustrates a general design goal for -I/O streams in Deno. - -Try the program: - -``` -> deno https://deno.land/x/examples/cat.ts /etc/passwd -``` - -### TCP echo server - -This is an example of a simple server which accepts connections on port 8080, -and returns to the client anything it sends. - -```ts -import { listen, copy } from "deno"; - -(async () => { - const addr = "0.0.0.0:8080"; - const listener = listen("tcp", addr); - console.log("listening on", addr); - while (true) { - const conn = await listener.accept(); - copy(conn, conn); - } -})(); -``` - -When this program is started, the user is prompted for permission to listen on -the network: - -``` -> deno https://deno.land/x/examples/echo_server.ts -⚠️ Deno requests network access to "listen". Grant? [yN] y -listening on 0.0.0.0:8080 -``` - -For security reasons, deno does not allow programs to access the network without -explicit permission. To avoid the console prompt, use a command-line flag: - -``` -> deno https://deno.land/x/examples/echo_server.ts --allow-net -``` - -To test it, try sending a HTTP request to it by using curl. The request gets -written directly back to the client. - -``` -> curl http://localhost:8080/ -GET / HTTP/1.1 -Host: localhost:8080 -User-Agent: curl/7.54.0 -Accept: */* -``` - -It's worth noting that like the `cat.ts` example, the `copy()` function here -also does not make unnecessary memory copies. It receives a packet from the -kernel and sends back, without further complexity. - -### Linking to third party code - -In the above examples, we saw that Deno could execute scripts from URLs. Like -browser JavaScript, Deno can import libraries directly from URLs. This example -uses a URL to import a test runner library: - -```ts -import { test, assertEqual } from "https://deno.land/x/testing/mod.ts"; - -test(function t1() { - assertEqual("hello", "hello"); -}); - -test(function t2() { - assertEqual("world", "world"); -}); -``` - -Try running this: - -``` -> deno https://deno.land/x/examples/example_test.ts -Compiling /Users/rld/src/deno_examples/example_test.ts -Downloading https://deno.land/x/testing/mod.ts -Compiling https://deno.land/x/testing/mod.ts -running 2 tests -test t1 -... ok -test t2 -... ok - -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -``` - -Note that we did not have to provide the `--allow-net` flag for this program, -and yet it accessed the network. The runtime has special access to download -imports and cache them to disk. - -Deno caches remote imports in a special directory specified by the `$DENO_DIR` -environmental variable. It default to `$HOME/.deno` if `$DENO_DIR` is not -specified. The next time you run the program, no downloads will be made. If the -program hasn't changed, it won't be recompiled either. - -**But what if `https://deno.land/` goes down?** Relying on external servers is -convenient for development but brittle in production. Production software should -always bundle its dependencies. In Deno this is done by checking the `$DENO_DIR` -into your source control system, and specifying that path as the `$DENO_DIR` -environmental variable at runtime. - -**How do you import to a specific version?** Simply specify the version in the -URL. For example, this URL fully specifies the code being run: -`https://unpkg.com/liltest@0.0.5/dist/liltest.js`. Combined with the -aforementioned technique of setting `$DENO_DIR` in production to stored code, -one can fully specify the exact code being run, and execute the code without -network access. - -**It seems unwieldy to import URLs everywhere. What if one of the URLs links to -a subtly different version of a library? Isn't it error prone to maintain URLs -everywhere in a large project?** The solution is to import and re-export your -external libraries in a central `package.ts` file (which serves the same purpose -as Node's `package.json` file). For example, let's say you were using the above -testing library across a large project. Rather than importing -`"https://deno.land/x/testing/mod.ts"` everywhere, you could create a -`package.ts` file the exports the third-party code: - -```ts -export { test, assertEqual } from "https://deno.land/x/testing/mod.ts"; -``` - -And throughout project one can import from the `package.ts` and avoid having -many references to the same URL: - -```ts -import { test, assertEqual } from "./package.ts"; -``` - -This design circumvents a plethora of complexity spawned by package management -software, centralized code repositories, and superfluous file formats. - -## Environmental Variables - -There are several env vars that control how Deno behaves: - -`DENO_DIR` defaults to `$HOME/.deno` but can be set to any path to control where -generated and cached source code is written and read to. - -`NO_COLOR` will turn off color output if set. See https://no-color.org/. User -code can test if `NO_COLOR` was set without having `--allow-env` by using the -boolean constant `deno.noColor`. - -## Browser compatibility - -The subset of Deno programs which are written completely in JavaScript and do -not import the special `"deno"` module, ought to also be able to be run in a -modern web browser without change. - -## Useful command line flags - -V8 has many many command-line flags, that you can see with `--v8-options`. Here -are a few particularly useful ones: - -``` ---async-stack-traces -``` - -## How to Profile deno - -To start profiling, - -```sh -# Make sure we're only building release. -export DENO_BUILD_MODE=release -# Build deno and V8's d8. -./tools/build.py d8 deno -# Start the program we want to benchmark with --prof -./target/release/deno tests/http_bench.ts --allow-net --prof & -# Exercise it. -third_party/wrk/linux/wrk http://localhost:4500/ -kill `pgrep deno` -``` - -V8 will write a file in the current directory that looks like this: -`isolate-0x7fad98242400-v8.log`. To examine this file: - -```sh -D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor -isolate-0x7fad98242400-v8.log > prof.log -# on macOS, use ./third_party/v8/tools/mac-tick-processor instead -``` - -`prof.log` will contain information about tick distribution of different calls. - -To view the log with Web UI, generate JSON file of the log: - -```sh -D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor -isolate-0x7fad98242400-v8.log --preprocess > prof.json -``` - -Open `third_party/v8/tools/profview/index.html` in your brower, and select -`prof.json` to view the distribution graphically. - -To learn more about `d8` and profiling, check out the following links: - -- [https://v8.dev/docs/d8](https://v8.dev/docs/d8) -- [https://v8.dev/docs/profile](https://v8.dev/docs/profile) - -## How to Debug deno - -We can use LLDB to debug deno. - -```sh -lldb -- target/debug/deno tests/worker.js -> run -> bt -> up -> up -> l -``` - -To debug Rust code, we can use `rust-lldb`. It should come with `rustc` and is a -wrapper around LLDB. - -```sh -rust-lldb -- ./target/debug/deno tests/http_bench.ts --allow-net -# On macOS, you might get warnings like -# `ImportError: cannot import name _remove_dead_weakref` -# In that case, use system python by setting PATH, e.g. -# PATH=/System/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH -(lldb) command script import "/Users/kevinqian/.rustup/toolchains/1.30.0-x86_64-apple-darwin/lib/rustlib/etc/lldb_rust_formatters.py" -(lldb) type summary add --no-value --python-function lldb_rust_formatters.print_val -x ".*" --category Rust -(lldb) type category enable Rust -(lldb) target create "../deno/target/debug/deno" -Current executable set to '../deno/target/debug/deno' (x86_64). -(lldb) settings set -- target.run-args "tests/http_bench.ts" "--allow-net" -(lldb) b op_start -(lldb) r -``` - -## Internals - -### Internal: libdeno API. - -deno's privileged side will primarily be programmed in Rust. However there will -be a small C API that wraps V8 to 1) define the low-level message passing -semantics, 2) provide a low-level test target, 3) provide an ANSI C API binding -interface for Rust. V8 plus this C API is called "libdeno" and the important -bits of the API is specified here: -https://github.com/denoland/deno/blob/master/libdeno/deno.h -https://github.com/denoland/deno/blob/master/js/libdeno.ts - -### Internal: Flatbuffers provide shared data between Rust and V8 - -We use Flatbuffers to define common structs and enums between TypeScript and -Rust. These common data structures are defined in -https://github.com/denoland/deno/blob/master/src/msg.fbs - -### Internal: Updating prebuilt binaries - -``` -./third_party/depot_tools/upload_to_google_storage.py -b denoland \ - -e ~/.config/gcloud/legacy_credentials/ry@tinyclouds.org/.boto `which sccache` -mv `which sccache`.sha1 prebuilt/linux64/ -gsutil acl ch -u AllUsers:R gs://denoland/608be47bf01004aa11d4ed06955414e93934516e -``` - -## Contributing - -See -[CONTRIBUTING.md](https://github.com/denoland/deno/blob/master/.github/CONTRIBUTING.md). +Moved to https://deno.land/manual.html diff --git a/README.md b/README.md index 2638c53d40..3b74e910ed 100644 --- a/README.md +++ b/README.md @@ -4,91 +4,7 @@ | :------------------------: | :------------------------: | | [![][tci badge]][tci link] | [![][avy badge]][avy link] | -## A new way to JavaScript. - -- Supports TypeScript out of the box. Uses a recent version of V8. That is, it's - very modern JavaScript. - -- No `package.json`. No npm. Not explicitly compatible with Node. - -- Imports reference source code URLs only. - - ```typescript - import { test } from "https://unpkg.com/deno_testing@0.0.5/testing.ts"; - import { log } from "./util.ts"; - ``` - - Remote code is fetched and cached on first execution, and never updated until - the code is run with the `--reload` flag. (So, this will still work on an - airplane. See `~/.deno/src` for details on the cache.) - -- File system and network access can be controlled in order to run sandboxed - code. Defaults to read-only file system access and no network access. Access - between V8 (unprivileged) and Rust (privileged) is only done via serialized - messages defined in this - [flatbuffer](https://github.com/denoland/deno/blob/master/src/msg.fbs). This - makes it easy to audit. To enable write access explicitly use `--allow-write` - and `--allow-net` for network access. - -- Single executable: - - ``` - > ls -lh target/release/deno - -rwxr-xr-x 1 rld staff 48M Aug 2 13:24 target/release/deno - > otool -L target/release/deno - target/release/deno: - /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1252.50.4) - /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0) - /System/Library/Frameworks/Security.framework/Versions/A/Security (compatibility version 1.0.0, current version 58286.51.6) - /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.0) - > - ``` - -- Always dies on uncaught errors. - -- [Aims to support top-level `await`.](https://github.com/denoland/deno/issues/471) - -- Aims to be browser compatible. - -See the website for more info [deno.land](https://deno.land). - -## Install - -With Shell: - -``` -curl -L https://deno.land/x/install/install.sh | bash -``` - -With PowerShell: - -```powershell -iex (iwr https://deno.land/x/install/install.ps1) -``` - -_Note: Depending on your security settings, you may have to run -`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded -scripts to be executed._ - -With [Scoop](https://scoop.sh/): - -``` -scoop install deno -``` - -Try it: - -``` -> deno https://deno.land/thumb.ts -``` - -See [deno_install](https://github.com/denoland/deno_install) for more -installation methods.. - -## Build locally (advanced users only) - -For instructions to build this project locally, please see -[the docs](https://github.com/denoland/deno/blob/master/Docs.md#build-instructions-for-advanced-users-only). +See documentation at https://deno.land/ [avy badge]: https://ci.appveyor.com/api/projects/status/yel7wtcqwoy0to8x?branch=master&svg=true diff --git a/Roadmap.md b/Roadmap.md deleted file mode 100644 index 572d03543c..0000000000 --- a/Roadmap.md +++ /dev/null @@ -1,61 +0,0 @@ -# Deno Roadmap - -API and Feature requests should be submitted as PRs to this document. - -## Security Model (partially implemented) - -- We want to be secure by default; user should be able to run untrusted code, - like the web. -- Threat model: - - Modifiying/deleting local files - - Leaking private information -- Disallowed default: - - Network access - - Local write access - - Non-JS extensions - - Subprocesses - - Env access -- Allowed default: - - Local read access. - - argv, stdout, stderr, stdin access always allowed. - - Maybe: temp dir write access. (But what if they create symlinks there?) -- The user gets prompted when the software tries to do something it doesn't have - the privilege for. -- Have an option to get a stack trace when access is requested. -- Worried that granting access per file will give a false sense of security due - to monkey patching techniques. Access should be granted per program (js - context). - -Example security prompts. Options are: YES, NO, PRINT STACK - -``` -Program requests write access to "~/.ssh/id_rsa". Grant? [yNs] -http://gist.github.com/asdfasd.js requests network access to "www.facebook.com". Grant? [yNs] -Program requests access to environment variables. Grant? [yNs] -Program requests to spawn `rm -rf /`. Grant? [yNs] -``` - -- cli flags to grant access ahead of time --allow-all --allow-write --allow-net - --allow-env --allow-exec -- in version two we will add ability to give finer grain access - --allow-net=facebook.com - -## Top-level Await (Not Implemented) - -[#471](https://github.com/denoland/deno/issues/471) - -This will be put off until at least deno2 Milestone1 is complete. One of the -major problems is that top-level await calls are not syntactically valid -TypeScript. - -### [Broken] List dependencies of a program. - -Currently broken: https://github.com/denoland/deno/issues/1011 - -``` -% deno --deps http://gist.com/blah.js -http://gist.com/blah.js -http://gist.com/dep.js -https://github.com/denoland/deno/master/testing.js -% -``` diff --git a/tools/format.ts b/tools/format.ts index 37fbd18e3a..8f86ea9797 100755 --- a/tools/format.ts +++ b/tools/format.ts @@ -61,7 +61,7 @@ async function run(...args: string[]): Promise { "--allow-write", "js/deps/https/deno.land/x/std/prettier/main.ts", "rollup.config.js", - ...findFiles(["."], [".json", ".md"], { depth: 1 }), + ...findFiles([".", "website"], [".json", ".md"], { depth: 1 }), ...findFiles( [".github", "js", "tests", "tools", "website"], [".js", ".json", ".ts", ".md"], diff --git a/website/README.md b/website/README.md deleted file mode 100644 index 1e6a13a158..0000000000 --- a/website/README.md +++ /dev/null @@ -1,32 +0,0 @@ -## About benchmark data - -The benchmark chart supposes `//website/data.json` has the type -`BenchmarkData[]` where `BenchmarkData` is defined like the below: - -```typescript -interface ExecTimeData { - mean: number; - stddev: number; - user: number; - system: number; - min: number; - max: number; -} - -interface BenchmarkData { - created_at: string; - sha1: string; - benchmark: { - [key: string]: ExecTimeData; - }; - binarySizeData: { - [key: string]: number; - }; - threadCountData: { - [key: string]: number; - }; - syscallCountData: { - [key: string]: number; - }; -} -``` diff --git a/website/all_benchmark.html b/website/all_benchmark.html deleted file mode 100644 index 1d73d58310..0000000000 --- a/website/all_benchmark.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - all benchmark data | deno - - - - - -
-

all benchmark data

- -

back - -

Execution time

-
- -

Throughput

-
- -

Req/Sec

-
- -

Executable size

-
- -

Thread count

-
- -

Syscall count

-
-
- - - - - - - diff --git a/website/app.js b/website/app.js index ed7d4baf2d..6e23befa91 100644 --- a/website/app.js +++ b/website/app.js @@ -126,6 +126,7 @@ function generate( ) { const yAxis = { padding: { bottom: 0 }, + min: 0, label: yLabel }; if (yTickFormat) { @@ -133,6 +134,7 @@ function generate( format: yTickFormat }; if (yTickFormat == logScale) { + delete yAxis.min; for (let col of columns) { for (let i = 1; i < col.length; i++) { if (col[i] == null) { @@ -221,7 +223,7 @@ export async function drawChartsFromBenchmarkData(dataUrl) { } gen("#exec-time-chart", execTimeColumns, "seconds", logScale); - gen("#throughput-chart", throughputColumns, "seconds"); + gen("#throughput-chart", throughputColumns, "seconds", logScale); gen("#req-per-sec-chart", reqPerSecColumns, "1000 req/sec", formatReqSec); gen("#binary-size-chart", binarySizeColumns, "megabytes", formatMB); gen("#thread-count-chart", threadCountColumns, "threads"); diff --git a/website/benchmarks.html b/website/benchmarks.html new file mode 100644 index 0000000000..0c270d2be5 --- /dev/null +++ b/website/benchmarks.html @@ -0,0 +1,137 @@ + + + + + Deno Benchmarks + + + + + +
+

Deno Continuous Benchmarks

+ +

+ These plots are updated on every commit to + master branch. +

+ +

recent data

+

all data (takes a moment to load)

+ +

Execution time #

+

+ This shows how much time total it takes to run a few simple deno + programs: + + tests/002_hello.ts + + and + tests/003_relative_import.ts. For deno to execute typescript, it must first compile it to JS. A + warm startup is when deno has a cached JS output already, so it should + be fast because it bypasses the TS compiler. A cold startup is when deno + must compile from scratch. +

+
+ +

Throughput #

+ +

+ Time it takes to pipe a certain amount of data through Deno. + + + echo_server.ts + + and + + cat.ts . Smaller is better. +

+ +
+ +

Req/Sec #

+ +

+ Tests HTTP server performance. 10 keep-alive connections do as many + hello-world requests as possible. Bigger is better. +

+ + + +
+ +

Executable size #

+

deno ships only a single binary. We track its size here.

+
+ +

Thread count #

+

How many threads various programs use.

+
+ +

Syscall count #

+

+ How many total syscalls are performed when executing a given script. +

+
+
+ + + + + + diff --git a/website/index.html b/website/index.html index 86463e5d80..ffd83a253d 100644 --- a/website/index.html +++ b/website/index.html @@ -3,26 +3,21 @@ Deno - - - +
- - - -

Deno

- -

- A new way to JavaScript - - -

+
+ + +
+

Deno

+ A new way to JavaScript +
+
@@ -31,30 +26,32 @@ - + - + @@ -64,7 +61,9 @@ - +
Windows
- deno - deno - + - +
- deno_std - deno_std - +
- + @@ -72,166 +71,73 @@ class="badge" href="https://ci.appveyor.com/project/deno/deno-install" > - +
- registry - registry
-

#Install

+

Install #

-

With Shell

-
curl -fL https://deno.land/x/install/install.sh | sh
-

With PowerShell

-
iex (iwr https://deno.land/x/install/install.ps1)
+

Mac or Linux

+
curl -fL https://deno.land/x/install/install.sh | sh
+

Windows (PowerShell)

+
iex (iwr https://deno.land/x/install/install.ps1)
-

#Mini-tutorial

+

Example #

+ +

Try running a simple program:

+
deno https://deno.land/welcome.js
+ +

Or a more complex one:

-

Try a Deno program. This one serves a local directory in HTTP.

-alias file_server="deno \
-  https://deno.land/x/http/file_server.ts --allow-net"
-      
+import { serve } from "https://deno.land/x/http/server.ts"; +const s = serve("0.0.0.0:8000"); -

Run it:

-
-% file_server .
-Downloading https://deno.land/x/http/file_server.ts...
-[...]
-HTTP server listening on http://0.0.0.0:4500/
-      
-

And if you ever want to upgrade to the latest published version:

-
file_server --reload
+async function main() { + for await (const req of s) { + req.respond({ body: new TextEncoder().encode("Hello World\n") }); + } +} -

#Dig in...

+main(); - - Documentation - +

Dig in... #

- API Reference + Manual

-

- - Links to other Deno resources. - -

+

API Reference

-

#Continuous Benchmarks

+

Style Guide

-

These plots are updated on every commit to

-

- master branch -

+

Module repository

-

#Execution time

-

This shows how much time total it takes to run a few simple deno programs:

- - tests/002_hello.ts - -

and

- Release notes - tests/003_relative_import.ts - -

-

- For deno to execute typescript, it must first compile it to JS. A warm - startup is when deno has a cached JS output already, so it should be fast - because it bypasses the TS compiler. A cold startup is when deno must - compile from scratch. -

-
- -

#Throughput

- -

Time it takes to pipe a certain amount of data through Deno.

- - - echo_server.ts - -

and

- - cat.ts - -

Smaller is better.

- -
- -

#Req/Sec

- -

- Tests HTTP server performance. 10 keep-alive connections do as many - hello-world requests as possible. Bigger is better.

- - -
- -

#Executable size

-

deno ships only a single binary. We track its size here.

-
- -

#Thread count

-

How many threads various programs use.

-
- -

#Syscall count

-

How many total syscalls are performed when executing a given script.

-
+

Benchmarks

- Historical benchmark data + A curated list of awesome Deno things

- - - - - diff --git a/website/manifest.json b/website/manifest.json deleted file mode 100644 index 67e8f1a0b3..0000000000 --- a/website/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "dir": "ltr", - "lang": "en", - "name": "Deno", - "scope": "/", - "display": "browser", - "start_url": "/", - "short_name": "Deno", - "theme_color": "#F0F0F0", - "description": "A new way to JavaScript", - "orientation": "any", - "background_color": "#F0F0F0" -} diff --git a/website/manual.html b/website/manual.html new file mode 100644 index 0000000000..1301b68957 --- /dev/null +++ b/website/manual.html @@ -0,0 +1,40 @@ + + + + + Deno Manual + + + + +
+
+ + + + +
+ + diff --git a/website/manual.md b/website/manual.md new file mode 100644 index 0000000000..bf5f6d2375 --- /dev/null +++ b/website/manual.md @@ -0,0 +1,656 @@ +# Deno Manual + +[toc] + +## Disclaimer + +A word of caution: Deno is very much under development. We encourage brave early +adopters, but expect bugs large and small. The API is subject to change without +notice. + +[Bug reports](https://github.com/denoland/deno/issues) do help! + +## Introduction + +### Philosophy + +Deno aims to be a useful multitool tool for the modern programmer. + +It will always be distributed as a single executable - and that executable will +be sufficient software to run any deno program. Given a URL to a deno program, +you should be able to execute it with nothing more than the 50M deno executable. + +Deno explicitly takes on the role of both runtime and package manager. It uses a +standard browser-compatible protocol for loading modules: URLs. + +Deno provides security guarantees about how programs can access your system with +the default being the most restrictive secure sandbox. + +Deno provides a set of reviewed +(audited) standard modules that are guaranteed to work with Deno. + +Deno is opinionated and defines style guides and has +automated +formatters. + +### Design goals + +- Support TypeScript out of the box. + +- No `package.json`. No npm. Not explicitly compatible with Node. + +- Like the browser, allows imports from URLs: + + ```typescript + import * as log from "https://deno.land/x/std/log/mod.ts"; + ``` + +- Remote code is fetched and cached on first execution, and never updated until + the code is run with the `--reload` flag. (So, this will still work on an + airplane. See `~/.deno/src` for details on the cache.) + +- Uses "ES Modules" and does not support `require()`. + +- File system and network access can be controlled in order to run sandboxed + code. Access between V8 (unprivileged) and Rust (privileged) is only done via + serialized messages defined in this + [flatbuffer](https://github.com/denoland/deno/blob/master/src/msg.fbs). This + makes it easy to audit. For example, to enable write access use the flag + `--allow-write` or for network access `--allow-net`. + +- Only ship a single executable. + +- Always dies on uncaught errors. + +- [Aims to support top-level `await`.](https://github.com/denoland/deno/issues/471) + +### Browser compatibility + +The subset of Deno programs which are written completely in JavaScript and do +not import the special `"deno"` module, ought to also be able to be run in a +modern web browser without change. + +## Setup + +### Binary Install + +Deno works on OSX, Linux, and Windows. Deno is a single binary executable. It +has no external dependencies. + +[deno_install](https://github.com/denoland/deno_install) provides convenience +scripts to download and install the binary. + +Using Shell: + +``` +curl -fL https://deno.land/x/install/install.sh | sh +``` + +Or using PowerShell: + +```powershell +iex (iwr https://deno.land/x/install/install.ps1) +``` + +_Note: Depending on your security settings, you may have to run +`Set-ExecutionPolicy RemoteSigned -Scope CurrentUser` first to allow downloaded +scripts to be executed._ + +With [Scoop](https://scoop.sh/): + +``` +scoop install deno +``` + +Deno can also be installed manually, by downloading a tarball or zip file at +[github.com/denoland/deno/releases](https://github.com/denoland/deno/releases). +These packages contain just a single executable file. You will have to set the +executable bit on Mac and Linux. + +Once it's installed and in your \$PATH, try it: + +``` +deno https://deno.land/welcome.js +``` + +### Build from source + +``` +# Fetch deps. +git clone --recurse-submodules https://github.com/denoland/deno.git +cd deno +./tools/setup.py + +# You may need to ensure that sccache is running. +# (TODO it's unclear if this is necessary or not.) +# prebuilt/mac/sccache --start-server + +# Build. +./tools/build.py + +# Run. +./target/debug/deno tests/002_hello.ts + +# Test. +./tools/test.py + +# Format code. +# TODO: set PYTHONPATH in format.ts when run API has env option. +PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run +``` + +#### Prerequisites + +To ensure reproducible builds, deno has most of its dependencies in a git +submodule. However, you need to install separately: + +1. [Rust](https://www.rust-lang.org/en-US/install.html) >= 1.31.1 +2. [Node](https://nodejs.org/) +3. Python 2. + [Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578). + +Extra steps for Mac users: + +1. [XCode](https://developer.apple.com/xcode/) +2. Openssl 1.1: `brew install openssl@1.1` (TODO: shouldn't be necessary) + +Extra steps for Windows users: + +1. Add `python.exe` to `PATH` (e.g. `set PATH=%PATH%;C:\Python27\python.exe`) +2. Get [VS Community 2017](https://www.visualstudio.com/downloads/) with + `Desktop development with C++` toolkit and make sure to select the following + required tools listed below along with all C++ tools. + - Windows 10 SDK >= 10.0.17134 + - Visual C++ ATL for x86 and x64 + - Visual C++ MFC for x86 and x64 + - C++ profiling tools +3. Enable `Debugging Tools for Windows`. Go to `Control Panel` → `Programs` → + `Programs and Features` → Select + `Windows Software Development Kit - Windows 10` → `Change` → `Change` → Check + `Debugging Tools For Windows` → `Change` -> `Finish`. + +#### Other useful commands + +``` +# Call ninja manually. +./third_party/depot_tools/ninja -C target/debug + +# Build a release binary. +DENO_BUILD_MODE=release ./tools/build.py :deno + +# List executable targets. +./third_party/depot_tools/gn ls target/debug //:* --as=output --type=executable + +# List build configuration. +./third_party/depot_tools/gn args target/debug/ --list + +# Edit build configuration. +./third_party/depot_tools/gn args target/debug/ + +# Describe a target. +./third_party/depot_tools/gn desc target/debug/ :deno +./third_party/depot_tools/gn help + +# Update third_party modules +git submodule update +``` + +Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`, +`DENO_DIR`. + +## API reference + +### deno --types + +To get an exact reference of deno's runtime API, run the following in the +command line: + +``` +deno --types +``` + +[This is what the output looks like.](https://gist.github.com/ry/46da4724168cdefa763e13207d27ede5) + +### Reference websites + +[TypeScript Deno API](https://deno.land/typedoc/index.html). + +If you are embedding deno in a Rust program, see +[Rust Deno API](https://deno.land/rustdoc/deno/index.html). + +## Examples + +### An implementation of the unix "cat" program + +In this program each command-line argument is assumed to be a filename, the file +is opened, and printed to stdout. + +```ts +import * as deno from "deno"; + +(async () => { + for (let i = 1; i < deno.args.length; i++) { + let filename = deno.args[i]; + let file = await deno.open(filename); + await deno.copy(deno.stdout, file); + file.close(); + } +})(); +``` + +The `copy()` function here actually makes no more than the necessary kernel -> +userspace -> kernel copies. That is, the same memory from which data is read +from the file, is written to stdout. This illustrates a general design goal for +I/O streams in Deno. + +Try the program: + +``` +> deno https://deno.land/x/examples/cat.ts /etc/passwd +``` + +### TCP echo server + +This is an example of a simple server which accepts connections on port 8080, +and returns to the client anything it sends. + +```ts +import { listen, copy } from "deno"; + +(async () => { + const addr = "0.0.0.0:8080"; + const listener = listen("tcp", addr); + console.log("listening on", addr); + while (true) { + const conn = await listener.accept(); + copy(conn, conn); + } +})(); +``` + +When this program is started, the user is prompted for permission to listen on +the network: + +``` +> deno https://deno.land/x/examples/echo_server.ts +⚠️ Deno requests network access to "listen". Grant? [yN] y +listening on 0.0.0.0:8080 +``` + +For security reasons, deno does not allow programs to access the network without +explicit permission. To avoid the console prompt, use a command-line flag: + +``` +> deno https://deno.land/x/examples/echo_server.ts --allow-net +``` + +To test it, try sending a HTTP request to it by using curl. The request gets +written directly back to the client. + +``` +> curl http://localhost:8080/ +GET / HTTP/1.1 +Host: localhost:8080 +User-Agent: curl/7.54.0 +Accept: */* +``` + +It's worth noting that like the `cat.ts` example, the `copy()` function here +also does not make unnecessary memory copies. It receives a packet from the +kernel and sends back, without further complexity. + +### File server + +This one serves a local directory in HTTP. + +``` +alias file_server="deno --allow-net --allow-read \ + https://deno.land/x/http/file_server.ts" +``` + +Run it: + +``` +% file_server . +Downloading https://deno.land/x/http/file_server.ts... +[...] +HTTP server listening on http://0.0.0.0:4500/ +``` + +And if you ever want to upgrade to the latest published version: + +``` +file_server --reload +``` + +### Linking to third party code + +In the above examples, we saw that Deno could execute scripts from URLs. Like +browser JavaScript, Deno can import libraries directly from URLs. This example +uses a URL to import a test runner library: + +```ts +import { test, assertEqual } from "https://deno.land/x/testing/mod.ts"; + +test(function t1() { + assertEqual("hello", "hello"); +}); + +test(function t2() { + assertEqual("world", "world"); +}); +``` + +Try running this: + +``` +> deno https://deno.land/x/examples/example_test.ts +Compiling /Users/rld/src/deno_examples/example_test.ts +Downloading https://deno.land/x/testing/mod.ts +Compiling https://deno.land/x/testing/mod.ts +running 2 tests +test t1 +... ok +test t2 +... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +``` + +Note that we did not have to provide the `--allow-net` flag for this program, +and yet it accessed the network. The runtime has special access to download +imports and cache them to disk. + +Deno caches remote imports in a special directory specified by the `$DENO_DIR` +environmental variable. It default to `$HOME/.deno` if `$DENO_DIR` is not +specified. The next time you run the program, no downloads will be made. If the +program hasn't changed, it won't be recompiled either. + +**But what if `https://deno.land/` goes down?** Relying on external servers is +convenient for development but brittle in production. Production software should +always bundle its dependencies. In Deno this is done by checking the `$DENO_DIR` +into your source control system, and specifying that path as the `$DENO_DIR` +environmental variable at runtime. + +**How do you import to a specific version?** Simply specify the version in the +URL. For example, this URL fully specifies the code being run: +`https://unpkg.com/liltest@0.0.5/dist/liltest.js`. Combined with the +aforementioned technique of setting `$DENO_DIR` in production to stored code, +one can fully specify the exact code being run, and execute the code without +network access. + +**It seems unwieldy to import URLs everywhere. What if one of the URLs links to +a subtly different version of a library? Isn't it error prone to maintain URLs +everywhere in a large project?** The solution is to import and re-export your +external libraries in a central `package.ts` file (which serves the same purpose +as Node's `package.json` file). For example, let's say you were using the above +testing library across a large project. Rather than importing +`"https://deno.land/x/testing/mod.ts"` everywhere, you could create a +`package.ts` file the exports the third-party code: + +```ts +export { test, assertEqual } from "https://deno.land/x/testing/mod.ts"; +``` + +And throughout project one can import from the `package.ts` and avoid having +many references to the same URL: + +```ts +import { test, assertEqual } from "./package.ts"; +``` + +This design circumvents a plethora of complexity spawned by package management +software, centralized code repositories, and superfluous file formats. + +## Command line interface + +### Flags + +``` +> deno -h +Usage: deno script.ts + +Options: + --allow-read Allow file system read access. + --allow-write Allow file system write access. + --allow-net Allow network access. + --allow-env Allow environment access. + --allow-run Allow running subprocesses. + -A, --allow-all Allow all permissions. + --recompile Force recompilation of TypeScript code. + -h, --help Print this message. + -D, --log-debug Log debug output. + -v, --version Print the version. + -r, --reload Reload cached remote resources. + --v8-options Print V8 command line options. + --types Print runtime TypeScript declarations. + --prefetch Prefetch the dependencies. + --info Show source file related info + --fmt Format code. + +Environment variables: + DENO_DIR Set deno's base directory. +``` + +### Environmental variables + +There are several env vars that control how Deno behaves: + +`DENO_DIR` defaults to `$HOME/.deno` but can be set to any path to control where +generated and cached source code is written and read to. + +`NO_COLOR` will turn off color output if set. See https://no-color.org/. User +code can test if `NO_COLOR` was set without having `--allow-env` by using the +boolean constant `deno.noColor`. + +### V8 flags + +V8 has many many internal command-line flags, that you can see with +`--v8-options`. +[It looks like this.](https://gist.github.com/ry/1c5b080dcbdc6367e5612392049c9ee7) + +Particularly useful ones: + +``` +--async-stack-trace +``` + +## Internal details + +### Schematic diagram + + + +### Profiling + +To start profiling, + +```sh +# Make sure we're only building release. +export DENO_BUILD_MODE=release +# Build deno and V8's d8. +./tools/build.py d8 deno +# Start the program we want to benchmark with --prof +./target/release/deno tests/http_bench.ts --allow-net --prof & +# Exercise it. +third_party/wrk/linux/wrk http://localhost:4500/ +kill `pgrep deno` +``` + +V8 will write a file in the current directory that looks like this: +`isolate-0x7fad98242400-v8.log`. To examine this file: + +```sh +D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor +isolate-0x7fad98242400-v8.log > prof.log +# on macOS, use ./third_party/v8/tools/mac-tick-processor instead +``` + +`prof.log` will contain information about tick distribution of different calls. + +To view the log with Web UI, generate JSON file of the log: + +```sh +D8_PATH=target/release/ ./third_party/v8/tools/linux-tick-processor +isolate-0x7fad98242400-v8.log --preprocess > prof.json +``` + +Open `third_party/v8/tools/profview/index.html` in your brower, and select +`prof.json` to view the distribution graphically. + +To learn more about `d8` and profiling, check out the following links: + +- [https://v8.dev/docs/d8](https://v8.dev/docs/d8) +- [https://v8.dev/docs/profile](https://v8.dev/docs/profile) + +### Debugging with LLDB + +We can use LLDB to debug deno. + +```sh +lldb -- target/debug/deno tests/worker.js +> run +> bt +> up +> up +> l +``` + +To debug Rust code, we can use `rust-lldb`. It should come with `rustc` and is a +wrapper around LLDB. + +```sh +rust-lldb -- ./target/debug/deno tests/http_bench.ts --allow-net +# On macOS, you might get warnings like +# `ImportError: cannot import name _remove_dead_weakref` +# In that case, use system python by setting PATH, e.g. +# PATH=/System/Library/Frameworks/Python.framework/Versions/2.7/bin:$PATH +(lldb) command script import "/Users/kevinqian/.rustup/toolchains/1.30.0-x86_64-apple-darwin/lib/rustlib/etc/lldb_rust_formatters.py" +(lldb) type summary add --no-value --python-function lldb_rust_formatters.print_val -x ".*" --category Rust +(lldb) type category enable Rust +(lldb) target create "../deno/target/debug/deno" +Current executable set to '../deno/target/debug/deno' (x86_64). +(lldb) settings set -- target.run-args "tests/http_bench.ts" "--allow-net" +(lldb) b op_start +(lldb) r +``` + +### libdeno + +deno's privileged side will primarily be programmed in Rust. However there will +be a small C API that wraps V8 to 1) define the low-level message passing +semantics, 2) provide a low-level test target, 3) provide an ANSI C API binding +interface for Rust. V8 plus this C API is called "libdeno" and the important +bits of the API is specified here: +[deno.h](https://github.com/denoland/deno/blob/master/libdeno/deno.h) +[libdeno.ts](https://github.com/denoland/deno/blob/master/js/libdeno.ts) + +### Flatbuffers + +We use Flatbuffers to define common structs and enums between TypeScript and +Rust. These common data structures are defined in +[msg.fbs](https://github.com/denoland/deno/blob/master/src/msg.fbs) + +### Updating prebuilt binaries + +``` +./third_party/depot_tools/upload_to_google_storage.py -b denoland \ + -e ~/.config/gcloud/legacy_credentials/ry@tinyclouds.org/.boto `which sccache` +mv `which sccache`.sha1 prebuilt/linux64/ +gsutil acl ch -u AllUsers:R gs://denoland/608be47bf01004aa11d4ed06955414e93934516e +``` + +### Continuous Benchmarks + +https://deno.land/benchmarks.html + +The benchmark chart supposes `//website/data.json` has the type +`BenchmarkData[]` where `BenchmarkData` is defined like the below: + +```typescript +interface ExecTimeData { + mean: number; + stddev: number; + user: number; + system: number; + min: number; + max: number; +} + +interface BenchmarkData { + created_at: string; + sha1: string; + benchmark: { + [key: string]: ExecTimeData; + }; + binarySizeData: { + [key: string]: number; + }; + threadCountData: { + [key: string]: number; + }; + syscallCountData: { + [key: string]: number; + }; +} +``` + +## Contributing + +[Style Guide](style_guide.html) + +Progress towards future releases is tracked +[here](https://github.com/denoland/deno/milestones). + +Please don't make [the benchmarks](https://deno.land/benchmarks.html) worse. + +Ask for help in the [community chat room](https://gitter.im/denolife/Lobby). + +### Submitting a pull request + +Before submitting, please make sure the following is done: + +1. There are tests that cover the changes. +2. Ensure `./tools/test.py` passes. +3. Format your code with + `PYTHONPATH=third_party/python_packages deno ./tools/format.ts --allow-read --allow-run`. + +4. Make sure `./tools/lint.py` passes. + +### Changes to `third_party` + +[`deno_third_party`](https://github.com/denoland/deno_third_party) contains most +of the external code that Deno depends on, so that we know exactly what we are +executing at any given time. It is carefully mantained with a mixture of manual +labor and private scripts. It's likely you will need help from @ry or +@piscisaureus to make changes. + +### Adding Ops (aka bindings) + +We are very concerned about making mistakes when adding new APIs. When adding an +Op to Deno, the counterpart interfaces on other platforms should be researched. +Please list how this functionality is done in Go, Node, Rust, and Python. + +As an example, see how `deno.rename()` was proposed and added in +[PR #671](https://github.com/denoland/deno/pull/671). + +### Documenting APIs + +It is important to document public APIs and we want to do that inline with the +code. This helps ensure that code and documentation are tightly coupled +together. + +#### Utilize JSDoc + +All publicly exposed APIs and types, both via the `deno` module as well as the +global/`window` namespace should have JSDoc documentation. This documentation is +parsed and available to the TypeScript compiler, and therefore easy to provide +further downstream. JSDoc blocks come just prior to the statement they apply to +and are denoted by a leading `/**` before terminating with a `*/`. For example: + +```ts +/** A simple JSDoc comment */ +export const FOO = "foo"; +``` diff --git a/website/schematic_v0.2.png b/website/schematic_v0.2.png new file mode 100644 index 0000000000000000000000000000000000000000..abf7b1f2ebe156130706d583f218f8b4f325f24a GIT binary patch literal 58275 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' + this.text + ""; + } + result += this.childrenToString(); + result += "\n"; + return result; + }; + + function sortHeader(tocEntries, level) { + level = level || 1; + var tagName = "H" + level, + result = [], + currentTocEntry; + + function push(tocEntry) { + if (tocEntry !== undefined) { + if (tocEntry.children.length > 0) { + tocEntry.children = sortHeader(tocEntry.children, level + 1); + } + result.push(tocEntry); + } + } + + for (var i = 0; i < tocEntries.length; i++) { + var tocEntry = tocEntries[i]; + if (tocEntry.tagName.toUpperCase() !== tagName) { + if (currentTocEntry === undefined) { + currentTocEntry = new TocEntry(); + } + currentTocEntry.children.push(tocEntry); + } else { + push(currentTocEntry); + currentTocEntry = tocEntry; + } + } + + push(currentTocEntry); + return result; + } + + return { + type: "output", + filter: function(sourceHtml) { + var headerList = getHeaderEntries(sourceHtml); + + // No header found + if (headerList.length === 0) { + return sourceHtml; + } + + // Sort header + headerList = sortHeader(headerList); + + // Skip the title. + if (headerList.length == 1) { + headerList = headerList[0].children; + } + + // Build result and replace all [toc] + var result = + '
\n
    \n' + headerList.join("") + "
\n
\n"; + return sourceHtml.replace(/\[toc\]/gi, result); + } + }; +}); diff --git a/website/style.css b/website/style.css index 5b44d37995..b16d33eb72 100644 --- a/website/style.css +++ b/website/style.css @@ -1,74 +1,91 @@ - body { - color: #111; + color: #444; background: #f0f0f0; - margin: 1em; - font-family: Arial; - font-size: 20px; + padding: 0; + + line-height: 1.5; + font-family: sans-serif; + + margin: 5ex 10ex; + max-width: 80ex; } -main { +#manual img { + width: 100%; max-width: 800px; - margin: 0px auto; } + + +h1, h2, h3, h4 { + font-weight: normal; + margin-bottom: 0; +} + +h1, h2, h3, h4, p, table { + margin-left: 8px; + margin-right: 8px; +} + +table { + border-collapse: collapse; +} +td, th { + font-weight: normal; + text-align: center; + border: 1px dotted #bbb; + padding: 4px; +} + svg { - margin: 0px auto; + margin: 0px; width: 100%; height: 300px; } a { - color: #333; -} -a:hover { - color: #488; + color: #106ad5; } -a.badge { - display: inline-block; - border-radius: 2px; - height: 20px; - transition: .3s box-shadow; -} -a.badge:hover { - box-shadow: 0 0 5px 0 #333; +pre a { + color: #001631; } -a[href^="#"] { /* Hash links */ - text-decoration: none; +h2 a, h3 a { + display: none; color: #3bace5; - margin-right: 0.5rem; + text-decoration: none; } -a[href^="#"]:hover { - text-decoration: underline; - color: #3d9bcc; + +h2:hover a, +h3:hover a { + display: inline; } pre { - background: #ddd; + /* background: rgba(36, 126, 233, 0.03); */ + color: #161616; + background: rgba(36, 126, 233, 0.1); padding: 15px; word-wrap: normal; overflow-x: auto; } -table { - border-collapse: collapse; - border-spacing: 0; +header { + display: flex; + align-items: center; + margin: 16px 4px; } -td, th { - text-align: center; - vertical-align: middle; - border: 1px solid #aaa; - padding: 6px; +header > * { + margin: 16px; } +header h1 { + margin: 8px 0; +} + + @media only screen and (max-device-width: 480px) { - - main { - margin: 15px; - } - body { margin: 0; } diff --git a/website/style_guide.html b/website/style_guide.html new file mode 100644 index 0000000000..4acf136499 --- /dev/null +++ b/website/style_guide.html @@ -0,0 +1,40 @@ + + + + + Deno Style Guide + + + + +
+
+ + + + +
+ + diff --git a/website/style_guide.md b/website/style_guide.md new file mode 100644 index 0000000000..d2cbbbf30d --- /dev/null +++ b/website/style_guide.md @@ -0,0 +1,264 @@ +# Deno Style Guide + +[toc] + +## Use TypeScript + +## Use the term "module" instead of "library" or "package" + +For clarity and consistency avoid the terms "library" and "package". Instead use +"module" to refer to a single JS or TS file and also to refer to a directory of +TS/JS code. + +## Do not use the filename `index.ts` nor `index.js` + +Deno does not treat "index.js" or "index.ts" in a special way. By using these +filenames, it suggests that they can be left out of the module specifier when +they cannot. This is confusing. + +If a directory of code needs a default entry point, use the filename `mod.ts`. +The filename `mod.ts` follows Rust’s convention, is shorter than `index.ts`, and +doesn’t come with any preconceived notions about how it might work. + +## Within `deno_std`, do not depend on external code + +`deno_std` is intended to be baseline functionality that all Deno programs can +rely on. We want to guarantee to users that this code does not include +potentially unreviewed third party code. + +## Within `deno_std`, minimize dependencies; do not make circular imports. + +Although `deno_std` is a standalone codebase, we must still be careful to keep +the internal dependencies simple and manageable. In particular, be careful to +not to introduce circular imports. + +## For consistency, use underscores, not dashes in filenames. + +Example: Instead of `file-server.ts` use `file_server.ts`. + +## Format code according using prettier. + +More specifically, code should be wrapped at 80 columns and use 2-space +indentation and use camel-case. Use `//format.ts` to invoke prettier. + +## Exported functions: max 2 args, put the rest into an options object. + +When designing function interfaces, stick to the following rules. + +1. A function that is part of the public API takes 0-2 required arguments, plus + (if necessary) an options object (so max 3 total). + +2. Optional parameters should generally go into the options object. + + An optional parameter that's not in an options object might be acceptable if + there is only one, and it seems inconceivable that we would add more optional + parameters in the future. + +3. The 'options' argument is the only argument that is a regular 'Object'. + + Other arguments can be objects, but they must be distinguishable from a + 'plain' Object runtime, by having either: + + - a distinguishing prototype (e.g. `Array`, `Map`, `Date`, `class MyThing`) + - a well-known symbol property (e.g. an iterable with `Symbol.iterator`). + + This allows the API to evolve in a backwards compatible way, even when the + position of the options object changes. + +```ts +// BAD: optional parameters not part of options object. (#2) +export function resolve( + hostname: string, + family?: "ipv4" | "ipv6", + timeout?: number +): IPAddress[] {} + +// GOOD. +export interface ResolveOptions { + family?: "ipv4" | "ipv6"; + timeout?: number; +} +export function resolve( + hostname: string, + options: ResolveOptions = {} +): IPAddress[] {} +``` + +```ts +export interface Environment { + [key: string]: string; +} + +// BAD: `env` could be a regular Object and is therefore indistinguishable +// from an options object. (#3) +export function runShellWithEnv(cmdline: string, env: Environment): string {} + +// GOOD. +export interface RunShellOptions { + env: Environment; +} +export function runShellWithEnv( + cmdline: string, + options: RunShellOptions +): string {} +``` + +```ts +// BAD: more than 3 arguments (#1), multiple optional parameters (#2). +export function renameSync( + oldname: string, + newname: string, + replaceExisting?: boolean, + followLinks?: boolean +) {} + +// GOOD. +interface RenameOptions { + replaceExisting?: boolean; + followLinks?: boolean; +} +export function renameSync( + oldname: string, + newname: string, + options: RenameOptions = {} +) {} +``` + +```ts +// BAD: too many arguments. (#1) +export function pwrite( + fd: number, + buffer: TypedArray, + offset: number, + length: number, + position: number +) {} + +// BETTER. +export interface PWrite { + fd: number; + buffer: TypedArray; + offset: number; + length: number; + position: number; +} +export function pwrite(options: PWrite) {} +``` + +## TODO Comments + +TODO comments should be include an issue or the author's github username in +parentheses. Example: + +``` +// TODO(ry) Add tests. +// TODO(#123) Support Windows. +``` + +## Copyright headers + +Most files in `deno_std` should have the following copyright header: + +``` +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +``` + +If the code originates elsewhere, ensure that the file has the proper copyright +headers. We only allow MIT, BSD, and Apache licensed code in `deno_std`. + +## Top level functions should not use arrow syntax + +Top level functions should use the `function` keyword. Arrow syntax should be +limited to closures. + +Bad + +``` +export const foo(): string => { + return "bar"; +} +``` + +Good + +``` +export function foo(): string { + return "bar"; +} +``` + +## Meta-programming is discouraged. Including the use of Proxy. + +Be explicit even when it means more code. + +There are some situations where it may make sense to use such techniques, but in +the vast majority of cases it does not. + +## If a filename starts with underscore, do not link to it: `_foo.ts` + +Sometimes there maybe situations where an internal module is necessary but its +API is not meant to be stable or linked to. In this case prefix it with an +underscore. By convention, only files in its own directory should import it. + +## Use JSDoc to document exported machinery + +We strive for complete documentation. Every exported symbol ideally should have +a documentation line. + +If possible, use a single line for the JS Doc. Example: + +```ts +/** foo does bar. */ +export function foo() { + // ... +} +``` + +It is important that documentation is easily human readable, but there is also a +need to provide additional styling information to ensure generated documentation +is more rich text. Therefore JSDoc should generally follow markdown markup to +enrich the text. + +While markdown supports HTML tags, it is forbidden in JSDoc blocks. + +Code string literals should be braced with the back-tick (\`) instead of quotes. +For example: + +```ts +/** Import something from the `deno` module. */ +``` + +Do not document function arguments unless they are non-obvious of their intent +(though if they are non-obvious intent, the API should be considered anyways). +Therefore `@param` should generally not be used. + +Vertical spacing should be minimized whenever possible. Therefore single line +comments should be written as: + +```ts +/** This is a good single line JSDoc */ +``` + +And not + +```ts +/** + * This is a bad single line JSDoc + */ +``` + +Code examples should not utilise the triple-back tick (\`\`\`) notation or tags. +They should just be marked by indentation, which requires a break before the +block and 6 additional spaces for each line of the example. This is 4 more than +the first column of the comment. For example: + +```ts +/** A straight forward comment and an example: + * + * import { foo } from "deno"; + * foo("bar"); + */ +``` + +Code examples should not contain additional comments. It is already inside a +comment. If it needs further comments is not a good example. diff --git a/website/welcome.js b/website/welcome.js new file mode 100644 index 0000000000..69f1069f81 --- /dev/null +++ b/website/welcome.js @@ -0,0 +1 @@ +console.log("Welcome to Deno 🦕");