113 lines
4.6 KiB
TypeScript
113 lines
4.6 KiB
TypeScript
import * as esbuild from 'esbuild';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
export function templatePlugin(): esbuild.Plugin {
|
|
return {
|
|
name: 'template-inliner',
|
|
setup(build) {
|
|
build.onLoad({ filter: /\.(ts)$/ }, async (args) => {
|
|
if (args.path.includes('node_modules')) {
|
|
return { contents: await fs.promises.readFile(args.path, 'utf8'), loader: 'ts' };
|
|
}
|
|
|
|
let source = await fs.promises.readFile(args.path, 'utf8');
|
|
|
|
if (source.includes('import type') || source.includes('export interface')) {
|
|
return { contents: source, loader: 'ts' };
|
|
}
|
|
|
|
const fileDir = path.dirname(args.path);
|
|
let modified = false;
|
|
|
|
const templateUrlRegex = /templateUrl\s*[:=]\s*['"`]([^'"`]+)['"`]/g;
|
|
let match;
|
|
|
|
console.log(`[template-plugin] Processing: ${args.path}`);
|
|
|
|
while ((match = templateUrlRegex.exec(source)) !== null) {
|
|
console.log(`[template-plugin] Found templateUrl: ${match[1]}`);
|
|
const templatePath = match[1];
|
|
const fullPath = path.resolve(fileDir, templatePath);
|
|
|
|
if (!fs.existsSync(fullPath)) {
|
|
throw new Error(`Template file not found: ${fullPath} (referenced in ${args.path})`);
|
|
}
|
|
|
|
const templateContent = await fs.promises.readFile(fullPath, 'utf8');
|
|
const escapedContent = templateContent
|
|
.replace(/\\/g, '\\\\')
|
|
.replace(/`/g, '\\`')
|
|
.replace(/\$/g, '\\$');
|
|
|
|
const replacement = `template = \`${escapedContent}\``;
|
|
console.log(`[template-plugin] Replacing "${match[0]}" with "${replacement}"`);
|
|
source = source.replace(match[0], `template = \`${escapedContent}\``);
|
|
modified = true;
|
|
}
|
|
|
|
const styleUrlRegex = /styleUrl\s*[:=]\s*['"`]([^'"`]+)['"`]/g;
|
|
|
|
while ((match = styleUrlRegex.exec(source)) !== null) {
|
|
const stylePath = match[1];
|
|
const fullPath = path.resolve(fileDir, stylePath);
|
|
|
|
if (!fs.existsSync(fullPath)) {
|
|
throw new Error(`Style file not found: ${fullPath} (referenced in ${args.path})`);
|
|
}
|
|
|
|
const styleContent = await fs.promises.readFile(fullPath, 'utf8');
|
|
const escapedContent = styleContent
|
|
.replace(/\\/g, '\\\\')
|
|
.replace(/`/g, '\\`')
|
|
.replace(/\$/g, '\\$');
|
|
|
|
source = source.replace(match[0], `style = \`${escapedContent}\``);
|
|
modified = true;
|
|
}
|
|
|
|
const styleUrlsRegex = /styleUrls\s*[:=]\s*\[([\s\S]*?)\]/g;
|
|
|
|
while ((match = styleUrlsRegex.exec(source)) !== null) {
|
|
const urlsContent = match[1];
|
|
const urlMatches = urlsContent.match(/['"`]([^'"`]+)['"`]/g);
|
|
|
|
if (urlMatches) {
|
|
const styles: string[] = [];
|
|
|
|
for (const urlMatch of urlMatches) {
|
|
const stylePath = urlMatch.replace(/['"`]/g, '');
|
|
const fullPath = path.resolve(fileDir, stylePath);
|
|
|
|
if (!fs.existsSync(fullPath)) {
|
|
throw new Error(`Style file not found: ${fullPath} (referenced in ${args.path})`);
|
|
}
|
|
|
|
const styleContent = await fs.promises.readFile(fullPath, 'utf8');
|
|
styles.push(styleContent);
|
|
}
|
|
|
|
const combinedStyles = styles.join('\n');
|
|
const escapedContent = combinedStyles
|
|
.replace(/\\/g, '\\\\')
|
|
.replace(/`/g, '\\`')
|
|
.replace(/\$/g, '\\$');
|
|
|
|
source = source.replace(match[0], `style = \`${escapedContent}\``);
|
|
modified = true;
|
|
}
|
|
}
|
|
|
|
if (modified) {
|
|
return {
|
|
contents: source,
|
|
loader: 'ts',
|
|
};
|
|
}
|
|
|
|
return { contents: source, loader: 'ts' };
|
|
});
|
|
},
|
|
};
|
|
}
|