Skip to content

Commit

Permalink
Merge pull request #21 from embroider-build/sourcemapping
Browse files Browse the repository at this point in the history
  • Loading branch information
ef4 authored Sep 14, 2023
2 parents c162043 + 49a9797 commit 227d58d
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 209 deletions.
231 changes: 110 additions & 121 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ swc_ecma_utils = { git = "https://github.com/ef4/swc.git", branch = "content-tag
swc_ecma_transforms = { git = "https://github.com/ef4/swc.git", branch = "content-tag" }
swc_error_reporters = { git = "https://github.com/ef4/swc.git", branch = "content-tag" }
lazy_static = "1.4.0"

base64 = "0.21.4"
wasm-bindgen = "0.2.63"
js-sys = "0.3.64"

Expand Down
12 changes: 6 additions & 6 deletions sample/component.gjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { template as t } from '@ember/template-compiler';

console.log(template

const Inner = <template>I am inner</template>
const Inner = <template>I am inner {{yield}}</template>

// here's a comment
export class Outer {
<template><Inner /></template>
<template>
<Inner>
Hello world
</Inner>
</template>
}
34 changes: 26 additions & 8 deletions src/bindings.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::{Options, Preprocessor as CorePreprocessor};
use std::{fmt, str};
use std::{fmt, str};
use swc_common::{
errors::Handler,
sync::{Lock, Lrc},
SourceMap,
Spanned,
SourceMap, Spanned,
};
use swc_error_reporters::{GraphicalReportHandler, GraphicalTheme, PrettyEmitter};
use wasm_bindgen::prelude::*;
Expand All @@ -29,7 +28,11 @@ impl fmt::Write for Writer {
}
}

fn capture_err_detail(err: swc_ecma_parser::error::Error, source_map: Lrc<SourceMap>, theme: GraphicalTheme) -> JsValue {
fn capture_err_detail(
err: swc_ecma_parser::error::Error,
source_map: Lrc<SourceMap>,
theme: GraphicalTheme,
) -> JsValue {
let wr = Writer::default();
let emitter = PrettyEmitter::new(
source_map,
Expand All @@ -46,8 +49,22 @@ fn capture_err_detail(err: swc_ecma_parser::error::Error, source_map: Lrc<Source
fn as_javascript_error(err: swc_ecma_parser::error::Error, source_map: Lrc<SourceMap>) -> JsValue {
let short_desc = format!("Parse Error at {}", source_map.span_to_string(err.span()));
let js_err = js_error(short_desc.into());
js_sys::Reflect::set(&js_err, &"source_code".into(), &capture_err_detail(err.clone(), source_map.clone(), GraphicalTheme::unicode_nocolor())).unwrap();
js_sys::Reflect::set(&js_err, &"source_code_color".into(), &capture_err_detail(err, source_map, GraphicalTheme::unicode())).unwrap();
js_sys::Reflect::set(
&js_err,
&"source_code".into(),
&capture_err_detail(
err.clone(),
source_map.clone(),
GraphicalTheme::unicode_nocolor(),
),
)
.unwrap();
js_sys::Reflect::set(
&js_err,
&"source_code_color".into(),
&capture_err_detail(err, source_map, GraphicalTheme::unicode()),
)
.unwrap();
return js_err;
}

Expand All @@ -64,8 +81,9 @@ impl Preprocessor {
let result = self.core.process(
&src,
Options {
filename: filename.map(|f| f.into())
}
filename: filename.map(|f| f.into()),
inline_source_map: false,
},
);

match result {
Expand Down
78 changes: 54 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#[macro_use]
extern crate lazy_static;

use base64::{engine::general_purpose, Engine as _};
use std::path::PathBuf;
use swc_common::comments::SingleThreadedComments;
use swc_common::source_map::SourceMapGenConfig;
use swc_common::Mark;
use swc_common::{self, sync::Lrc, FileName, SourceMap};
use swc_core::common::GLOBALS;
Expand All @@ -13,7 +15,7 @@ use swc_ecma_ast::{
ModuleItem,
};
use swc_ecma_codegen::Emitter;
use swc_ecma_parser::{lexer::Lexer, TsConfig, Parser, StringInput, Syntax};
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig};
use swc_ecma_transforms::hygiene::hygiene_with_config;
use swc_ecma_transforms::resolver;
use swc_ecma_utils::private_ident;
Expand All @@ -26,13 +28,25 @@ mod transform;
#[derive(Default)]
pub struct Options {
pub filename: Option<PathBuf>,
pub inline_source_map: bool,
}

pub struct Preprocessor {
source_map: Lrc<SourceMap>,
comments: SingleThreadedComments,
}

struct SourceMapConfig;
impl SourceMapGenConfig for SourceMapConfig {
fn file_name_to_source(&self, f: &swc_common::FileName) -> String {
f.to_string()
}

fn inline_sources_content(&self, _: &swc_common::FileName) -> bool {
true
}
}

impl Preprocessor {
pub fn new() -> Self {
Self {
Expand All @@ -49,13 +63,11 @@ impl Preprocessor {
let target_specifier = "template";
let target_module = "@ember/template-compiler";
let filename = match options.filename {
Some(name) => FileName::Real(name),
Some(name) => FileName::Real(name),
None => FileName::Anon,
};

let source_file = self
.source_map
.new_source_file(filename, src.to_string());
let source_file = self.source_map.new_source_file(filename, src.to_string());

let lexer = Lexer::new(
Syntax::Typescript(TsConfig {
Expand Down Expand Up @@ -98,24 +110,45 @@ impl Preprocessor {

simplify_imports(&mut parsed_module);

Ok(self.print(&parsed_module))
Ok(self.print(&parsed_module, options.inline_source_map))
})
}

fn print(&self, module: &Module) -> String {
fn print(&self, module: &Module, inline_source_map: bool) -> String {
let mut buf = vec![];
let mut srcmap = vec![];
let mut emitter = Emitter {
cfg: Default::default(),
cm: self.source_map.clone(),
wr: Box::new(swc_ecma_codegen::text_writer::JsWriter::new(
self.source_map.clone(),
wr: swc_ecma_codegen::text_writer::JsWriter::new(
self.source_map().clone(),
"\n",
&mut buf,
None,
)),
Some(&mut srcmap),
),
comments: Some(&self.comments),
};
emitter.emit_module(module).unwrap();

if inline_source_map {
let mut source_map_buffer = vec![];
self.source_map()
.build_source_map_with_config(&srcmap, None, SourceMapConfig {})
.to_writer(&mut source_map_buffer)
.unwrap();

let mut comment = "//# sourceMappingURL=data:application/json;base64,"
.to_owned()
.into_bytes();
buf.append(&mut comment);

let mut encoded = general_purpose::URL_SAFE_NO_PAD
.encode(source_map_buffer)
.into_bytes();

buf.append(&mut encoded);
}

let s = String::from_utf8_lossy(&buf);
s.to_string()
}
Expand Down Expand Up @@ -230,23 +263,23 @@ testcase! {
no_preexisting_import,
r#"let x = <template>hello</template>"#,
r#"import { template } from "@ember/template-compiler";
let x = template("hello", { eval() { return eval(arguments[0])} });"#
let x = template(`hello`, { eval() { return eval(arguments[0])} });"#
}

testcase! {
uses_preexisting_import,
r#"import { template } from "@ember/template-compiler";
let x = <template>hello</template>"#,
r#"import { template } from "@ember/template-compiler";
let x = template("hello", { eval() { return eval(arguments[0])} });"#
let x = template(`hello`, { eval() { return eval(arguments[0])} });"#
}

testcase! {
uses_preexisting_renamed_import,
r#"import { template as t } from "@ember/template-compiler";
let x = <template>hello</template>"#,
r#"import { template as t } from "@ember/template-compiler";
let x = t("hello", { eval() { return eval(arguments[0])} })"#
let x = t(`hello`, { eval() { return eval(arguments[0])} })"#
}

testcase! {
Expand All @@ -263,7 +296,7 @@ testcase! {
r#"import { template as template1 } from "@ember/template-compiler";
function template() {};
console.log(template());
export default template1("Hi", { eval() { return eval(arguments[0])} });"#
export default template1(`Hi`, { eval() { return eval(arguments[0])} });"#
}

testcase! {
Expand All @@ -275,22 +308,19 @@ testcase! {
r#"import { template as template1 } from "@ember/template-compiler";
export default function(template) {
console.log(template);
return template1("X", { eval() { return eval(arguments[0])} });
return template1(`X`, { eval() { return eval(arguments[0])} });
};"#
}


testcase! {
handles_typescript,
r#"function makeComponent(message: string) {
handles_typescript,
r#"function makeComponent(message: string) {
console.log(message);
return <template>hello</template>
}"#,
r#"import { template } from "@ember/template-compiler";
r#"import { template } from "@ember/template-compiler";
function makeComponent(message: string) {
console.log(message);
return template("hello", { eval() { return eval(arguments[0]) } });
return template(`hello`, { eval() { return eval(arguments[0]) } });
}"#
}


}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn main() {
&src,
Options {
filename: Some(filename),
inline_source_map: true,
},
);

Expand Down
36 changes: 29 additions & 7 deletions src/snippets.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use swc_common::comments::SingleThreadedComments;
use swc_common::Span;
use swc_common::{self, sync::Lrc, FileName, SourceMap};
use swc_ecma_ast::Expr;
use swc_ecma_ast::{Expr, Module};
use swc_ecma_parser::{lexer::Lexer, EsConfig, Parser, StringInput, Syntax};
use swc_ecma_visit::{as_folder, VisitMut, VisitMutWith};

lazy_static! {
pub static ref SCOPE_PARAMS: Box<Expr> =
parse_expression(r#"({ eval() { return eval(arguments[0]); } })"#);
static ref SCOPE_PARAMS: Module = parse(r#"({ eval() { return eval(arguments[0]); } })"#);
}

lazy_static! {
pub static ref SCOPE_PARAMS_WITH_THIS: Box<Expr> =
parse_expression(r#"({ component: this, eval() { return eval(arguments[0]); } })"#);
static ref SCOPE_PARAMS_WITH_THIS: Module =
parse(r#"({ component: this, eval() { return eval(arguments[0]); } })"#);
}

fn parse_expression(src: &str) -> Box<Expr> {
fn parse(src: &str) -> Module {
let filename = "glimmer-template-prelude.js".into();
let source_map: Lrc<SourceMap> = Default::default();
let comments = SingleThreadedComments::default();
Expand All @@ -31,8 +32,21 @@ fn parse_expression(src: &str) -> Box<Expr> {
);

let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().unwrap();
parser.parse_module().unwrap()
}

struct SpanReplacer {
span: Span,
}
impl VisitMut for SpanReplacer {
fn visit_mut_span(&mut self, n: &mut Span) {
*n = self.span;
}
}

fn generate_expression(span: Span, template_module: &Module) -> Box<Expr> {
let mut module = template_module.clone();
module.visit_mut_with(&mut as_folder(SpanReplacer { span }));
module
.body
.first()
Expand All @@ -47,3 +61,11 @@ fn parse_expression(src: &str) -> Box<Expr> {
.expr
.clone()
}

pub fn scope_params(span: Span) -> Box<Expr> {
generate_expression(span, &(*SCOPE_PARAMS))
}

pub fn scope_params_with_this(span: Span) -> Box<Expr> {
generate_expression(span, &(*SCOPE_PARAMS_WITH_THIS))
}
Loading

0 comments on commit 227d58d

Please sign in to comment.