mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): parse multiple script tags in astro file (#1898)
This commit is contained in:
parent
4c5c61e5f9
commit
8a3eff1bee
3 changed files with 74 additions and 9 deletions
|
|
@ -1,3 +1,20 @@
|
|||
---
|
||||
debugger
|
||||
---
|
||||
|
||||
<!-- Store the message prop as a data attribute. -->
|
||||
<astro-greet data-message={message}>
|
||||
<button>Say hi!</button>
|
||||
</astro-greet>
|
||||
|
||||
<script asdf >
|
||||
debugger
|
||||
</script>
|
||||
|
||||
<script asdf>
|
||||
debugger
|
||||
</script>
|
||||
|
||||
<script>
|
||||
debugger
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ mod test {
|
|||
let args = &["fixtures/astro/debugger.astro"];
|
||||
let result = test(args);
|
||||
assert_eq!(result.number_of_files, 1);
|
||||
assert_eq!(result.number_of_warnings, 1);
|
||||
assert_eq!(result.number_of_warnings, 4);
|
||||
assert_eq!(result.number_of_errors, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
use memchr::memmem;
|
||||
use memchr::memmem::Finder;
|
||||
|
||||
use oxc_span::{SourceType, Span};
|
||||
|
||||
use super::JavaScriptSource;
|
||||
|
||||
const ASTRO_SPLIT: &str = "---";
|
||||
const SCRIPT_START: &str = "<script";
|
||||
const SCRIPT_END: &str = "</script>";
|
||||
|
||||
pub struct AstroPartialLoader<'a> {
|
||||
source_text: &'a str,
|
||||
}
|
||||
|
|
@ -15,28 +19,72 @@ impl<'a> AstroPartialLoader<'a> {
|
|||
|
||||
pub fn parse(self) -> Vec<JavaScriptSource<'a>> {
|
||||
let mut results = vec![];
|
||||
results.extend(self.parse_frontmatter());
|
||||
let frontmatter = self.parse_frontmatter();
|
||||
let start = frontmatter.as_ref().map_or(0, |r| r.source_text.len() + ASTRO_SPLIT.len() * 2);
|
||||
results.extend(frontmatter);
|
||||
results.extend(self.parse_scripts(start));
|
||||
results
|
||||
}
|
||||
|
||||
/// Parse `---` front matter block
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn parse_frontmatter(&self) -> Option<JavaScriptSource<'a>> {
|
||||
let split = "---";
|
||||
let indexes = memmem::find_iter(self.source_text.as_bytes(), split).collect::<Vec<_>>();
|
||||
if indexes.len() <= 1 {
|
||||
let split_finder = Finder::new(ASTRO_SPLIT);
|
||||
let offsets = split_finder.find_iter(self.source_text.as_bytes()).collect::<Vec<_>>();
|
||||
if offsets.len() <= 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let start = indexes.first()?;
|
||||
let end = indexes.last()?;
|
||||
let start = offsets.first()?;
|
||||
let end = offsets.last()?;
|
||||
let Ok(start) = u32::try_from(*start) else { return None };
|
||||
let Ok(end) = u32::try_from(*end) else { return None };
|
||||
|
||||
let js_code = Span::new(start + split.len() as u32, end).source_text(self.source_text);
|
||||
let js_code =
|
||||
Span::new(start + ASTRO_SPLIT.len() as u32, end).source_text(self.source_text);
|
||||
Some(JavaScriptSource::new(
|
||||
js_code,
|
||||
SourceType::default().with_typescript(true).with_module(true),
|
||||
))
|
||||
}
|
||||
|
||||
/// In .astro files, you can add client-side JavaScript by adding one (or more) <script> tags.
|
||||
/// https://docs.astro.build/en/guides/client-side-scripts/#using-script-in-astro
|
||||
fn parse_scripts(&self, start: usize) -> Vec<JavaScriptSource<'a>> {
|
||||
let script_start_finder = Finder::new(SCRIPT_START);
|
||||
let script_end_finder = Finder::new(SCRIPT_END);
|
||||
|
||||
let mut results = vec![];
|
||||
let mut pointer = start;
|
||||
|
||||
loop {
|
||||
let js_start;
|
||||
let js_end;
|
||||
// find opening "<script"
|
||||
if let Some(offset) = script_start_finder.find(self.source_text[pointer..].as_bytes()) {
|
||||
pointer += offset + SCRIPT_START.len();
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
// find closing ">"
|
||||
if let Some(offset) = self.source_text[pointer..].find('>') {
|
||||
pointer += offset + 1;
|
||||
js_start = pointer;
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
// find "</script>"
|
||||
if let Some(offset) = script_end_finder.find(self.source_text[pointer..].as_bytes()) {
|
||||
js_end = pointer + offset;
|
||||
pointer += offset + SCRIPT_END.len();
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
results.push(JavaScriptSource::new(
|
||||
&self.source_text[js_start..js_end],
|
||||
SourceType::default().with_typescript(true).with_module(true),
|
||||
));
|
||||
}
|
||||
results
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue