Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support analysis of require() statements #69

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 11 additions & 19 deletions README.md
Expand Up @@ -41,9 +41,9 @@ 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.
implementations. `resolve` takes the string specifier from the source, the
referring specifier, and the dependency kind. It 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
Expand Down Expand Up @@ -99,14 +99,6 @@ Currently part of the the `deno_core` crate. `deno_graph` explicitly doesn't
depend on `deno_core` or any part of the Deno CLI. It exports the type alias
publicably for re-use by other crates.

#### `MediaType` enum

Currently part of the `deno_cli` crate, this enum represents the various media
types that the Deno CLI can resolve and handle. Since `deno_graph` doesn't rely
upon any part of the Deno CLI, it was necessary to implement this in this crate,
and the implementation here will eventually replace the implementation in
`deno_cli`.

## Usage from Deno CLI or Deploy

This repository includes a compiled version of the Rust crate as Web Assembly
Expand All @@ -129,19 +121,19 @@ will serve as the roots of the module graph.
There are several options that can be passed the function in the optional
`options` argument:

- `load` - a callback function that takes a URL string and a flag indicating if
the dependency was required dynamically (e.g.
`const m = await import("mod.ts")`) and resolves with a `LoadResponse`. By
default a `load()` function that will attempt to load local modules via
- `load` - a callback function that takes a URL string, a flag indicating if the
dependency was required dynamically (e.g. `const m = await import("mod.ts")`),
and a dependency kind. It resolves with a `LoadResponse`. By default a
`load()` function that will attempt to load local modules via
`Deno.readFile()` and load remote modules via `fetch()`.
- `cacheInfo` - a callback function that takes a URL string and returns a
`CacheInfo` object. In the Deno CLI, the `DENO_DIR` cache info is passed back
using this interface. If the function is not provided, the information is not
present in the module graph.
- `resolve` - a callback function that takes a string and a referring URL string
and returns a fully qualified URL string. In the Deno CLI, import maps provide
this callback functionality of potentially resolving modules differently than
the default resolution.
- `resolve` - a callback function that takes a string, a referring URL string,
and a dependency kind enum/string. It returns a fully qualified URL string. In
the Deno CLI, import maps provide this callback functionality of potentially
resolving modules differently than the default resolution.
- `resolveTypes` - a callback function that takes a URL string and returns the
types dependency for the specifier, along with optionally the source of the
types dependency. This only gets called in situations where the module is
Expand Down
17 changes: 14 additions & 3 deletions lib/deno_graph.generated.js
Expand Up @@ -334,7 +334,7 @@ function handleError(f, args) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
}
function __wbg_adapter_76(arg0, arg1, arg2, arg3) {
function __wbg_adapter_78(arg0, arg1, arg2, arg3) {
wasm.wasm_bindgen__convert__closures__invoke2_mut__h667c772906bdb548(
arg0,
arg1,
Expand Down Expand Up @@ -722,6 +722,17 @@ const imports = {
return addHeapObject(ret);
}, arguments);
},
__wbg_call_d89773a0fc264fb1: function () {
return handleError(function (arg0, arg1, arg2, arg3, arg4) {
var ret = getObject(arg0).call(
getObject(arg1),
getObject(arg2),
getObject(arg3),
getObject(arg4),
);
return addHeapObject(ret);
}, arguments);
},
__wbg_set_a46091b120cc63e9: function (arg0, arg1, arg2) {
var ret = getObject(arg0).set(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
Expand All @@ -739,7 +750,7 @@ const imports = {
const a = state0.a;
state0.a = 0;
try {
return __wbg_adapter_76(a, state0.b, arg0, arg1);
return __wbg_adapter_78(a, state0.b, arg0, arg1);
} finally {
state0.a = a;
}
Expand Down Expand Up @@ -803,7 +814,7 @@ const imports = {
__wbindgen_rethrow: function (arg0) {
throw takeObject(arg0);
},
__wbindgen_closure_wrapper1338: function (arg0, arg1, arg2) {
__wbindgen_closure_wrapper1354: function (arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 266, __wbg_adapter_24);
return addHeapObject(ret);
},
Expand Down
Binary file modified lib/deno_graph_bg.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion lib/loader.ts
@@ -1,6 +1,6 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.

import type { LoadResponse } from "./types.d.ts";
import type { LoadResponse } from "./types.ts";

const hasPermissions = "permissions" in Deno;
let readRequested = false;
Expand Down
27 changes: 22 additions & 5 deletions lib/types.d.ts → lib/types.ts
Expand Up @@ -134,12 +134,29 @@ export interface Dependency {
* populated when the `@deno-types` directive was used to supply a type
* definition file for a dependency. */
type?: ResolvedDependency;
/** A flag indicating if the dependency was dynamic. (e.g.
* `await import("mod.ts")`) */
isDynamic?: true;
/** An enum/string that indicates the kind of dependency. */
kind: DependencyKind;
}

export enum DependencyKind {
/** The dependency was provided as an explicit import into the graph, either a
* root module or via a synthetic import */
Explicit = "Explicit",
/** The dependency was identified via an `import` or `import type`
* statement */
Import = "Import",
/** The dependency was identified via an `export` or `export type`
* statement */
Export = "Export",
/** The dependency was identified via a dynamic `import()` statement */
DynamicImport = "DynamicImport",
/** The dependency was identified via a `require` statement */
Require = "Require",
/** The dependency was identified via a pragma within the file */
Pragma = "Pragma",
}

export class Module {
export declare class Module {
private constructor();

/** Any cache information that was available on the module when the graph
Expand Down Expand Up @@ -174,7 +191,7 @@ export class Module {
}

/** An interface to the web assembly structure of a built module graph. */
export class ModuleGraph {
export declare class ModuleGraph {
private constructor();

/** The modules that are part of the module graph. */
Expand Down
26 changes: 20 additions & 6 deletions mod.ts
Expand Up @@ -5,23 +5,25 @@ import {
parseModule as jsParseModule,
} from "./lib/deno_graph.generated.js";
import { load as defaultLoad } from "./lib/loader.ts";
import { DependencyKind } from "./lib/types.ts";
import type {
CacheInfo,
LoadResponse,
Module,
ModuleGraph,
TypesDependency,
} from "./lib/types.d.ts";
} from "./lib/types.ts";

export { load } from "./lib/loader.ts";
export { DependencyKind } from "./lib/types.ts";
export type {
CacheInfo,
Dependency,
LoadResponse,
Module,
ModuleGraph,
TypesDependency,
} from "./lib/types.d.ts";
} from "./lib/types.ts";

export interface CreateGraphOptions {
/**
Expand All @@ -32,11 +34,15 @@ export interface CreateGraphOptions {
* returned.
*
* @param specifier The URL string of the resource to be loaded and resolved
* @param isDynamic A flag that indicates if the module was being loaded dynamically
* @param isDynamic A flag that indicates if the module or its parent was
* being loaded dynamically
* @param kind An enumerated value/string which indicates why the module is
* being loaded into the graph
*/
load?(
specifier: string,
isDynamic: boolean,
kind: DependencyKind,
): Promise<LoadResponse | undefined>;
/** When identifying a `@jsxImportSource` pragma, what module name will be
* appended to the import source. This defaults to `jsx-runtime`. */
Expand All @@ -49,8 +55,16 @@ export interface CreateGraphOptions {
* module graph to be "overridden". This is intended to allow items like an
* import map to be used with the module graph. The callback takes the string
* of the module specifier from the referrer and the string URL of the
* referrer. The callback then returns a resolved URL string specifier. */
resolve?(specifier: string, referrer: string): string;
* referrer. The callback then returns a resolved URL string specifier.
*
* @param specifier The string used to specify a dependency within
* the referrer
* @param referrer The URL string of the referrer that resolving the
* dependency should be used as a base
* @param kind A enum/string that indicates how the module is being asked to
* be resolved.
*/
resolve?(specifier: string, referrer: string, kind: DependencyKind): string;
/** An optional callback that can allow custom logic of how type dependencies
* of a module to be provided. This will be called if a module is being added
* to the graph that is is non-typed source code (e.g. JavaScript/JSX) and
Expand Down Expand Up @@ -170,7 +184,7 @@ export interface ParseModuleOptions {
* import map to be used with the module graph. The callback takes the string
* of the module specifier from the referrer and the string URL of the
* referrer. The callback then returns a resolved URL string specifier. */
resolve?(specifier: string, referrer: string): string;
resolve?(specifier: string, referrer: string, kind: DependencyKind): string;
/** An optional callback that can allow custom logic of how type dependencies
* of a module to be provided. This will be called if a module is being added
* to the graph that is is non-typed source code (e.g. JavaScript/JSX) and
Expand Down
26 changes: 9 additions & 17 deletions src/ast.rs
Expand Up @@ -2,8 +2,7 @@

use crate::module_specifier::ModuleSpecifier;

pub use deno_ast::swc::dep_graph::DependencyDescriptor;
pub use deno_ast::swc::dep_graph::DependencyKind;
use deno_ast::swc::dep_graph::DependencyDescriptor;

use anyhow::Result;
use deno_ast::parse_module;
Expand Down Expand Up @@ -47,19 +46,6 @@ pub enum TypeScriptReference {
Types(String, Span),
}

/// Gets all the dependencies of this module.
pub fn analyze_dependencies(
source: &ParsedSource,
) -> Vec<DependencyDescriptor> {
deno_ast::swc::dep_graph::analyze_dependencies(
source.module(),
source.comments(),
)
.into_iter()
.filter(|desc| desc.kind != DependencyKind::Require)
.collect()
}

/// Searches comments for any `@deno-types` compiler hints.
pub fn analyze_deno_types(
desc: &DependencyDescriptor,
Expand Down Expand Up @@ -258,7 +244,10 @@ mod tests {
let result = parser.parse_module(&specifier, source, MediaType::Tsx);
assert!(result.is_ok());
let parsed_source = result.unwrap();
let dependencies = analyze_dependencies(&parsed_source);
let dependencies = deno_ast::swc::dep_graph::analyze_dependencies(
parsed_source.module(),
parsed_source.comments(),
);
assert_eq!(dependencies.len(), 6);

let ts_references = analyze_ts_references(&parsed_source);
Expand Down Expand Up @@ -320,7 +309,10 @@ mod tests {
let result = parser.parse_module(&specifier, source, MediaType::TypeScript);
assert!(result.is_ok());
let parsed_source = result.unwrap();
let dependencies = analyze_dependencies(&parsed_source);
let dependencies = deno_ast::swc::dep_graph::analyze_dependencies(
parsed_source.module(),
parsed_source.comments(),
);
assert_eq!(dependencies.len(), 10);
assert_eq!(dependencies[0].specifier.to_string(), "./a.ts");
assert_eq!(
Expand Down