sim_codec_typescript/types.rs
1//! Public TypeScript extension data.
2
3use sim_codec_javascript::{Node, Span, Token};
4
5/// TypeScript or TSX input mode.
6#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub enum Language {
8 /// TypeScript module notation.
9 TypeScript,
10 /// TypeScript with JSX notation.
11 Tsx,
12}
13
14/// Resource limits for the extension scan.
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub struct Limits {
17 /// Maximum source bytes.
18 pub max_bytes: usize,
19 /// Maximum extension nodes.
20 pub max_nodes: usize,
21 /// Maximum delimiter nesting.
22 pub max_nesting: usize,
23}
24impl Default for Limits {
25 fn default() -> Self {
26 Self {
27 max_bytes: 4 * 1024 * 1024,
28 max_nodes: 1_000_000,
29 max_nesting: 256,
30 }
31 }
32}
33
34/// TypeScript-only concrete syntax category.
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum SyntaxKind {
37 /// `interface`, `type`, `enum`, `namespace`, or ambient declaration.
38 Declaration,
39 /// A `: Type` annotation.
40 Annotation,
41 /// A generic parameter or argument list.
42 TypeArguments,
43 /// A TypeScript type node or operator.
44 TypeNode,
45 /// A TypeScript declaration/member modifier.
46 Modifier,
47 /// A JSX element, fragment, attribute, expression, or text region.
48 Jsx,
49}
50
51/// A syntax node in the composed tree.
52#[derive(Clone, Debug, Eq, PartialEq)]
53pub enum SyntaxNode {
54 /// An unchanged ECMAScript node produced by the JavaScript frontend.
55 JavaScript(Node),
56 /// TypeScript-only notation layered over JavaScript.
57 TypeScript {
58 /// Extension category.
59 kind: SyntaxKind,
60 /// Exact byte range in the source.
61 span: Span,
62 /// Parser context recorded at the node.
63 context: Vec<String>,
64 },
65}
66
67/// Complete lossless composed syntax tree.
68#[derive(Clone, Debug, Eq, PartialEq)]
69pub struct SyntaxTree {
70 pub(crate) source: String,
71 /// Selected language mode.
72 pub language: Language,
73 /// Lossless JavaScript token seam, including trivia.
74 pub tokens: Vec<Token>,
75 /// JavaScript and TypeScript nodes.
76 pub nodes: Vec<SyntaxNode>,
77}
78impl SyntaxTree {
79 /// Returns the exact admitted input.
80 #[must_use]
81 pub fn source(&self) -> &str {
82 &self.source
83 }
84 /// Re-emits the admitted input byte-for-byte.
85 #[must_use]
86 pub fn preserve_source(&self) -> String {
87 self.source.clone()
88 }
89}
90
91/// Stable diagnostic category.
92#[derive(Clone, Copy, Debug, Eq, PartialEq)]
93pub enum DiagnosticCode {
94 /// A configured resource bound was crossed.
95 ResourceLimit,
96 /// Delimiters, strings, comments, templates, or JSX were not closed.
97 UnclosedSyntax,
98 /// JSX notation was used outside TSX mode.
99 JsxInTypeScript,
100}
101
102/// Deterministic located frontend failure.
103#[derive(Clone, Debug, Eq, PartialEq)]
104pub struct Diagnostic {
105 /// Stable category.
106 pub code: DiagnosticCode,
107 /// Offending source range.
108 pub span: Span,
109 /// One-based line.
110 pub line: usize,
111 /// Zero-based Unicode-scalar column.
112 pub column: usize,
113 /// Stable detail.
114 pub message: String,
115}
116impl std::fmt::Display for Diagnostic {
117 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
118 write!(f, "{}:{}: {}", self.line, self.column, self.message)
119 }
120}
121impl std::error::Error for Diagnostic {}