Skip to content

Commit

Permalink
feat: support identifying jsxImportSource pragma dependencies (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitsonk authored Nov 2, 2021
1 parent 45b7c04 commit 9ce1792
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 16 deletions.
40 changes: 32 additions & 8 deletions lib/deno_graph.generated.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ function isLikeNone(x) {
/**
* @param {string} specifier
* @param {any} maybe_headers
* @param {string | undefined} maybe_jsx_import_source_module
* @param {string} content
* @param {Function | undefined} maybe_resolve
* @param {Function | undefined} maybe_resolve_types
Expand All @@ -229,6 +230,7 @@ function isLikeNone(x) {
export function parseModule(
specifier,
maybe_headers,
maybe_jsx_import_source_module,
content,
maybe_resolve,
maybe_resolve_types,
Expand All @@ -239,18 +241,28 @@ export function parseModule(
wasm.__wbindgen_realloc,
);
var len0 = WASM_VECTOR_LEN;
var ptr1 = passStringToWasm0(
var ptr1 = isLikeNone(maybe_jsx_import_source_module)
? 0
: passStringToWasm0(
maybe_jsx_import_source_module,
wasm.__wbindgen_malloc,
wasm.__wbindgen_realloc,
);
var len1 = WASM_VECTOR_LEN;
var ptr2 = passStringToWasm0(
content,
wasm.__wbindgen_malloc,
wasm.__wbindgen_realloc,
);
var len1 = WASM_VECTOR_LEN;
var len2 = WASM_VECTOR_LEN;
var ret = wasm.parseModule(
ptr0,
len0,
addHeapObject(maybe_headers),
ptr1,
len1,
ptr2,
len2,
isLikeNone(maybe_resolve) ? 0 : addHeapObject(maybe_resolve),
isLikeNone(maybe_resolve_types) ? 0 : addHeapObject(maybe_resolve_types),
);
Expand All @@ -260,6 +272,7 @@ export function parseModule(
/**
* @param {any} roots
* @param {Function} load
* @param {string | undefined} maybe_jsx_import_source_module
* @param {Function | undefined} maybe_cache_info
* @param {Function | undefined} maybe_resolve
* @param {Function | undefined} maybe_resolve_types
Expand All @@ -272,6 +285,7 @@ export function parseModule(
export function createGraph(
roots,
load,
maybe_jsx_import_source_module,
maybe_cache_info,
maybe_resolve,
maybe_resolve_types,
Expand All @@ -280,24 +294,34 @@ export function createGraph(
maybe_lockfile_name,
maybe_imports,
) {
var ptr0 = isLikeNone(maybe_lockfile_name)
var ptr0 = isLikeNone(maybe_jsx_import_source_module)
? 0
: passStringToWasm0(
maybe_lockfile_name,
maybe_jsx_import_source_module,
wasm.__wbindgen_malloc,
wasm.__wbindgen_realloc,
);
var len0 = WASM_VECTOR_LEN;
var ptr1 = isLikeNone(maybe_lockfile_name)
? 0
: passStringToWasm0(
maybe_lockfile_name,
wasm.__wbindgen_malloc,
wasm.__wbindgen_realloc,
);
var len1 = WASM_VECTOR_LEN;
var ret = wasm.createGraph(
addHeapObject(roots),
addHeapObject(load),
ptr0,
len0,
isLikeNone(maybe_cache_info) ? 0 : addHeapObject(maybe_cache_info),
isLikeNone(maybe_resolve) ? 0 : addHeapObject(maybe_resolve),
isLikeNone(maybe_resolve_types) ? 0 : addHeapObject(maybe_resolve_types),
isLikeNone(maybe_check) ? 0 : addHeapObject(maybe_check),
isLikeNone(maybe_get_checksum) ? 0 : addHeapObject(maybe_get_checksum),
ptr0,
len0,
ptr1,
len1,
addHeapObject(maybe_imports),
);
return takeObject(ret);
Expand Down Expand Up @@ -779,8 +803,8 @@ const imports = {
__wbindgen_rethrow: function (arg0) {
throw takeObject(arg0);
},
__wbindgen_closure_wrapper1325: function (arg0, arg1, arg2) {
var ret = makeMutClosure(arg0, arg1, 262, __wbg_adapter_24);
__wbindgen_closure_wrapper1333: 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.
11 changes: 10 additions & 1 deletion mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export interface CreateGraphOptions {
specifier: string,
isDynamic: boolean,
): Promise<LoadResponse | undefined>;
/** When identifying a `@jsxImportSource` pragma, what module name will be
* appended to the import source. This defaults to `jsx-runtime`. */
jsxImportSourceModule?: string;
/** An optional callback that will be called with a URL string of the resource
* to provide additional meta data about the resource to enrich the module
* graph. */
Expand Down Expand Up @@ -131,6 +134,7 @@ export function createGraph(
: [rootSpecifiers];
const {
load = defaultLoad,
jsxImportSourceModule,
cacheInfo,
resolve,
resolveTypes,
Expand All @@ -142,6 +146,7 @@ export function createGraph(
return jsCreateGraph(
rootSpecifiers,
load,
jsxImportSourceModule,
cacheInfo,
resolve,
resolveTypes,
Expand All @@ -157,6 +162,9 @@ export interface ParseModuleOptions {
/** For remote resources, a record of headers should be set, where the key's
* have been normalized to be lower case values. */
headers?: Record<string, string>;
/** When identifying a `@jsxImportSource` pragma, what module name will be
* appended to the import source. This defaults to `jsx-runtime`. */
jsxImportSourceModule?: string;
/** An optional callback that allows the default resolution logic of the
* 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
Expand Down Expand Up @@ -184,10 +192,11 @@ export function parseModule(
content: string,
options: ParseModuleOptions = {},
): Module {
const { headers, resolve, resolveTypes } = options;
const { headers, jsxImportSourceModule, resolve, resolveTypes } = options;
return jsParseModule(
specifier,
headers,
jsxImportSourceModule,
content,
resolve,
resolveTypes,
Expand Down
32 changes: 29 additions & 3 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ use std::collections::HashMap;
use std::sync::Arc;

lazy_static! {
/// Matched the `@deno-types` pragma.
/// Matches the `@deno-types` pragma.
static ref DENO_TYPES_RE: Regex =
Regex::new(r#"(?i)^\s*@deno-types\s*=\s*(?:["']([^"']+)["']|(\S+))"#)
.unwrap();
/// Matches the `@jsxImportSource` pragma.
static ref JSX_IMPORT_SOURCE_RE: Regex = Regex::new(r#"(?i)^[\s*]*@jsxImportSource\s+(\S+)"#).unwrap();
/// Matches a `/// <reference ... />` comment reference.
static ref TRIPLE_SLASH_REFERENCE_RE: Regex =
Regex::new(r"(?i)^/\s*<reference\s.*?/>").unwrap();
Expand Down Expand Up @@ -79,6 +81,22 @@ pub fn analyze_deno_types(
}
}

/// Searches comments for a `@jsxImportSource` pragma on JSX/TSX media types
pub fn analyze_jsx_import_sources(
parsed_source: &ParsedSource,
) -> Option<(String, Span)> {
match parsed_source.media_type() {
MediaType::Jsx | MediaType::Tsx => {
parsed_source.get_leading_comments().iter().find_map(|c| {
let captures = JSX_IMPORT_SOURCE_RE.captures(&c.text)?;
let m = captures.get(1)?;
Some((m.as_str().to_string(), comment_match_to_swc_span(c, &m)))
})
}
_ => None,
}
}

fn comment_match_to_swc_span(comment: &Comment, m: &Match) -> Span {
// the comment text starts after the double slash or slash star, so add 2
let comment_start = comment.span.lo + BytePos(2);
Expand Down Expand Up @@ -211,11 +229,12 @@ mod tests {
#[test]
fn test_parse() {
let specifier =
ModuleSpecifier::parse("file:///a/test.ts").expect("bad specifier");
ModuleSpecifier::parse("file:///a/test.tsx").expect("bad specifier");
let source = Arc::new(
r#"
/// <reference path="./ref.d.ts" />
/// <reference types="./types.d.ts" />
/* @jsxImportSource http://example.com/preact */
import {
A,
B,
Expand All @@ -236,7 +255,7 @@ mod tests {
.to_string(),
);
let parser = DefaultSourceParser::new();
let result = parser.parse_module(&specifier, source, MediaType::TypeScript);
let result = parser.parse_module(&specifier, source, MediaType::Tsx);
assert!(result.is_ok());
let parsed_source = result.unwrap();
let dependencies = analyze_dependencies(&parsed_source);
Expand Down Expand Up @@ -268,6 +287,13 @@ mod tests {
parsed_source.source().span_text(&dep_deno_types.1),
"https://deno.land/x/types/react/index.d.ts"
);

let (specifier, span) = analyze_jsx_import_sources(&parsed_source).unwrap();
assert_eq!(specifier, "http://example.com/preact");
assert_eq!(
parsed_source.source().span_text(&span),
"http://example.com/preact"
);
}

#[test]
Expand Down
14 changes: 14 additions & 0 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use crate::ast;
use crate::ast::analyze_deno_types;
use crate::ast::analyze_dependencies;
use crate::ast::analyze_jsx_import_sources;
use crate::ast::analyze_ts_references;
use crate::ast::SourceParser;
use crate::module_specifier::resolve_import;
Expand Down Expand Up @@ -1017,6 +1018,19 @@ pub(crate) fn parse_module_from_ast(
}
}

// Analyze any JSX Import Source pragma
if let Some((import_source, span)) = analyze_jsx_import_sources(parsed_source)
{
let jsx_import_source_module = maybe_resolver
.map(|r| r.jsx_import_source_module())
.unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE);
let specifier = format!("{}/{}", import_source, jsx_import_source_module);
let range = Range::from_swc_span(&module.specifier, parsed_source, &span);
let resolved_dependency = resolve(&specifier, &range, maybe_resolver);
let dep = module.dependencies.entry(specifier).or_default();
dep.maybe_code = resolved_dependency;
}

// Analyze the X-TypeScript-Types header
if module.maybe_types_dependency.is_none() {
if let Some(headers) = maybe_headers {
Expand Down
11 changes: 11 additions & 0 deletions src/js_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::source::LoadFuture;
use crate::source::Loader;
use crate::source::Locker;
use crate::source::Resolver;
use crate::source::DEFAULT_JSX_IMPORT_SOURCE_MODULE;

use anyhow::anyhow;
use anyhow::Result;
Expand Down Expand Up @@ -145,16 +146,19 @@ impl Locker for JsLocker {

#[derive(Debug)]
pub struct JsResolver {
maybe_jsx_import_source_module: Option<String>,
maybe_resolve: Option<js_sys::Function>,
maybe_resolve_types: Option<js_sys::Function>,
}

impl JsResolver {
pub fn new(
maybe_jsx_import_source_module: Option<String>,
maybe_resolve: Option<js_sys::Function>,
maybe_resolve_types: Option<js_sys::Function>,
) -> Self {
Self {
maybe_jsx_import_source_module,
maybe_resolve,
maybe_resolve_types,
}
Expand All @@ -168,6 +172,13 @@ struct JsResolveTypesResponse {
}

impl Resolver for JsResolver {
fn jsx_import_source_module(&self) -> &str {
self
.maybe_jsx_import_source_module
.as_deref()
.unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE)
}

fn resolve(
&self,
specifier: &str,
Expand Down
Loading

0 comments on commit 9ce1792

Please sign in to comment.