Socket
Socket
Sign inDemoInstall

@riotjs/compiler

Package Overview
Dependencies
Maintainers
1
Versions
126
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@riotjs/compiler - npm Package Compare versions

Comparing version 4.0.0-alpha.9 to 4.0.0-alpha.10

src/utils/add-lines-offset.js

4

CHANGELOG.md
# Compiler Changes
### v4.0.0-alpha.10
- Update enhance sourcemaps generation
- Change second arguments for the pre/post processors. The `meta` object will contain info about the current compilation
### v4.0.0-alpha.9

@@ -4,0 +8,0 @@ - Fix move `recast` into the package dependencies

415

dist/index.esm.js
/* Riot Compiler WIP, @license MIT */
import recast from 'recast';
import recastUtil from 'recast/lib/util';
import { SourceMapGenerator } from 'source-map';
import recast from 'recast';
import curry from 'curri';

@@ -14,2 +14,14 @@ import globalScope from 'globals';

const types = recast.types;
const builders = types.builders;
const namedTypes = types.namedTypes;
function nullNode() {
return builders.literal(null)
}
function simplePropertyNode(key, value) {
return builders.property('init', builders.literal(key), value, false)
}
/**

@@ -74,15 +86,17 @@ * Detect node js environements

* @param { SourceMapGenerator } data.map - source map generated along with the code
* @param { Object } options - user options, probably containing the path to the source file
* @param { Object } meta - compilation meta infomration
* @returns { Output } output container object
*/
function createOutput(data, options) {
const output = Object.seal({
function createOutput(data, meta) {
const output = {
...Output,
...data,
meta: { options }
});
meta
};
if (!output.map && options && options.file) Object.assign(output, {
map: createSourcemap({ file: options.file })
});
if (!output.map && meta && meta.options && meta.options.file)
return {
...output,
map: createSourcemap({ file: meta.options.file })
}

@@ -95,9 +109,9 @@ return output

* @param { Function } compiler - function needed to generate the output code
* @param { Object } options - options to pass to the compilert
* @param { Object } meta - compilation meta information
* @param { string } source - source code
* @returns { Promise<Output> } output - the result of the compiler
*/
async function transform(compiler, options, source) {
const result = await (compiler ? compiler(source, options) : { code: source });
return createOutput(result, options)
async function transform(compiler, meta, source) {
const result = await (compiler ? compiler(source, meta) : { code: source });
return createOutput(result, meta)
}

@@ -134,15 +148,15 @@

* @param { Output } compilerOutput - output generated by the compiler
* @param { Object } options - user options received by the compiler
* @param { Object } meta - compiling meta information
* @returns { Promise<Output> } object containing output code and source map
*/
async function execute(compilerOutput, options) {
async function execute(compilerOutput, meta) {
return Array.from(postprocessors).reduce(async function(acc, postprocessor) {
const { code, map } = await acc;
const output = await postprocessor(code, options);
const output = await postprocessor(code, meta);
return {
code: output.code,
map: composeSourcemaps(output.map, map)
map: composeSourcemaps(map, output.map)
}
}, Promise.resolve(createOutput(compilerOutput, options)))
}, Promise.resolve(createOutput(compilerOutput, meta)))
}

@@ -194,25 +208,13 @@

* @param { string } name - unique preprocessor id
* @param { Object } options - preprocessor options
* @param { Object } meta - preprocessor meta information
* @param { string } source - source code
* @returns { Promise<Output> } object containing a sourcemap and a code string
*/
async function execute$1(type, name, options, source) {
async function execute$1(type, name, meta, source) {
if (!preprocessors[type]) preprocessorTypeError(type);
if (!preprocessors[type].has(name)) preprocessorNameNotFoundError(name);
return await transform(preprocessors[type].get(name), options, source)
return await transform(preprocessors[type].get(name), meta, source)
}
/**
* Parse a js source to generate the AST
* @param {string} source - javascript source
* @param {Object} options - parser options
* @returns {AST} AST tree
*/
function generateAST(source, options) {
return recast.parse(source, {
...options
})
}
const ATTRIBUTE_TYPE_NAME = 'type';

@@ -244,42 +246,6 @@

/**
* Count spaces before first character of a string
* @param { string } string - target string
* @returns { number } amount of spaces before the first char
*/
function getColum(string) {
const spacesAmount = string.search(/\S/);
return spacesAmount > 0 ? spacesAmount : 0
}
const LINES_RE = /\r\n?|\n/g;
/**
* Split a string into a rows array generated from its EOL matches
* @param { string } string [description]
* @returns { Array } array containing all the string rows
*/
function splitStringByEOL(string) {
return string.split(LINES_RE)
}
/**
* Get the line and the column of a source text based on its position in the string
* @param { string } string - target string
* @param { number } position - target position
* @returns { Object } object containing the source text line and column
*/
function getLineAndColumnByPosition(string, position) {
const lines = splitStringByEOL(string.slice(0, position));
return {
line: lines.length,
column: getColum(lines[lines.length - 1])
}
}
/**
* Preprocess a riot parser node
* @param { string } preprocessorType - either css, js
* @param { string } preprocessorName - preprocessor id
* @param { Object } options - options that will be passed to the compiler
* @param { Object } meta - compilation meta information
* @param { string } source - tag source code

@@ -289,9 +255,7 @@ * @param { RiotParser.nodeTypes } node - css node detected by the parser

*/
async function preprocess(preprocessorType, preprocessorName, options, source, node) {
const { column } = getLineAndColumnByPosition(source, node.start);
const offsetTop = '\n'.repeat(column);
const code = `${offsetTop}\n${node.text}`;
async function preprocess(preprocessorType, preprocessorName, meta, source, node) {
const code = node.text;
return await (preprocessorName ?
execute$1(preprocessorType, preprocessorName, options, code) :
execute$1(preprocessorType, preprocessorName, meta, code) :
{ code }

@@ -301,6 +265,2 @@ )

const types = recast.types;
const builders = types.builders;
const namedTypes = types.namedTypes;
/**

@@ -370,23 +330,24 @@ * Source for creating regexes matching valid quoted, single-line JavaScript strings.

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function css(sourceNode, source, options, ast) {
async function css(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode);
const { options } = meta;
const cssNode = sourceNode.text;
const preprocessorOutput = await preprocess('css', preprocessorName, options, source, cssNode);
const preprocessorOutput = await preprocess('css', preprocessorName, meta, source, cssNode);
const cssCode = (options.scopedCss ?
scopedCSS(options.tagName, preprocessorOutput.code) :
scopedCSS(meta.tagName, preprocessorOutput.code) :
preprocessorOutput.code
).trim();
const generatedCss = generateAST(`\`${cssCode}\``, {
sourceFileName: options.file,
inputSourceMap: preprocessorOutput.map
});
types.visit(ast, {
visitProperty(path) {
if (path.value.key.name === TAG_CSS_PROPERTY) {
path.value.value = generatedCss.program.body[0].expression;
if (path.value.key.value === TAG_CSS_PROPERTY) {
path.value.value = builders.templateLiteral(
[builders.templateElement({ raw: cssCode, cooked: '' }, false)],
[]
);
return false

@@ -402,25 +363,52 @@ }

const LINES_RE = /\r\n?|\n/g;
/**
* Create a raw sourcemap for a single riot parser node
* @param {RiotParser.Node} node - riot parser node
* @param {string} sourceFile - component source file
* @param {string} sourceCode - original source code
* @returns {SourceMapGenerator} source map generated
* Split a string into a rows array generated from its EOL matches
* @param { string } string [description]
* @returns { Array } array containing all the string rows
*/
function createNodeSourcemap(node, sourceFile, sourceCode) {
const sourcemap = createSourcemap({ file: sourceFile })
function splitStringByEOL(string) {
return string.split(LINES_RE)
}
;[node.start, node.end].forEach(position => {
const location = getLineAndColumnByPosition(sourceCode, position);
/**
* Get the line and the column of a source text based on its position in the string
* @param { string } string - target string
* @param { number } position - target position
* @returns { Object } object containing the source text line and column
*/
function getLineAndColumnByPosition(string, position) {
const lines = splitStringByEOL(string.slice(0, position));
sourcemap.addMapping({
source: sourceFile,
generated: location,
original: location
});
});
return {
line: lines.length,
column: lines[lines.length - 1].length
}
}
return sourcemap
/**
* Add the offset to the code that must be parsed in order to generate properly the sourcemaps
* @param {string} input - input string
* @param {string} source - original source code
* @param {RiotParser.Node} node - node that we are going to transform
* @return {string} the input string with the offset properly set
*/
function addLineOffset(input, source, node) {
const {column, line} = getLineAndColumnByPosition(source, node.start);
return `${'\n'.repeat(line - 1)}${' '.repeat(column + 1)}${input}`
}
/**
* Parse a js source to generate the AST
* @param {string} source - javascript source
* @param {Object} options - parser options
* @returns {AST} AST tree
*/
function generateAST(source, options) {
return recast.parse(source, {
...options
})
}
const browserAPIs = Object.keys(globalScope.browser);

@@ -466,3 +454,3 @@ const builtinAPIs = Object.keys(globalScope.builtin);

function getProgramBody(ast) {
return ast.program.body
return ast.body || ast.program.body
}

@@ -479,3 +467,3 @@

visitProperty(path) {
if (path.value.key.name === TAG_LOGIC_PROPERTY) {
if (path.value.key.value === TAG_LOGIC_PROPERTY) {
path.value.value = exportDefaultNode.declaration;

@@ -496,22 +484,21 @@ return false

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function javascript(sourceNode, source, options, ast) {
async function javascript(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode);
const javascriptNode = sourceNode.text;
const preprocessorOutput = await preprocess('js', preprocessorName, options, source, javascriptNode);
const jsInputSourceMap = composeSourcemaps(
createNodeSourcemap(sourceNode, options.file, source),
preprocessorOutput.map
);
const generatedAst = generateAST(preprocessorOutput.code, {
sourceFileName: options.file,
inputSourceMap: jsInputSourceMap
});
const { options } = meta;
const preprocessorOutput = await preprocess('js', preprocessorName, meta, source, javascriptNode);
const generatedAst = generateAST(
addLineOffset(preprocessorOutput.code, source, sourceNode), {
sourceFileName: options.file
});
const generatedAstBody = getProgramBody(generatedAst);
const bodyWithoutExportDefault = filterNonExportDefaultStatements(generatedAstBody);
const exportDefaultNode = findExportDefaultStatement(generatedAstBody);
const outputBody = getProgramBody(ast);

@@ -581,10 +568,2 @@

function nullNode() {
return builders.literal(null)
}
function simplePropertyNode(key, value) {
return builders.property('init', builders.literal(key), value, false)
}
/* eslint-disable */

@@ -594,2 +573,22 @@ // source: https://30secondsofcode.org/function#compose

/**
* Generate the pure immutable string chunks from a RiotParser.Node.Text
* @param {RiotParser.Node.Text} node - riot parser text node
* @param {string} sourceCode sourceCode - source code
* @returns {Array} array containing the immutable string chunks
*/
function generateLiteralStringChunksFromNode(node, sourceCode) {
return node.expressions.reduce((chunks, expression, index) => {
const start = index ? node.expressions[index - 1].end : node.start;
chunks.push(sourceCode.substring(start, expression.start));
// add the tail to the string
if (index === node.expressions.length - 1)
chunks.push(sourceCode.substring(expression.end, node.end));
return chunks
}, [])
}
const scope = builders.identifier(SCOPE);

@@ -724,5 +723,8 @@ const getName = node => node && node.name ? node.name : node;

function createASTFromExpression(expression, sourceFile, sourceCode) {
return generateAST(`(${expression.text})`, {
sourceFileName: sourceFile,
inputSourceMap: sourceFile && createNodeSourcemap(expression, sourceFile, sourceCode)
const code = sourceFile ?
addLineOffset(expression.text, sourceCode, expression) :
expression.text;
return generateAST(`(${code})`, {
sourceFileName: sourceFile
})

@@ -748,3 +750,2 @@ }

if (!isExpressionStatement(firstNode)) {

@@ -805,2 +806,17 @@ panic(`The each directives supported should be of type "ExpressionStatement",you have provided a "${firstNode.type}"`);

/**
* Wrap the ast generated in a function call providing the scope argument
* @param {Object} ast - function body
* @returns {FunctionExpresion} function having the scope argument injected
*/
function wrapASTInFunctionWithScope(ast) {
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
ast
)])
)
}
/**
* Convert any parser option to a valid template one

@@ -819,23 +835,25 @@ * @param { RiotParser.Node.Expression } expression - expression parsed by the riot parser

function toScopedFunction(expression, sourceFile, sourceCode) {
const ast = createASTFromExpression(expression, sourceFile, sourceCode);
const generatedAST = updateNodesScope(ast);
const astBody = generatedAST.program.body;
const expressionAST = astBody[0] ? astBody[0].expression : astBody;
return compose(
wrapASTInFunctionWithScope,
transformExpression,
)(expression, sourceFile, sourceCode)
}
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
expressionAST
)])
)
function transformExpression(expression, sourceFile, sourceCode) {
return compose(
getExpressionAST,
updateNodesScope,
createASTFromExpression
)(expression, sourceFile, sourceCode)
}
/**
* Wrap a string in a template literal expression
* @param {string} string - target string
* @returns {string} a template literal
* Get the parsed AST expression of riot expression node
* @param {AST.Program} sourceAST - raw node parsed
* @returns {AST.Expression} program expression output
*/
function wrapInBacktick(string) {
return `\`${string}\``
function getExpressionAST(sourceAST) {
const astBody = sourceAST.program.body;
return astBody[0] ? astBody[0].expression : astBody
}

@@ -847,22 +865,16 @@

* @param {RiotParser.Node} node - riot parser node
* @returns {string} either a string representing a template literal or simply the first expression matched
* @param {string} sourceFile - original tag file
* @param {string} sourceCode - original tag source code
* @returns { Object } a FunctionExpression object
*/
function mergeNodeExpressions(node) {
if (node.expressions.length === 1) {
return node.expressions[0].text
}
function mergeNodeExpressions(node, sourceFile, sourceCode) {
if (node.expressions.length === 1)
return transformExpression(node.expressions[0], sourceFile, sourceCode)
const charAddedProIteration = 3; // ${}
const pureStringChunks = generateLiteralStringChunksFromNode(node, sourceCode);
// a tricky way to merge nodes containing multiple expressions in the same string
const values = node.expressions.reduce((string, expression, index) => {
const bracketsLength = expression.end - expression.start - expression.text.length;
const offset = index * (charAddedProIteration - bracketsLength);
const expressionStart = expression.start - node.start + offset;
const expressionEnd = expression.end - node.start + offset;
return `${string.substring(0, expressionStart)}$\{${expression.text}}${string.substring(expressionEnd)}`
}, node.text);
return wrapInBacktick(values)
return builders.templateLiteral(
pureStringChunks.map(str => builders.templateElement({ raw: str, cooked: '' }, false)),
node.expressions.map(expression => transformExpression(expression, sourceFile, sourceCode))
)
}

@@ -1337,3 +1349,3 @@

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
),

@@ -1379,3 +1391,3 @@ ...createSelectorProperties(selectorAttribute),

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
)

@@ -1432,7 +1444,5 @@ ])

BINDING_EVALUATE_KEY,
toScopedFunction({
start: sourceNode.start,
end: sourceNode.end,
text: mergeNodeExpressions(sourceNode)
}, sourceFile, sourceCode)
wrapASTInFunctionWithScope(
mergeNodeExpressions(sourceNode, sourceFile, sourceCode)
)
)

@@ -1662,3 +1672,3 @@ ])

visitProperty(path) {
if (path.value.key.name === TAG_TEMPLATE_PROPERTY) {
if (path.value.key.value === TAG_TEMPLATE_PROPERTY) {
path.value.value = builders.functionExpression(

@@ -1699,7 +1709,8 @@ null,

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function template(sourceNode, source, options, ast) {
async function template(sourceNode, source, meta, ast) {
const { options } = meta;
return extendTemplateProperty(ast, options.file, source, sourceNode)

@@ -1716,4 +1727,2 @@ }

* Create the initial AST
* @param { Sourcemap } map - initial sourcemap
* @param { string } file - path to the original source file
* @returns { AST } the initial AST

@@ -1724,8 +1733,20 @@ *

*/
function createInitialInput(map, file) {
const code = `export default { ${TAG_CSS_PROPERTY}: null, ${TAG_LOGIC_PROPERTY}: null, ${TAG_TEMPLATE_PROPERTY}: null }`;
return generateAST(code, {
sourceFileName: file,
inputSourceMap: map
})
function createInitialInput() {
/*
generates
export default {
${TAG_CSS_PROPERTY}: null,
${TAG_LOGIC_PROPERTY}: null,
${TAG_TEMPLATE_PROPERTY}: null
}
*/
return builders.program([
builders.exportDefaultDeclaration(
builders.objectExpression([
simplePropertyNode(TAG_CSS_PROPERTY, nullNode()),
simplePropertyNode(TAG_LOGIC_PROPERTY, nullNode()),
simplePropertyNode(TAG_TEMPLATE_PROPERTY, nullNode())
])
)]
)
}

@@ -1744,7 +1765,12 @@

};
const meta = {
source,
options: opts
};
const { code, map } = await execute$1('template', opts.template, opts, source);
const { code, map } = await execute$1('template', opts.template, meta, source);
const { template: template$$1, css: css$$1, javascript: javascript$$1 } = riotParser(opts).parse(code).output;
const meta = {
options: opts,
// extend the meta object with the result of the parsing
Object.assign(meta, {
tagName: template$$1.name,

@@ -1756,13 +1782,14 @@ fragments: {

}
};
});
return ruit(
createInitialInput(map),
hookGenerator(css, css$$1, code, opts),
hookGenerator(javascript, javascript$$1, code, opts),
hookGenerator(template, template$$1, code, opts),
createInitialInput(),
hookGenerator(css, css$$1, code, meta),
hookGenerator(javascript, javascript$$1, code, meta),
hookGenerator(template, template$$1, code, meta),
ast => recast.print(ast, {
sourceMapName: 'map.json'
sourceMapName: 'map.json',
inputSourcemap: map
}),
result => execute(result, opts),
result => execute(result, meta),
result => ({

@@ -1780,6 +1807,6 @@ ...result,

* @param { string } source - component source code
* @param { Object } options - compiling options
* @param { Object } meta - compilation meta information
* @returns { Promise<Output> } object containing output code and source map
*/
function hookGenerator(transformer, sourceNode, source, options) {
function hookGenerator(transformer, sourceNode, source, meta) {
if (!sourceNode || (sourceNode.nodes && !sourceNode.nodes.length)) {

@@ -1789,3 +1816,3 @@ return result => result

return curry(transformer)(sourceNode, source, options)
return curry(transformer)(sourceNode, source, meta)
}

@@ -1792,0 +1819,0 @@

@@ -8,5 +8,5 @@ /* Riot Compiler WIP, @license MIT */

var recast = _interopDefault(require('recast'));
var recastUtil = _interopDefault(require('recast/lib/util'));
var sourceMap = require('source-map');
var recast = _interopDefault(require('recast'));
var curry = _interopDefault(require('curri'));

@@ -22,2 +22,14 @@ var globalScope = _interopDefault(require('globals'));

const types = recast.types;
const builders = types.builders;
const namedTypes = types.namedTypes;
function nullNode() {
return builders.literal(null)
}
function simplePropertyNode(key, value) {
return builders.property('init', builders.literal(key), value, false)
}
/**

@@ -82,15 +94,17 @@ * Detect node js environements

* @param { SourceMapGenerator } data.map - source map generated along with the code
* @param { Object } options - user options, probably containing the path to the source file
* @param { Object } meta - compilation meta infomration
* @returns { Output } output container object
*/
function createOutput(data, options) {
const output = Object.seal({
function createOutput(data, meta) {
const output = {
...Output,
...data,
meta: { options }
});
meta
};
if (!output.map && options && options.file) Object.assign(output, {
map: createSourcemap({ file: options.file })
});
if (!output.map && meta && meta.options && meta.options.file)
return {
...output,
map: createSourcemap({ file: meta.options.file })
}

@@ -103,9 +117,9 @@ return output

* @param { Function } compiler - function needed to generate the output code
* @param { Object } options - options to pass to the compilert
* @param { Object } meta - compilation meta information
* @param { string } source - source code
* @returns { Promise<Output> } output - the result of the compiler
*/
async function transform(compiler, options, source) {
const result = await (compiler ? compiler(source, options) : { code: source });
return createOutput(result, options)
async function transform(compiler, meta, source) {
const result = await (compiler ? compiler(source, meta) : { code: source });
return createOutput(result, meta)
}

@@ -142,15 +156,15 @@

* @param { Output } compilerOutput - output generated by the compiler
* @param { Object } options - user options received by the compiler
* @param { Object } meta - compiling meta information
* @returns { Promise<Output> } object containing output code and source map
*/
async function execute(compilerOutput, options) {
async function execute(compilerOutput, meta) {
return Array.from(postprocessors).reduce(async function(acc, postprocessor) {
const { code, map } = await acc;
const output = await postprocessor(code, options);
const output = await postprocessor(code, meta);
return {
code: output.code,
map: composeSourcemaps(output.map, map)
map: composeSourcemaps(map, output.map)
}
}, Promise.resolve(createOutput(compilerOutput, options)))
}, Promise.resolve(createOutput(compilerOutput, meta)))
}

@@ -202,25 +216,13 @@

* @param { string } name - unique preprocessor id
* @param { Object } options - preprocessor options
* @param { Object } meta - preprocessor meta information
* @param { string } source - source code
* @returns { Promise<Output> } object containing a sourcemap and a code string
*/
async function execute$1(type, name, options, source) {
async function execute$1(type, name, meta, source) {
if (!preprocessors[type]) preprocessorTypeError(type);
if (!preprocessors[type].has(name)) preprocessorNameNotFoundError(name);
return await transform(preprocessors[type].get(name), options, source)
return await transform(preprocessors[type].get(name), meta, source)
}
/**
* Parse a js source to generate the AST
* @param {string} source - javascript source
* @param {Object} options - parser options
* @returns {AST} AST tree
*/
function generateAST(source, options) {
return recast.parse(source, {
...options
})
}
const ATTRIBUTE_TYPE_NAME = 'type';

@@ -252,42 +254,6 @@

/**
* Count spaces before first character of a string
* @param { string } string - target string
* @returns { number } amount of spaces before the first char
*/
function getColum(string) {
const spacesAmount = string.search(/\S/);
return spacesAmount > 0 ? spacesAmount : 0
}
const LINES_RE = /\r\n?|\n/g;
/**
* Split a string into a rows array generated from its EOL matches
* @param { string } string [description]
* @returns { Array } array containing all the string rows
*/
function splitStringByEOL(string) {
return string.split(LINES_RE)
}
/**
* Get the line and the column of a source text based on its position in the string
* @param { string } string - target string
* @param { number } position - target position
* @returns { Object } object containing the source text line and column
*/
function getLineAndColumnByPosition(string, position) {
const lines = splitStringByEOL(string.slice(0, position));
return {
line: lines.length,
column: getColum(lines[lines.length - 1])
}
}
/**
* Preprocess a riot parser node
* @param { string } preprocessorType - either css, js
* @param { string } preprocessorName - preprocessor id
* @param { Object } options - options that will be passed to the compiler
* @param { Object } meta - compilation meta information
* @param { string } source - tag source code

@@ -297,9 +263,7 @@ * @param { RiotParser.nodeTypes } node - css node detected by the parser

*/
async function preprocess(preprocessorType, preprocessorName, options, source, node) {
const { column } = getLineAndColumnByPosition(source, node.start);
const offsetTop = '\n'.repeat(column);
const code = `${offsetTop}\n${node.text}`;
async function preprocess(preprocessorType, preprocessorName, meta, source, node) {
const code = node.text;
return await (preprocessorName ?
execute$1(preprocessorType, preprocessorName, options, code) :
execute$1(preprocessorType, preprocessorName, meta, code) :
{ code }

@@ -309,6 +273,2 @@ )

const types = recast.types;
const builders = types.builders;
const namedTypes = types.namedTypes;
/**

@@ -378,23 +338,24 @@ * Source for creating regexes matching valid quoted, single-line JavaScript strings.

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function css(sourceNode, source, options, ast) {
async function css(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode);
const { options } = meta;
const cssNode = sourceNode.text;
const preprocessorOutput = await preprocess('css', preprocessorName, options, source, cssNode);
const preprocessorOutput = await preprocess('css', preprocessorName, meta, source, cssNode);
const cssCode = (options.scopedCss ?
scopedCSS(options.tagName, preprocessorOutput.code) :
scopedCSS(meta.tagName, preprocessorOutput.code) :
preprocessorOutput.code
).trim();
const generatedCss = generateAST(`\`${cssCode}\``, {
sourceFileName: options.file,
inputSourceMap: preprocessorOutput.map
});
types.visit(ast, {
visitProperty(path) {
if (path.value.key.name === TAG_CSS_PROPERTY) {
path.value.value = generatedCss.program.body[0].expression;
if (path.value.key.value === TAG_CSS_PROPERTY) {
path.value.value = builders.templateLiteral(
[builders.templateElement({ raw: cssCode, cooked: '' }, false)],
[]
);
return false

@@ -410,25 +371,52 @@ }

const LINES_RE = /\r\n?|\n/g;
/**
* Create a raw sourcemap for a single riot parser node
* @param {RiotParser.Node} node - riot parser node
* @param {string} sourceFile - component source file
* @param {string} sourceCode - original source code
* @returns {SourceMapGenerator} source map generated
* Split a string into a rows array generated from its EOL matches
* @param { string } string [description]
* @returns { Array } array containing all the string rows
*/
function createNodeSourcemap(node, sourceFile, sourceCode) {
const sourcemap = createSourcemap({ file: sourceFile })
function splitStringByEOL(string) {
return string.split(LINES_RE)
}
;[node.start, node.end].forEach(position => {
const location = getLineAndColumnByPosition(sourceCode, position);
/**
* Get the line and the column of a source text based on its position in the string
* @param { string } string - target string
* @param { number } position - target position
* @returns { Object } object containing the source text line and column
*/
function getLineAndColumnByPosition(string, position) {
const lines = splitStringByEOL(string.slice(0, position));
sourcemap.addMapping({
source: sourceFile,
generated: location,
original: location
});
});
return {
line: lines.length,
column: lines[lines.length - 1].length
}
}
return sourcemap
/**
* Add the offset to the code that must be parsed in order to generate properly the sourcemaps
* @param {string} input - input string
* @param {string} source - original source code
* @param {RiotParser.Node} node - node that we are going to transform
* @return {string} the input string with the offset properly set
*/
function addLineOffset(input, source, node) {
const {column, line} = getLineAndColumnByPosition(source, node.start);
return `${'\n'.repeat(line - 1)}${' '.repeat(column + 1)}${input}`
}
/**
* Parse a js source to generate the AST
* @param {string} source - javascript source
* @param {Object} options - parser options
* @returns {AST} AST tree
*/
function generateAST(source, options) {
return recast.parse(source, {
...options
})
}
const browserAPIs = Object.keys(globalScope.browser);

@@ -474,3 +462,3 @@ const builtinAPIs = Object.keys(globalScope.builtin);

function getProgramBody(ast) {
return ast.program.body
return ast.body || ast.program.body
}

@@ -487,3 +475,3 @@

visitProperty(path) {
if (path.value.key.name === TAG_LOGIC_PROPERTY) {
if (path.value.key.value === TAG_LOGIC_PROPERTY) {
path.value.value = exportDefaultNode.declaration;

@@ -504,22 +492,21 @@ return false

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function javascript(sourceNode, source, options, ast) {
async function javascript(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode);
const javascriptNode = sourceNode.text;
const preprocessorOutput = await preprocess('js', preprocessorName, options, source, javascriptNode);
const jsInputSourceMap = composeSourcemaps(
createNodeSourcemap(sourceNode, options.file, source),
preprocessorOutput.map
);
const generatedAst = generateAST(preprocessorOutput.code, {
sourceFileName: options.file,
inputSourceMap: jsInputSourceMap
});
const { options } = meta;
const preprocessorOutput = await preprocess('js', preprocessorName, meta, source, javascriptNode);
const generatedAst = generateAST(
addLineOffset(preprocessorOutput.code, source, sourceNode), {
sourceFileName: options.file
});
const generatedAstBody = getProgramBody(generatedAst);
const bodyWithoutExportDefault = filterNonExportDefaultStatements(generatedAstBody);
const exportDefaultNode = findExportDefaultStatement(generatedAstBody);
const outputBody = getProgramBody(ast);

@@ -589,10 +576,2 @@

function nullNode() {
return builders.literal(null)
}
function simplePropertyNode(key, value) {
return builders.property('init', builders.literal(key), value, false)
}
/* eslint-disable */

@@ -602,2 +581,22 @@ // source: https://30secondsofcode.org/function#compose

/**
* Generate the pure immutable string chunks from a RiotParser.Node.Text
* @param {RiotParser.Node.Text} node - riot parser text node
* @param {string} sourceCode sourceCode - source code
* @returns {Array} array containing the immutable string chunks
*/
function generateLiteralStringChunksFromNode(node, sourceCode) {
return node.expressions.reduce((chunks, expression, index) => {
const start = index ? node.expressions[index - 1].end : node.start;
chunks.push(sourceCode.substring(start, expression.start));
// add the tail to the string
if (index === node.expressions.length - 1)
chunks.push(sourceCode.substring(expression.end, node.end));
return chunks
}, [])
}
const scope = builders.identifier(SCOPE);

@@ -732,5 +731,8 @@ const getName = node => node && node.name ? node.name : node;

function createASTFromExpression(expression, sourceFile, sourceCode) {
return generateAST(`(${expression.text})`, {
sourceFileName: sourceFile,
inputSourceMap: sourceFile && createNodeSourcemap(expression, sourceFile, sourceCode)
const code = sourceFile ?
addLineOffset(expression.text, sourceCode, expression) :
expression.text;
return generateAST(`(${code})`, {
sourceFileName: sourceFile
})

@@ -756,3 +758,2 @@ }

if (!isExpressionStatement(firstNode)) {

@@ -813,2 +814,17 @@ panic(`The each directives supported should be of type "ExpressionStatement",you have provided a "${firstNode.type}"`);

/**
* Wrap the ast generated in a function call providing the scope argument
* @param {Object} ast - function body
* @returns {FunctionExpresion} function having the scope argument injected
*/
function wrapASTInFunctionWithScope(ast) {
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
ast
)])
)
}
/**
* Convert any parser option to a valid template one

@@ -827,23 +843,25 @@ * @param { RiotParser.Node.Expression } expression - expression parsed by the riot parser

function toScopedFunction(expression, sourceFile, sourceCode) {
const ast = createASTFromExpression(expression, sourceFile, sourceCode);
const generatedAST = updateNodesScope(ast);
const astBody = generatedAST.program.body;
const expressionAST = astBody[0] ? astBody[0].expression : astBody;
return compose(
wrapASTInFunctionWithScope,
transformExpression,
)(expression, sourceFile, sourceCode)
}
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
expressionAST
)])
)
function transformExpression(expression, sourceFile, sourceCode) {
return compose(
getExpressionAST,
updateNodesScope,
createASTFromExpression
)(expression, sourceFile, sourceCode)
}
/**
* Wrap a string in a template literal expression
* @param {string} string - target string
* @returns {string} a template literal
* Get the parsed AST expression of riot expression node
* @param {AST.Program} sourceAST - raw node parsed
* @returns {AST.Expression} program expression output
*/
function wrapInBacktick(string) {
return `\`${string}\``
function getExpressionAST(sourceAST) {
const astBody = sourceAST.program.body;
return astBody[0] ? astBody[0].expression : astBody
}

@@ -855,22 +873,16 @@

* @param {RiotParser.Node} node - riot parser node
* @returns {string} either a string representing a template literal or simply the first expression matched
* @param {string} sourceFile - original tag file
* @param {string} sourceCode - original tag source code
* @returns { Object } a FunctionExpression object
*/
function mergeNodeExpressions(node) {
if (node.expressions.length === 1) {
return node.expressions[0].text
}
function mergeNodeExpressions(node, sourceFile, sourceCode) {
if (node.expressions.length === 1)
return transformExpression(node.expressions[0], sourceFile, sourceCode)
const charAddedProIteration = 3; // ${}
const pureStringChunks = generateLiteralStringChunksFromNode(node, sourceCode);
// a tricky way to merge nodes containing multiple expressions in the same string
const values = node.expressions.reduce((string, expression, index) => {
const bracketsLength = expression.end - expression.start - expression.text.length;
const offset = index * (charAddedProIteration - bracketsLength);
const expressionStart = expression.start - node.start + offset;
const expressionEnd = expression.end - node.start + offset;
return `${string.substring(0, expressionStart)}$\{${expression.text}}${string.substring(expressionEnd)}`
}, node.text);
return wrapInBacktick(values)
return builders.templateLiteral(
pureStringChunks.map(str => builders.templateElement({ raw: str, cooked: '' }, false)),
node.expressions.map(expression => transformExpression(expression, sourceFile, sourceCode))
)
}

@@ -1345,3 +1357,3 @@

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
),

@@ -1387,3 +1399,3 @@ ...createSelectorProperties(selectorAttribute),

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
)

@@ -1440,7 +1452,5 @@ ])

BINDING_EVALUATE_KEY,
toScopedFunction({
start: sourceNode.start,
end: sourceNode.end,
text: mergeNodeExpressions(sourceNode)
}, sourceFile, sourceCode)
wrapASTInFunctionWithScope(
mergeNodeExpressions(sourceNode, sourceFile, sourceCode)
)
)

@@ -1670,3 +1680,3 @@ ])

visitProperty(path) {
if (path.value.key.name === TAG_TEMPLATE_PROPERTY) {
if (path.value.key.value === TAG_TEMPLATE_PROPERTY) {
path.value.value = builders.functionExpression(

@@ -1707,7 +1717,8 @@ null,

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
async function template(sourceNode, source, options, ast) {
async function template(sourceNode, source, meta, ast) {
const { options } = meta;
return extendTemplateProperty(ast, options.file, source, sourceNode)

@@ -1724,4 +1735,2 @@ }

* Create the initial AST
* @param { Sourcemap } map - initial sourcemap
* @param { string } file - path to the original source file
* @returns { AST } the initial AST

@@ -1732,8 +1741,20 @@ *

*/
function createInitialInput(map, file) {
const code = `export default { ${TAG_CSS_PROPERTY}: null, ${TAG_LOGIC_PROPERTY}: null, ${TAG_TEMPLATE_PROPERTY}: null }`;
return generateAST(code, {
sourceFileName: file,
inputSourceMap: map
})
function createInitialInput() {
/*
generates
export default {
${TAG_CSS_PROPERTY}: null,
${TAG_LOGIC_PROPERTY}: null,
${TAG_TEMPLATE_PROPERTY}: null
}
*/
return builders.program([
builders.exportDefaultDeclaration(
builders.objectExpression([
simplePropertyNode(TAG_CSS_PROPERTY, nullNode()),
simplePropertyNode(TAG_LOGIC_PROPERTY, nullNode()),
simplePropertyNode(TAG_TEMPLATE_PROPERTY, nullNode())
])
)]
)
}

@@ -1752,7 +1773,12 @@

};
const meta = {
source,
options: opts
};
const { code, map } = await execute$1('template', opts.template, opts, source);
const { code, map } = await execute$1('template', opts.template, meta, source);
const { template: template$$1, css: css$$1, javascript: javascript$$1 } = riotParser__default(opts).parse(code).output;
const meta = {
options: opts,
// extend the meta object with the result of the parsing
Object.assign(meta, {
tagName: template$$1.name,

@@ -1764,13 +1790,14 @@ fragments: {

}
};
});
return ruit(
createInitialInput(map),
hookGenerator(css, css$$1, code, opts),
hookGenerator(javascript, javascript$$1, code, opts),
hookGenerator(template, template$$1, code, opts),
createInitialInput(),
hookGenerator(css, css$$1, code, meta),
hookGenerator(javascript, javascript$$1, code, meta),
hookGenerator(template, template$$1, code, meta),
ast => recast.print(ast, {
sourceMapName: 'map.json'
sourceMapName: 'map.json',
inputSourcemap: map
}),
result => execute(result, opts),
result => execute(result, meta),
result => ({

@@ -1788,6 +1815,6 @@ ...result,

* @param { string } source - component source code
* @param { Object } options - compiling options
* @param { Object } meta - compilation meta information
* @returns { Promise<Output> } object containing output code and source map
*/
function hookGenerator(transformer, sourceNode, source, options) {
function hookGenerator(transformer, sourceNode, source, meta) {
if (!sourceNode || (sourceNode.nodes && !sourceNode.nodes.length)) {

@@ -1797,3 +1824,3 @@ return result => result

return curry(transformer)(sourceNode, source, options)
return curry(transformer)(sourceNode, source, meta)
}

@@ -1800,0 +1827,0 @@

{
"name": "@riotjs/compiler",
"version": "4.0.0-alpha.9",
"version": "4.0.0-alpha.10",
"description": "Compiler for riot .tag files",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -32,3 +32,4 @@ [![Build Status][travis-image]][travis-url]

// process your tag template before it will be compiled
registerPreprocessor('template', 'pug', async function(code, { file }) {
registerPreprocessor('template', 'pug', async function(code, { meta }) {
const { file } = meta
console.log('your file path is:', file)

@@ -39,3 +40,4 @@ return await pug.compile(code)

// your compiler output will pass from here
registerPostprocessor(async function(code, { file }) {
registerPostprocessor(async function(code, { meta }) {
const { file } = meta
console.log('your file path is:', file)

@@ -42,0 +44,0 @@ return await buble.transform(code)

@@ -0,6 +1,5 @@

import {builders, types} from '../../utils/build-types'
import {TAG_CSS_PROPERTY} from '../constants'
import generateAST from '../../utils/generate-ast'
import getPreprocessorTypeByAttribute from '../../utils/get-preprocessor-type-by-attribute'
import preprocess from '../../utils/preprocess-node'
import {types} from '../../utils/build-types'

@@ -71,23 +70,24 @@ /**

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function css(sourceNode, source, options, ast) {
export default async function css(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode)
const { options } = meta
const cssNode = sourceNode.text
const preprocessorOutput = await preprocess('css', preprocessorName, options, source, cssNode)
const preprocessorOutput = await preprocess('css', preprocessorName, meta, source, cssNode)
const cssCode = (options.scopedCss ?
scopedCSS(options.tagName, preprocessorOutput.code) :
scopedCSS(meta.tagName, preprocessorOutput.code) :
preprocessorOutput.code
).trim()
const generatedCss = generateAST(`\`${cssCode}\``, {
sourceFileName: options.file,
inputSourceMap: preprocessorOutput.map
})
types.visit(ast, {
visitProperty(path) {
if (path.value.key.name === TAG_CSS_PROPERTY) {
path.value.value = generatedCss.program.body[0].expression
if (path.value.key.value === TAG_CSS_PROPERTY) {
path.value.value = builders.templateLiteral(
[builders.templateElement({ raw: cssCode, cooked: '' }, false)],
[]
)
return false

@@ -94,0 +94,0 @@ }

import {TAG_LOGIC_PROPERTY} from '../constants'
import composeSourcemaps from '../../utils/compose-sourcemaps'
import createNodeSourcemap from '../../utils/create-node-sourcemap'
import addLinesOffset from '../../utils/add-lines-offset'
import generateAST from '../../utils/generate-ast'

@@ -34,3 +33,3 @@ import getPreprocessorTypeByAttribute from '../../utils/get-preprocessor-type-by-attribute'

function getProgramBody(ast) {
return ast.program.body
return ast.body || ast.program.body
}

@@ -47,3 +46,3 @@

visitProperty(path) {
if (path.value.key.name === TAG_LOGIC_PROPERTY) {
if (path.value.key.value === TAG_LOGIC_PROPERTY) {
path.value.value = exportDefaultNode.declaration

@@ -64,22 +63,21 @@ return false

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function javascript(sourceNode, source, options, ast) {
export default async function javascript(sourceNode, source, meta, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode)
const javascriptNode = sourceNode.text
const preprocessorOutput = await preprocess('js', preprocessorName, options, source, javascriptNode)
const jsInputSourceMap = composeSourcemaps(
createNodeSourcemap(sourceNode, options.file, source),
preprocessorOutput.map
)
const generatedAst = generateAST(preprocessorOutput.code, {
sourceFileName: options.file,
inputSourceMap: jsInputSourceMap
})
const { options } = meta
const preprocessorOutput = await preprocess('js', preprocessorName, meta, source, javascriptNode)
const generatedAst = generateAST(
addLinesOffset(preprocessorOutput.code, source, sourceNode), {
sourceFileName: options.file
})
const generatedAstBody = getProgramBody(generatedAst)
const bodyWithoutExportDefault = filterNonExportDefaultStatements(generatedAstBody)
const exportDefaultNode = findExportDefaultStatement(generatedAstBody)
const outputBody = getProgramBody(ast)

@@ -86,0 +84,0 @@

@@ -65,3 +65,3 @@ import {

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
),

@@ -68,0 +68,0 @@ ...createSelectorProperties(selectorAttribute),

@@ -56,5 +56,5 @@ import {

] :
build(createRootNode(sourceNode), sourceCode, sourceCode)
build(createRootNode(sourceNode), sourceFile, sourceCode)
)
])
}

@@ -8,6 +8,3 @@ import {

} from '../constants'
import {
mergeNodeExpressions,
toScopedFunction
} from '../utils'
import {mergeNodeExpressions,wrapASTInFunctionWithScope} from '../utils'
import {builders} from '../../../utils/build-types'

@@ -39,9 +36,7 @@ import {simplePropertyNode} from '../../../utils/custom-ast-nodes'

BINDING_EVALUATE_KEY,
toScopedFunction({
start: sourceNode.start,
end: sourceNode.end,
text: mergeNodeExpressions(sourceNode)
}, sourceFile, sourceCode)
wrapASTInFunctionWithScope(
mergeNodeExpressions(sourceNode, sourceFile, sourceCode)
)
)
])
}

@@ -18,3 +18,3 @@ import {BINDING_TYPES, EXPRESSION_TYPES, GET_COMPONENT_FN, TEMPLATE_FN} from './constants'

visitProperty(path) {
if (path.value.key.name === TAG_TEMPLATE_PROPERTY) {
if (path.value.key.value === TAG_TEMPLATE_PROPERTY) {
path.value.value = builders.functionExpression(

@@ -55,8 +55,9 @@ null,

* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } meta - compilation meta information
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function template(sourceNode, source, options, ast) {
export default async function template(sourceNode, source, meta, ast) {
const { options } = meta
return extendTemplateProperty(ast, options.file, source, sourceNode)
}

@@ -33,6 +33,7 @@ import {

import {nullNode, simplePropertyNode} from '../../utils/custom-ast-nodes'
import addLinesOffset from '../../utils/add-lines-offset'
import compose from '../../utils/compose'
import createNodeSourcemap from '../../utils/create-node-sourcemap'
import curry from 'curri'
import generateAST from '../../utils/generate-ast'
import generateLiteralStringChunksFromNode from '../../utils/generate-literal-string-chunk-from-node'
import {nodeTypes} from '@riotjs/parser'

@@ -171,5 +172,8 @@ import panic from '../../utils/panic'

export function createASTFromExpression(expression, sourceFile, sourceCode) {
return generateAST(`(${expression.text})`, {
sourceFileName: sourceFile,
inputSourceMap: sourceFile && createNodeSourcemap(expression, sourceFile, sourceCode)
const code = sourceFile ?
addLinesOffset(expression.text, sourceCode, expression) :
expression.text
return generateAST(`(${code})`, {
sourceFileName: sourceFile
})

@@ -195,3 +199,2 @@ }

if (!isExpressionStatement(firstNode)) {

@@ -252,2 +255,17 @@ panic(`The each directives supported should be of type "ExpressionStatement",you have provided a "${firstNode.type}"`)

/**
* Wrap the ast generated in a function call providing the scope argument
* @param {Object} ast - function body
* @returns {FunctionExpresion} function having the scope argument injected
*/
export function wrapASTInFunctionWithScope(ast) {
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
ast
)])
)
}
/**
* Convert any parser option to a valid template one

@@ -266,23 +284,25 @@ * @param { RiotParser.Node.Expression } expression - expression parsed by the riot parser

export function toScopedFunction(expression, sourceFile, sourceCode) {
const ast = createASTFromExpression(expression, sourceFile, sourceCode)
const generatedAST = updateNodesScope(ast)
const astBody = generatedAST.program.body
const expressionAST = astBody[0] ? astBody[0].expression : astBody
return compose(
wrapASTInFunctionWithScope,
transformExpression,
)(expression, sourceFile, sourceCode)
}
return builders.functionExpression(
null,
[scope],
builders.blockStatement([builders.returnStatement(
expressionAST
)])
)
export function transformExpression(expression, sourceFile, sourceCode) {
return compose(
getExpressionAST,
updateNodesScope,
createASTFromExpression
)(expression, sourceFile, sourceCode)
}
/**
* Wrap a string in a template literal expression
* @param {string} string - target string
* @returns {string} a template literal
* Get the parsed AST expression of riot expression node
* @param {AST.Program} sourceAST - raw node parsed
* @returns {AST.Expression} program expression output
*/
export function wrapInBacktick(string) {
return `\`${string}\``
export function getExpressionAST(sourceAST) {
const astBody = sourceAST.program.body
return astBody[0] ? astBody[0].expression : astBody
}

@@ -294,22 +314,16 @@

* @param {RiotParser.Node} node - riot parser node
* @returns {string} either a string representing a template literal or simply the first expression matched
* @param {string} sourceFile - original tag file
* @param {string} sourceCode - original tag source code
* @returns { Object } a FunctionExpression object
*/
export function mergeNodeExpressions(node) {
if (node.expressions.length === 1) {
return node.expressions[0].text
}
export function mergeNodeExpressions(node, sourceFile, sourceCode) {
if (node.expressions.length === 1)
return transformExpression(node.expressions[0], sourceFile, sourceCode)
const charAddedProIteration = 3 // ${}
const pureStringChunks = generateLiteralStringChunksFromNode(node, sourceCode)
// a tricky way to merge nodes containing multiple expressions in the same string
const values = node.expressions.reduce((string, expression, index) => {
const bracketsLength = expression.end - expression.start - expression.text.length
const offset = index * (charAddedProIteration - bracketsLength)
const expressionStart = expression.start - node.start + offset
const expressionEnd = expression.end - node.start + offset
return `${string.substring(0, expressionStart)}$\{${expression.text}}${string.substring(expressionEnd)}`
}, node.text)
return wrapInBacktick(values)
return builders.templateLiteral(
pureStringChunks.map(str => builders.templateElement({ raw: str, cooked: '' }, false)),
node.expressions.map(expression => transformExpression(expression, sourceFile, sourceCode))
)
}

@@ -316,0 +330,0 @@

import { TAG_CSS_PROPERTY, TAG_LOGIC_PROPERTY, TAG_TEMPLATE_PROPERTY} from './generators/constants'
import { nullNode, simplePropertyNode } from './utils/custom-ast-nodes'
import { register as registerPostproc, execute as runPostprocessors } from './postprocessors'
import { register as registerPreproc, execute as runPreprocessor } from './preprocessors'
import {builders} from './utils/build-types'
import cssGenerator from './generators/css/index'
import curry from 'curri'
import generateAST from './utils/generate-ast'
import javascriptGenerator from './generators/javascript/index'

@@ -21,4 +22,2 @@ import recast from 'recast'

* Create the initial AST
* @param { Sourcemap } map - initial sourcemap
* @param { string } file - path to the original source file
* @returns { AST } the initial AST

@@ -29,8 +28,20 @@ *

*/
export function createInitialInput(map, file) {
const code = `export default { ${TAG_CSS_PROPERTY}: null, ${TAG_LOGIC_PROPERTY}: null, ${TAG_TEMPLATE_PROPERTY}: null }`
return generateAST(code, {
sourceFileName: file,
inputSourceMap: map
})
export function createInitialInput() {
/*
generates
export default {
${TAG_CSS_PROPERTY}: null,
${TAG_LOGIC_PROPERTY}: null,
${TAG_TEMPLATE_PROPERTY}: null
}
*/
return builders.program([
builders.exportDefaultDeclaration(
builders.objectExpression([
simplePropertyNode(TAG_CSS_PROPERTY, nullNode()),
simplePropertyNode(TAG_LOGIC_PROPERTY, nullNode()),
simplePropertyNode(TAG_TEMPLATE_PROPERTY, nullNode())
])
)]
)
}

@@ -49,7 +60,12 @@

}
const meta = {
source,
options: opts
}
const { code, map } = await runPreprocessor('template', opts.template, opts, source)
const { code, map } = await runPreprocessor('template', opts.template, meta, source)
const { template, css, javascript } = riotParser(opts).parse(code).output
const meta = {
options: opts,
// extend the meta object with the result of the parsing
Object.assign(meta, {
tagName: template.name,

@@ -61,13 +77,14 @@ fragments: {

}
}
})
return ruit(
createInitialInput(map),
hookGenerator(cssGenerator, css, code, opts),
hookGenerator(javascriptGenerator, javascript, code, opts),
hookGenerator(templateGenerator, template, code, opts),
createInitialInput(),
hookGenerator(cssGenerator, css, code, meta),
hookGenerator(javascriptGenerator, javascript, code, meta),
hookGenerator(templateGenerator, template, code, meta),
ast => recast.print(ast, {
sourceMapName: 'map.json'
sourceMapName: 'map.json',
inputSourcemap: map
}),
result => runPostprocessors(result, opts),
result => runPostprocessors(result, meta),
result => ({

@@ -85,6 +102,6 @@ ...result,

* @param { string } source - component source code
* @param { Object } options - compiling options
* @param { Object } meta - compilation meta information
* @returns { Promise<Output> } object containing output code and source map
*/
function hookGenerator(transformer, sourceNode, source, options) {
function hookGenerator(transformer, sourceNode, source, meta) {
if (!sourceNode || (sourceNode.nodes && !sourceNode.nodes.length)) {

@@ -94,3 +111,3 @@ return result => result

return curry(transformer)(sourceNode, source, options)
return curry(transformer)(sourceNode, source, meta)
}

@@ -97,0 +114,0 @@

@@ -40,15 +40,15 @@ import composeSourcemaps from './utils/compose-sourcemaps'

* @param { Output } compilerOutput - output generated by the compiler
* @param { Object } options - user options received by the compiler
* @param { Object } meta - compiling meta information
* @returns { Promise<Output> } object containing output code and source map
*/
export async function execute(compilerOutput, options) {
export async function execute(compilerOutput, meta) {
return Array.from(postprocessors).reduce(async function(acc, postprocessor) {
const { code, map } = await acc
const output = await postprocessor(code, options)
const output = await postprocessor(code, meta)
return {
code: output.code,
map: composeSourcemaps(output.map, map)
map: composeSourcemaps(map, output.map)
}
}, Promise.resolve(createOutput(compilerOutput, options)))
}, Promise.resolve(createOutput(compilerOutput, meta)))
}

@@ -64,11 +64,11 @@ import panic from './utils/panic'

* @param { string } name - unique preprocessor id
* @param { Object } options - preprocessor options
* @param { Object } meta - preprocessor meta information
* @param { string } source - source code
* @returns { Promise<Output> } object containing a sourcemap and a code string
*/
export async function execute(type, name, options, source) {
export async function execute(type, name, meta, source) {
if (!preprocessors[type]) preprocessorTypeError(type)
if (!preprocessors[type].has(name)) preprocessorNameNotFoundError(name)
return await transform(preprocessors[type].get(name), options, source)
return await transform(preprocessors[type].get(name), meta, source)
}

@@ -16,15 +16,17 @@ import createSourcemap from './utils/create-sourcemap'

* @param { SourceMapGenerator } data.map - source map generated along with the code
* @param { Object } options - user options, probably containing the path to the source file
* @param { Object } meta - compilation meta infomration
* @returns { Output } output container object
*/
export function createOutput(data, options) {
const output = Object.seal({
export function createOutput(data, meta) {
const output = {
...Output,
...data,
meta: { options }
})
meta
}
if (!output.map && options && options.file) Object.assign(output, {
map: createSourcemap({ file: options.file })
})
if (!output.map && meta && meta.options && meta.options.file)
return {
...output,
map: createSourcemap({ file: meta.options.file })
}

@@ -37,9 +39,9 @@ return output

* @param { Function } compiler - function needed to generate the output code
* @param { Object } options - options to pass to the compilert
* @param { Object } meta - compilation meta information
* @param { string } source - source code
* @returns { Promise<Output> } output - the result of the compiler
*/
export async function transform(compiler, options, source) {
const result = await (compiler ? compiler(source, options) : { code: source })
return createOutput(result, options)
export async function transform(compiler, meta, source) {
const result = await (compiler ? compiler(source, meta) : { code: source })
return createOutput(result, meta)
}

@@ -1,2 +0,1 @@

import getColumn from './get-column'
import splitStringByEOL from './split-string-by-EOL'

@@ -15,4 +14,4 @@

line: lines.length,
column: getColumn(lines[lines.length - 1])
column: lines[lines.length - 1].length
}
}

@@ -1,2 +0,1 @@

import getLineAndColumnByPosition from './get-line-and-column-by-position'
import {execute as runPreprocessor} from '../preprocessors'

@@ -8,3 +7,3 @@

* @param { string } preprocessorName - preprocessor id
* @param { Object } options - options that will be passed to the compiler
* @param { Object } meta - compilation meta information
* @param { string } source - tag source code

@@ -14,11 +13,9 @@ * @param { RiotParser.nodeTypes } node - css node detected by the parser

*/
export default async function preprocess(preprocessorType, preprocessorName, options, source, node) {
const { column } = getLineAndColumnByPosition(source, node.start)
const offsetTop = '\n'.repeat(column)
const code = `${offsetTop}\n${node.text}`
export default async function preprocess(preprocessorType, preprocessorName, meta, source, node) {
const code = node.text
return await (preprocessorName ?
runPreprocessor(preprocessorType, preprocessorName, options, code) :
runPreprocessor(preprocessorType, preprocessorName, meta, code) :
{ code }
)
}

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc