index.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. const indentString = require('indent-string');
  2. module.exports = function toString(sfcDescriptor, options = {}) {
  3. const {
  4. template,
  5. script,
  6. styles,
  7. customBlocks
  8. } = sfcDescriptor;
  9. const indents = Object.assign({
  10. template: 2,
  11. script: 0,
  12. style: 0
  13. }, options.indents);
  14. return [template, script, ...styles, ...customBlocks]
  15. // discard blocks that don't exist
  16. .filter(block => block != null)
  17. // sort blocks by source position
  18. .sort((a, b) => a.start - b.start)
  19. // figure out exact source positions of blocks
  20. .map(block => {
  21. const openTag = makeOpenTag(block);
  22. const closeTag = makeCloseTag(block);
  23. return Object.assign({}, block, {
  24. openTag,
  25. closeTag,
  26. startOfOpenTag: block.start - openTag.length,
  27. endOfOpenTag: block.start,
  28. startOfCloseTag: block.end,
  29. endOfCloseTag: block.end + closeTag.length
  30. });
  31. })
  32. // generate sfc source
  33. .reduce((sfcCode, block, index, array) => {
  34. const first = index === 0;
  35. let newlinesBefore = 0;
  36. if (first) {
  37. newlinesBefore = block.startOfOpenTag;
  38. } else {
  39. const prevBlock = array[index - 1];
  40. newlinesBefore = block.startOfOpenTag - prevBlock.endOfCloseTag;
  41. }
  42. return sfcCode
  43. + '\n'.repeat(newlinesBefore)
  44. + block.openTag
  45. + indentString(block.content, indents[block.type] || 0)
  46. + block.closeTag;
  47. }, '');
  48. }
  49. function makeOpenTag(block) {
  50. let source = '<' + block.type;
  51. source += Object.keys(block.attrs)
  52. .sort()
  53. .map(name => {
  54. const value = block.attrs[name];
  55. if (value === true) {
  56. return name;
  57. } else {
  58. return `${name}="${value}"`;
  59. }
  60. })
  61. .map(attr => ' ' + attr)
  62. .join('');
  63. return source + '>';
  64. }
  65. function makeCloseTag(block) {
  66. return `</${block.type}>\n`
  67. }