Coder Social home page Coder Social logo

deno_graph's Introduction

deno_graph

deno doc Build Status - Cirrus Twitter handle Discord Chat

The module graph/dependency logic for the Deno CLI.

This repository is a Rust crate which provides the foundational code to be able to build a module graph, following the Deno CLI's module resolution logic. It also provides a web assembly interface to the built code, making it possible to leverage the logic outside of the Deno CLI from JavaScript/TypeScript.

Rust usage

ModuleGraph::new(...)

ModuleGraph::new(GraphKind::All) creates a new module graph. From there, you can use the .build(...).await method to add roots. The build method requires the root module specifiers/URLs for the graph and an implementation of the source::Loader trait. It also optionally takes implementation of the source::Resolver trait. It will load and parse the root module and recursively all of its dependencies, returning asynchronously a resulting ModuleGraph.

source::Loader trait

Implementing this trait requires the load() method and optionally the get_cache_into() method. The load() method returns a future with the requested module specifier and the resulting load response. This allows the module graph to deal with redirections, error conditions, and local and remote content.

The get_cache_info() is the API for exposing additional meta data about a module specifier as it resides in the cache so it can be part of a module graphs information. When the graph is built, the method will be called with each resolved module in the graph to see if the additional information is available.

source::Resolver trait

This trait "replaces" the default resolution logic of the module graph. It is intended to allow concepts like import maps and alternative resolution logic to "plug" into the module graph.

It has two methods, resolve and resolve_types, which both have default implementations. resolve takes the string specifier from the source and the referring specifier and is expected to return a result with the resolved specifier.

resolve_types takes a specifier and is expected to return a result with an optional module specifier and optional source range of the types that should be used. For example, if you are trying represent the "typings" field from a package.json file, when you receive the request on resolve_types for the main module of the package, you would respond with the absolute specifier to the types along with a range that indicates the file URL to the package.json and the range where it was specified. Including the range is useful to allow errors produced from the graph to indicate "where" the dependency came from.

source::MemoryLoader struct

MemoryLoader is a structure that implements the source::Loader trait and is designed so that a cache of modules can be stored in memory to be parsed and retrieved when building a module graph. This is useful for testing purposes or in situations where the module contents is already available and dynamically loading them is not practical or desirable.

A minimal example would look like this:

use deno_graph::ModuleSpecifier;
use deno_graph::ModuleGraph;
use deno_graph::GraphKind;
use deno_graph::source::MemoryLoader;
use deno_graph::source::Source;
use futures::executor::block_on;

fn main() {
  let mut loader = MemoryLoader::new(
    vec![
      (
        "file:///test.ts",
        Source::Module {
          specifier: "file:///test.ts",
          maybe_headers: None,
          content: "import * as a from \"./a.ts\";"
        }
      ),
      (
        "file:///a.ts",
        Source::Module {
          specifier: "file:///a.ts",
          maybe_headers: None,
          content: "export const a = \"a\";",
        }
      ),
    ],
    Vec::new(),
  );
  let roots = vec![ModuleSpecifier::parse("file:///test.ts").unwrap()];
  let future = async move {
    let mut graph = ModuleGraph::new(GraphKind::All);
    graph.build(roots, &mut loader, Default::default()).await;
    println!("{:#?}", graph);
  };
  block_on(future)
}

Usage from Deno CLI or Deploy

See js/README.md.

Building Web Assembly

The build script (_build.ts) requires the Deno CLI to be installed and available in the path. If it is, the following command should just work:

> deno task build

Contributing

We appreciate your help!

To contribute, please read our contributing instructions.

This repository includes .devcontainer metadata which will allow a development container to be built which has all the development pre-requisites available to make contribution easier.

deno_graph's People

Contributors

