From c253454db6e56f693e5f5947433115103844ce7e Mon Sep 17 00:00:00 2001 From: Gianluca Guarini Date: Fri, 29 Nov 2024 22:43:27 +0100 Subject: [PATCH] closes #178 --- src/index.js | 17 ++++------------ src/utils/pre-process-source.js | 36 +++++++++++++++++++++++++++++++++ test/core.spec.js | 21 ++++++++++++++++++- 3 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 src/utils/pre-process-source.js diff --git a/src/index.js b/src/index.js index c604cb1..248ee24 100644 --- a/src/index.js +++ b/src/index.js @@ -24,13 +24,13 @@ import { createSlotsArray } from './generators/template/bindings/tag.js' import cssGenerator from './generators/css/index.js' import curry from 'curri' import generateJavascript from './utils/generate-javascript.js' -import hasHTMLOutsideRootNode from './utils/has-html-outside-root-node.js' import isEmptyArray from './utils/is-empty-array.js' import isEmptySourcemap from './utils/is-empty-sourcemap.js' import javascriptGenerator from './generators/javascript/index.js' import riotParser from '@riotjs/parser' import sourcemapAsJSON from './utils/sourcemap-as-json.js' import templateGenerator from './generators/template/index.js' +import preProcessSource from './utils/pre-process-source.js' const DEFAULT_OPTIONS = { template: 'default', @@ -156,26 +156,17 @@ export function generateTemplateFunctionFromString(source, parserOptions) { /** * Generate the output code source together with the sourcemap - * @param { string } source - source code of the tag we will need to compile + * @param { string | ParserResult } source - source code of the tag we will need to compile or a parsed Component AST * @param { Object } opts - compiling options * @returns { Output } object containing output code and source map */ export function compile(source, opts = {}) { const meta = createMeta(source, opts) const { options } = meta - const { code, map } = runPreprocessor( - 'template', - options.template, - meta, + const { template, css, javascript, map, code } = preProcessSource( source, + meta, ) - const { parse } = riotParser(options) - const { template, css, javascript } = parse(code).output - - // see also https://github.com/riot/compiler/issues/130 - if (hasHTMLOutsideRootNode(template || css || javascript, code, parse)) { - throw new Error('Multiple HTML root nodes are not supported') - } // extend the meta object with the result of the parsing Object.assign(meta, { diff --git a/src/utils/pre-process-source.js b/src/utils/pre-process-source.js new file mode 100644 index 0000000..2bbe36a --- /dev/null +++ b/src/utils/pre-process-source.js @@ -0,0 +1,36 @@ +import { isObject } from '@riotjs/util' +import riotParser from '@riotjs/parser' +import hasHTMLOutsideRootNode from './has-html-outside-root-node.js' +import { execute as runPreprocessor } from '../preprocessors.js' + +/** + * Get an object containing the template, css and javascript ast. The origianl source code and the sourcemap are also included + * + * @param { string | ParserResult.Output } source - source code of the tag we will need to compile or a parsed Component AST + * @param { Object } meta - compiler meta object that will be used to store the meta information of the input across the whole compilation + * @returns { Object } object that will be used to generate the output code + */ +export default function preProcessSource(source, meta) { + // if the source is a parser output we can return it directly + // @link https://github.com/riot/compiler/issues/178 + if (isObject(source)) return { ...source, code: '', map: null } + + const { options } = meta + + const { code, map } = runPreprocessor( + 'template', + options.template, + meta, + source, + ) + + const parse = riotParser(options).parse + const { template, css, javascript } = parse(code).output + + // see also https://github.com/riot/compiler/issues/130 + if (hasHTMLOutsideRootNode(template || css || javascript, source, parse)) { + throw new Error('Multiple HTML root nodes are not supported') + } + + return { template, css, javascript, map, code } +} diff --git a/test/core.spec.js b/test/core.spec.js index 011bc83..8e771cd 100644 --- a/test/core.spec.js +++ b/test/core.spec.js @@ -9,6 +9,7 @@ import { evaluateScript, getFixture, sassPreprocessor } from './helpers.js' import { SourceMapConsumer } from 'source-map' import { expect } from 'chai' import pug from 'pug' +import riotParser from '@riotjs/parser' import { unregister } from '../src/preprocessors.js' describe('Core specs', () => { @@ -33,12 +34,30 @@ describe('Core specs', () => { sourcemapConsumer.destroy() }) - it('TypeScript script syntax are supported', function () { + it('TypeScript script syntax is supported', function () { expect(() => compile(getFixture('typescript-script-type.riot')), ).to.not.throw() }) + it('The compiler accepts also parsed components AST', async function () { + const { parse } = riotParser() + const parserResult = parse(getFixture('my-component.riot')) + const result = compile(parserResult.output) + const output = evaluateScript(result.code) + + expect(result.code).to.be.a('string') + expect(result.map).to.be.not.an('undefined') + expect(result.meta).to.be.an('object') + expect(result.meta.tagName).to.be.equal('my-component') + expect(output.default).to.have.all.keys( + 'exports', + 'css', + 'template', + 'name', + ) + }) + it('String attributes should not be removed from the root node (https://github.com/riot/riot/issues/2761)', () => { const result = compile(getFixture('static-attributes.riot'))