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 0000000000..abf7b1f2eb Binary files /dev/null and b/website/schematic_v0.2.png differ diff --git a/website/showdown_toc.js b/website/showdown_toc.js new file mode 100644 index 0000000000..ba1f65c719 --- /dev/null +++ b/website/showdown_toc.js @@ -0,0 +1,142 @@ +// Extension loading compatible with AMD and CommonJs +(function(extension) { + "use strict"; + + if (typeof showdown === "object") { + // global (browser or nodejs global) + showdown.extension("toc", extension()); + } else if (typeof define === "function" && define.amd) { + // AMD + define("toc", extension()); + } else if (typeof exports === "object") { + // Node, CommonJS-like + module.exports = extension(); + } else { + // showdown was not found so we throw + throw Error("Could not find showdown library"); + } +})(function() { + function getHeaderEntries(sourceHtml) { + if (typeof window === "undefined") { + return getHeaderEntriesInNodeJs(sourceHtml); + } else { + return getHeaderEntriesInBrowser(sourceHtml); + } + } + + function getHeaderEntriesInNodeJs(sourceHtml) { + var cheerio = require("cheerio"); + var $ = cheerio.load(sourceHtml); + var headers = $("h1, h2, h3, h4, h5, h6"); + + var headerList = []; + for (var i = 0; i < headers.length; i++) { + var el = headers[i]; + headerList.push(new TocEntry(el.name, $(el).text(), $(el).attr("id"))); + } + + return headerList; + } + + function getHeaderEntriesInBrowser(sourceHtml) { + // Generate dummy element + var source = document.createElement("div"); + source.innerHTML = sourceHtml; + + // Find headers + var headers = source.querySelectorAll("h1, h2, h3, h4, h5, h6"); + var headerList = []; + for (var i = 0; i < headers.length; i++) { + var el = headers[i]; + headerList.push(new TocEntry(el.tagName, el.textContent, el.id)); + } + + return headerList; + } + + function TocEntry(tagName, text, anchor) { + this.tagName = tagName; + this.text = text; + this.anchor = anchor; + this.children = []; + } + + TocEntry.prototype.childrenToString = function() { + if (this.children.length === 0) { + return ""; + } + var result = "\n"; + return result; + }; + + TocEntry.prototype.toString = function() { + var result = "
  • "; + if (this.text) { + result += '' + 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
    \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 🦕");