Skip to content

Commit

Permalink
updated: enhance source map generation
Browse files Browse the repository at this point in the history
  • Loading branch information
GianlucaGuarini committed Jan 27, 2019
1 parent 39f17e7 commit 9de6843
Show file tree
Hide file tree
Showing 16 changed files with 166 additions and 93 deletions.
5 changes: 4 additions & 1 deletion build/rollup.browser.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export default {
name: 'compiler',
file: './dist/compiler.js',
format: 'umd',
globals: ignredModules,
globals: ignredModules.reduce((acc, dep) => ({
[dep]: dep,
...acc
}), {}),
...defaultConfig.output
},
external: ignredModules,
Expand Down
5 changes: 4 additions & 1 deletion build/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
export default {
input: './src/index.js',
interop: false,
onwarn: function(error) {
if (/external dependency|Circular dependency/.test(error.message)) return
console.error(error.message) // eslint-disable-line
},
output: {
banner: '/* Riot Compiler WIP, @license MIT */'
}
Expand Down
27 changes: 16 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"eslint-config-riot": "^2.0.0",
"mocha": "^5.2.0",
"nyc": "^13.1.0",
"recast": "^0.17.2",
"reify": "^0.18.1",
"rollup": "^1.0.0",
"rollup-plugin-alias": "^1.4.0",
Expand All @@ -61,7 +62,6 @@
"globals": "^11.8.0",
"node-sass": "^4.9.4",
"pug": "^2.0.3",
"recast": "^0.16.0",
"ruit": "^1.0.4",
"source-map": "^0.7.3"
}
Expand Down
16 changes: 7 additions & 9 deletions src/generators/css/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import {TAG_CSS_PROPERTY} from '../constants'
import composeSourcemaps from '../../utils/compose-sourcemaps'
import generateAST from '../../utils/generate-ast'
import getPreprocessorTypeByAttribute from '../../utils/get-preprocessor-type-by-attribute'
import preprocess from '../../utils/preprocess-node'
import recast from 'recast'
import {types} from '../../utils/build-types'

/**
Expand Down Expand Up @@ -70,21 +69,20 @@ function scopedCSS(tag, css) {
* @param { Object } sourceNode - node generated by the riot compiler
* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Object } output - current compiler output
* @returns { Promise<Output> } - the current ast program and the original sourcemap
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function css(sourceNode, source, options, { ast, map }) {
export default async function css(sourceNode, source, options, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode)
const cssNode = sourceNode.text
const preprocessorOutput = await preprocess('css', preprocessorName, options, source, cssNode)
const cssCode = (options.scopedCss ?
scopedCSS(options.tagName, preprocessorOutput.code) :
preprocessorOutput.code
).trim()

const generatedCss = recast.parse(`\`${cssCode}\``, {
const generatedCss = generateAST(`\`${cssCode}\``, {
sourceFileName: options.file,
inputSourceMap: composeSourcemaps(map, preprocessorOutput.map)
inputSourceMap: preprocessorOutput.map
})

types.visit(ast, {
Expand All @@ -98,5 +96,5 @@ export default async function css(sourceNode, source, options, { ast, map }) {
}
})

return { ast, map, code: recast.print(ast).code }
return ast
}
29 changes: 15 additions & 14 deletions src/generators/javascript/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {namedTypes, types} from '../../utils/build-types'
import {TAG_LOGIC_PROPERTY} from '../constants'
import composeSourcemaps from '../../utils/compose-sourcemaps'
import createNodeSourcemap from '../../utils/create-node-sourcemap'
import generateAST from '../../utils/generate-ast'
import getPreprocessorTypeByAttribute from '../../utils/get-preprocessor-type-by-attribute'
import {isExportDefaultStatement} from '../../utils/ast-nodes-checks'
import preprocess from '../../utils/preprocess-node'
import recast from 'recast'

const isExportDefaultStatement = namedTypes.ExportDefaultDeclaration.check
import {types} from '../../utils/build-types'

/**
* Find the export default statement
Expand Down Expand Up @@ -60,17 +60,22 @@ function extendTagProperty(ast, exportDefaultNode) {
* @param { Object } sourceNode - node generated by the riot compiler
* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Output } output - current compiler output
* @returns { Promise<Output> } - enhanced output with the result of the current generator
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function javascript(sourceNode, source, options, { ast, map }) {
export default async function javascript(sourceNode, source, options, ast) {
const preprocessorName = getPreprocessorTypeByAttribute(sourceNode)
const javascriptNode = sourceNode.text
const preprocessorOutput = await preprocess('js', preprocessorName, options, source, javascriptNode)
const generatedAst = recast.parse(preprocessorOutput.code, {
const jsInputSourceMap = composeSourcemaps(
createNodeSourcemap(sourceNode, options.file, source),
preprocessorOutput.map
)
const generatedAst = generateAST(preprocessorOutput.code, {
sourceFileName: options.file,
inputSourceMap: composeSourcemaps(map, preprocessorOutput.map)
inputSourceMap: jsInputSourceMap
})

const generatedAstBody = getProgramBody(generatedAst)
const bodyWithoutExportDefault = filterNonExportDefaultStatements(generatedAstBody)
const exportDefaultNode = findExportDefaultStatement(generatedAstBody)
Expand All @@ -82,9 +87,5 @@ export default async function javascript(sourceNode, source, options, { ast, map
// convert the export default adding its content to the "tag" property exported
if (exportDefaultNode) extendTagProperty(ast, exportDefaultNode)

return {
ast,
map,
code: recast.print(ast).code
}
return ast
}
11 changes: 4 additions & 7 deletions src/generators/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {builders, types} from '../../utils/build-types'
import {callTemplateFunction, createRootNode} from './utils'
import {TAG_TEMPLATE_PROPERTY} from '../constants'
import build from './builder'
import recast from 'recast'

/**
* Extend the AST adding the new template property containing our template call to render the component
Expand Down Expand Up @@ -53,11 +52,9 @@ function extendTemplateProperty(ast, sourceFile, sourceCode, sourceNode) {
* @param { Object } sourceNode - node generated by the riot compiler
* @param { string } source - original component source code
* @param { Object } options - user options
* @param { Output } output - current compiler output
* @returns { Promise<Output> } - enhanced output with the result of the current generator
* @param { AST } ast - current AST output
* @returns { AST } the AST generated
*/
export default async function template(sourceNode, source, options, { ast, map }) {
const output = extendTemplateProperty(ast, options.file, source, sourceNode)

return { ast: output, map, code: recast.print(output).code }
export default async function template(sourceNode, source, options, ast) {
return extendTemplateProperty(ast, options.file, source, sourceNode)
}
22 changes: 4 additions & 18 deletions src/generators/template/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import {
} from '../../utils/ast-nodes-checks'
import {nullNode, simplePropertyNode} from '../../utils/custom-ast-nodes'
import compose from '../../utils/compose'
import createSourcemap from '../../utils/create-sourcemap'
import createNodeSourcemap from '../../utils/create-node-sourcemap'
import curry from 'curri'
import getLineAndColumnByPosition from '../../utils/get-line-and-column-by-position'
import generateAST from '../../utils/generate-ast'
import {nodeTypes} from '@riotjs/parser'
import panic from '../../utils/panic'
import recast from 'recast'
Expand All @@ -60,20 +60,6 @@ export const hasEachAttribute = compose(Boolean, findEachAttribute)
export const hasKeyAttribute = compose(Boolean, findKeyAttribute)
export const hasIsAttribute = compose(Boolean, findIsAttribute)

export function createExpressionSourcemap(expression, sourceFile, sourceCode) {
const sourcemap = createSourcemap({ file: sourceFile })

;[expression.start, expression.end].forEach(position => {
const location = getLineAndColumnByPosition(sourceCode, position)

sourcemap.addMapping({
source: sourceFile,
generated: location,
original: location
})
})
}

/**
* Check if a node name is part of the browser or builtin javascript api or it belongs to the current scope
* @param { types.NodePath } path - containing the current node visited
Expand Down Expand Up @@ -181,9 +167,9 @@ export function updateNodesScope(ast) {
* @returns { Object } the ast generated
*/
export function createASTFromExpression(expression, sourceFile, sourceCode) {
return recast.parse(`(${expression.text})`, {
return generateAST(`(${expression.text})`, {
sourceFileName: sourceFile,
inputSourceMap: sourceFile && createExpressionSourcemap(expression, sourceFile, sourceCode)
inputSourceMap: sourceFile && createNodeSourcemap(expression, sourceFile, sourceCode)
})
}

Expand Down
44 changes: 28 additions & 16 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { register as registerPostproc, execute as runPostprocessors } from './p
import { register as registerPreproc, execute as runPreprocessor } from './preprocessors'
import cssGenerator from './generators/css/index'
import curry from 'curri'
import generateAST from './utils/generate-ast'
import javascriptGenerator from './generators/javascript/index'
import recast from 'recast'
import riotParser from '@riotjs/parser'
Expand All @@ -16,20 +17,20 @@ const DEFAULT_OPTIONS = {
}

/**
* Create the initial output
* Create the initial AST
* @param { Sourcemap } map - initial sourcemap
* @returns { Output } containing the initial code and AST
* @param { string } file - path to the original source file
* @returns { AST } the initial AST
*
* @example
* // the output represents the following string in AST
*/
export function createInitialInput(map) {
export function createInitialInput(map, file) {
const code = `export default { ${TAG_CSS_PROPERTY}: null, ${TAG_LOGIC_PROPERTY}: null, ${TAG_TEMPLATE_PROPERTY}: null }`
return {
ast: recast.parse(code),
code,
map
}
return generateAST(code, {
sourceFileName: file,
inputSourceMap: map
})
}

/**
Expand All @@ -46,18 +47,29 @@ export async function compile(source, options = {}) {

const { code, map } = await runPreprocessor('template', opts.template, opts, source)
const { template, css, javascript } = riotParser(opts).parse(code).output
const meta = {
options: opts,
tagName: template.name,
fragments: {
template,
css,
javascript
}
}

// generate the tag name in runtime
Object.assign(opts, {
tagName: template.name
})

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

Expand Down
4 changes: 3 additions & 1 deletion src/transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import createSourcemap from './utils/create-sourcemap'
export const Output = Object.freeze({
code: '',
ast: [],
meta: {},
map: null
})

Expand All @@ -18,7 +19,8 @@ export const Output = Object.freeze({
export function createOutput(data, options) {
const output = Object.seal({
...Output,
...data
...data,
meta: { options }
})

if (!output.map && options && options.file) Object.assign(output, {
Expand Down
15 changes: 8 additions & 7 deletions src/utils/ast-nodes-checks.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import {namedTypes} from './build-types'
const browserAPIs = Object.keys(globalScope.browser)
const builtinAPIs = Object.keys(globalScope.builtin)

export const isIdentifier = namedTypes.Identifier.check
export const isLiteral = namedTypes.Literal.check
export const isExpressionStatement = namedTypes.ExpressionStatement.check
export const isObjectExpression = namedTypes.ObjectExpression.check
export const isThisExpression = namedTypes.ThisExpression.check
export const isSequenceExpression = namedTypes.SequenceExpression.check
export const isBinaryExpression = namedTypes.BinaryExpression.check
export const isIdentifier = namedTypes.Identifier.check.bind(namedTypes.Identifier)
export const isLiteral = namedTypes.Literal.check.bind(namedTypes.Literal)
export const isExpressionStatement = namedTypes.ExpressionStatement.check.bind(namedTypes.ExpressionStatement)
export const isObjectExpression = namedTypes.ObjectExpression.check.bind(namedTypes.ObjectExpression)
export const isThisExpression = namedTypes.ThisExpression.check.bind(namedTypes.ThisExpression)
export const isSequenceExpression = namedTypes.SequenceExpression.check.bind(namedTypes.SequenceExpression)
export const isBinaryExpression = namedTypes.BinaryExpression.check.bind(namedTypes.BinaryExpression)
export const isExportDefaultStatement = namedTypes.ExportDefaultDeclaration.check.bind(namedTypes.ExportDefaultDeclaration)

export const isBrowserAPI = ({name}) => browserAPIs.includes(name)
export const isBuiltinAPI = ({name}) => builtinAPIs.includes(name)
Expand Down
Loading

0 comments on commit 9de6843

Please sign in to comment.