diff --git a/packages/gogocode-core/src/vue-core/generate.js b/packages/gogocode-core/src/vue-core/generate.js
index 63cd28b..437c79e 100644
--- a/packages/gogocode-core/src/vue-core/generate.js
+++ b/packages/gogocode-core/src/vue-core/generate.js
@@ -1,123 +1,18 @@
-const indentString = require('indent-string');
-const jsGenerate = require('../js-core/generate')
-const htmlGenerate = require('../html-core/serialize-node')
-/**
- * The following function is adapted from https://github.com/psalaets/vue-sfc-descriptor-to-string/blob/master/index.js
- */
-
-/**
- * The MIT License (MIT)
- * Copyright (c) 2018 Paul Salaets
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-module.exports = function toString(sfcDescriptor, options = {}) {
- let { template, script, scriptSetup, styles = [], customBlocks = [], templateAst, scriptAst, scriptSetupAst } = sfcDescriptor;
- if (templateAst && templateAst.node) {
- template.content = htmlGenerate(templateAst.node);
- }
- if (scriptAst && scriptAst.node) {
- script.content = jsGenerate(scriptAst.node);
- }
-
- if (scriptSetupAst && scriptSetupAst.node) {
- scriptSetup.content = jsGenerate(scriptSetupAst.node);
- }
-
- const indents = Object.assign(
- {
- template: 2,
- script: 0,
- style: 0
- },
- options.indents
- );
-
- return (
- [template, script, scriptSetup, ...styles, ...customBlocks]
- // discard blocks that don't exist
- .filter((block) => block != null)
- // sort blocks by source position
- .sort((a, b) => a.start - b.start)
- // figure out exact source positions of blocks
- .map((block) => {
- const openTag = makeOpenTag(block);
- const closeTag = makeCloseTag(block);
-
- return Object.assign({}, block, {
- openTag,
- closeTag,
-
- startOfOpenTag: block.start - openTag.length,
- endOfOpenTag: block.start,
-
- startOfCloseTag: block.end,
- endOfCloseTag: block.end + closeTag.length
- });
- })
- // generate sfc source
- .reduce((sfcCode, block, index, array) => {
- const first = index === 0;
-
- let newlinesBefore = 0;
-
- if (first) {
- newlinesBefore = block.startOfOpenTag;
- } else {
- const prevBlock = array[index - 1];
- newlinesBefore =
- block.startOfOpenTag - prevBlock.endOfCloseTag;
- }
-
- newlinesBefore = newlinesBefore || 1
-
- return (
- sfcCode +
- '\n'.repeat(newlinesBefore) +
- block.openTag +
- indentString(block.content, indents[block.type] || 0) +
- block.closeTag
- );
- }, '')
- );
-}
-
-function makeOpenTag(block) {
- let source = '<' + block.type;
-
- source += Object.keys(block.attrs)
- .sort()
- .map((name) => {
- const value = block.attrs[name];
-
- if (value === true) {
- return name;
- } else {
- return `${name}="${value}"`;
- }
- })
- .map((attr) => ' ' + attr)
- .join('');
-
- return source + '>';
-}
-
-function makeCloseTag(block) {
- return `${block.type}>\n`;
+const jsGenerate = require('../js-core/generate');
+const htmlGenerate = require('../html-core/serialize-node');
+
+module.exports = function toString(sfcDescriptor) {
+ const { source } = sfcDescriptor
+ return ['template', 'script', 'scriptSetup'].reduce((acc, blockType) => {
+ const block = sfcDescriptor[blockType]
+ const ast = sfcDescriptor[blockType + 'Ast']
+ if (!block || !ast?.node) {
+ return acc
+ }
+ const offset = source.length - acc.length
+ const transform = blockType === 'template' ? htmlGenerate : jsGenerate
+ const before = acc.slice(0, block.loc.start.offset - offset)
+ const after = acc.slice(block.loc.end.offset - offset, acc.length)
+ return before + transform(ast.node) + after
+ }, source)
}
diff --git a/packages/gogocode-core/test/G.vue.test.js b/packages/gogocode-core/test/G.vue.test.js
index 7f32c1a..675d03c 100644
--- a/packages/gogocode-core/test/G.vue.test.js
+++ b/packages/gogocode-core/test/G.vue.test.js
@@ -26,7 +26,7 @@ const code = `
`, { parseOptions: { language: 'vue' }})
@@ -635,3 +635,146 @@ test('test vue parseoptions', () => {
const res = ast.generate()
expect(res.match('&&')).toBeTruthy()
})
+
+test('block sort order', () => {
+ const ast = $(`
+
+