pasaran / yate Goto Github PK
View Code? Open in Web Editor NEWYet Another Template Engine
License: MIT License
Yet Another Template Engine
License: MIT License
Example:
<div>
<h1>
"Hello"
</>
</>
Хочу обратиться к свойству объекта, название свойства при этом хранится в переменной.
Пример, где это было бы полезно:
var data = {
image: {
url_s: "...", width_s: 30, height_s: 40,
url_m: "...", width_m: 60, height_m: 80,
url_l: "...", width_l: 120, height_l: 160,
url_xl: "...", width_xl: 240, height_xl: 240
}
};
match .image img {
size = "xl"
<img src="{.['url_' + size]}" width="{.['width_' + size]}" height="{.['height_' + size]}" />
}
Тесткейс в #60
Right now it's impossible to use "absolute" jpath in match:
match /.foo.bar { // ERROR
"Hello"
}
That's because /
is a separate entity and not part of jpath syntax.
Tempate
match / {
apply .blocks.app
}
match .blocks.app {
name()
}
fails to execute
TypeError: string is not a function
at String.CALL_NON_FUNCTION (native)
at [object Object].matched (evalmachine.:206:22)
at [object Object].applyValue (evalmachine.:54:22)
at Object.body (evalmachine.:381:25)
at [object Object].applyValue (evalmachine.:61:35)
at Function.run (evalmachine.:19:18)
at evalmachine.:450:8
at Object.run (/home/lynn/www/times/yate/yatelib.js:3964:21)
at Object. (/home/lynn/www/times/yate/yate:23:23)
at Module._compile (module.js:444:26)
Seems like it's a bad idea to have different meanings for double and single quotes.
match / {
"Hello, '{ .username }'"
'Hello, "{ .username }"'
}
Test stylesheet:
match / {
hello("hello")
}
func hello(text) {
if text { // Here!
text
}
}
Пример
match / {
<div>
@class = apply . class
"Hello"
</div>
}
match / class {
"b-hello"
}
Запускаем
$ ./yate a.yate
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: ERROR: Cannot convert type from xml to scalar apply
at (18, 3) in /.../a.yate:
@class = apply . class
-----------------^
at [object Object].error (/.../yatelib.js:209:11)
at [object Object].cast (/.../yatelib.js:362:18)
at [object Object].setTypes (/.../yatelib.js:2601:16)
at /.../yatelib.js:3919:13
at [object Object].walkBefore (/.../yatelib.js:316:5)
at [object Object].walkBefore (/.../yatelib.js:785:18)
at [object Object].walkBefore (/.../yatelib.js:323:19)
at [object Object].walkBefore (/.../yatelib.js:323:19)
at [object Object].walkBefore (/.../yatelib.js:323:19)
at [object Object].walkBefore (/.../yatelib.js:785:18)
Then it will be possible to completely decouple runtime and generated stylesheet.
Also it will reduce start-up time of stylesheet so we could use small templates without evaluating all global variables.
Сейчас можно написать как-то вот так:
match / {
class = @class = "b-hello"
...
}
И это выглядит, мягко говоря, странно.
И еще есть вариант с +=
, который совсем мне не нравится.
Альтернативный синтаксис:
match / {
<div>
// Можно задать несколько атрибутов через запятую.
@id: .id, @data-nb: "popup"
// Вместо += предлагается использовать "текущее значение" @class.
@class: "b-hello { @class }"
"Hello"
</div>
// Тоже самое, но в переменных.
attrs = @class: "b-hello", @id: .id
attrs = (
// Вот тут "текущее значение" @class зависит от контекста.
@class: "b-hello { @class }"
@id: .id
)
}
Test functions.12 -- failed.
4f97f08
Хочется, писать условия проще, что бы они были ближе к JS-ным.
Сейчас только пустой массив и undefined
считаются ложными условиями.
Хочется, что бы пустая строка, false
, 0
, null
тоже считались ложными
02.json
{
"sOK": "OK",
"sEmpty": "", // false
"sZero": "0",
"bTrue": true,
"bFalse": false, // false
"nZero": 0, // false
"nOne": 1,
"Null": null, // false
"Undef": undefined,
"oEmpty": {},
"oOne": { "a": 1 },
"aEmpty": [],
"aZero": [0],
"aOne": [1]
}
if.02.yate
match / {
"sOK: "
if .sOK { "true" } else { "false" }
"\n"
"sEmpty: "
if .sEmpty { "true" } else { "false" }
"\n"
"sZero: "
if .sZero { "true" } else { "false" }
"\n"
"bTrue: "
if .bTrue { "true" } else { "false" }
"\n"
"bFalse: "
if .bFalse { "true" } else { "false" }
"\n"
"nZero: "
if .nZero { "true" } else { "false" }
"\n"
"nOne: "
if .nOne { "true" } else { "false" }
"\n"
"Null: "
if .Null { "true" } else { "false" }
"\n"
"Undef: "
if .Undef { "true" } else { "false" }
"\n"
"oEmpty: "
if .oEmpty { "true" } else { "false" }
"\n"
"oOne: "
if .oOne { "true" } else { "false" }
"\n"
"aEmpty: "
if .aEmpty { "true" } else { "false" }
"\n"
"aZero: "
if .aZero { "true" } else { "false" }
"\n"
"aOne: "
if .aOne { "true" } else { "false" }
}
Результат
sOK: true
sEmpty: true
sZero: true
bTrue: true
bFalse: true
nZero: true
nOne: true
Null: true
Undef: false
oEmpty: true
oOne: true
aEmpty: false
aZero: true
aOne: true
Отсюда: nanoblocks/nanoblocks#66 (comment)
match / {
<script>
"""
var foo = {{ .params.foo }};
if (foo) {
doSomething();
}
"""
</script>
}
Нужна возможность подключать рантайм на странице отдельно, что бы не дублировать код если на странице есть несколько шаблонов.
Test failed: dbeaae8
For example:
match / class {
apply .foo.bar "{ . }-content"
}
match .foo.bar class-content {
"b-foo"
}
Currently I cannot use such construction as
if () {}
else if () {}
else {}
instead I must place all next level if's in else section, like so:
if () {}
else {
if () {}
else {}
}
Интересно, как должны интерпретироваться вложенные массивы?
Например jpath .item.*
для
{ item: [ [ 13, 42 ] ] }
вернёт два элемента с именами 0
и 1
.
Думаю, что пока можно не заморачиваться, так что это вопрос на подумать.
коммит ef4ecf1 сломал тест include.01.yate
a = .foo.bar // lazy
b = 42 // constant
А это действительно очень сложно давать записывать тэг на несколько строк?
Не так:
<a href="..." class="..." onclick="...">click</a>
а так:
<a href="..." class="..."
onclick="...">click</a>
Со стороны выглядит довольно просто:
Считать следующий символ в строке.
Если это '<' - значит это начало xml тэга.
Пока не найден символ '>' прибавлять к текущей строке следующую строку.
Считать тэгом всё, что оказалось между первым '<' и найденым в процессе '>'.
Test: 17ea921
Possible syntax:
<div>
@{ name } = "b-hello"
"Hello"
</div>
Например
key(.items.item, .id + .title) {
.
}
не работает.
Нужно описание include
-ов.
К примеру:
include
в середине файла;dir/
dir/*.yate
:)
Now in match
section in jpath we have to use a point prefix for node:
apply .node mode
match .node mode { ... }
But when I look at match .node
I think we are taking current node and are matching on the node
property of it, while in reality we want to match on current node, if it is a node
node :)
So, I think we can skip leading point in match
section, like so:
apply .node mode
match node mode { ... }
Это конечно синтетические примеры, но всё же неаккуратно.
Например такой шаблон
match .*[count()] {
}
компилируется в
// count()
function p0(c0, index, count) {
return count;
};
var j0 = [ 0, "*", 3, count ]; // .*[ count() ]
и приводит к ошибке выполнения, потому что не определена переменная count
использованная в j0
.
А такой код
match .*[3 == count()] {}
вообще не компилируется
Error: ERROR: Cannot convert type from boolean to scalar inline_eq
at (10, 1) in /.../count.yate:
match .*[3 == count()] {}
Right now there isn't special character for mode in match
and apply
:
match .foo content {
"Hello"
apply .bar content
}
Maybe we need one. Like this:
match .foo #content {
"Hello"
apply .bar #content
}
Тесткейс
alexeyten/yate@f56b56b348e99b316daaf5bd40708e911256a620
I would like to write match /[ condition ]
Тесткейс простой как палка:
match / {
v = f()
}
func f() { }
компилируется в
...
// match /
var t0 = {
jpath: null,
body: function(c0, a0, index, count) {
var r0 = '';
var v0 = f0(c0, /*====>*/ a1 /*<=====*/, index, count);
return r0;
}
};
...
Откуда там берётся a1
непонятно, но получается
./yate a.yate tests/01.json
node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
ReferenceError: a1 is not defined
at Object.body (evalmachine.<anonymous>:381:29)
at [object Object].applyValue (evalmachine.<anonymous>:61:35)
at Function.run (evalmachine.<anonymous>:20:18)
at evalmachine.<anonymous>:438:8
at Object.run (/home/lynn/Public/yate/lib/yate.js:117:22)
at Object.<anonymous> (/home/lynn/Public/yate/yate:42:23)
at Module._compile (module.js:441:26)
at Object..js (module.js:459:10)
at Module.load (module.js:348:31)
at Function._load (module.js:308:12)
В #11 тесткейсы не работают в первую очередь из-за этого, а не потому что там атрибуты.
И #51 тоже про это.
Такой код
var = "<"
var2 = "&"
match / {
<tag a="<" b="{var}">
@c=var
</>
<tag a="<" b="{var}">
</>
"\n"
<tag a="&" b="{var2}">
@c=var2
</>
"\n"
<tag a="&" b="{var2}">
</>
}
выдаёт безумный результат
<tag a="&lt;" b="&lt;" c="<"></tag>
<tag a="<" b="<"></tag>
<tag a="&" b="&amp;" c="&"></tag>
<tag a="&" b="&"></tag>
я ожидал бы такой:
<tag a="<" b="<" c="<"></tag>
<tag a="<" b="<"></tag>
<tag a="&" b="&" c="&"></tag>
<tag a="&" b="&"></tag>
add conditional class to empty (undefined) class generates bogus class.
match / {
<h1>
@class += if 1 { "b-hello" }
"Hello, { .username }"
</h1>
}
produces
<h1 class="undefinedb-hello">Hello, nop</h1>
Сейчас функции - это аналог именованных шаблонов в xslt.
А как насчёт функций для вычислений?
У которых есть return value
, к примеру, которое можно сохранить в переменную и дальше на нём вызвать шаблон, к примеру.
match / {
<div> // No comments here
<div></div> // And here
</div>
}
Иногда хочется использовать html-entity, например написать что-нибудь типа
<div title="I ♥ NY">I ♥ NY</div>
но из-за квотинга получается
<div title="I &hearts; NY">I &hearts; NY</div>
Я не очень представляю как с этим быть.
Из такого кода
match / {
<div>
@x = 0
</div>
}
Получается
<div x=""></div>
Баг в функции attrQuote
У меня нет до конца продуманного синтаксиса для построения объектов/массивов (т.е. это аналог для временного дерева в xslt
).
С объектами все более-менее просто:
match / {
obj = {
"a": 42
if .foo {
"foo": .foo
}
"subobject": {
for .items.item {
"id-{ .id }": .title
}
}
"html": (
<div>
@class = "b-hello"
"Hello"
</div>
)
}
}
Т.е. объект заворачивается в { ... }
и состоит из "пар" -- слева ключ (может быть любым скалярным инлайновым выражением), справа выражение.
Template
func f1(x) {
...
}
func f2(x) {
...
}
...
fails to compile with error ERROR: Повторное определение аргумента x
Это видимо последствия #38
match / {
<div id="{.id}">
@class = "b-hello"
"Hello"
</div>
}
выдаёт
<div id="[object Object]" class="b-hello">Hello</div>
match .photo controls {
foo( "" ) // empty string as a param
}
func foo( p ) {
// We get bug here: r0 += scalar2xml( f2(c0, index, count,) ); :3402 Uncaught SyntaxError: Unexpected token )
// A comma is missing after count variable.
}
Test functions.13 -- failed.
4f97f08
Сейчас сигнатура внешних функций никак не типизируется и внутри функции приходится вручную приводить аргументы к желаемому виду.
Было бы удобно написать
external scalar upperCase(scalar)
...
upperCase(.summary | .post | .title | .url)
и быть уверенным, что в функцию придёт строка(число). Да, сейчас можно написать
upperCase("" + (.summary | .post | .title | .url))
но это некрасиво и неудобно.
Сейчас функции - это аналог именованных шаблонов в xslt.
А как насчёт функций для вычислений?
У которых есть return value
, к примеру, которое можно сохранить в переменную и дальше на нём вызвать шаблон, к примеру.
count(nodeset) — number of nodes
...
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.