Task 800: .VUE File Format
Task 800: .VUE File Format
The .VUE file format refers to the Vue.js Single-File Component (SFC) format, which encapsulates a Vue component's template, logic, and styling in a single text-based file with an HTML-like syntax. The format is documented in the official Vue.js SFC specification.
- The properties intrinsic to the .VUE file format are as follows, based on its structural elements and attributes:
- Filename: Used for automatic component name inference (e.g., for DevTools, self-references, and warnings).
- Template block: A single optional top-level <template> block containing the component's HTML structure.
- Template language: Specified via the 'lang' attribute on the <template> block (e.g., 'pug' for Pug templating).
- Template source: Specified via the 'src' attribute on the <template> block for external file imports.
- Script block: A single optional top-level <script> block containing the component's JavaScript logic (executed as an ES module).
- Script setup: A boolean indicator for whether the script block uses the 'setup' attribute (i.e., <script setup>), enabling composition API features.
- Script language: Specified via the 'lang' attribute on the <script> block (e.g., 'ts' for TypeScript).
- Script source: Specified via the 'src' attribute on the <script> block for external file imports.
- Style blocks: Zero or more <style> blocks containing CSS for the component (multiple allowed with different encapsulation modes).
- Style scoped: A boolean attribute on a <style> block to scope styles to the component.
- Style module: A boolean attribute on a <style> block to enable CSS modules.
- Style language: Specified via the 'lang' attribute on a <style> block (e.g., 'scss' for SCSS).
- Style source: Specified via the 'src' attribute on a <style> block for external file imports.
- Custom blocks: Zero or more custom top-level blocks (e.g., <docs>) for project-specific content.
- Custom block tag: The tag name of each custom block.
- Custom block language: Specified via the 'lang' attribute on a custom block.
- Custom block source: Specified via the 'src' attribute on a custom block for external file imports.
- Comments: Top-level comments using HTML syntax (), or language-specific comments within blocks.
- Two direct download links for .VUE files:
- https://raw.githubusercontent.com/hiroyuki12/vercel-vite-vue/main/src/components/HelloWorld.vue
- https://raw.githubusercontent.com/hiroyuki12/vercel-vite-vue/main/src/App.vue
- The following is an HTML document with embedded JavaScript that enables drag-and-drop functionality for a .VUE file. Upon dropping a file, it parses the content and displays all properties listed in item 1 on the screen.
Drag and drop a .VUE file here
The following is a Python class that can open, parse (decode), read, write, and print to console all properties from the list in item 1.
import xml.etree.ElementTree as ET
import os
class VueFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.properties = {
'filename': os.path.basename(filepath).replace('.vue', ''),
'templateBlock': None,
'templateLang': None,
'templateSrc': None,
'scriptBlock': None,
'scriptSetup': False,
'scriptLang': None,
'scriptSrc': None,
'styleBlocks': [],
'customBlocks': [],
'comments': []
}
self.parse()
def parse(self):
with open(self.filepath, 'r', encoding='utf-8') as f:
content = f.read()
# Extract comments
import re
comment_regex = r'<!--([\s\S]*?)-->'
self.properties['comments'] = re.findall(comment_regex, content)
# Parse as XML (wrap in root for validity)
try:
root = ET.fromstring(f'<root>{content}</root>')
template = root.find('template')
if template is not None:
self.properties['templateBlock'] = ET.tostring(template, encoding='unicode', method='html').replace('<template>', '').replace('</template>', '').strip()
self.properties['templateLang'] = template.get('lang')
self.properties['templateSrc'] = template.get('src')
script = root.find('script')
if script is not None:
self.properties['scriptBlock'] = ET.tostring(script, encoding='unicode', method='html').replace('<script>', '').replace('</script>', '').strip()
self.properties['scriptSetup'] = 'setup' in script.attrib
self.properties['scriptLang'] = script.get('lang')
self.properties['scriptSrc'] = script.get('src')
for style in root.findall('style'):
self.properties['styleBlocks'].append({
'content': ET.tostring(style, encoding='unicode', method='html').replace('<style>', '').replace('</style>', '').strip(),
'scoped': 'scoped' in style.attrib,
'module': 'module' in style.attrib,
'lang': style.get('lang'),
'src': style.get('src')
})
for child in root:
tag = child.tag.lower()
if tag not in ['template', 'script', 'style']:
self.properties['customBlocks'].append({
'tag': tag,
'content': ET.tostring(child, encoding='unicode', method='html').strip(),
'lang': child.get('lang'),
'src': child.get('src')
})
except ET.ParseError as e:
print(f"Parse error: {e}")
def print_properties(self):
import json
print(json.dumps(self.properties, indent=4, ensure_ascii=False))
def write(self, output_path=None):
if output_path is None:
output_path = self.filepath
content = ''
if self.properties['comments']:
content += '\n'.join([f'<!--{c}-->' for c in self.properties['comments']]) + '\n'
if self.properties['templateBlock']:
attrs = ''
if self.properties['templateLang']: attrs += f' lang="{self.properties["templateLang"]}"'
if self.properties['templateSrc']: attrs += f' src="{self.properties["templateSrc"]}"'
content += f'<template{attrs}>{self.properties["templateBlock"]}</template>\n'
if self.properties['scriptBlock']:
attrs = ''
if self.properties['scriptSetup']: attrs += ' setup'
if self.properties['scriptLang']: attrs += f' lang="{self.properties["scriptLang"]}"'
if self.properties['scriptSrc']: attrs += f' src="{self.properties["scriptSrc"]}"'
content += f'<script{attrs}>{self.properties["scriptBlock"]}</script>\n'
for style in self.properties['styleBlocks']:
attrs = ''
if style['scoped']: attrs += ' scoped'
if style['module']: attrs += ' module'
if style['lang']: attrs += f' lang="{style["lang"]}"'
if style['src']: attrs += f' src="{style["src"]}"'
content += f'<style{attrs}>{style["content"]}</style>\n'
for custom in self.properties['customBlocks']:
attrs = ''
if custom['lang']: attrs += f' lang="{custom["lang"]}"'
if custom['src']: attrs += f' src="{custom["src"]}"'
content += f'<{custom["tag"]}{attrs}>{custom["content"]}</{custom["tag"]}>\n'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(content)
# Example usage:
# handler = VueFileHandler('path/to/file.vue')
# handler.print_properties()
# handler.write('path/to/output.vue')The following is a Java class that can open, parse (decode), read, write, and print to console all properties from the list in item 1.
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class VueFileHandler {
private String filepath;
private Map<String, Object> properties;
public VueFileHandler(String filepath) {
this.filepath = filepath;
this.properties = new HashMap<>();
properties.put("filename", new File(filepath).getName().replace(".vue", ""));
properties.put("templateBlock", null);
properties.put("templateLang", null);
properties.put("templateSrc", null);
properties.put("scriptBlock", null);
properties.put("scriptSetup", false);
properties.put("scriptLang", null);
properties.put("scriptSrc", null);
properties.put("styleBlocks", new ArrayList<Map<String, Object>>());
properties.put("customBlocks", new ArrayList<Map<String, Object>>());
properties.put("comments", new ArrayList<String>());
parse();
}
private void parse() {
try (BufferedReader br = new BufferedReader(new FileReader(filepath))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
String fileContent = content.toString();
// Extract comments
Pattern commentPattern = Pattern.compile("<!--([\\s\\S]*?)-->");
Matcher matcher = commentPattern.matcher(fileContent);
List<String> comments = (List<String>) properties.get("comments");
while (matcher.find()) {
comments.add(matcher.group(1).trim());
}
// Parse as XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream is = new ByteArrayInputStream(("<root>" + fileContent + "</root>").getBytes("UTF-8"));
Document doc = builder.parse(is);
Node template = doc.getElementsByTagName("template").item(0);
if (template != null) {
properties.put("templateBlock", getInnerContent(template));
NamedNodeMap attrs = template.getAttributes();
properties.put("templateLang", attrs.getNamedItem("lang") != null ? attrs.getNamedItem("lang").getNodeValue() : null);
properties.put("templateSrc", attrs.getNamedItem("src") != null ? attrs.getNamedItem("src").getNodeValue() : null);
}
Node script = doc.getElementsByTagName("script").item(0);
if (script != null) {
properties.put("scriptBlock", getInnerContent(script));
NamedNodeMap attrs = script.getAttributes();
properties.put("scriptSetup", attrs.getNamedItem("setup") != null);
properties.put("scriptLang", attrs.getNamedItem("lang") != null ? attrs.getNamedItem("lang").getNodeValue() : null);
properties.put("scriptSrc", attrs.getNamedItem("src") != null ? attrs.getNamedItem("src").getNodeValue() : null);
}
NodeList styles = doc.getElementsByTagName("style");
List<Map<String, Object>> styleBlocks = (List<Map<String, Object>>) properties.get("styleBlocks");
for (int i = 0; i < styles.getLength(); i++) {
Node style = styles.item(i);
NamedNodeMap attrs = style.getAttributes();
Map<String, Object> styleMap = new HashMap<>();
styleMap.put("content", getInnerContent(style));
styleMap.put("scoped", attrs.getNamedItem("scoped") != null);
styleMap.put("module", attrs.getNamedItem("module") != null);
styleMap.put("lang", attrs.getNamedItem("lang") != null ? attrs.getNamedItem("lang").getNodeValue() : null);
styleMap.put("src", attrs.getNamedItem("src") != null ? attrs.getNamedItem("src").getNodeValue() : null);
styleBlocks.add(styleMap);
}
NodeList children = doc.getDocumentElement().getChildNodes();
List<Map<String, Object>> customBlocks = (List<Map<String, Object>>) properties.get("customBlocks");
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
String tag = child.getNodeName().toLowerCase();
if (!tag.equals("template") && !tag.equals("script") && !tag.equals("style")) {
NamedNodeMap attrs = child.getAttributes();
Map<String, Object> customMap = new HashMap<>();
customMap.put("tag", tag);
customMap.put("content", getInnerContent(child));
customMap.put("lang", attrs.getNamedItem("lang") != null ? attrs.getNamedItem("lang").getNodeValue() : null);
customMap.put("src", attrs.getNamedItem("src") != null ? attrs.getNamedItem("src").getNodeValue() : null);
customBlocks.add(customMap);
}
}
}
} catch (Exception e) {
System.err.println("Parse error: " + e.getMessage());
}
}
private String getInnerContent(Node node) {
StringBuilder sb = new StringBuilder();
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeType() == Node.TEXT_NODE || child.getNodeType() == Node.CDATA_SECTION_NODE) {
sb.append(child.getNodeValue());
} else if (child.getNodeType() == Node.ELEMENT_NODE) {
sb.append(child.getTextContent());
}
}
return sb.toString().trim();
}
public void printProperties() {
System.out.println(new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(properties));
}
public void write(String outputPath) throws IOException {
if (outputPath == null) outputPath = filepath;
try (BufferedWriter bw = new BufferedWriter(new FileWriter(outputPath))) {
List<String> comments = (List<String>) properties.get("comments");
for (String comment : comments) {
bw.write("<!--" + comment + "-->\n");
}
if (properties.get("templateBlock") != null) {
String attrs = "";
if (properties.get("templateLang") != null) attrs += " lang=\"" + properties.get("templateLang") + "\"";
if (properties.get("templateSrc") != null) attrs += " src=\"" + properties.get("templateSrc") + "\"";
bw.write("<template" + attrs + ">" + properties.get("templateBlock") + "</template>\n");
}
if (properties.get("scriptBlock") != null) {
String attrs = "";
if ((Boolean) properties.get("scriptSetup")) attrs += " setup";
if (properties.get("scriptLang") != null) attrs += " lang=\"" + properties.get("scriptLang") + "\"";
if (properties.get("scriptSrc") != null) attrs += " src=\"" + properties.get("scriptSrc") + "\"";
bw.write("<script" + attrs + ">" + properties.get("scriptBlock") + "</script>\n");
}
List<Map<String, Object>> styleBlocks = (List<Map<String, Object>>) properties.get("styleBlocks");
for (Map<String, Object> style : styleBlocks) {
String attrs = "";
if ((Boolean) style.get("scoped")) attrs += " scoped";
if ((Boolean) style.get("module")) attrs += " module";
if (style.get("lang") != null) attrs += " lang=\"" + style.get("lang") + "\"";
if (style.get("src") != null) attrs += " src=\"" + style.get("src") + "\"";
bw.write("<style" + attrs + ">" + style.get("content") + "</style>\n");
}
List<Map<String, Object>> customBlocks = (List<Map<String, Object>>) properties.get("customBlocks");
for (Map<String, Object> custom : customBlocks) {
String attrs = "";
if (custom.get("lang") != null) attrs += " lang=\"" + custom.get("lang") + "\"";
if (custom.get("src") != null) attrs += " src=\"" + custom.get("src") + "\"";
bw.write("<" + custom.get("tag") + attrs + ">" + custom.get("content") + "</" + custom.get("tag") + ">\n");
}
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// VueFileHandler handler = new VueFileHandler("path/to/file.vue");
// handler.printProperties();
// handler.write("path/to/output.vue");
// }
}- The following is a JavaScript class that can open, parse (decode), read, write, and print to console all properties from the list in item 1. (Note: File operations require Node.js environment.)
const fs = require('fs');
const { DOMParser } = require('xmldom');
class VueFileHandler {
constructor(filepath) {
this.filepath = filepath;
this.properties = {
filename: filepath.split('/').pop().replace('.vue', ''),
templateBlock: null,
templateLang: null,
templateSrc: null,
scriptBlock: null,
scriptSetup: false,
scriptLang: null,
scriptSrc: null,
styleBlocks: [],
customBlocks: [],
comments: []
};
this.parse();
}
parse() {
const content = fs.readFileSync(this.filepath, 'utf-8');
// Extract comments
const commentRegex = /<!--([\s\S]*?)-->/g;
let match;
while ((match = commentRegex.exec(content)) !== null) {
this.properties.comments.push(match[1].trim());
}
// Parse as XML
const parser = new DOMParser();
const doc = parser.parseFromString(`<root>${content}</root>`, 'text/xml');
const template = doc.getElementsByTagName('template')[0];
if (template) {
this.properties.templateBlock = template.textContent.trim();
this.properties.templateLang = template.getAttribute('lang');
this.properties.templateSrc = template.getAttribute('src');
}
const script = doc.getElementsByTagName('script')[0];
if (script) {
this.properties.scriptBlock = script.textContent.trim();
this.properties.scriptSetup = script.hasAttribute('setup');
this.properties.scriptLang = script.getAttribute('lang');
this.properties.scriptSrc = script.getAttribute('src');
}
const styles = doc.getElementsByTagName('style');
for (let i = 0; i < styles.length; i++) {
const style = styles[i];
this.properties.styleBlocks.push({
content: style.textContent.trim(),
scoped: style.hasAttribute('scoped'),
module: style.hasAttribute('module'),
lang: style.getAttribute('lang'),
src: style.getAttribute('src')
});
}
const children = doc.documentElement.childNodes;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (child.nodeType === 1) { // Element node
const tag = child.tagName.toLowerCase();
if (!['template', 'script', 'style'].includes(tag)) {
this.properties.customBlocks.push({
tag: tag,
content: child.textContent.trim(),
lang: child.getAttribute('lang'),
src: child.getAttribute('src')
});
}
}
}
}
printProperties() {
console.log(JSON.stringify(this.properties, null, 2));
}
write(outputPath = this.filepath) {
let content = '';
this.properties.comments.forEach(c => {
content += `<!--${c}-->\n`;
});
if (this.properties.templateBlock) {
let attrs = '';
if (this.properties.templateLang) attrs += ` lang="${this.properties.templateLang}"`;
if (this.properties.templateSrc) attrs += ` src="${this.properties.templateSrc}"`;
content += `<template${attrs}>${this.properties.templateBlock}</template>\n`;
}
if (this.properties.scriptBlock) {
let attrs = '';
if (this.properties.scriptSetup) attrs += ' setup';
if (this.properties.scriptLang) attrs += ` lang="${this.properties.scriptLang}"`;
if (this.properties.scriptSrc) attrs += ` src="${this.properties.scriptSrc}"`;
content += `<script${attrs}>${this.properties.scriptBlock}</script>\n`;
}
this.properties.styleBlocks.forEach(style => {
let attrs = '';
if (style.scoped) attrs += ' scoped';
if (style.module) attrs += ' module';
if (style.lang) attrs += ` lang="${style.lang}"`;
if (style.src) attrs += ` src="${style.src}"`;
content += `<style${attrs}>${style.content}</style>\n`;
});
this.properties.customBlocks.forEach(custom => {
let attrs = '';
if (custom.lang) attrs += ` lang="${custom.lang}"`;
if (custom.src) attrs += ` src="${custom.src}"`;
content += `<${custom.tag}${attrs}>${custom.content}</${custom.tag}>\n`;
});
fs.writeFileSync(outputPath, content, 'utf-8');
}
}
// Example usage:
// const handler = new VueFileHandler('path/to/file.vue');
// handler.printProperties();
// handler.write('path/to/output.vue');- The following is a C++ class that can open, parse (decode), read, write, and print to console all properties from the list in item 1. (Note: Parsing is simplified using regex and string manipulation due to lack of built-in XML support; for production, use a library like TinyXML.)
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <map>
struct StyleBlock {
std::string content;
bool scoped;
bool module;
std::string lang;
std::string src;
};
struct CustomBlock {
std::string tag;
std::string content;
std::string lang;
std::string src;
};
class VueFileHandler {
private:
std::string filepath;
std::string filename;
std::string templateBlock;
std::string templateLang;
std::string templateSrc;
std::string scriptBlock;
bool scriptSetup;
std::string scriptLang;
std::string scriptSrc;
std::vector<StyleBlock> styleBlocks;
std::vector<CustomBlock> customBlocks;
std::vector<std::string> comments;
void extractAttribute(const std::string& block, const std::string& attr, std::string& value) {
std::regex attrRegex(attr + R"(="([^"]*)")");
std::smatch match;
if (std::regex_search(block, match, attrRegex)) {
value = match[1];
}
}
bool hasAttribute(const std::string& block, const std::string& attr) {
return block.find(attr + " ") != std::string::npos || block.find(attr + ">") != std::string::npos || block.find(attr + "=\"") != std::string::npos;
}
public:
VueFileHandler(const std::string& fp) : filepath(fp), scriptSetup(false) {
size_t pos = filepath.find_last_of('/');
filename = (pos == std::string::npos ? filepath : filepath.substr(pos + 1)).substr(0, filepath.rfind(".vue"));
parse();
}
void parse() {
std::ifstream file(filepath);
if (!file.is_open()) {
std::cerr << "Failed to open file." << std::endl;
return;
}
std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
file.close();
// Extract comments
std::regex commentRegex(R"(<!--([\s\S]*?)-->)");
std::sregex_iterator iter(content.begin(), content.end(), commentRegex);
std::sregex_iterator end;
for (; iter != end; ++iter) {
comments.push_back(iter->str(1));
}
// Simplified block extraction using regex (not full parser)
std::regex blockRegex(R"(<(\w+)([^>]*)>([\s\S]*?)</\1>)");
std::sregex_iterator blockIter(content.begin(), content.end(), blockRegex);
for (; blockIter != end; ++blockIter) {
std::string tag = blockIter->str(1);
std::string attrs = blockIter->str(2);
std::string inner = blockIter->str(3);
if (tag == "template") {
templateBlock = inner;
extractAttribute(attrs, "lang", templateLang);
extractAttribute(attrs, "src", templateSrc);
} else if (tag == "script") {
scriptBlock = inner;
scriptSetup = hasAttribute(attrs, "setup");
extractAttribute(attrs, "lang", scriptLang);
extractAttribute(attrs, "src", scriptSrc);
} else if (tag == "style") {
StyleBlock sb;
sb.content = inner;
sb.scoped = hasAttribute(attrs, "scoped");
sb.module = hasAttribute(attrs, "module");
extractAttribute(attrs, "lang", sb.lang);
extractAttribute(attrs, "src", sb.src);
styleBlocks.push_back(sb);
} else {
CustomBlock cb;
cb.tag = tag;
cb.content = inner;
extractAttribute(attrs, "lang", cb.lang);
extractAttribute(attrs, "src", cb.src);
customBlocks.push_back(cb);
}
}
}
void printProperties() {
std::cout << "{\n";
std::cout << " \"filename\": \"" << filename << "\",\n";
std::cout << " \"templateBlock\": " << (templateBlock.empty() ? "null" : "\"" + templateBlock + "\"") << ",\n";
std::cout << " \"templateLang\": " << (templateLang.empty() ? "null" : "\"" + templateLang + "\"") << ",\n";
std::cout << " \"templateSrc\": " << (templateSrc.empty() ? "null" : "\"" + templateSrc + "\"") << ",\n";
std::cout << " \"scriptBlock\": " << (scriptBlock.empty() ? "null" : "\"" + scriptBlock + "\"") << ",\n";
std::cout << " \"scriptSetup\": " << (scriptSetup ? "true" : "false") << ",\n";
std::cout << " \"scriptLang\": " << (scriptLang.empty() ? "null" : "\"" + scriptLang + "\"") << ",\n";
std::cout << " \"scriptSrc\": " << (scriptSrc.empty() ? "null" : "\"" + scriptSrc + "\"") << ",\n";
std::cout << " \"styleBlocks\": [\n";
for (size_t i = 0; i < styleBlocks.size(); ++i) {
auto& sb = styleBlocks[i];
std::cout << " {\n";
std::cout << " \"content\": \"" << sb.content << "\",\n";
std::cout << " \"scoped\": " << (sb.scoped ? "true" : "false") << ",\n";
std::cout << " \"module\": " << (sb.module ? "true" : "false") << ",\n";
std::cout << " \"lang\": " << (sb.lang.empty() ? "null" : "\"" + sb.lang + "\"") << ",\n";
std::cout << " \"src\": " << (sb.src.empty() ? "null" : "\"" + sb.src + "\"") << "\n";
std::cout << " }" << (i < styleBlocks.size() - 1 ? "," : "") << "\n";
}
std::cout << " ],\n";
std::cout << " \"customBlocks\": [\n";
for (size_t i = 0; i < customBlocks.size(); ++i) {
auto& cb = customBlocks[i];
std::cout << " {\n";
std::cout << " \"tag\": \"" << cb.tag << "\",\n";
std::cout << " \"content\": \"" << cb.content << "\",\n";
std::cout << " \"lang\": " << (cb.lang.empty() ? "null" : "\"" + cb.lang + "\"") << ",\n";
std::cout << " \"src\": " << (cb.src.empty() ? "null" : "\"" + cb.src + "\"") << "\n";
std::cout << " }" << (i < customBlocks.size() - 1 ? "," : "") << "\n";
}
std::cout << " ],\n";
std::cout << " \"comments\": [\n";
for (size_t i = 0; i < comments.size(); ++i) {
std::cout << " \"" << comments[i] << "\"" << (i < comments.size() - 1 ? "," : "") << "\n";
}
std::cout << " ]\n";
std::cout << "}\n";
}
void write(const std::string& outputPath) {
std::ofstream file(outputPath.empty() ? filepath : outputPath);
if (!file.is_open()) {
std::cerr << "Failed to write file." << std::endl;
return;
}
for (const auto& c : comments) {
file << "<!--" << c << "-->\n";
}
if (!templateBlock.empty()) {
file << "<template";
if (!templateLang.empty()) file << " lang=\"" << templateLang << "\"";
if (!templateSrc.empty()) file << " src=\"" << templateSrc << "\"";
file << ">" << templateBlock << "</template>\n";
}
if (!scriptBlock.empty()) {
file << "<script";
if (scriptSetup) file << " setup";
if (!scriptLang.empty()) file << " lang=\"" << scriptLang << "\"";
if (!scriptSrc.empty()) file << " src=\"" << scriptSrc << "\"";
file << ">" << scriptBlock << "</script>\n";
}
for (const auto& sb : styleBlocks) {
file << "<style";
if (sb.scoped) file << " scoped";
if (sb.module) file << " module";
if (!sb.lang.empty()) file << " lang=\"" << sb.lang << "\"";
if (!sb.src.empty()) file << " src=\"" << sb.src << "\"";
file << ">" << sb.content << "</style>\n";
}
for (const auto& cb : customBlocks) {
file << "<" << cb.tag;
if (!cb.lang.empty()) file << " lang=\"" << cb.lang << "\"";
if (!cb.src.empty()) file << " src=\"" << cb.src << "\"";
file << ">" << cb.content << "</" << cb.tag << ">\n";
}
file.close();
}
};
// Example usage:
// int main() {
// VueFileHandler handler("path/to/file.vue");
// handler.printProperties();
// handler.write("path/to/output.vue");
// return 0;
// }