use super::ProgramInput;
use crate::file::{Export, FileArtifact, Import, Namespace, ScriptUnit, ScriptUnitId};
use oxc_ast::ast::StringLiteral;
use vize_l0::Span;
mod read;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModuleSourceErrorKind {
Source,
Profile,
MissingUnit,
ProgramOrigin,
EmptyProgram,
IncompleteFile,
DynamicImport,
EmptySourceExport,
OriginalSite,
LoneSurrogateRequest,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ModuleSourceError {
pub unit: ScriptUnitId,
pub span: Span,
pub kind: ModuleSourceErrorKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModuleSourceKind {
Import,
NamedReexport,
AllReexport,
}
pub struct OriginalModuleSources<'f, 'p, 'a> {
file: &'f FileArtifact<'a>,
input: ProgramInput<'p, 'a>,
unit: &'f ScriptUnit,
}
impl<'a> FileArtifact<'a> {
pub fn original_module_sources<'f, 'p>(
&'f self,
input: ProgramInput<'p, 'a>,
) -> Result<OriginalModuleSources<'f, 'p, 'a>, ModuleSourceError> {
let reject = |kind| ModuleSourceError {
unit: ScriptUnitId(input.index),
span: input.block.span(),
kind,
};
if !core::ptr::eq(self.artifact().source(), input.block.root_source()) {
return Err(reject(ModuleSourceErrorKind::Source));
}
let profile = input.source_type();
if !profile.is_module() || profile.is_typescript_definition() {
return Err(reject(ModuleSourceErrorKind::Profile));
}
let Some(unit) = self
.units()
.iter()
.find(|unit| unit.id.index() == input.index)
else {
return Err(reject(ModuleSourceErrorKind::MissingUnit));
};
if unit.span != input.block.span() {
return Err(reject(ModuleSourceErrorKind::Source));
}
if unit.profile != input.profile {
return Err(reject(ModuleSourceErrorKind::Profile));
}
let program = input.references.program();
if program.body.is_empty() {
return Err(reject(ModuleSourceErrorKind::EmptyProgram));
}
if unit.origin.body != program.body.as_ptr() as usize
|| unit.origin.length != program.body.len()
{
return Err(reject(ModuleSourceErrorKind::ProgramOrigin));
}
if !self.is_complete() || !unit.walk_completed() {
return Err(reject(ModuleSourceErrorKind::IncompleteFile));
}
if unit.origin.module_source_gaps & crate::file::DYNAMIC_IMPORT != 0 {
return Err(reject(ModuleSourceErrorKind::DynamicImport));
}
if unit.origin.module_source_gaps & crate::file::EMPTY_SOURCE_EXPORT != 0 {
return Err(reject(ModuleSourceErrorKind::EmptySourceExport));
}
Ok(OriginalModuleSources {
file: self,
input,
unit,
})
}
}
#[derive(Clone, Copy)]
enum Row<'f> {
Import(&'f Import),
Export(&'f Export),
}
pub struct OriginalModuleSource<'f, 'p, 'a> {
file: &'f FileArtifact<'a>,
row: Row<'f>,
literal: &'p StringLiteral<'a>,
raw: &'a str,
authored: &'a str,
copied: &'f str,
quoted: Span,
content: Span,
declaration: Span,
kind: ModuleSourceKind,
namespace: Namespace,
}
impl<'f, 'p, 'a> OriginalModuleSource<'f, 'p, 'a> {
pub fn file(&self) -> &'f FileArtifact<'a> {
self.file
}
pub fn literal(&self) -> &'p StringLiteral<'a> {
self.literal
}
pub fn quoted_span(&self) -> Span {
self.quoted
}
pub fn content_span(&self) -> Span {
self.content
}
pub fn declaration_span(&self) -> Span {
self.declaration
}
pub fn kind(&self) -> ModuleSourceKind {
self.kind
}
pub fn namespace(&self) -> Namespace {
self.namespace
}
pub fn raw(&self) -> &'a str {
self.raw
}
pub fn authored_content(&self) -> &'a str {
self.authored
}
pub fn decoded_request(&self) -> &'a str {
self.literal.value.as_str()
}
pub fn copied_request(&self) -> &'f str {
self.copied
}
pub fn import(&self) -> Option<&'f Import> {
if let Row::Import(row) = self.row {
Some(row)
} else {
None
}
}
pub fn export(&self) -> Option<&'f Export> {
if let Row::Export(row) = self.row {
Some(row)
} else {
None
}
}
}