0f-0b avatar arunsathiya avatar bartlomieju avatar deckchairlabs avatar deer avatar denobot avatar dsherret avatar honzasp avatar irbull avatar johnspurlock avatar johnspurlock-skymethod avatar kitsonk avatar kt3k avatar linbingquan avatar lino-levan avatar littledivy avatar lucacasonato avatar magurotuna avatar marvinhagemeister avatar mmastrac avatar nayeemrmn avatar relrelb avatar ry avatar ultirequiem avatar yacinehmito avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deno_graph's Issues

Add cargo version parsing

Right now we only have Version::parse_from_npm, but it would be useful to just have cargo version parsing for stuff like deno upgrade (allows us to drop the semver dependency).

WASM dependency analysis

To unblock denoland/deno#2552, deno_graph needs to be able to represent WASM modules in a module graph. To do this, we need to parse out the import sections in a module, because with the ESM-WASM integration, these can reference other JS / WASM modules (and thus they need to be part of the module graph).

To do the analysis of the WASM modules we can probably use wasmparser. It is a streaming parser, so we don't waste compute cycles and memory getting an entire WASM AST just to extract the imports.

`deno info` incorrectly errors when root is redirected

When running e.g. deno info https://deno.land/std/http/mod.ts, I get

Download https://deno.land/std/http/mod.ts
Warning Implicitly using latest version (0.112.0) for https://deno.land/std/http/mod.ts
Download https://deno.land/[email protected]/http/mod.ts
Download https://deno.land/[email protected]/http/cookie.ts
Download https://deno.land/[email protected]/http/http_status.ts
Download https://deno.land/[email protected]/http/server.ts
Download https://deno.land/[email protected]/_util/assert.ts
Download https://deno.land/[email protected]/datetime/mod.ts
Download https://deno.land/[email protected]/async/mod.ts
Download https://deno.land/[email protected]/datetime/formatter.ts
Download https://deno.land/[email protected]/async/deadline.ts
Download https://deno.land/[email protected]/async/debounce.ts
Download https://deno.land/[email protected]/async/deferred.ts
Download https://deno.land/[email protected]/async/delay.ts
Download https://deno.land/[email protected]/async/mux_async_iterator.ts
Download https://deno.land/[email protected]/async/pool.ts
Download https://deno.land/[email protected]/async/tee.ts
Download https://deno.land/[email protected]/datetime/tokenizer.ts
error: an internal error occured

and @lucacasonato seemed to be able to reproduce it as well. The same happens for other std modules with that URL pattern. The CLI returns with a 0 exit code though.

I am on 1.15.2 but cannot say for sure if it was just introduced by that patch or not.

Lazily construct wasm module

To support CJS (remove top level await) and scenarios where deno graph is imported but not used, we should support lazily creating a deno_graph.

For example:

import { load } from "...";

const denoGraph = await load();

await denoGraph.createGraph(....);

Ability to get deno-types dependencies of a module

Given a module I would like to know all its deno-types references. Is there a way to do this without having to traverse the AST to get the module specifiers? I think this is only currently possible in Wasm since in the module.dependencies it exposes maybe_type and maybe_code for Wasm, but I didn't see a way to do this in Rust.

I want to do this because I would like to know up front all the /// @deno-types="..." that a file has in order to find out the declaration files used for a module (for the purposes of the deno -> node transform).

Ref #32.

Improve error message for wrong JSON imports

$ cat test.js
import * as data from "./data.json";
$ cargo run -- run -A test.js
error: An unsupported media type was attempted to be imported as a module.
  Specifier: file:///Users/biwanczuk/dev/deno/data.json
  MediaType: Json
    at file:///Users/biwanczuk/dev/deno/test.js:1:23

The error message should suggest to add assert {type: "json} to the import statement.

For reference Chrome gives following message:

Expected a JavaScript module script but the server responded with a MIME type of "application/json". Strict MIME type checking is enforced for module scripts per HTML spec.

CC @kitsonk

Suggestion: Remove Locker from deno_graph

It looks like we could remove the concept of "locking" from deno graph and instead keep this functionality completely in the CLI. All we really need is a list of modules and their sources to do this, so this could help us simplify deno graph and we could also do this work more easily in parallel in the CLI.

Ability to discern between types directive and x-TypeScript-types

For deno vendor, it might be nice to have a way to represent /// <reference types="..." /> and x-TypeScript-types separately in the graph while still providing a common method for the maybe_types_dependency.

This would also help us remove Range from being necessary for x-typescript-types as the types directive could have a range, but the x-typescript-types doesn't need one:

deno_graph/src/graph.rs

Lines 1331 to 1340 in f8adbe4

if let Some(types_header) = headers.get("x-typescript-types") {
let range = Range {
specifier: module.specifier.clone(),
start: Position::zeroed(),
end: Position::zeroed(),
};
let resolved_dependency = resolve(types_header, &range, maybe_resolver);
module.maybe_types_dependency =
Some((types_header.clone(), resolved_dependency));
}

Alternatively, I can just do a check for the start and end position all being zero, but that seems a little hacky.

I have a module, now what?

Ok suppose I've got parseModule/createGraph resolving modules correctly. How can I now execute the module?

const m = await denoGraph.parseModule("http://example.ts", "export default { foo: true }")

const { foo } = // ??
console.log(foo)

Modules returned by `createGraph` are missing the `local` property

Modules returned by createGraph seem to have an undefined local property. Is there a reason it is on the type def if it's known to be unimplemented?

  /** The string path to where the local version of the content is located. For
   * non `file:` URLs, this is the location of the cached content, otherwise it
   * is the absolute path to the local file. */
  local?: string;

Include a version number in the serialized JSON output

Weโ€™re going to be changing the output of deno info --json in 2.0. To help with this change and future changes, we should include a version number in the JSON output so people using this output can quickly tell if they support it without having to version sniff the binary and know which version something changed or have to detect the shape.

Related: #228

This should only be done when releasing deno_graph with the new schema changes.

Add `ModuleKind` to graph and be returned by `Resolver.resolve`

Was talking to @bartlomieju today so this is a quick summary of the discussion. For denoland/deno#12648 we'll need a way to identify if .js/MediaType::JavaScript files are CJS or MJS. This can be determined a number of ways in node (ex. a package.json having say "type": "module") which is information that's known by the node compat resolvers in the CLI. Perhaps it would be useful to introduce a ModuleType enum that has members ModuleType::Cjs & ModuleType::Mjs and the Resolver.resolve method could return that value which would then be stored in the graph.

Use byte indexes instead of lines and columns

I think lines and columns is an LSP & display concern and we should remove it from deno_graph. I think deno_graph should just return byte indexes or at least have both. It would also be good to standardize any unit types with deno_ast (so probably just use swc's Span for ranges... or maybe we could make our own type that uses usize and easily converts to an swc span)

discussion_r767983595

Add ability to have _type only_ and _code only_ graphs

Currently, when building a graph, both type dependencies and code dependencies are analysed, because most consumers care about both of these types of dependencies, but when generating documentation (e.g. deno_doc) or just running code (e.g. Deploy/eszip) only parts of the graph are needed, but both kinds will be loaded and followed fully to generate the graph.

When generating documentation on the fly, this causes a lot of wasted CPU cycles, potentially loading runtime code that can't impact the typing of the code, and when creating a "runtime" code graph, wastes cycles on analysing type only dependencies.

We should have an option when building the graph to have All TypeOnly and CodeOnly options and visiting only those modules as appropriate.

Dynamic import not reported

Given thoses files :

// file://root/page.ts
function main() {
  import('./script.ts')
}

// file://root/script.ts
function main() {
  console.log('hello world')
}

If i run this :

    const moduleGraph = await graph.createGraph(`file://root/page.ts`)
    
    console.log(JSON.stringify(moduleGraph, null, 4))

I get the following JSON :

{
    "roots": [
        "file:///root/page.ts"
    ],
    "modules": [
        {
            "dependencies": [
                {
                    "specifier": "./script.ts",
                    "code": {
                        "specifier": "file:///root/script.ts",
                        "span": {
                            "start": {
                                "line": 1,
                                "character": 11
                            },
                            "end": {
                                "line": 1,
                                "character": 25
                            }
                        }
                    }
                }
            ],
            "mediaType": "TypeScript",
            "size": 59,
            "specifier": "file:///root/page.ts"
        },
        {
            "dependencies": [],
            "mediaType": "TypeScript",
            "size": 97,
            "specifier": "file:///root/script.ts"
        }
    ],
    "redirects": {}
}

I expected that for the module with specifier "file:///root/page.ts", there would be one dependency with the property isDynamic: true. Instead the property isDynamic is missing.

Edit:
If i understand #32 correctly, the property is_dynamic is not exposed by the underlying rust struct. But given the signature of the loadย function, i would expect this information to be exposed.

Support CommonJs dependency analysis

swc already supports parsing this out (we just simply discard those nodes at the moment), but I think the best way we can identify them in the graph is to add a is_require to the resolved dependency and pass it in the load() method, like we do with is_dynamic.

I will work on a PR for it. Makes me feel a bit ๐Ÿคข though ๐Ÿ˜‰.

Provide an API for allowing type dependencies to be resolved

Currently deno_graph has strong opinions about how type dependencies are resolved when building a graph, but this ability should be extended.

Specifically, a module has a maybe_types_dependency and this gets determined one of two ways:

  • The file is a JavaScript file and it contains a leading triple-slash reference types directive.
  • When loading a module, the module contains a header of X-TypeScript-Types

But other resolution algorithms maybe have other semantics, for example:

  • A package.json is inspected and there is a "typings" property.
  • When looking at files on the disk, there is a desire to resolve a .d.ts file and a .js file for an import.
  • It is determined that a @types dependency is available locally or remotely.

I want to do a little bit more thinking about it, so we don't just "hack" it in there, but I think we need to come up with a solution, but I am currently thinking that the Loader trait would have a new optional method:

  • fn resolve_types(&self, specifier: &ModuleSpecifier) -> Result<Option<ModuleSpecifier>>

It would only get called if the media type for the module was not TypeScript or TSX and the built-in logic did not identify a types dependency. It would be called with the media specifier returned from the load result, so in the case of a redirect, it would call with the final specifier.

cc/ @bartlomieju and @dsherret

Graph does not support multiple imports of the same specifier

When doing something like this:

import a from "./a.js";
import * as b from "./a.js";
const c = await import("./a.js");

The dependencies for the module only include one import site. They should actually be two seperate dependency objects, as they "may" differ in ways (like import assertions or type definitions).

That being said, it still works and adding support for it would make everything related to it fairly complex, as knowing the import location would become essential for accessing information (unless we stored a vec of locations, and associated information, like it being a dynamic import and any import assertions).

Is there a command like `npm explain` or `yarn why`?

As the deno version is upgraded to 1.14.0, an error occurs in the following module, I wonder why this module was installed.

โฏ deno run ...blabla
Check file:///...blabla
error: TS2801 [ERROR]: This condition will always return true since this 'Promise<Deno.PermissionStatus>' is always defined.
  if (Deno.permissions.query({ name: "env" })) {
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    at https://deno.land/x/[email protected]/is_interactive.ts:2:7

TS2773 [ERROR]:     Did you forget to use 'await'?
      if (Deno.permissions.query({ name: "env" })) {
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        at https://deno.land/x/[email protected]/is_interactive.ts:2:7

The deno info command didn't give me the info I needed.

โฏ deno info https://deno.land/x/[email protected]/is_interactive.ts
local: /Users/me/Library/Caches/deno/deps/https/deno.land/26e835f96821d84b7a10ed84ee8bf125c1bf7bbdbf8f1cfc5cd8b03d96a83ae0
type: TypeScript
emit: /Users/me/Library/Caches/deno/gen/https/deno.land/26e835f96821d84b7a10ed84ee8bf125c1bf7bbdbf8f1cfc5cd8b03d96a83ae0.js
dependencies: 0 unique (total 275B)

https://deno.land/x/[email protected]/is_interactive.ts (275B)

error: Loading unprepared module

tl/dr minimal reproduction lives here https://github.com/deckchairlabs/deno-loading-unprepared-module-error

I'm receiving the following error error: Loading unprepared module: file:///workspace/deno.json, when trying to do the below:

Note removing the compilerOptions related to jsx, the code runs without issue.

main.ts

import config from "./deno.json" assert { type: "json" };
console.log(config);

deno.json

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "react"
  },
  "importMap": "./importMap.json"
}

importMap.json

{
  "imports": {
    "react": "https://esm.sh/react@18",
    "react/jsx-runtime": "https://esm.sh/react@18/jsx-runtime.js"
  }
}

Validation should follow descendents

When validating a graph and reaching a type branch, current behaviour descends into the children imports, treating them as code imports, and therefore erroring when there is a type branch only error, which it shouldn't.

See: denoland/deno#15295

Identify source map URLs in modules

When analyzing sources, any "upstream" source maps should be identified and become part of the module graph. This would allow consumers of the graph information to be able to easily identify any upstream source maps and consume them.

This would help enable denoland/deno#4499

Location of create_graph and add new element on struct

I just wonder when I see on forked deno_graph , I can't see create_graph function .
confused sorry for this question .

Another question I have , is , shall we add one element in Module struct or Specifier our absolute remote Url which may change on requesting and when we want to vendor it , it doesn't build with main package name and it could be strange name with path . I have just PR on deno which resolved this issue but wonder if we can create vendored path with main package name in importing . appreciate to help out and permit me to do it.

Allow representation of external and built-in dependencies

The graph should allow a loader to represent a load request with an External and BuiltIn load result. These would become the ModuleKind for the module slot and no dependency analysis would be performed. This would be an indictor to implementors that these require special loading at runtime.

Ability to tell about any dynamic import specifiers deno_graph could not statically analyze

It would be useful for deno vendor to warn when there's a dynamic import specifier that deno_graph can't statically analyze.

For example, given the following:

const value = (() => "./logger.ts")();
const { Logger } = await import(value);

This might be and is at the current moment a dynamic import deno_graph doesn't know how to statically analyze for. It would be useful for deno_graph to be able to say that somehow so the CLI can warn about these for deno vendor.

Support multiple ranges for an import in the graph

Currently the graph cannot represent multiple locations an import specifier might be imported in a file. For example, an import can be like this:

import * as a from "https://example.com/a";
import { default as b } from "https://example.com/a";

In addition, in theory, a module can be statically and dynamically imported:

import * as a from "https://example.com/a";
const b = await import("https://example.com/a";

Or in TypeScript the same specifier can be provided for a type only import:

import { a } from "https://example.com/a";
import type { A } from "https://example.com/a";

Currently we only store the last range for the specifier in the graph. This makes it difficult when trying to rewrite specifiers (like in dnt or deno vendor) as well as means that diagnostics are only issued for the "last" import location, not all import locations for a given specifier.

We should enhance the graph to be able to store this information, which is likely going to be a breaking change, but one that increases the usability of the graph.

Store all redirects completely resolved

I don't believe we should need this kind of code when resolving on a resolved graph:

deno_graph/src/graph.rs

Lines 1185 to 1202 in 2356edc

pub fn resolve(&self, specifier: &ModuleSpecifier) -> ModuleSpecifier {
let mut redirected_specifier = specifier;
let max_redirects = 10;
let mut seen = HashSet::with_capacity(max_redirects);
seen.insert(redirected_specifier);
while let Some(specifier) = self.redirects.get(redirected_specifier) {
if !seen.insert(specifier) {
eprintln!("An infinite loop of redirections detected.\n Original specifier: {specifier}");
break;
}
redirected_specifier = specifier;
if seen.len() >= max_redirects {
eprintln!("An excessive number of redirections detected.\n Original specifier: {specifier}");
break;
}
}
redirected_specifier.clone()
}

Resolving once the graph is resolved can be one step to the destination for performance reasons. I don't believe storing all the steps is necessary. If it's infinite, then we should store that in the graph as an error at the redirect.

Add "ProgressReporter" to track module graph building progress

It would be great if the graph builder allowed one to slot in a ProgressReporter into the graph builder that would be used to report graph building progress to the caller. How I imagine this working like so:

struct GraphLoadStats {
  /// The number of unique module specifiers that have been seen by the graph,
  /// that are done loading and parsing.
  completed_modules: usize,
  /// The number of unique module specifiers that have been seen by the graph,
  /// including ones where loading is still "in progress".
  seen_modules: usize,
}

trait ProgressReporter {
  /// This function is called after each module is done loading and parsing.
  fn on_load(&self, specifier: &Url, stats: GraphLoadStats);
}

This allows for progress indicators to display the progress of building the graph.

graph does not analyze JSDoc imports

https://github.com/denoland/deno/blob/1eb78731eb57b1d0eb7c0ece97b2018c1724989e/cli/lsp/documents.rs#L1025-L1059

This is where it goes wrong. Because the dependencies list is empty, it fails to resolve the imported module.
I think think it might be possible to fix this without making changes to swc.
If you add a regular import at the top of a file, that fixes the jsdoc import:

import {Bar} from "./Bar.js";

/** @type {import("./Bar.js").Bar} */
const foo = null;

Originally posted by @jespertheend in https://github.com/denoland/vscode_deno/issues/588#issuecomment-998330173

Improve documentation on `Module`

I've had to look at the deno_graph source code or run the code to understand what the key values and tuples parts are. We should add some documentation comments describing what the non-descriptive parts of the Module interface mean (and perhaps in the future we should switch to a more descriptive interface).

deno_graph/src/graph.rs

Lines 580 to 610 in f8adbe4

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Module {
#[serde(
skip_serializing_if = "BTreeMap::is_empty",
serialize_with = "serialize_dependencies"
)]
pub dependencies: BTreeMap<String, Dependency>,
pub kind: ModuleKind,
#[serde(flatten, skip_serializing_if = "Option::is_none")]
pub maybe_cache_info: Option<CacheInfo>,
#[serde(rename = "checksum", skip_serializing_if = "Option::is_none")]
pub maybe_checksum: Option<String>,
#[serde(skip_serializing)]
pub maybe_parsed_source: Option<ParsedSource>,
#[serde(
rename = "size",
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_maybe_source"
)]
pub maybe_source: Option<Arc<String>>,
#[serde(
rename = "typesDependency",
skip_serializing_if = "Option::is_none",
serialize_with = "serialize_type_dependency"
)]
pub maybe_types_dependency: Option<(String, Resolved)>,
#[serde(skip_serializing_if = "is_media_type_unknown")]
pub media_type: MediaType,
pub specifier: ModuleSpecifier,
}

There are actually just two properties that could be easily improved with some docs.

Matching pattern for JSDoc `import()` not wide enough

This works:

/** @type {import("./Foo.js").Foo?} */
const x = null;

But this doesn't:

/** @type {Set<import("./Foo.js").Foo>} */
const x = new Set();
error: TS2694 [ERROR]: Namespace '__' has no exported member 'Foo'.
/** @type {Set<import("./Foo.js").Foo>} */
                                  ~~~

Reduced test case here: jsdocimport.zip
Simply run deno run mod.js

I suppose this is an issue with deno_graph just like with denoland/deno#13156
ref: #91 #92

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.