esbuild-plugin-scriptable
Advanced tools
Comparing version 0.6.7 to 0.7.0
'use strict'; | ||
const levels = { | ||
verbose: 0, | ||
info: 1, | ||
warn: 2, | ||
error: 3 | ||
}; | ||
class Logger { | ||
namespace; | ||
level; | ||
enabled; | ||
constructor(namespace, options = {}) { | ||
this.namespace = namespace; | ||
this.level = options.level || "info"; | ||
this.enabled = options.enabled ?? true; | ||
} | ||
shouldLog(msgLevel) { | ||
return this.enabled && levels[msgLevel] >= levels[this.level]; | ||
} | ||
verbose(...args) { | ||
if (this.shouldLog("verbose")) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
var chalk = require('chalk'); | ||
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } | ||
var chalk__default = /*#__PURE__*/_interopDefault(chalk); | ||
const timers = /* @__PURE__ */ new Map(); | ||
function createLogger(prefix, options = {}) { | ||
const { level = "info" } = options; | ||
const formatPrefix = () => chalk__default.default.cyan(`[${prefix}]`); | ||
const formatTime = (ms) => chalk__default.default.gray(`(${ms}ms)`); | ||
return { | ||
info: (message, ...args) => { | ||
console.log(`${formatPrefix()} ${message}`, ...args); | ||
}, | ||
warn: (message, ...args) => { | ||
console.warn(`${formatPrefix()} ${chalk__default.default.yellow("warning")} ${message}`, ...args); | ||
}, | ||
error: (message, ...args) => { | ||
console.error(`${formatPrefix()} ${chalk__default.default.red("error")} ${message}`, ...args); | ||
}, | ||
success: (message, ...args) => { | ||
console.log(`${formatPrefix()} ${chalk__default.default.green("\u2713")} ${message}`, ...args); | ||
}, | ||
report: (stats) => { | ||
const { total, success, skipped, failed } = stats; | ||
const hasIssues = failed > 0 || skipped > 0; | ||
console.log("\n" + formatPrefix() + " " + chalk__default.default.bold("Build Summary:")); | ||
const rows = [ | ||
[` ${chalk__default.default.bold("Total files:")}`, `${total}`], | ||
[` ${chalk__default.default.bold("Processed:")}`, `${chalk__default.default.green(success)}`], | ||
[` ${chalk__default.default.bold("Skipped:")}`, `${skipped > 0 ? chalk__default.default.yellow(skipped) : skipped}`], | ||
[` ${chalk__default.default.bold("Failed:")}`, `${failed > 0 ? chalk__default.default.red(failed) : failed}`] | ||
]; | ||
rows.forEach(([label, value]) => { | ||
console.log(`${label.padEnd(20)}${value}`); | ||
}); | ||
if (hasIssues) { | ||
console.log("\n" + formatPrefix() + " " + chalk__default.default.yellow("\u26A0\uFE0F Some files were not processed successfully")); | ||
} else { | ||
console.log("\n" + formatPrefix() + " " + chalk__default.default.green("\u2728 All files processed successfully")); | ||
} | ||
console.log(); | ||
}, | ||
time: (label) => { | ||
timers.set(label, performance.now()); | ||
}, | ||
timeEnd: (label) => { | ||
const start = timers.get(label); | ||
if (start) { | ||
const duration = Math.round(performance.now() - start); | ||
console.log(`${formatPrefix()} ${label} ${formatTime(duration)}`); | ||
timers.delete(label); | ||
} | ||
}, | ||
verbose: (message, ...args) => { | ||
if (level === "verbose") { | ||
console.log(`${formatPrefix()} ${chalk__default.default.gray(message)}`, ...args); | ||
} | ||
} | ||
} | ||
info(...args) { | ||
if (this.shouldLog("info")) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
warn(...args) { | ||
if (this.shouldLog("warn")) { | ||
console.warn(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
error(...args) { | ||
if (this.shouldLog("error")) { | ||
console.error(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
}; | ||
} | ||
function createLogger(namespace, options) { | ||
return new Logger(namespace, options); | ||
} | ||
exports.Logger = Logger; | ||
exports.createLogger = createLogger; | ||
//# sourceMappingURL=logger.js.map | ||
//# sourceMappingURL=logger.js.map |
@@ -69,2 +69,3 @@ 'use strict'; | ||
build.onEnd(async (result) => { | ||
logger$1.time("Banner Processing"); | ||
if (!result.metafile || Object.keys(result.metafile.outputs).length === 0) { | ||
@@ -76,4 +77,11 @@ logger$1.warn( | ||
} | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0 | ||
}; | ||
const outputs = result.metafile.outputs; | ||
for (const outputPath of Object.keys(outputs)) { | ||
stats.total++; | ||
const outputMeta = outputs[outputPath]; | ||
@@ -84,4 +92,5 @@ const entryPoint = outputMeta?.entryPoint ?? ""; | ||
if (warnOnMissingEntry) { | ||
logger$1.warn(`No matching entry point found for output file: ${outputPath}`); | ||
logger$1.warn(`No matching entry point for: ${outputPath}`); | ||
} | ||
stats.skipped++; | ||
continue; | ||
@@ -98,2 +107,4 @@ } | ||
outputFile.contents = Buffer.from(banner + outputFile.text.trimEnd()); | ||
stats.success++; | ||
logger$1.success(`Added banner to ${outputPath}`); | ||
} | ||
@@ -106,5 +117,8 @@ } else { | ||
await promises.writeFile(outputPath, updatedContent, "utf8"); | ||
stats.success++; | ||
logger$1.success(`Added banner to ${outputPath}`); | ||
} catch (error) { | ||
stats.failed++; | ||
logger$1.error( | ||
`Failed to process file ${outputPath}: ${error instanceof Error ? error.message : String(error)}` | ||
`Failed to process ${outputPath}: ${error instanceof Error ? error.message : String(error)}` | ||
); | ||
@@ -114,5 +128,8 @@ } | ||
} catch (error) { | ||
logger$1.error(`Failed to process output file: ${outputPath}`, error); | ||
stats.failed++; | ||
logger$1.error(`Failed to process ${outputPath}`, error); | ||
} | ||
} | ||
logger$1.timeEnd("Banner Processing"); | ||
logger$1.report(stats); | ||
}); | ||
@@ -119,0 +136,0 @@ } |
@@ -76,2 +76,9 @@ 'use strict'; | ||
} | ||
logger$1.time("Deploy Processing"); | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0 | ||
}; | ||
try { | ||
@@ -82,45 +89,56 @@ const outputs = Object.keys(result.metafile.outputs).filter((file) => { | ||
}); | ||
stats.total = outputs.length; | ||
for (const file of outputs) { | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
if (!sourceFile) { | ||
throw new Error(`No entry point found for ${file}`); | ||
} | ||
let content; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find((f) => utils.isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} else { | ||
await utils.waitForFile(file); | ||
content = await promises.readFile(file, "utf-8"); | ||
} | ||
let targetFileName = path.basename(file); | ||
let manifest = null; | ||
try { | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
if (!sourceFile) { | ||
logger$1.warn(`No entry point found for ${file}`); | ||
stats.skipped++; | ||
continue; | ||
} | ||
} catch (error) { | ||
logger$1.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = path.join(targetDir, targetFileName); | ||
if (addBanner && manifest) { | ||
let content; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find((f) => utils.isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} else { | ||
await utils.waitForFile(file); | ||
content = await promises.readFile(file, "utf-8"); | ||
} | ||
let targetFileName = path.basename(file); | ||
let manifest = null; | ||
try { | ||
const banner = generateScriptableBanner.generateScriptableBanner(manifest); | ||
const newContent = banner + "\n" + content; | ||
await promises.writeFile(targetPath, newContent); | ||
logger$1.info(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
} | ||
} catch (error) { | ||
logger$1.warn(`Failed to add banner to ${file}: ${error}`); | ||
logger$1.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = path.join(targetDir, targetFileName); | ||
if (addBanner && manifest) { | ||
try { | ||
const banner = generateScriptableBanner.generateScriptableBanner(manifest); | ||
const newContent = banner + "\n" + content; | ||
await promises.writeFile(targetPath, newContent); | ||
stats.success++; | ||
logger$1.success(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
} catch (error) { | ||
logger$1.warn(`Failed to add banner to ${file}: ${error}`); | ||
} | ||
} | ||
await promises.writeFile(targetPath, content); | ||
stats.success++; | ||
logger$1.success(`Deployed: ${file} -> ${targetPath}`); | ||
} catch (error) { | ||
stats.failed++; | ||
logger$1.error(`Failed to deploy ${file}: ${error instanceof Error ? error.message : String(error)}`); | ||
} | ||
await promises.writeFile(targetPath, content); | ||
logger$1.info(`Deployed: ${file} -> ${targetPath}`); | ||
} | ||
logger$1.info(`Successfully deployed ${outputs.length} files`); | ||
logger$1.timeEnd("Deploy Processing"); | ||
logger$1.report(stats); | ||
} catch (error) { | ||
@@ -127,0 +145,0 @@ logger$1.error(`Deploy failed: ${error.message}`); |
@@ -1,19 +0,21 @@ | ||
type LogLevel = 'verbose' | 'info' | 'warn' | 'error'; | ||
interface Logger { | ||
info: (message: string, ...args: any[]) => void; | ||
warn: (message: string, ...args: any[]) => void; | ||
error: (message: string, ...args: any[]) => void; | ||
success: (message: string, ...args: any[]) => void; | ||
report: (stats: { | ||
total: number; | ||
success: number; | ||
skipped: number; | ||
failed: number; | ||
}) => void; | ||
time: (label: string) => void; | ||
timeEnd: (label: string) => void; | ||
verbose: (message: string, ...args: any[]) => void; | ||
} | ||
interface LoggerOptions { | ||
level?: LogLevel; | ||
enabled?: boolean; | ||
level?: 'verbose' | 'info'; | ||
} | ||
declare class Logger { | ||
private namespace; | ||
private level; | ||
private enabled; | ||
constructor(namespace: string, options?: LoggerOptions); | ||
private shouldLog; | ||
verbose(...args: any[]): void; | ||
info(...args: any[]): void; | ||
warn(...args: any[]): void; | ||
error(...args: any[]): void; | ||
} | ||
declare function createLogger(namespace: string, options?: LoggerOptions): Logger; | ||
declare function createLogger(prefix: string, options?: LoggerOptions): Logger; | ||
export { type LogLevel, Logger, type LoggerOptions, createLogger }; | ||
export { type Logger, type LoggerOptions, createLogger }; |
@@ -1,46 +0,62 @@ | ||
const levels = { | ||
verbose: 0, | ||
info: 1, | ||
warn: 2, | ||
error: 3 | ||
}; | ||
class Logger { | ||
namespace; | ||
level; | ||
enabled; | ||
constructor(namespace, options = {}) { | ||
this.namespace = namespace; | ||
this.level = options.level || "info"; | ||
this.enabled = options.enabled ?? true; | ||
} | ||
shouldLog(msgLevel) { | ||
return this.enabled && levels[msgLevel] >= levels[this.level]; | ||
} | ||
verbose(...args) { | ||
if (this.shouldLog("verbose")) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
import chalk from 'chalk'; | ||
const timers = /* @__PURE__ */ new Map(); | ||
function createLogger(prefix, options = {}) { | ||
const { level = "info" } = options; | ||
const formatPrefix = () => chalk.cyan(`[${prefix}]`); | ||
const formatTime = (ms) => chalk.gray(`(${ms}ms)`); | ||
return { | ||
info: (message, ...args) => { | ||
console.log(`${formatPrefix()} ${message}`, ...args); | ||
}, | ||
warn: (message, ...args) => { | ||
console.warn(`${formatPrefix()} ${chalk.yellow("warning")} ${message}`, ...args); | ||
}, | ||
error: (message, ...args) => { | ||
console.error(`${formatPrefix()} ${chalk.red("error")} ${message}`, ...args); | ||
}, | ||
success: (message, ...args) => { | ||
console.log(`${formatPrefix()} ${chalk.green("\u2713")} ${message}`, ...args); | ||
}, | ||
report: (stats) => { | ||
const { total, success, skipped, failed } = stats; | ||
const hasIssues = failed > 0 || skipped > 0; | ||
console.log("\n" + formatPrefix() + " " + chalk.bold("Build Summary:")); | ||
const rows = [ | ||
[` ${chalk.bold("Total files:")}`, `${total}`], | ||
[` ${chalk.bold("Processed:")}`, `${chalk.green(success)}`], | ||
[` ${chalk.bold("Skipped:")}`, `${skipped > 0 ? chalk.yellow(skipped) : skipped}`], | ||
[` ${chalk.bold("Failed:")}`, `${failed > 0 ? chalk.red(failed) : failed}`] | ||
]; | ||
rows.forEach(([label, value]) => { | ||
console.log(`${label.padEnd(20)}${value}`); | ||
}); | ||
if (hasIssues) { | ||
console.log("\n" + formatPrefix() + " " + chalk.yellow("\u26A0\uFE0F Some files were not processed successfully")); | ||
} else { | ||
console.log("\n" + formatPrefix() + " " + chalk.green("\u2728 All files processed successfully")); | ||
} | ||
console.log(); | ||
}, | ||
time: (label) => { | ||
timers.set(label, performance.now()); | ||
}, | ||
timeEnd: (label) => { | ||
const start = timers.get(label); | ||
if (start) { | ||
const duration = Math.round(performance.now() - start); | ||
console.log(`${formatPrefix()} ${label} ${formatTime(duration)}`); | ||
timers.delete(label); | ||
} | ||
}, | ||
verbose: (message, ...args) => { | ||
if (level === "verbose") { | ||
console.log(`${formatPrefix()} ${chalk.gray(message)}`, ...args); | ||
} | ||
} | ||
} | ||
info(...args) { | ||
if (this.shouldLog("info")) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
warn(...args) { | ||
if (this.shouldLog("warn")) { | ||
console.warn(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
error(...args) { | ||
if (this.shouldLog("error")) { | ||
console.error(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
}; | ||
} | ||
function createLogger(namespace, options) { | ||
return new Logger(namespace, options); | ||
} | ||
export { Logger, createLogger }; | ||
export { createLogger }; | ||
//# sourceMappingURL=logger.js.map | ||
//# sourceMappingURL=logger.js.map |
@@ -59,2 +59,3 @@ import { generateScriptableBanner } from "@scriptables/manifest/generateScriptableBanner"; | ||
build.onEnd(async (result) => { | ||
logger.time("Banner Processing"); | ||
if (!result.metafile || Object.keys(result.metafile.outputs).length === 0) { | ||
@@ -64,4 +65,11 @@ logger.warn("Skipping banner addition because \"metafile\" is not available or contains no outputs. Ensure \"metafile: true\" is set in esbuild options if write is enabled."); | ||
} | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0 | ||
}; | ||
const outputs = result.metafile.outputs; | ||
for (const outputPath of Object.keys(outputs)) { | ||
stats.total++; | ||
const outputMeta = outputs[outputPath]; | ||
@@ -72,4 +80,5 @@ const entryPoint = outputMeta?.entryPoint ?? ""; | ||
if (warnOnMissingEntry) { | ||
logger.warn(`No matching entry point found for output file: ${outputPath}`); | ||
logger.warn(`No matching entry point for: ${outputPath}`); | ||
} | ||
stats.skipped++; | ||
continue; | ||
@@ -84,2 +93,4 @@ } | ||
outputFile.contents = Buffer.from(banner + outputFile.text.trimEnd()); | ||
stats.success++; | ||
logger.success(`Added banner to ${outputPath}`); | ||
} | ||
@@ -93,5 +104,8 @@ } | ||
await writeFile(outputPath, updatedContent, "utf8"); | ||
stats.success++; | ||
logger.success(`Added banner to ${outputPath}`); | ||
} | ||
catch (error) { | ||
logger.error(`Failed to process file ${outputPath}: ${error instanceof Error ? error.message : String(error)}`); | ||
stats.failed++; | ||
logger.error(`Failed to process ${outputPath}: ${error instanceof Error ? error.message : String(error)}`); | ||
} | ||
@@ -101,5 +115,8 @@ } | ||
catch (error) { | ||
logger.error(`Failed to process output file: ${outputPath}`, error); | ||
stats.failed++; | ||
logger.error(`Failed to process ${outputPath}`, error); | ||
} | ||
} | ||
logger.timeEnd("Banner Processing"); | ||
logger.report(stats); | ||
}); | ||
@@ -106,0 +123,0 @@ } |
@@ -68,2 +68,9 @@ import { generateScriptableBanner } from "@scriptables/manifest/generateScriptableBanner"; | ||
} | ||
logger.time("Deploy Processing"); | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0 | ||
}; | ||
try { | ||
@@ -74,48 +81,60 @@ const outputs = Object.keys(result.metafile.outputs).filter((file) => { | ||
}); | ||
stats.total = outputs.length; | ||
for (const file of outputs) { | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
if (!sourceFile) { | ||
throw new Error(`No entry point found for ${file}`); | ||
} | ||
let content; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find((f) => isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} | ||
else { | ||
await waitForFile(file); | ||
content = await readFile(file, "utf-8"); | ||
} | ||
let targetFileName = basename(file); | ||
let manifest = null; | ||
try { | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
if (!sourceFile) { | ||
logger.warn(`No entry point found for ${file}`); | ||
stats.skipped++; | ||
continue; | ||
} | ||
} | ||
catch (error) { | ||
logger.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = join(targetDir, targetFileName); | ||
if (addBanner && manifest) { | ||
let content; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find((f) => isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} | ||
else { | ||
await waitForFile(file); | ||
content = await readFile(file, "utf-8"); | ||
} | ||
let targetFileName = basename(file); | ||
let manifest = null; | ||
try { | ||
const banner = generateScriptableBanner(manifest); | ||
const newContent = banner + "\n" + content; | ||
await writeFile(targetPath, newContent); | ||
logger.info(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
} | ||
} | ||
catch (error) { | ||
logger.warn(`Failed to add banner to ${file}: ${error}`); | ||
logger.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = join(targetDir, targetFileName); | ||
if (addBanner && manifest) { | ||
try { | ||
const banner = generateScriptableBanner(manifest); | ||
const newContent = banner + "\n" + content; | ||
await writeFile(targetPath, newContent); | ||
stats.success++; | ||
logger.success(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
} | ||
catch (error) { | ||
logger.warn(`Failed to add banner to ${file}: ${error}`); | ||
} | ||
} | ||
await writeFile(targetPath, content); | ||
stats.success++; | ||
logger.success(`Deployed: ${file} -> ${targetPath}`); | ||
} | ||
await writeFile(targetPath, content); | ||
logger.info(`Deployed: ${file} -> ${targetPath}`); | ||
catch (error) { | ||
stats.failed++; | ||
logger.error(`Failed to deploy ${file}: ${error instanceof Error ? error.message : String(error)}`); | ||
} | ||
} | ||
logger.info(`Successfully deployed ${outputs.length} files`); | ||
logger.timeEnd("Deploy Processing"); | ||
logger.report(stats); | ||
} | ||
@@ -122,0 +141,0 @@ catch (error) { |
{ | ||
"name": "esbuild-plugin-scriptable", | ||
"description": "An ESBuild plugin for developing Scriptable iOS app scripts with TypeScript, manifest support and auto-deployment", | ||
"version": "0.6.7", | ||
"version": "0.7.0", | ||
"keywords": [ | ||
@@ -29,2 +29,3 @@ "scriptable", | ||
"dependencies": { | ||
"chalk": "^4.1.2", | ||
"findicloud": "^0.1.3", | ||
@@ -31,0 +32,0 @@ "micromatch": "^4.0.8", |
@@ -1,57 +0,81 @@ | ||
export type LogLevel = 'verbose' | 'info' | 'warn' | 'error'; | ||
import chalk from 'chalk'; | ||
export interface LoggerOptions { | ||
level?: LogLevel; | ||
enabled?: boolean; | ||
export interface Logger { | ||
info: (message: string, ...args: any[]) => void; | ||
warn: (message: string, ...args: any[]) => void; | ||
error: (message: string, ...args: any[]) => void; | ||
success: (message: string, ...args: any[]) => void; | ||
report: (stats: {total: number; success: number; skipped: number; failed: number}) => void; | ||
time: (label: string) => void; | ||
timeEnd: (label: string) => void; | ||
verbose: (message: string, ...args: any[]) => void; | ||
} | ||
const levels: Record<LogLevel, number> = { | ||
verbose: 0, | ||
info: 1, | ||
warn: 2, | ||
error: 3, | ||
}; | ||
const timers = new Map<string, number>(); | ||
export class Logger { | ||
private namespace: string; | ||
private level: LogLevel; | ||
private enabled: boolean; | ||
export interface LoggerOptions { | ||
level?: 'verbose' | 'info'; | ||
} | ||
constructor(namespace: string, options: LoggerOptions = {}) { | ||
this.namespace = namespace; | ||
this.level = options.level || 'info'; | ||
this.enabled = options.enabled ?? true; | ||
} | ||
export function createLogger(prefix: string, options: LoggerOptions = {}): Logger { | ||
const {level = 'info'} = options; | ||
const formatPrefix = () => chalk.cyan(`[${prefix}]`); | ||
const formatTime = (ms: number) => chalk.gray(`(${ms}ms)`); | ||
private shouldLog(msgLevel: LogLevel): boolean { | ||
return this.enabled && levels[msgLevel] >= levels[this.level]; | ||
} | ||
return { | ||
info: (message: string, ...args) => { | ||
console.log(`${formatPrefix()} ${message}`, ...args); | ||
}, | ||
warn: (message: string, ...args) => { | ||
console.warn(`${formatPrefix()} ${chalk.yellow('warning')} ${message}`, ...args); | ||
}, | ||
error: (message: string, ...args) => { | ||
console.error(`${formatPrefix()} ${chalk.red('error')} ${message}`, ...args); | ||
}, | ||
success: (message: string, ...args) => { | ||
console.log(`${formatPrefix()} ${chalk.green('✓')} ${message}`, ...args); | ||
}, | ||
report: stats => { | ||
const {total, success, skipped, failed} = stats; | ||
const hasIssues = failed > 0 || skipped > 0; | ||
verbose(...args: any[]): void { | ||
if (this.shouldLog('verbose')) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
console.log('\n' + formatPrefix() + ' ' + chalk.bold('Build Summary:')); | ||
info(...args: any[]): void { | ||
if (this.shouldLog('info')) { | ||
console.log(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
// 使用表格样式展示统计 | ||
const rows = [ | ||
[` ${chalk.bold('Total files:')}`, `${total}`], | ||
[` ${chalk.bold('Processed:')}`, `${chalk.green(success)}`], | ||
[` ${chalk.bold('Skipped:')}`, `${skipped > 0 ? chalk.yellow(skipped) : skipped}`], | ||
[` ${chalk.bold('Failed:')}`, `${failed > 0 ? chalk.red(failed) : failed}`], | ||
]; | ||
warn(...args: any[]): void { | ||
if (this.shouldLog('warn')) { | ||
console.warn(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
rows.forEach(([label, value]) => { | ||
console.log(`${label.padEnd(20)}${value}`); | ||
}); | ||
error(...args: any[]): void { | ||
if (this.shouldLog('error')) { | ||
console.error(`[${this.namespace}]`, ...args); | ||
} | ||
} | ||
// 如果有问题,添加提示 | ||
if (hasIssues) { | ||
console.log('\n' + formatPrefix() + ' ' + chalk.yellow('⚠️ Some files were not processed successfully')); | ||
} else { | ||
console.log('\n' + formatPrefix() + ' ' + chalk.green('✨ All files processed successfully')); | ||
} | ||
console.log(); // 空行 | ||
}, | ||
time: (label: string) => { | ||
timers.set(label, performance.now()); | ||
}, | ||
timeEnd: (label: string) => { | ||
const start = timers.get(label); | ||
if (start) { | ||
const duration = Math.round(performance.now() - start); | ||
console.log(`${formatPrefix()} ${label} ${formatTime(duration)}`); | ||
timers.delete(label); | ||
} | ||
}, | ||
verbose: (message: string, ...args) => { | ||
if (level === 'verbose') { | ||
console.log(`${formatPrefix()} ${chalk.gray(message)}`, ...args); | ||
} | ||
}, | ||
}; | ||
} | ||
export function createLogger(namespace: string, options?: LoggerOptions): Logger { | ||
return new Logger(namespace, options); | ||
} |
@@ -111,2 +111,4 @@ import type {ScriptableManifest} from '@scriptables/manifest'; | ||
build.onEnd(async result => { | ||
logger.time('Banner Processing'); | ||
if (!result.metafile || Object.keys(result.metafile.outputs).length === 0) { | ||
@@ -121,4 +123,13 @@ logger.warn( | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0, | ||
}; | ||
const outputs = result.metafile.outputs; | ||
for (const outputPath of Object.keys(outputs)) { | ||
stats.total++; | ||
const outputMeta = outputs[outputPath]; | ||
@@ -130,4 +141,5 @@ const entryPoint = outputMeta?.entryPoint ?? ''; | ||
if (warnOnMissingEntry) { | ||
logger.warn(`No matching entry point found for output file: ${outputPath}`); | ||
logger.warn(`No matching entry point for: ${outputPath}`); | ||
} | ||
stats.skipped++; | ||
continue; | ||
@@ -141,3 +153,2 @@ } | ||
if (result.outputFiles) { | ||
// Memory mode: Modify outputFiles directly | ||
const outputFile = result.outputFiles.find( | ||
@@ -148,5 +159,6 @@ file => isSamePath(file.path, outputPath) || file.path === '<stdout>', | ||
outputFile.contents = Buffer.from(banner + outputFile.text.trimEnd()); | ||
stats.success++; | ||
logger.success(`Added banner to ${outputPath}`); | ||
} | ||
} else { | ||
// File Write Mode: Wait for the file to be written for processing | ||
try { | ||
@@ -157,5 +169,8 @@ await waitForFile(outputPath); | ||
await writeFile(outputPath, updatedContent, 'utf8'); | ||
stats.success++; | ||
logger.success(`Added banner to ${outputPath}`); | ||
} catch (error) { | ||
stats.failed++; | ||
logger.error( | ||
`Failed to process file ${outputPath}: ${error instanceof Error ? error.message : String(error)}`, | ||
`Failed to process ${outputPath}: ${error instanceof Error ? error.message : String(error)}`, | ||
); | ||
@@ -165,5 +180,9 @@ } | ||
} catch (error) { | ||
logger.error(`Failed to process output file: ${outputPath}`, error); | ||
stats.failed++; | ||
logger.error(`Failed to process ${outputPath}`, error); | ||
} | ||
} | ||
logger.timeEnd('Banner Processing'); | ||
logger.report(stats); | ||
}); | ||
@@ -170,0 +189,0 @@ }, |
@@ -137,2 +137,11 @@ import type {ScriptableManifest} from '@scriptables/manifest'; | ||
logger.time('Deploy Processing'); | ||
const stats = { | ||
total: 0, | ||
success: 0, | ||
skipped: 0, | ||
failed: 0, | ||
}; | ||
try { | ||
@@ -145,58 +154,68 @@ const outputs = Object.keys(result.metafile.outputs).filter(file => { | ||
stats.total = outputs.length; | ||
for (const file of outputs) { | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
try { | ||
const output = result.metafile.outputs[file]; | ||
const sourceFile = output.entryPoint; | ||
if (!sourceFile) { | ||
throw new Error(`No entry point found for ${file}`); | ||
} | ||
// Get file content | ||
let content: string; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find(f => isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
if (!sourceFile) { | ||
logger.warn(`No entry point found for ${file}`); | ||
stats.skipped++; | ||
continue; | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} else { | ||
await waitForFile(file); | ||
content = await readFile(file, 'utf-8'); | ||
} | ||
// Try to read the manifest using entryPoint | ||
let targetFileName = basename(file); | ||
let manifest: ScriptableManifest | null = null; | ||
try { | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
// If the name is defined in the manifest, use it as the target file name | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
// Get file content | ||
let content: string; | ||
if (result.outputFiles) { | ||
const outputFile = result.outputFiles.find(f => isSamePath(f.path, file)); | ||
if (!outputFile) { | ||
throw new Error(`Output file not found: ${file}`); | ||
} | ||
content = new TextDecoder().decode(outputFile.contents); | ||
} else { | ||
await waitForFile(file); | ||
content = await readFile(file, 'utf-8'); | ||
} | ||
} catch (error) { | ||
logger.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = join(targetDir, targetFileName); | ||
// Try to read the manifest using entryPoint | ||
let targetFileName = basename(file); | ||
let manifest: ScriptableManifest | null = null; | ||
if (addBanner && manifest) { | ||
try { | ||
const banner = generateScriptableBanner(manifest); | ||
const newContent = banner + '\n' + content; | ||
await writeFile(targetPath, newContent); | ||
logger.info(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
manifest = await tryReadManifest(sourceFile, manifestExtensions); | ||
if (manifest?.name) { | ||
targetFileName = `${manifest.name}.js`; | ||
} | ||
} catch (error) { | ||
logger.warn(`Failed to add banner to ${file}: ${error}`); | ||
logger.warn(`Failed to read manifest for ${file}: ${error}`); | ||
} | ||
const targetPath = join(targetDir, targetFileName); | ||
if (addBanner && manifest) { | ||
try { | ||
const banner = generateScriptableBanner(manifest); | ||
const newContent = banner + '\n' + content; | ||
await writeFile(targetPath, newContent); | ||
stats.success++; | ||
logger.success(`Deployed with banner: ${file} -> ${targetPath}`); | ||
continue; | ||
} catch (error) { | ||
logger.warn(`Failed to add banner to ${file}: ${error}`); | ||
} | ||
} | ||
// If the banner is not needed or the processing fails, write the content directly | ||
await writeFile(targetPath, content); | ||
stats.success++; | ||
logger.success(`Deployed: ${file} -> ${targetPath}`); | ||
} catch (error) { | ||
stats.failed++; | ||
logger.error(`Failed to deploy ${file}: ${error instanceof Error ? error.message : String(error)}`); | ||
} | ||
// If the banner is not needed or the processing fails, write the content directly | ||
await writeFile(targetPath, content); | ||
logger.info(`Deployed: ${file} -> ${targetPath}`); | ||
} | ||
logger.info(`Successfully deployed ${outputs.length} files`); | ||
logger.timeEnd('Deploy Processing'); | ||
logger.report(stats); | ||
} catch (error) { | ||
@@ -203,0 +222,0 @@ logger.error(`Deploy failed: ${(error as Error).message}`); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
144319
1483
5
+ Addedchalk@^4.1.2
+ Addedansi-styles@4.3.0(transitive)
+ Addedchalk@4.1.2(transitive)
+ Addedcolor-convert@2.0.1(transitive)
+ Addedcolor-name@1.1.4(transitive)
+ Addedhas-flag@4.0.0(transitive)
+ Addedsupports-color@7.2.0(transitive)