diff --git a/src/generator/svg-extended.js b/src/generator/svg-extended.js new file mode 100644 index 0000000..9403177 --- /dev/null +++ b/src/generator/svg-extended.js @@ -0,0 +1,35 @@ +function generate(token, indent = 0) { + let result = ''; + if (token.type === 'block') { + if (token.times) { + result += '@M' + token.times + '(' + token.pureName + '{'; + } else { + result += token.name + '{'; + } + if (Array.isArray(token.value) && token.value.length) { + for (let t of token.value) { + result += generate(t, indent + 2); + } + } + if (token.times) { + result += '})'; + } else { + result += '}'; + } + } else if (token.type === 'statement') { + if (token.value && token.value.type) { + result += token.name + ':' + generate(token.value, indent); + } else { + result += token.name + ':' + token.value + ';'; + } + } + return result; +} + +function generate_svg_extended(token) { + return generate(token).trim(); +} + +export { + generate_svg_extended, +} diff --git a/src/parser/parse-css.js b/src/parser/parse-css.js index e198a71..b9b0c42 100644 --- a/src/parser/parse-css.js +++ b/src/parser/parse-css.js @@ -1,6 +1,8 @@ // I need to rewrite this import parse_var from './parse-var.js'; +import parse_svg from './parse-svg.js'; +import { generate_svg_extended } from '../generator/svg-extended.js'; import { first, last, clone } from '../utils/list.js'; const Tokens = { @@ -260,8 +262,10 @@ function read_property(it) { function read_arguments(it, composition, doodle) { let args = [], group = [], stack = [], arg = '', c; + let raw = ''; while (!it.end()) { c = it.curr(); + let start = it.index(); if ((/[\('"`]/.test(c) && it.curr(-1) !== '\\')) { if (stack.length) { if (c != '(' && c === last(stack)) { @@ -291,7 +295,6 @@ function read_arguments(it, composition, doodle) { } arg += c; } - else { if (arg.length) { if (!group.length) { @@ -328,10 +331,11 @@ function read_arguments(it, composition, doodle) { break; } else { + raw += it.range(start, it.index() + 1); it.next(); } } - return skip_last_empty_args(args); + return [skip_last_empty_args(args), raw]; } function skip_last_empty_args(args) { @@ -390,6 +394,11 @@ function seperate_func_name(name) { return { fname, extra }; } +function has_times_syntax(token) { + let str = JSON.stringify(token); + return str.includes('pureName') && str.includes('times'); +} + function read_func(it) { let func = Tokens.func(); let name = '@', c; @@ -403,7 +412,18 @@ function read_func(it) { if (c == '(' || composition) { has_argument = true; it.next(); - func.arguments = read_arguments(it, composition, composible(name)); + let [args, raw_args] = read_arguments(it, composition, composible(name)); + if (name === '@svg') { + let parsed_svg = parse_svg(raw_args); + if (has_times_syntax(parsed_svg)) { + let svg = generate_svg_extended(parsed_svg); + // compatible with old iterator + svg += ')'; + let extended = read_arguments(iterator(svg), composition, composible(name)); + args = extended[0]; + } + } + func.arguments = args; break; } else if (!has_argument && next !== '(' && !/[0-9a-zA-Z_\-.]/.test(next)) { name += c; @@ -504,7 +524,7 @@ function read_cond_selector(it) { while (!it.end()) { if ((c = it.curr()) == '(') { it.next(); - selector.arguments = read_arguments(it); + selector.arguments = read_arguments(it)[0]; } else if (/[){]/.test(c)) break; else if (!is.white_space(c)) selector.name += c; diff --git a/src/parser/parse-svg.js b/src/parser/parse-svg.js index 8d0810e..81cee33 100644 --- a/src/parser/parse-svg.js +++ b/src/parser/parse-svg.js @@ -25,18 +25,19 @@ function readStatement(iter, token) { } let tokenName = selectors.pop(); let skip = isSkip(...selectors, tokenName); - inlineBlock = resolveId(walk(iter, { + inlineBlock = resolveId(walk(iter, splitTimes(tokenName, { type: 'block', - name: tokenName, inline: true, - value: [] - }), skip); + name: tokenName, + value: [], + })), skip); + while (tokenName = selectors.pop()) { - inlineBlock = resolveId({ + inlineBlock = resolveId(splitTimes(tokenName, { type: 'block', name: tokenName, value: [inlineBlock] - }, skip); + }), skip); } break; } @@ -94,17 +95,17 @@ function walk(iter, parentToken) { } let tokenName = selectors.pop(); let skip = isSkip(...selectors, parentToken.name, tokenName); - let block = resolveId(walk(iter, { + let block = resolveId(walk(iter, splitTimes(tokenName, { type: 'block', name: tokenName, value: [] - }), skip); + })), skip); while (tokenName = selectors.pop()) { - block = resolveId({ + block = resolveId(splitTimes(tokenName, { type: 'block', name: tokenName, value: [block] - }, skip); + }), skip); } rules.push(block); fragment = []; @@ -205,6 +206,18 @@ function getGroups(tokens, fn) { return group; } +function splitTimes(name, object) { + let target = Object.assign({}, object); + if (/\*[0-9]/.test(name)) { + let [tokenName, times] = name.split('*'); + if (times) { + target.times = times; + target.pureName = tokenName; + } + } + return target; +} + function isSkip(...names) { return names.some(n => n === 'style'); } diff --git a/test/generate-svg-extended.js b/test/generate-svg-extended.js new file mode 100644 index 0000000..a867333 --- /dev/null +++ b/test/generate-svg-extended.js @@ -0,0 +1,28 @@ +import test from 'ava'; + +import parseSvg from '../src/parser/parse-svg.js'; +import { generate_svg_extended } from '../src/generator/svg-extended.js'; +import compare from './_compare.js'; + +compare.use(input => { + return generate_svg_extended(parseSvg(input)); +}); + +test('code transformation', t => { + + compare(t, + `circle {}`, + `svg{circle{}}` + ); + + compare(t, + `circle*10 {}`, + `svg{@M10(circle{})}` + ); + + compare(t, + `g circle*10x10 {}`, + `svg{g{@M10x10(circle{})}}` + ); + +}); diff --git a/test/parse-svg.js b/test/parse-svg.js index cd8ece7..1f535df 100644 --- a/test/parse-svg.js +++ b/test/parse-svg.js @@ -321,3 +321,20 @@ test('statement end on quotes', t => { }] }); }); + +test('times syntas', t => { + compare(t, ` + circle*10 {} + `, { + type: 'block', + name: 'svg', + value: [{ + type: 'block', + name: 'circle*10', + pureName: 'circle', + times: '10', + value: [] + }] + }); + +});