diff --git a/spec/compilers2/defer_2 b/spec/compilers2/defer_2
new file mode 100644
index 000000000..6c22dcc1b
--- /dev/null
+++ b/spec/compilers2/defer_2
@@ -0,0 +1,53 @@
+module Data {
+ const ITEMS = defer [ defer ITEM_1 ]
+ const ITEM_1 = "Hello"
+}
+
+component Main {
+ fun componentDidMount : Promise(String) {
+ let [item] = await Data.ITEMS or return ""
+ await item
+ }
+
+ fun render : Html {
+
""
+ }
+}
+--------------------------------------------------------------------------------
+---=== /index.js ===---
+import {
+ patternVariable as E,
+ createElement as F,
+ destructure as C,
+ useEffect as B,
+ load as D
+} from "runtime";
+
+export const
+ a = `/__mint__/d5f8d9aa357303a4ba78b554c55d598bd238f679b.js`,
+ A = () => {
+ B(() => {
+ (async () => {
+ const b = C(await D(a), [E]);
+ if (b === false) {
+ return ``
+ };
+ const [c] = b;
+ return await D(c)
+ })()
+ }, []);
+ return F(`div`, {}, [``])
+ };
+
+---=== /__mint__/d96571c631d11ed793b887a131e80107a65e05223.js ===---
+export const
+ a = `Hello`,
+ b = a;
+
+export default b;
+
+---=== /__mint__/d5f8d9aa357303a4ba78b554c55d598bd238f679b.js ===---
+export const a = [`/__mint__/d96571c631d11ed793b887a131e80107a65e05223.js`];
+
+export default a;
+
diff --git a/spec/compilers2/here_doc_markdown_escape b/spec/compilers2/here_doc_markdown_escape
index f50dc7715..3cf29eb3a 100644
--- a/spec/compilers2/here_doc_markdown_escape
+++ b/spec/compilers2/here_doc_markdown_escape
@@ -1,7 +1,10 @@
component Main {
fun render : Html {
<<#MARKDOWN(highlight)
+ \#{name}
```mint
+ `Something`
+ "\#{name}"
"First line" \
"Second line" \
"Third line"
@@ -16,35 +19,59 @@ import {
} from "runtime";
export const A = () => {
- return B(C, {}, [B('pre', {}, [B('code', {
- class: "language-mint"
- }, [
- B('span', {
- className: "line"
+ return B(C, {}, [
+ B('p', {}, [`#{name}`]),
+ B('pre', {}, [B('code', {
+ class: "language-mint"
}, [
B('span', {
- className: "string"
- }, [`"First line" \\`]),
- `
+ className: "line"
+ }, [`\`Something\`
+`]),
+ B('span', {
+ className: "line"
+ }, [
+ ``,
+ B('span', {
+ className: "string"
+ }, [`"#{`]),
+ B('span', {
+ className: "variable"
+ }, [`name`]),
+ B('span', {
+ className: "string"
+ }, [`}"`]),
+ `
`
- ]),
- B('span', {
- className: "line"
- }, [
- ``,
+ ]),
B('span', {
- className: "string"
- }, [`"Second line" \\`]),
- `
+ className: "line"
+ }, [
+ ``,
+ B('span', {
+ className: "string"
+ }, [`"First line" \`]),
+ `
`
- ]),
- B('span', {
- className: "line"
- }, [
- ``,
+ ]),
+ B('span', {
+ className: "line"
+ }, [
+ ``,
+ B('span', {
+ className: "string"
+ }, [`"Second line" \`]),
+ `
+`
+ ]),
B('span', {
- className: "string"
- }, [`"Third line"`])
- ])
- ])])])
+ className: "line"
+ }, [
+ ``,
+ B('span', {
+ className: "string"
+ }, [`"Third line"`])
+ ])
+ ])])
+ ])
};
diff --git a/spec/compilers2/store_with_get b/spec/compilers2/store_with_get
index a7502efad..ae643d762 100644
--- a/spec/compilers2/store_with_get
+++ b/spec/compilers2/store_with_get
@@ -11,6 +11,7 @@ component Main {
fun render : String {
xxx
+ Test.hello
}
}
--------------------------------------------------------------------------------
@@ -22,6 +23,7 @@ export const
return `hello`
},
B = () => {
- return a.value
+ a.value;
+ return b()
};
diff --git a/spec/compilers2/string_literal_escaped b/spec/compilers2/string_literal_escaped
index 9d563c800..5df330860 100644
--- a/spec/compilers2/string_literal_escaped
+++ b/spec/compilers2/string_literal_escaped
@@ -5,5 +5,5 @@ component Main {
}
--------------------------------------------------------------------------------
export const A = () => {
- return `Hello There \"Joe\"`
+ return `Hello There "Joe"`
};
diff --git a/spec/compilers2/string_literal_with_escaped_interpolation b/spec/compilers2/string_literal_with_escaped_interpolation
new file mode 100644
index 000000000..f05bee66c
--- /dev/null
+++ b/spec/compilers2/string_literal_with_escaped_interpolation
@@ -0,0 +1,9 @@
+component Main {
+ fun render : String {
+ "Hello There \#{name}"
+ }
+}
+--------------------------------------------------------------------------------
+export const A = () => {
+ return `Hello There #{name}`
+};
diff --git a/src/compiler2/js.cr b/src/compiler2/js.cr
index 051fc3428..7007127f8 100644
--- a/src/compiler2/js.cr
+++ b/src/compiler2/js.cr
@@ -26,7 +26,7 @@ module Mint
end
def string(value : String) : Compiled
- ["`", Raw.new(value), "`"] of Item
+ ["`", Raw.new(value.gsub('`', "\\`").gsub("${", "\\${`")), "`"] of Item
end
# Renders an object destructuring.
diff --git a/src/compiler2/program.cr b/src/compiler2/program.cr
index 1d9617b05..9dfbb0201 100644
--- a/src/compiler2/program.cr
+++ b/src/compiler2/program.cr
@@ -13,6 +13,33 @@ module Mint
end
end
+ def self.dbg_name(node)
+ case x = node
+ when Ast::Component
+ "<#{x.name.value}>"
+ when Ast::Module, Ast::Store, Ast::Provider
+ x.name.value
+ when Ast::Function, Ast::Constant, Ast::Get, Ast::State
+ "#{dbg_name(x.parent)}.#{x.name.value}"
+ when Ast::Block
+ "{block}"
+ when Ast::Access
+ "{access .#{x.field.value}}"
+ when Ast::Statement
+ name =
+ case target = x.target
+ when Ast::Variable
+ " #{target.value}"
+ end
+
+ "{statement#{name}}"
+ when Ast::Route
+ "{route #{x.url}}"
+ else
+ x.class.name
+ end
+ end
+
def self.program(
artifacts : TypeChecker::Artifacts,
config : Config
@@ -105,6 +132,25 @@ module Mint
end
end
+ # bundles.each do |node, items|
+ # entities =
+ # items.compact_map do |item|
+ # if item[0] == node
+ # next if node.is_a?(Ast::Defer)
+ # else
+ # next if item[0].is_a?(Ast::Component) &&
+ # item[0].as(Ast::Component).async?
+ # end
+
+ # dbg_name(item[0])
+ # end
+
+ # puts bundle_name(node)
+ # entities.sort.each do |item|
+ # puts " > #{item}"
+ # end
+ # end
+
# Add not already added items to the main bundle.
bundles[nil].concat(compiler.compiled)
diff --git a/src/compiler2/utils.cr b/src/compiler2/utils.cr
index ae9805f28..485234b64 100644
--- a/src/compiler2/utils.cr
+++ b/src/compiler2/utils.cr
@@ -59,14 +59,14 @@ module Mint
parts.map do |item|
case item
in String
- ["`", Raw.new(item.escape_for_javascript), "`"] of Item
+ js.string(item)
in Tuple(SemanticTokenizer::TokenType, String)
js.call(Builtin::CreateElement, [
[%("span")] of Item,
js.object({"className".as(Item) => [
%("#{item[0].to_s.underscore}"),
] of Item}),
- js.array([["`", Raw.new(item[1].escape_for_javascript), "`"] of Item]),
+ js.array([js.string(item[1])]),
])
end
end
diff --git a/src/compilers2/directives/format.cr b/src/compilers2/directives/format.cr
index 66aa3430c..54349ce0f 100644
--- a/src/compilers2/directives/format.cr
+++ b/src/compilers2/directives/format.cr
@@ -9,8 +9,6 @@ module Mint
Formatter.new
.format(node.content, Formatter::BlockFormat::Naked)
.gsub('\\', "\\\\")
- .gsub('`', "\\`")
- .gsub("${", "\\${")
js.array([content, js.string(formatted)])
end
diff --git a/src/compilers2/env.cr b/src/compilers2/env.cr
index 7ec81c922..852b28023 100644
--- a/src/compilers2/env.cr
+++ b/src/compilers2/env.cr
@@ -3,7 +3,7 @@ module Mint
def compile(node : Ast::Env) : Compiled
compile node do
value =
- MINT_ENV[node.name].to_s.gsub('`', "\\`")
+ MINT_ENV[node.name].to_s
js.string(value)
end
diff --git a/src/compilers2/here_doc.cr b/src/compilers2/here_doc.cr
index 866256a9e..20c464819 100644
--- a/src/compilers2/here_doc.cr
+++ b/src/compilers2/here_doc.cr
@@ -27,6 +27,7 @@ module Mint
.lchop('\r')
.lchop("\n\r")
.rstrip
+ .gsub("\\\#{", "\#{")
if node.modifier == '#'
document =
diff --git a/src/compilers2/js.cr b/src/compilers2/js.cr
index 9e20a4e7e..cabf68c58 100644
--- a/src/compilers2/js.cr
+++ b/src/compilers2/js.cr
@@ -15,10 +15,10 @@ module Mint
value =
node.value.flat_map do |entity|
case entity
- when Ast::Node
+ in Ast::Node
compile entity
- else
- entity
+ in String
+ entity.gsub("\\`", '`')
end
end
diff --git a/src/compilers2/string_literal.cr b/src/compilers2/string_literal.cr
index 788488c92..5a82cae50 100644
--- a/src/compilers2/string_literal.cr
+++ b/src/compilers2/string_literal.cr
@@ -10,7 +10,9 @@ module Mint
[
item
.gsub('`', "\\`")
- .gsub("${", "\\${"),
+ .gsub("${", "\\${")
+ .gsub("\\\"", "\"")
+ .gsub("\\\#{", "\#{"),
]
end
end
diff --git a/src/formatters/js.cr b/src/formatters/js.cr
index 321ef593e..2f234bdee 100644
--- a/src/formatters/js.cr
+++ b/src/formatters/js.cr
@@ -7,7 +7,7 @@ module Mint
when Ast::Interpolation
item.source
else
- format(item).gsub('`', "\\`")
+ format(item)
end
end
diff --git a/src/parsers/js.cr b/src/parsers/js.cr
index 61599c07d..fe63db6c9 100644
--- a/src/parsers/js.cr
+++ b/src/parsers/js.cr
@@ -6,7 +6,7 @@ module Mint
value =
many(parse_whitespace: false) do
- raw('`').try(&.gsub("\\`", '`')) || interpolation
+ raw('`') || interpolation
end
next error :js_expected_closing_tick do
diff --git a/src/parsers/operator.cr b/src/parsers/operator.cr
index e71d44314..37b303a59 100644
--- a/src/parsers/operator.cr
+++ b/src/parsers/operator.cr
@@ -52,9 +52,14 @@ module Mint
next unless operator
next if operator != "|>" && !whitespace?
- ast.operators << {saved_position, saved_position + operator.size}
- whitespace
+ case operator
+ when "or"
+ ast.keywords << {saved_position, saved_position + operator.size}
+ else
+ ast.operators << {saved_position, saved_position + operator.size}
+ end
+ whitespace
operator
end
end
diff --git a/src/reactor.cr b/src/reactor.cr
index 14f008d76..fdb8183f2 100644
--- a/src/reactor.cr
+++ b/src/reactor.cr
@@ -30,7 +30,7 @@ module Mint
workspace = Workspace.current
workspace.format = auto_format
workspace.check_env = true
- workspace.check_everything = true
+ workspace.check_everything = false
workspace.on "change" do |result|
case result
diff --git a/src/semantic_tokenizer.cr b/src/semantic_tokenizer.cr
index a70213581..042f760be 100644
--- a/src/semantic_tokenizer.cr
+++ b/src/semantic_tokenizer.cr
@@ -23,7 +23,6 @@ module Mint
TOKEN_MAP = {
Ast::TypeVariable => TokenType::TypeParameter,
Ast::Comment => TokenType::Comment,
- Ast::StringLiteral => TokenType::String,
Ast::RegexpLiteral => TokenType::Regexp,
Ast::NumberLiteral => TokenType::Number,
Ast::Id => TokenType::Type,
@@ -154,6 +153,46 @@ module Mint
add(node.tag, TokenType::Namespace)
end
+ def tokenize(node : Ast::StringLiteral)
+ if node.value.size == 0
+ add(node, TokenType::String)
+ else
+ position =
+ node.from
+
+ node.value.each_with_index do |item, index|
+ last =
+ index == (node.value.size - 1)
+
+ case item
+ in Ast::Interpolation
+ # We skip interpolations because they will be process separately
+ # but we need to proceed the position to it's end, also we need
+ # to add `#{` as a string which is everything up to the boxed
+ # expressions start.
+ add(position, item.expression.from, TokenType::String)
+ position = item.expression.to
+
+ if last
+ add(position, node.to, TokenType::String)
+ end
+ in String
+ from =
+ position
+
+ position =
+ if last
+ node.to
+ else
+ position + item.size
+ end
+
+ add(from, position, TokenType::String)
+ end
+ end
+ end
+ end
+
def tokenize(node : Ast::HtmlComponent)
node.closing_tag_position.try do |position|
add(position, position + node.component.value.size, :type)
diff --git a/src/type_checker.cr b/src/type_checker.cr
index 3980abc33..e43ae2aa9 100644
--- a/src/type_checker.cr
+++ b/src/type_checker.cr
@@ -89,14 +89,7 @@ module Mint
def print_stack
@stack.each_with_index do |i, index|
- x = case i
- when Ast::Component then ""
- when Ast::Function then ""
- when Ast::Block then ""
- when Ast::Call then ""
- else
- i
- end
+ x = Compiler2.dbg_name(i)
if index == 0
puts x
@@ -240,26 +233,44 @@ module Mint
# Already tracked
if cache[node]?
- @ref_stack[node]?.try(&.each { |child| track_references(child) })
+ @ref_stack[node]?.try(&.each do |child|
+ # If we hit a defer we break out of the loop
+ # since it will always be in a different file.
+ case child
+ when Ast::Defer
+ break
+ else
+ track_references(child)
+ end
+ end)
end
references[node] ||= Set(Ast::Node | Nil).new
# case node
- # when Ast::Function
- # if node.name.value == "test"
- # puts node
- # puts "-----"
+ # when Ast::Constant
+ # if node.name.value == "INDEX"
+ # puts "TRACK STACK #{Compiler2.dbg_name(node)}"
# print_stack
+ # @ref_stack[node]?.try(&.each { |child| Compiler2.dbg_name(child) })
# puts component_stack.size
+ # pp caller.reverse
# end
# end
if component_stack.empty?
references[node].add(nil)
else
- component_stack.each do |component|
+ component_stack.reverse_each do |component|
references[node].add(component)
+
+ # If we hit a defer we break out of the loop
+ # since it will always be that defers file (
+ # which we added above)
+ case component
+ when Ast::Defer
+ break
+ end
end
end
end
diff --git a/src/type_checkers/if.cr b/src/type_checkers/if.cr
index 90c9b4e3a..bb19f11b8 100644
--- a/src/type_checkers/if.cr
+++ b/src/type_checkers/if.cr
@@ -7,8 +7,11 @@ module Mint
variables, await =
case item = node.condition
when Ast::Statement
- if item.target.is_a?(Ast::TypeDestructuring)
- {destructure(item.target.as(Ast::TypeDestructuring), condition), item.await}
+ case item.target
+ when Ast::TupleDestructuring,
+ Ast::ArrayDestructuring,
+ Ast::TypeDestructuring
+ {destructure(item.target, condition), item.await}
end
end || {[] of VariableScope, false}
diff --git a/src/utils/markd_vdom_renderer2.cr b/src/utils/markd_vdom_renderer2.cr
index effc4dc40..8e2864d8a 100644
--- a/src/utils/markd_vdom_renderer2.cr
+++ b/src/utils/markd_vdom_renderer2.cr
@@ -36,11 +36,12 @@ module Mint
if node == separator
replacements.shift
else
- ["`", Raw.new(node.escape_for_javascript), "`"] of Item
+ js.string(node)
end
in Node
attributes =
- node.attributes
+ node
+ .attributes
.transform_values { |value| [%("#{value}")] of Item }
children =