Skip to content

Commit f64ece2

Browse files
committed
feat!: add experimental RFC opt-ins
1 parent 672683a commit f64ece2

72 files changed

Lines changed: 1175 additions & 52 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/vize/src/commands/build/runner.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ pub(crate) fn run(args: BuildArgs) {
5555
} else {
5656
crate::config::load_compiler_template_syntax(args.config.as_deref())
5757
};
58+
let config_features = if args.no_config {
59+
crate::config::ConfigFeatureFlags::default()
60+
} else {
61+
crate::config::load_config_with_features_and_source(args.config.as_deref()).features
62+
};
63+
let configured_vapor = if args.no_config {
64+
None
65+
} else {
66+
crate::config::load_compiler_vapor(args.config.as_deref())
67+
};
5868
let configured_dialect = if args.no_config {
5969
None
6070
} else {
@@ -114,12 +124,15 @@ pub(crate) fn run(args: BuildArgs) {
114124
let compile_start = Instant::now();
115125
let compile_settings = CompileFileSettings {
116126
ssr: args.ssr,
117-
vapor: args.vapor,
127+
vapor: args.vapor || configured_vapor.unwrap_or(false),
118128
custom_renderer: args.custom_renderer,
119129
template_syntax: args
120130
.template_syntax
121131
.map(Into::into)
122132
.unwrap_or_else(|| template_syntax_mode(compiler_template_syntax)),
133+
experimental_in_tag_comments: config_features.experimental_in_tag_comments,
134+
experimental_patterned_template: config_features.experimental_patterned_template,
135+
experimental_server_script: config_features.experimental_server_script,
123136
dialect: configured_dialect.unwrap_or_default(),
124137
script_ext: args.script_ext,
125138
record_profile_totals: args.profile,

crates/vize/src/commands/build/runner/compile.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ pub(super) fn compile_file_with_profile(
118118
ssr: settings.ssr,
119119
is_ts,
120120
custom_renderer: settings.custom_renderer,
121+
experimental_in_tag_comments: settings.experimental_in_tag_comments,
122+
experimental_patterned_template: settings.experimental_patterned_template,
123+
experimental_server_script: settings.experimental_server_script,
121124
dialect: settings.dialect,
122125
..Default::default()
123126
},

crates/vize/src/commands/build/runner/compile_stats.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ pub(super) fn compile_file_stats_with_cache(
179179
ssr: settings.ssr,
180180
is_ts,
181181
custom_renderer: settings.custom_renderer,
182+
experimental_in_tag_comments: settings.experimental_in_tag_comments,
183+
experimental_patterned_template: settings.experimental_patterned_template,
184+
experimental_server_script: settings.experimental_server_script,
182185
dialect: settings.dialect,
183186
..Default::default()
184187
},

crates/vize/src/commands/build/runner/settings.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ pub(super) struct CompileFileSettings {
1212
pub(super) vapor: bool,
1313
pub(super) custom_renderer: bool,
1414
pub(super) template_syntax: TemplateSyntaxMode,
15+
pub(super) experimental_in_tag_comments: bool,
16+
pub(super) experimental_patterned_template: bool,
17+
pub(super) experimental_server_script: bool,
1518
/// Vue dialect from `vue.version`; defaults to [`VueVersion::V3`] and is
1619
/// threaded into each file's compile options.
1720
pub(super) dialect: VueVersion,
@@ -36,6 +39,9 @@ impl CompileFileSettings {
3639
ScriptExtension::Downcompile => 0,
3740
}
3841
| (u16::from(dialect_bits(self.dialect)) << 6)
42+
| (u16::from(self.experimental_in_tag_comments) << 9)
43+
| (u16::from(self.experimental_patterned_template) << 10)
44+
| (u16::from(self.experimental_server_script) << 11)
3945
}
4046
}
4147

crates/vize/src/commands/check/runner.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ pub(crate) fn run_direct(args: &CheckArgs) {
311311
checker.enable_jsx_typecheck();
312312
}
313313
checker.set_template_syntax(template_syntax_mode(compiler_template_syntax));
314+
checker.set_experimental_in_tag_comments(loaded_config.features.experimental_in_tag_comments);
314315
checker.set_dialect(dialect);
315316
checker.set_virtual_ts_checks(
316317
config.type_checker.check_props && !args.no_check_props,

crates/vize_armature/src/parser.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ impl<'a> Parser<'a> {
240240
// We need to use a struct that implements Callbacks
241241
// Create a wrapper that can capture the parser
242242
let document = self.document;
243+
let in_tag_comments = self.options.experimental_in_tag_comments;
243244
#[cfg(feature = "legacy")]
244245
let triple_mustache = self.raw_html_interpolation_enabled();
245246
let mut tokenizer = Tokenizer::with_delimiters(
@@ -249,6 +250,7 @@ impl<'a> Parser<'a> {
249250
&delimiter_close,
250251
);
251252
tokenizer.set_tolerate_declarations(document);
253+
tokenizer.set_in_tag_comments(in_tag_comments);
252254
#[cfg(feature = "legacy")]
253255
tokenizer.set_triple_mustache(triple_mustache);
254256
tokenizer.tokenize();

crates/vize_armature/src/parser/callbacks.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ impl<'a, 'p> Callbacks for ParserCallbacks<'a, 'p> {
105105
self.parser.on_comment_impl(start, end);
106106
}
107107

108+
fn on_in_tag_comment(&mut self, start: usize, end: usize) {
109+
self.parser.on_in_tag_comment_impl(start, end);
110+
}
111+
108112
fn on_cdata(&mut self, start: usize, end: usize) {
109113
self.parser.on_cdata_impl(start, end);
110114
}

crates/vize_armature/src/parser/element/comment.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ impl<'a> Parser<'a> {
2828
self.add_child(TemplateChildNode::Comment(boxed));
2929
}
3030

31+
/// Process experimental in-tag `//` comments.
32+
pub(in crate::parser) fn on_in_tag_comment_impl(&mut self, start: usize, end: usize) {
33+
let content_start = start.saturating_add(2).min(end);
34+
let comment = CommentNode::new_in_tag(
35+
self.get_source(content_start, end),
36+
self.create_loc(start, end),
37+
);
38+
if let Some(root) = self.root.as_mut() {
39+
root.comments.push(comment);
40+
}
41+
}
42+
3143
fn comment_loc_end(&self, start: usize, end: usize) -> usize {
3244
let end = self.clamp_to_char_boundary(end);
3345
let rest = &self.source[end..];

crates/vize_armature/src/parser/tests.rs

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use super::{
77
};
88
use vize_carton::Bump;
99
use vize_relief::{
10-
ElementType, ExpressionNode, Namespace, PropNode, TemplateChildNode,
10+
CommentKind, ElementType, ExpressionNode, Namespace, PropNode, TemplateChildNode,
1111
errors::{CompilerError, ErrorCode},
1212
options::{ParserOptions, TemplateSyntaxMode},
1313
};
@@ -626,6 +626,93 @@ fn test_parse_whitespace_condense_skips_comment_gaps_when_comments_disabled() {
626626
}
627627
}
628628

629+
#[test]
630+
fn test_parse_experimental_in_tag_comments() {
631+
let allocator = Bump::new();
632+
let (root, errors) = parse_with_options(
633+
&allocator,
634+
"<LegacySelect\n :options=\"options\"\n // @vue-expect-error legacy API\n :selected-id=\"selectedId\"\n/>",
635+
ParserOptions {
636+
experimental_in_tag_comments: true,
637+
..ParserOptions::default()
638+
},
639+
);
640+
641+
assert!(errors.is_empty());
642+
assert_eq!(root.comments.len(), 1);
643+
assert_eq!(root.comments[0].kind, CommentKind::InTag);
644+
assert_eq!(
645+
root.comments[0].content.as_str(),
646+
" @vue-expect-error legacy API"
647+
);
648+
649+
let TemplateChildNode::Element(el) = &root.children[0] else {
650+
panic!("Expected element");
651+
};
652+
assert_eq!(el.props.len(), 2);
653+
assert!(
654+
root.children
655+
.iter()
656+
.all(|child| !matches!(child, TemplateChildNode::Comment(_)))
657+
);
658+
}
659+
660+
#[test]
661+
fn test_parse_in_tag_comments_are_opt_in() {
662+
let allocator = Bump::new();
663+
let (_root, errors) = parse(&allocator, "<LegacySelect\n // note\n/>");
664+
665+
assert!(
666+
errors
667+
.iter()
668+
.any(|error| error.code == ErrorCode::UnexpectedSolidusInTag)
669+
);
670+
}
671+
672+
#[test]
673+
fn test_parse_in_tag_comments_preserve_when_comments_disabled() {
674+
let allocator = Bump::new();
675+
let (root, errors) = parse_with_options(
676+
&allocator,
677+
"<LegacySelect\n // note\n/>",
678+
ParserOptions {
679+
comments: false,
680+
experimental_in_tag_comments: true,
681+
..ParserOptions::default()
682+
},
683+
);
684+
685+
assert!(errors.is_empty());
686+
assert_eq!(root.comments.len(), 1);
687+
assert_eq!(root.children.len(), 1);
688+
}
689+
690+
#[test]
691+
fn test_parse_slash_slash_inside_attribute_value_is_not_in_tag_comment() {
692+
let allocator = Bump::new();
693+
let (root, errors) = parse_with_options(
694+
&allocator,
695+
r#"<div title="not // a comment"></div>"#,
696+
ParserOptions {
697+
experimental_in_tag_comments: true,
698+
..ParserOptions::default()
699+
},
700+
);
701+
702+
assert!(errors.is_empty());
703+
assert!(root.comments.is_empty());
704+
let TemplateChildNode::Element(el) = &root.children[0] else {
705+
panic!("Expected element");
706+
};
707+
let PropNode::Attribute(attr) = &el.props[0] else {
708+
panic!("Expected attribute");
709+
};
710+
assert_eq!(
711+
attr.value.as_ref().map(|value| value.content.as_str()),
712+
Some("not // a comment")
713+
);
714+
}
715+
629716
#[test]
630717
fn test_parse_whitespace_condense_preserves_pre_children() {
631718
let allocator = Bump::new();

crates/vize_armature/src/tokenizer.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ pub struct Tokenizer<'a, C: Callbacks> {
8080
/// one. Reset when the interpolation closes; meaningless (always `false`)
8181
/// unless [`Tokenizer::triple_mustache`] is set.
8282
in_raw_interpolation: bool,
83+
84+
/// Whether to recognize experimental Vue `//` in-tag comments in opening
85+
/// tag attribute lists.
86+
in_tag_comments: bool,
8387
}
8488

8589
impl<'a, C: Callbacks> Tokenizer<'a, C> {
@@ -115,6 +119,7 @@ impl<'a, C: Callbacks> Tokenizer<'a, C> {
115119
tolerate_declarations: false,
116120
triple_mustache: false,
117121
in_raw_interpolation: false,
122+
in_tag_comments: false,
118123
}
119124
}
120125

@@ -132,6 +137,11 @@ impl<'a, C: Callbacks> Tokenizer<'a, C> {
132137
self.triple_mustache = enabled && self.delimiter_open == b"{{";
133138
}
134139

140+
/// Enable experimental Vue `//` in-tag comments in opening tag attribute lists.
141+
pub fn set_in_tag_comments(&mut self, enabled: bool) {
142+
self.in_tag_comments = enabled;
143+
}
144+
135145
/// Get the position for a given index
136146
pub fn get_pos(&self, index: usize) -> Position {
137147
// Binary search for line number
@@ -191,6 +201,7 @@ impl<'a, C: Callbacks> Tokenizer<'a, C> {
191201
State::InClosingTagName => self.state_in_closing_tag_name(c),
192202
State::AfterClosingTagName => self.state_after_closing_tag_name(c),
193203
State::BeforeAttrName => self.state_before_attr_name(c),
204+
State::InTagComment => self.state_in_tag_comment(c),
194205
State::InAttrName => self.state_in_attr_name(c),
195206
State::InDirName => self.state_in_dir_name(c),
196207
State::InDirArg => self.state_in_dir_arg(c),

0 commit comments

Comments
 (0)