fusee-framework 2.7.0 → 2.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +56 -2
  2. package/bin/create-fusee-linux +0 -0
  3. package/bin/create-fusee-mac-arm64 +0 -0
  4. package/bin/create-fusee-mac-intel +0 -0
  5. package/bin/create-fusee-win.exe +0 -0
  6. package/framework/auto-import-preset.js +20 -12
  7. package/framework/auto-imports.d.ts +68 -39
  8. package/framework/core/compiler.js +310 -310
  9. package/framework/core/component-core.js +445 -0
  10. package/framework/core/component.js +11 -440
  11. package/framework/core/composable.js +29 -29
  12. package/framework/core/h.js +588 -557
  13. package/framework/core/jsx-helpers.js +11 -2
  14. package/framework/core/jsx-runtime.js +73 -73
  15. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm +0 -0
  16. package/framework/core/store.js +333 -333
  17. package/framework/globals.js +42 -0
  18. package/framework/index.js +22 -55
  19. package/framework/router/file-router.js +184 -184
  20. package/framework/server/actions.js +183 -183
  21. package/framework/server/generate-manifest.js +3 -3
  22. package/framework/types/component.d.ts +97 -86
  23. package/framework/types/index.d.ts +118 -117
  24. package/package.json +83 -80
  25. package/framework/core/rust-compiler/Cargo.toml +0 -31
  26. package/framework/core/rust-compiler/README.md +0 -69
  27. package/framework/core/rust-compiler/pkg/README.md +0 -69
  28. package/framework/core/rust-compiler/pkg/fusee_compiler.d.ts +0 -6
  29. package/framework/core/rust-compiler/pkg/fusee_compiler.js +0 -9
  30. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.js +0 -137
  31. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm.d.ts +0 -11
  32. package/framework/core/rust-compiler/pkg/package.json +0 -18
  33. package/framework/core/rust-compiler/src/ast.rs +0 -274
  34. package/framework/core/rust-compiler/src/errors.rs +0 -204
  35. package/framework/core/rust-compiler/src/generator.rs +0 -583
  36. package/framework/core/rust-compiler/src/lexer.rs +0 -414
  37. package/framework/core/rust-compiler/src/lib.rs +0 -87
  38. package/framework/core/rust-compiler/src/main_compiler.rs +0 -165
  39. package/framework/core/rust-compiler/src/parser.rs +0 -516
  40. package/framework/core/rust-compiler/src/ssr_generator.rs +0 -688
  41. package/framework/core/rust-compiler/src/transformer.rs +0 -562
  42. package/framework/core/rust-compiler/src/utils.rs +0 -10
  43. package/framework/engine-go/actions.go +0 -112
  44. package/framework/engine-go/cmd/server/main.go +0 -233
  45. package/framework/engine-go/comet/comet.go +0 -41
  46. package/framework/engine-go/comet/fragment.go +0 -51
  47. package/framework/engine-go/dispatcher.go +0 -120
  48. package/framework/engine-go/elements.go +0 -248
  49. package/framework/engine-go/evalexpr/evalexpr.go +0 -733
  50. package/framework/engine-go/go.mod +0 -3
  51. package/framework/engine-go/hydration.go +0 -43
  52. package/framework/engine-go/load-helpers.go +0 -29
  53. package/framework/engine-go/manifest.go +0 -41
  54. package/framework/engine-go/reactive.go +0 -123
  55. package/framework/engine-go/render.go +0 -635
  56. package/framework/engine-go/reqcontext.go +0 -48
  57. package/framework/engine-go/router.go +0 -85
  58. package/framework/engine-go/rustast/rustast.go +0 -317
  59. package/framework/engine-go/ssr.go +0 -103
  60. package/framework/engine-go/static-assets.go +0 -139
  61. package/framework/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -1,137 +0,0 @@
