Skip to content

Commit

Permalink
feat(#22): implement name inference
Browse files Browse the repository at this point in the history
  • Loading branch information
phoenix-ru committed Apr 4, 2024
1 parent bf8d2c5 commit 304911d
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 65 deletions.
1 change: 1 addition & 0 deletions crates/fervid/benches/parser_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn parser_benchmark(c: &mut Criterion) {
c.bench_with_input(
BenchmarkId::new("parser: parse", input.0),
&input.1,
#[allow(deprecated)]
|b, component| b.iter(|| fervid::parser_old::core::parse_sfc(black_box(component))),
);
}
Expand Down
56 changes: 49 additions & 7 deletions crates/fervid/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
//! let sfc = parser.parse_sfc().unwrap();
//!
//! // Do the necessary transformations
//! let is_prod = true;
//! let mut transform_errors = Vec::new();
//! let transform_result = fervid_transform::transform_sfc(sfc, is_prod, "filehash", &mut transform_errors);
//! let transform_options = fervid_transform::TransformSfcOptions {
//! is_prod: true,
//! scope_id: "filehash",
//! filename: "input.vue"
//! };
//! let transform_result = fervid_transform::transform_sfc(sfc, transform_options, &mut transform_errors);
//!
//! // Create the context and generate the template block
//! let mut ctx = fervid_codegen::CodegenContext::with_bindings_helper(transform_result.bindings_helper);
Expand Down Expand Up @@ -52,13 +56,37 @@ use errors::CompileError;
use fervid_codegen::CodegenContext;
pub use fervid_core::*;
use fervid_parser::SfcParser;
use fervid_transform::{style::should_transform_style_block, transform_sfc};
use std::hash::{DefaultHasher, Hash, Hasher};
use fervid_transform::{style::should_transform_style_block, transform_sfc, TransformSfcOptions};
use std::{borrow::Cow, hash::{DefaultHasher, Hash, Hasher}};
use swc_core::ecma::ast::Expr;

// TODO Add severity to errors
// TODO Better structs

#[derive(Debug, Clone)]
pub struct CompileOptions<'o> {
// ast?: RootNode;
pub filename: Cow<'o, str>,
pub id: Cow<'o, str>,
// pub scoped: Option<bool>,
// pub slotted: Option<bool>,
pub is_prod: Option<bool>,
pub ssr: Option<bool>,
// pub ssrCssVars?: string[],
// pub inMap?: RawSourceMap,
// pub compiler?: TemplateCompiler,
// pub compilerOptions?: CompilerOptions,
// pub preprocessLang?: string,
// pub preprocessOptions?: any,
// In some cases, compiler-sfc may not be inside the project root (e.g. when
// linked or globally installed). In such cases a custom `require` can be
// passed to correctly resolve the preprocessors.
// preprocessCustomRequire?: (id: string) => any;
// Configure what tags/attributes to transform into asset url imports,
// or disable the transform altogether with `false`.
// transformAssetUrls?: AssetURLOptions | AssetURLTagConfig | boolean;
}

pub struct CompileResult {
pub code: String,
pub file_hash: String,
Expand All @@ -83,16 +111,20 @@ pub struct CompileEmittedAsset {

/// A more general-purpose SFC compilation function.
/// Not production-ready yet.
pub fn compile(source: &str, is_prod: bool) -> Result<CompileResult, CompileError> {
pub fn compile(source: &str, options: CompileOptions) -> Result<CompileResult, CompileError> {
let mut all_errors = Vec::<CompileError>::new();

// Options
let is_prod = options.is_prod.unwrap_or_default();

// Parse
let mut sfc_parsing_errors = Vec::new();
let mut parser = SfcParser::new(source, &mut sfc_parsing_errors);
let sfc = parser.parse_sfc()?;
all_errors.extend(sfc_parsing_errors.into_iter().map(From::from));

// For scopes
// TODO Research if it's better to compute that on the caller site or here
let file_hash = {
let mut hasher = DefaultHasher::default();
source.hash(&mut hasher);
Expand All @@ -102,7 +134,12 @@ pub fn compile(source: &str, is_prod: bool) -> Result<CompileResult, CompileErro

// Transform
let mut transform_errors = Vec::new();
let transform_result = transform_sfc(sfc, is_prod, &file_hash, &mut transform_errors);
let transform_options = TransformSfcOptions {
is_prod,
scope_id: &file_hash,
filename: &options.filename,
};
let transform_result = transform_sfc(sfc, transform_options, &mut transform_errors);
all_errors.extend(transform_errors.into_iter().map(From::from));

// Codegen
Expand Down Expand Up @@ -182,7 +219,12 @@ pub fn compile_sync_naive(source: &str, is_prod: bool) -> Result<String, String>

// Transform
let mut transform_errors = Vec::new();
let transform_result = transform_sfc(sfc, is_prod, &file_hash, &mut transform_errors);
let tranform_options = TransformSfcOptions {
is_prod,
scope_id: &file_hash,
filename: "anonymous.vue".into(),
};
let transform_result = transform_sfc(sfc, tranform_options, &mut transform_errors);

// Codegen
let mut ctx = CodegenContext::with_bindings_helper(transform_result.bindings_helper);
Expand Down
Binary file modified crates/fervid_napi/.yarn/install-state.gz
Binary file not shown.
13 changes: 10 additions & 3 deletions crates/fervid_napi/__tests__/compileHelloWorld.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { test, expect } from 'vitest'

import { Compiler } from '../index'
import { Compiler, FervidCompileOptions } from '../index'

const options: FervidCompileOptions = {
filename: 'anonymous.vue',
id: ''
}

const HELLO_WORLD = `
<template>
Expand All @@ -17,10 +22,11 @@ const compilerName = ref('fervid')
`

test('should work', () => {
expect(new Compiler().compileSync(HELLO_WORLD).code).toMatchInlineSnapshot(`
expect(new Compiler().compileSync(HELLO_WORLD, options).code).toMatchInlineSnapshot(`
"import { ref } from 'vue';
import { createElementBlock as _createElementBlock, openBlock as _openBlock, toDisplayString as _toDisplayString } from "vue";
export default {
__name: "anonymous",
render (_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createElementBlock("div", {
class: "simple compiler input"
Expand All @@ -36,10 +42,11 @@ test('should work', () => {
"
`)

expect(new Compiler({ isProduction: true }).compileSync(HELLO_WORLD).code).toMatchInlineSnapshot(`
expect(new Compiler({ isProduction: true }).compileSync(HELLO_WORLD, options).code).toMatchInlineSnapshot(`
"import { ref } from 'vue';
import { createElementBlock as _createElementBlock, openBlock as _openBlock, toDisplayString as _toDisplayString } from "vue";
export default {
__name: "anonymous",
setup () {
const compilerName = ref('fervid');
return (_ctx, _cache)=>(_openBlock(), _createElementBlock("div", {
Expand Down
15 changes: 10 additions & 5 deletions crates/fervid_napi/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

/* auto-generated by NAPI-RS */

/** Raw options passed from the Node.js side */
export interface FervidJsCompilerOptions {
/** Apply production optimizations. Default: false */
isProduction?: boolean
Expand Down Expand Up @@ -47,6 +48,12 @@ export interface FervidJsCompilerOptionsStyle {
/** Ignored */
trim?: boolean
}
export interface FervidCompileOptions {
/** Scope ID for prefixing injected CSS variables */
id: string
/** Filename is used for automatic component name inference and self-referential imports */
filename: string
}
export interface CompileResult {
code: string
styles: Array<Style>
Expand All @@ -73,10 +80,8 @@ export interface SerializedError {
export type FervidJsCompiler = Compiler
/** Fervid: a compiler for Vue.js written in Rust */
export class Compiler {
isProduction: boolean
ssr: boolean
sourceMap: boolean
options: FervidJsCompilerOptions
constructor(options?: FervidJsCompilerOptions | undefined | null)
compileSync(source: string): CompileResult
compileAsync(source: string, signal?: AbortSignal | undefined | null): Promise<unknown>
compileSync(source: string, options: FervidCompileOptions): CompileResult
compileAsync(source: string, options: FervidCompileOptions, signal?: AbortSignal | undefined | null): Promise<unknown>
}
42 changes: 29 additions & 13 deletions crates/fervid_napi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#[global_allocator]
static ALLOC: mimalloc_rust::GlobalMiMalloc = mimalloc_rust::GlobalMiMalloc;

use std::borrow::Cow;

use napi::bindgen_prelude::*;
use napi_derive::napi;

use fervid::compile;
use structs::{CompileResult, FervidJsCompiler, FervidJsCompilerOptions};
use fervid::{compile, CompileOptions};
use structs::{CompileResult, FervidCompileOptions, FervidJsCompiler, FervidJsCompilerOptions};

mod structs;

Expand All @@ -17,35 +19,48 @@ impl FervidJsCompiler {
#[napi(constructor)]
pub fn new(options: Option<FervidJsCompilerOptions>) -> Self {
let options = options.unwrap_or_else(Default::default);

FervidJsCompiler {
is_production: options.is_production.unwrap_or(false),
ssr: options.ssr.unwrap_or(false),
source_map: options.source_map.unwrap_or(false),
}
FervidJsCompiler { options }
}

#[napi]
pub fn compile_sync(&self, source: String) -> Result<CompileResult> {
self.compile_and_convert(&source)
pub fn compile_sync(
&self,
source: String,
options: FervidCompileOptions,
) -> Result<CompileResult> {
self.compile_and_convert(&source, &options)
}

#[napi]
pub fn compile_async(
&self,
source: String,
options: FervidCompileOptions,
signal: Option<AbortSignal>,
) -> AsyncTask<CompileTask> {
let task = CompileTask {
compiler: self.to_owned(),
input: source,
options,
};
AsyncTask::with_optional_signal(task, signal)
}

fn compile_and_convert(&self, source: &str) -> Result<CompileResult> {
fn compile_and_convert(
&self,
source: &str,
options: &FervidCompileOptions,
) -> Result<CompileResult> {
// Normalize options to the ones defined in fervid
let compile_options = CompileOptions {
filename: Cow::Borrowed(&options.filename),
id: Cow::Borrowed(&options.id),
is_prod: self.options.is_production,
ssr: self.options.ssr
};

let native_compile_result =
compile(source, self.is_production).map_err(|e| Error::from_reason(e.to_string()))?;
compile(source, compile_options).map_err(|e| Error::from_reason(e.to_string()))?;

Ok(CompileResult {
code: native_compile_result.code,
Expand All @@ -71,6 +86,7 @@ impl FervidJsCompiler {
pub struct CompileTask {
compiler: FervidJsCompiler,
input: String,
options: FervidCompileOptions,
}

#[napi]
Expand All @@ -79,7 +95,7 @@ impl Task for CompileTask {
type Output = CompileResult;

fn compute(&mut self) -> napi::Result<Self::Output> {
self.compiler.compile_and_convert(&self.input)
self.compiler.compile_and_convert(&self.input, &self.options)
}

fn resolve(&mut self, _env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
Expand Down
21 changes: 16 additions & 5 deletions crates/fervid_napi/src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ use swc_core::common::Spanned;
#[napi(js_name = "Compiler")]
#[derive(Clone)]
pub struct FervidJsCompiler {
pub is_production: bool,
pub ssr: bool,
pub source_map: bool,
pub options: FervidJsCompilerOptions,
}

/// Raw options passed from the Node.js side
#[napi(object)]
#[derive(Default)]
#[derive(Default, Clone)]
pub struct FervidJsCompilerOptions {
/// Apply production optimizations. Default: false
pub is_production: Option<bool>,
Expand Down Expand Up @@ -41,7 +40,6 @@ pub struct FervidJsCompilerOptions {
/// - `string | RegExp`: matched files are converted into custom elements
/// Default: files ending with `.ce.vue`
pub custom_element: Option<()>,

// Ignored
// pub compiler: Option<()>,

Expand All @@ -50,9 +48,11 @@ pub struct FervidJsCompilerOptions {
}

#[napi(object)]
#[derive(Clone)]
pub struct FervidJsCompilerOptionsTemplate {}

#[napi(object)]
#[derive(Clone)]
pub struct FervidJsCompilerOptionsScript {
/// Ignored
/// Hoist <script setup> static constants.
Expand All @@ -62,11 +62,22 @@ pub struct FervidJsCompilerOptionsScript {
}

#[napi(object)]
#[derive(Clone)]
pub struct FervidJsCompilerOptionsStyle {
/// Ignored
pub trim: Option<bool>,
}

#[napi(object)]
#[derive(Clone)]
pub struct FervidCompileOptions {
/// Scope ID for prefixing injected CSS variables
pub id: String,

/// Filename is used for automatic component name inference and self-referential imports
pub filename: String,
}

#[napi(object)]
pub struct CompileResult {
pub code: String,
Expand Down
Loading

0 comments on commit 304911d

Please sign in to comment.