1
- /**
2
- * @param {string} source
3
- * @param {string} options_json
4
- * @returns {string}
5
- */
6
- export function compile(source, options_json) {
7
- let deferred4_0;
8
- let deferred4_1;
9
- try {
10
- const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
11
- const len0 = WASM_VECTOR_LEN;
12
- const ptr1 = passStringToWasm0(options_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
13
- const len1 = WASM_VECTOR_LEN;
14
- const ret = wasm.compile(ptr0, len0, ptr1, len1);
15
- var ptr3 = ret[0];
16
- var len3 = ret[1];
17
- if (ret[3]) {
18
- ptr3 = 0; len3 = 0;
19
- throw takeFromExternrefTable0(ret[2]);
20
- }
21
- deferred4_0 = ptr3;
22
- deferred4_1 = len3;
23
- return getStringFromWasm0(ptr3, len3);
24
- } finally {
25
- wasm.__wbindgen_free(deferred4_0, deferred4_1, 1);
26
- }
27
- }
28
-
29
- export function greet() {
30
- wasm.greet();
31
- }
32
- export function __wbg_alert_f3c04f14b1e59052(arg0, arg1) {
33
- alert(getStringFromWasm0(arg0, arg1));
34
- }
35
- export function __wbindgen_generic_0000000000000001(arg0, arg1) {
36
- // Cast intrinsic for `Ref(String) -> Externref`.
37
- const ret = getStringFromWasm0(arg0, arg1);
38
- return ret;
39
- }
40
- export function __wbindgen_init_externref_table() {
41
- const table = wasm.__wbindgen_externrefs;
42
- const offset = table.grow(4);
43
- table.set(0, undefined);
44
- table.set(offset + 0, undefined);
45
- table.set(offset + 1, null);
46
- table.set(offset + 2, true);
47
- table.set(offset + 3, false);
48
- }
49
- function getStringFromWasm0(ptr, len) {
50
- return decodeText(ptr >>> 0, len);
51
- }
52
-
53
- let cachedUint8ArrayMemory0 = null;
54
- function getUint8ArrayMemory0() {
55
- if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
56
- cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
57
- }
58
- return cachedUint8ArrayMemory0;
59
- }
60
-
61
- function passStringToWasm0(arg, malloc, realloc) {
62
- if (realloc === undefined) {
63
- const buf = cachedTextEncoder.encode(arg);
64
- const ptr = malloc(buf.length, 1) >>> 0;
65
- getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
66
- WASM_VECTOR_LEN = buf.length;
67
- return ptr;
68
- }
69
-
70
- let len = arg.length;
71
- let ptr = malloc(len, 1) >>> 0;
72
-
73
- const mem = getUint8ArrayMemory0();
74
-
75
- let offset = 0;
76
-
77
- for (; offset < len; offset++) {
78
- const code = arg.charCodeAt(offset);
79
- if (code > 0x7F) break;
80
- mem[ptr + offset] = code;
81
- }
82
- if (offset !== len) {
83
- if (offset !== 0) {
84
- arg = arg.slice(offset);
85
- }
86
- ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
87
- const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
88
- const ret = cachedTextEncoder.encodeInto(arg, view);
89
-
90
- offset += ret.written;
91
- ptr = realloc(ptr, len, offset, 1) >>> 0;
92
- }
93
-
94
- WASM_VECTOR_LEN = offset;
95
- return ptr;
96
- }
97
-
98
- function takeFromExternrefTable0(idx) {
99
- const value = wasm.__wbindgen_externrefs.get(idx);
100
- wasm.__externref_table_dealloc(idx);
101
- return value;
102
- }
103
-
104
- let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
105
- cachedTextDecoder.decode();
106
- const MAX_SAFARI_DECODE_BYTES = 2146435072;
107
- let numBytesDecoded = 0;
108
- function decodeText(ptr, len) {
109
- numBytesDecoded += len;
110
- if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
111
- cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
112
- cachedTextDecoder.decode();
113
- numBytesDecoded = len;
114
- }
115
- return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
116
- }
117
-
118
- const cachedTextEncoder = new TextEncoder();
119
-
120
- if (!('encodeInto' in cachedTextEncoder)) {
121
- cachedTextEncoder.encodeInto = function (arg, view) {
122
- const buf = cachedTextEncoder.encode(arg);
123
- view.set(buf);
124
- return {
125
- read: arg.length,
126
- written: buf.length
127
- };
128
- };
129
- }
130
-
131
- let WASM_VECTOR_LEN = 0;
132
-
133
-
134
- let wasm;
135
- export function __wbg_set_wasm(val) {
136
- wasm = val;
137
- }
@@ -1,11 +0,0 @@
1
- /* tslint:disable */
2
- /* eslint-disable */
3
- export const memory: WebAssembly.Memory;
4
- export const compile: (a: number, b: number, c: number, d: number) => [number, number, number, number];
5
- export const greet: () => void;
6
- export const __wbindgen_externrefs: WebAssembly.Table;
7
- export const __wbindgen_malloc: (a: number, b: number) => number;
8
- export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
9
- export const __externref_table_dealloc: (a: number) => void;
10
- export const __wbindgen_free: (a: number, b: number, c: number) => void;
11
- export const __wbindgen_start: () => void;
@@ -1,18 +0,0 @@
1
- {
2
- "name": "fusee-compiler",
3
- "type": "module",
4
- "description": "Fusée template compiler — lexer/parser/transformer/generator — Rust+WASM port",
5
- "version": "0.1.0",
6
- "files": [
7
- "fusee_compiler_bg.wasm",
8
- "fusee_compiler.js",
9
- "fusee_compiler_bg.js",
10
- "fusee_compiler.d.ts"
11
- ],
12
- "main": "fusee_compiler.js",
13
- "types": "fusee_compiler.d.ts",
14
- "sideEffects": [
15
- "./fusee_compiler.js",
16
- "./snippets/*"
17
- ]
18
- }
@@ -1,274 +0,0 @@
1
- use serde::{Deserialize, Serialize};
2
-
3
- pub type NodeId = usize;
4
-
5
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6
- pub struct Pos {
7
- pub line: usize,
8
- pub col: usize,
9
- pub offset: usize,
10
- }
11
-
12
- impl Pos {
13
- pub fn new(line: usize, col: usize, offset: usize) -> Self {
14
- Pos { line, col, offset }
15
- }
16
- }
17
-
18
- #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
19
- pub struct Loc {
20
- pub start: Pos,
21
- pub end: Pos,
22
- }
23
-
24
- impl Loc {
25
- pub fn new(start: Pos, end: Pos) -> Self {
26
- Loc { start, end }
27
- }
28
- pub fn point(p: Pos) -> Self {
29
- Loc { start: p, end: p }
30
- }
31
- }
32
-
33
- #[derive(Debug, Clone, Serialize, Deserialize)]
34
- pub struct Expression {
35
- pub content: String,
36
- pub is_static: bool,
37
- pub is_for_key: bool,
38
- pub loc: Loc,
39
- }
40
-
41
- impl Expression {
42
- pub fn new(content: impl Into<String>, is_static: bool, loc: Loc) -> Self {
43
- Expression {
44
- content: content.into(),
45
- is_static,
46
- is_for_key: false,
47
- loc,
48
- }
49
- }
50
- }
51
-
52
- #[derive(Debug, Clone, Serialize, Deserialize)]
53
- pub struct AttributeNode {
54
- pub name: String,
55
- pub value: Option<String>,
56
- pub loc: Loc,
57
- }
58
-
59
- #[derive(Debug, Clone, Serialize, Deserialize)]
60
- pub struct BindingNode {
61
- pub name: String,
62
- pub expression: Expression,
63
- pub is_prop: bool,
64
- pub loc: Loc,
65
- }
66
-
67
- #[derive(Debug, Clone, Serialize, Deserialize)]
68
- pub struct EventNode {
69
- pub name: String,
70
- pub expression: Expression,
71
- pub modifiers: Vec<String>,
72
- pub loc: Loc,
73
- }
74
-
75
- #[derive(Debug, Clone, Serialize, Deserialize)]
76
- pub struct ForArg {
77
- pub item: String,
78
- pub source: String,
79
- pub index: Option<String>,
80
- pub loc: Loc,
81
- }
82
-
83
- #[derive(Debug, Clone, Serialize, Deserialize)]
84
- pub struct DirectiveNode {
85
- pub name: String,
86
- pub expression: Option<Expression>,
87
- pub arg: Option<ForArg>,
88
- pub loc: Loc,
89
- }
90
-
91
- #[derive(Debug, Clone, Serialize, Deserialize)]
92
- #[serde(tag = "type")]
93
- pub enum Prop {
94
- Attribute(AttributeNode),
95
- Binding(BindingNode),
96
- Event(EventNode),
97
- Directive(DirectiveNode),
98
- }
99
-
100
- impl Prop {
101
- pub fn loc(&self) -> &Loc {
102
- match self {
103
- Prop::Attribute(a) => &a.loc,
104
- Prop::Binding(b) => &b.loc,
105
- Prop::Event(e) => &e.loc,
106
- Prop::Directive(d) => &d.loc,
107
- }
108
- }
109
-
110
- pub fn as_directive(&self) -> Option<&DirectiveNode> {
111
- match self {
112
- Prop::Directive(d) => Some(d),
113
- _ => None,
114
- }
115
- }
116
-
117
- pub fn as_binding(&self) -> Option<&BindingNode> {
118
- match self {
119
- Prop::Binding(b) => Some(b),
120
- _ => None,
121
- }
122
- }
123
- }
124
-
125
- #[derive(Debug, Clone, Serialize, Deserialize)]
126
- pub struct Branch {
127
- pub condition: Option<Expression>,
128
- pub node: Box<Node>,
129
- }
130
-
131
- #[derive(Debug, Clone, Serialize, Deserialize)]
132
- pub struct ElementNode {
133
- pub id: NodeId,
134
- pub tag: String,
135
- pub props: Vec<Prop>,
136
- pub children: Vec<Node>,
137
- pub self_closing: bool,
138
- pub is_static: bool,
139
- pub hoisted: bool,
140
- pub loc: Loc,
141
- }
142
-
143
- #[derive(Debug, Clone, Serialize, Deserialize)]
144
- pub struct ComponentNode {
145
- pub id: NodeId,
146
- pub name: String,
147
- pub props: Vec<Prop>,
148
- pub slots: Vec<(String, Vec<Node>)>,
149
- pub loc: Loc,
150
- }
151
-
152
- impl ComponentNode {
153
- pub fn slot(&self, name: &str) -> Option<&Vec<Node>> {
154
- self.slots.iter().find(|(n, _)| n == name).map(|(_, c)| c)
155
- }
156
- }
157
-
158
- #[derive(Debug, Clone, Serialize, Deserialize)]
159
- pub struct TextNode {
160
- pub content: String,
161
- pub is_static: bool,
162
- pub loc: Loc,
163
- }
164
-
165
- #[derive(Debug, Clone, Serialize, Deserialize)]
166
- pub struct InterpolationNode {
167
- pub expression: Expression,
168
- pub is_static: bool,
169
- pub loc: Loc,
170
- }
171
-
172
- #[derive(Debug, Clone, Serialize, Deserialize)]
173
- pub struct SlotOutletNode {
174
- pub slot_name: String,
175
- pub fallback: Vec<Node>,
176
- pub loc: Loc,
177
- }
178
-
179
- #[derive(Debug, Clone, Serialize, Deserialize)]
180
- pub struct SlotContentNode {
181
- pub slot_name: String,
182
- pub children: Vec<Node>,
183
- pub loc: Loc,
184
- }
185
-
186
- #[derive(Debug, Clone, Serialize, Deserialize)]
187
- pub struct IfNode {
188
- pub branches: Vec<Branch>,
189
- pub loc: Loc,
190
- }
191
-
192
- #[derive(Debug, Clone, Serialize, Deserialize)]
193
- pub struct RootNode {
194
- pub children: Vec<Node>,
195
- pub hoisted: Vec<NodeId>,
196
- pub loc: Loc,
197
- }
198
-
199
- #[derive(Debug, Clone, Serialize, Deserialize)]
200
- #[serde(tag = "type")]
201
- pub enum Node {
202
- Root(RootNode),
203
- Element(ElementNode),
204
- Component(ComponentNode),
205
- Text(TextNode),
206
- Interpolation(InterpolationNode),
207
- SlotOutlet(SlotOutletNode),
208
- SlotContent(SlotContentNode),
209
- If(IfNode),
210
- }
211
-
212
- impl Node {
213
- pub fn loc(&self) -> &Loc {
214
- match self {
215
- Node::Root(n) => &n.loc,
216
- Node::Element(n) => &n.loc,
217
- Node::Component(n) => &n.loc,
218
- Node::Text(n) => &n.loc,
219
- Node::Interpolation(n) => &n.loc,
220
- Node::SlotOutlet(n) => &n.loc,
221
- Node::SlotContent(n) => &n.loc,
222
- Node::If(n) => &n.loc,
223
- }
224
- }
225
-
226
- pub fn is_element(&self) -> bool {
227
- matches!(self, Node::Element(_))
228
- }
229
- pub fn is_component(&self) -> bool {
230
- matches!(self, Node::Component(_))
231
- }
232
- pub fn is_element_or_component(&self) -> bool {
233
- self.is_element() || self.is_component()
234
- }
235
-
236
- pub fn props(&self) -> Option<&Vec<Prop>> {
237
- match self {
238
- Node::Element(n) => Some(&n.props),
239
- Node::Component(n) => Some(&n.props),
240
- _ => None,
241
- }
242
- }
243
-
244
- pub fn children(&self) -> Option<&Vec<Node>> {
245
- match self {
246
- Node::Root(n) => Some(&n.children),
247
- Node::Element(n) => Some(&n.children),
248
- _ => None,
249
- }
250
- }
251
-
252
- pub fn find_directive(&self, name: &str) -> Option<&DirectiveNode> {
253
- self.props()?
254
- .iter()
255
- .find_map(|p| p.as_directive().filter(|d| d.name == name))
256
- }
257
-
258
- pub fn tag_or_name(&self) -> &str {
259
- match self {
260
- Node::Element(n) => &n.tag,
261
- Node::Component(n) => &n.name,
262
- _ => "",
263
- }
264
- }
265
-
266
- pub fn set_is_static(&mut self, v: bool) {
267
- match self {
268
- Node::Element(n) => n.is_static = v,
269
- Node::Text(n) => n.is_static = v,
270
- Node::Interpolation(n) => n.is_static = v,
271
- _ => {}
272
- }
273
- }
274
- }
@@ -1,204 +0,0 @@
1
- use crate::ast::Loc;
2
- use once_cell::sync::Lazy;
3
- use regex::Regex;
4
- use serde::{Deserialize, Serialize};
5
-
6
- #[macro_export]
7
- macro_rules! args {
8
- () => { Vec::new() };
9
- ($($e:expr),+ $(,)?) => { vec![$($e.to_string()),+] };
10
- }
11
-
12
- #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13
- pub enum ErrorCode {
14
- UnexpectedChar,
15
- UnterminatedString,
16
- UnterminatedMustache,
17
- UnterminatedTag,
18
- MalformedComment,
19
- UnexpectedToken,
20
- MissingClosingTag,
21
- UnexpectedClosingTag,
22
- InvalidDirectiveSyntax,
23
- InvalidForSyntax,
24
- DuplicateKey,
25
- VElseNoIf,
26
- EmptyExpression,
27
- InvalidSlotName,
28
- DuplicateDirective,
29
- ForMissingKey,
30
- ModelOnNonInput,
31
- ComponentNotRegistered,
32
- UnknownIdentifier,
33
- StaticForKey,
34
- UnknownNodeType,
35
- }
36
-
37
- impl ErrorCode {
38
- pub fn as_str(self) -> &'static str {
39
- match self {
40
- ErrorCode::UnexpectedChar => "E001",
41
- ErrorCode::UnterminatedString => "E002",
42
- ErrorCode::UnterminatedMustache => "E003",
43
- ErrorCode::UnterminatedTag => "E004",
44
- ErrorCode::MalformedComment => "E005",
45
- ErrorCode::UnexpectedToken => "P001",
46
- ErrorCode::MissingClosingTag => "P002",
47
- ErrorCode::UnexpectedClosingTag => "P003",
48
- ErrorCode::InvalidDirectiveSyntax => "P004",
49
- ErrorCode::InvalidForSyntax => "P005",
50
- ErrorCode::DuplicateKey => "P006",
51
- ErrorCode::VElseNoIf => "P007",
52
- ErrorCode::EmptyExpression => "P008",
53
- ErrorCode::InvalidSlotName => "P009",
54
- ErrorCode::DuplicateDirective => "T001",
55
- ErrorCode::ForMissingKey => "T002",
56
- ErrorCode::ModelOnNonInput => "T003",
57
- ErrorCode::ComponentNotRegistered => "T004",
58
- ErrorCode::UnknownIdentifier => "S001",
59
- ErrorCode::StaticForKey => "S002",
60
- ErrorCode::UnknownNodeType => "G001",
61
- }
62
- }
63
- }
64
-
65
- fn template_for(code: ErrorCode) -> &'static str {
66
- match code {
67
- ErrorCode::UnexpectedChar => "Unexpected character \"{0}\"",
68
- ErrorCode::UnterminatedString => "Unterminated string literal",
69
- ErrorCode::UnterminatedMustache => "Unterminated mustache expression \"{0}\"",
70
- ErrorCode::UnterminatedTag => "Unterminated tag \"<{0}\"",
71
- ErrorCode::MalformedComment => "Malformed HTML comment",
72
- ErrorCode::UnexpectedToken => "Unexpected token \"{0}\", expected \"{1}\"",
73
- ErrorCode::MissingClosingTag => "Missing closing tag for <{0}>",
74
- ErrorCode::UnexpectedClosingTag => "Unexpected closing tag </{0}>",
75
- ErrorCode::InvalidDirectiveSyntax => "Invalid directive syntax: \"{0}\"",
76
- ErrorCode::InvalidForSyntax => {
77
- "Invalid f-for syntax: \"{0}\". Expected \"(item, index) in source\" or \"item in source\""
78
- }
79
- ErrorCode::DuplicateKey => "Duplicate attribute \"{0}\" on element <{1}>",
80
- ErrorCode::VElseNoIf => "f-else / f-else-if has no matching f-if",
81
- ErrorCode::EmptyExpression => "Expression in \"{0}\" must not be empty",
82
- ErrorCode::InvalidSlotName => "Invalid slot name \"{0}\"",
83
- ErrorCode::DuplicateDirective => "Duplicate directive \"f-{0}\" on element <{1}>",
84
- ErrorCode::ForMissingKey => {
85
- "f-for on <{0}> is missing a :key binding — add :key=\"<unique expr>\""
86
- }
87
- ErrorCode::ModelOnNonInput => {
88
- "f-model can only be used on <input>, <textarea> or <select>, got <{0}>"
89
- }
90
- ErrorCode::ComponentNotRegistered => {
91
- "Component \"{0}\" is used in the template but not registered"
92
- }
93
- ErrorCode::UnknownIdentifier => {
94
- "Unknown identifier \"{0}\" in expression \"{1}\" — not found in component scope"
95
- }
96
- ErrorCode::StaticForKey => {
97
- ":key=\"{0}\" is a static literal — keys must be unique per item (use a dynamic expression like :key=\"item.id\")"
98
- }
99
- ErrorCode::UnknownNodeType => "Unknown AST node type \"{0}\" encountered in generator",
100
- }
101
- }
102
-
103
- static PLACEHOLDER_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"\{(\d+)\}").unwrap());
104
-
105
- fn interpolate(template: &str, args: &[String]) -> String {
106
- PLACEHOLDER_RE
107
- .replace(template, |caps: &regex::Captures| {
108
- let idx: usize = caps[1].parse().unwrap_or(0);
109
- args.get(idx).map(|s| s.as_str()).unwrap_or("")
110
- })
111
- .into_owned()
112
- }
113
-
114
- #[derive(Debug, Clone, Serialize)]
115
- pub struct CompileError {
116
- pub message: String,
117
- pub code: ErrorCode,
118
- pub loc: Loc,
119
- pub source: String,
120
- }
121
-
122
- impl CompileError {
123
- pub fn new(code: ErrorCode, loc: Loc, source: &str, args: impl AsRef<[String]>, ) -> Self {
124
- let template = template_for(code);
125
- let message = interpolate(template, args.as_ref());
126
- CompileError {
127
- message,
128
- code,
129
- loc,
130
- source: source.to_string(),
131
- }
132
- }
133
-
134
- pub fn format(&self, file_path: &str) -> String {
135
- let start = &self.loc.start;
136
- let header = format!("[fusée] CompileError {} at {}:{}:{}", self.code.as_str(), file_path, start.line, start.col);
137
- let snippet = self.build_snippet();
138
- if snippet.is_empty() {
139
- format!("{header}\n{}", self.message)
140
- } else {
141
- format!("{header}\n{}\n\n{snippet}", self.message)
142
- }
143
- }
144
-
145
- fn build_snippet(&self) -> String {
146
- if self.source.is_empty() || self.loc.start.line == 0 {
147
- return String::new();
148
- }
149
- let lines: Vec<&str> = self.source.split('\n').collect();
150
- let line_idx = self.loc.start.line - 1;
151
- if line_idx >= lines.len() {
152
- return String::new();
153
- }
154
- let col = self.loc.start.col;
155
- let context = 2;
156
- let first_line = line_idx.saturating_sub(context);
157
- let last_line = (line_idx + context).min(lines.len() - 1);
158
- let width = (last_line + 1).to_string().len();
159
-
160
- let mut parts: Vec<String> = Vec::new();
161
- for i in first_line..=last_line {
162
- let line_no = format!("{:width$}", i + 1, width = width);
163
- let prefix = if i == line_idx { "> " } else { " " };
164
- parts.push(format!("{prefix}{line_no} | {}", lines[i]));
165
- if i == line_idx {
166
- let caret_pad = " ".repeat(width + 4 + col.saturating_sub(1));
167
- let end_col = if self.loc.end.col > 0 {
168
- self.loc.end.col
169
- } else {
170
- col
171
- };
172
- let caret_len = end_col.saturating_sub(col).max(1);
173
- parts.push(format!("{caret_pad}{}", "~".repeat(caret_len)));
174
- }
175
- }
176
- parts.join("\n")
177
- }
178
- }
179
-
180
- #[derive(Debug, Clone, Serialize)]
181
- pub struct CompileWarning {
182
- pub message: String,
183
- pub code: ErrorCode,
184
- pub loc: Loc,
185
- pub source: String,
186
- }
187
-
188
- impl CompileWarning {
189
- pub fn new(code: ErrorCode, loc: Loc, source: &str, args: impl AsRef<[String]>) -> Self {
190
- let template = template_for(code);
191
- let message = interpolate(template, args.as_ref());
192
- CompileWarning {
193
- message,
194
- code,
195
- loc,
196
- source: source.to_string(),
197
- }
198
- }
199
-
200
- pub fn format(&self, file_path: &str) -> String {
201
- let start = &self.loc.start;
202
- format!("[fusée] Warning {} at {}:{}:{}\n{}", self.code.as_str(), file_path, start.line, start.col, self.message)
203
- }
204
- }