Skip to content

Commit 84d77ff

Browse files
authored
Merge pull request #9537 from keymanapp/feat/developer/add-logFormat-to-kmc
feat(developer): add --log-format to kmc 🎺
2 parents 65d95d3 + b8cf546 commit 84d77ff

File tree

7 files changed

+75
-23
lines changed

7 files changed

+75
-23
lines changed

common/web/types/src/main.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ export { defaultCompilerOptions, CompilerBaseOptions, CompilerCallbacks, Compile
2525
CompilerErrorSeverity, CompilerPathCallbacks, CompilerFileSystemCallbacks, CompilerCallbackOptions,
2626
CompilerError, CompilerMessageSpec, compilerErrorSeverity, CompilerErrorMask, CompilerFileCallbacks, compilerErrorSeverityName,
2727
compilerExceptionToString, compilerErrorFormatCode,
28-
compilerLogLevelToSeverity, CompilerLogLevel, compilerEventFormat, ALL_COMPILER_LOG_LEVELS } from './util/compiler-interfaces.js';
28+
compilerLogLevelToSeverity, CompilerLogLevel, compilerEventFormat, ALL_COMPILER_LOG_LEVELS,
29+
ALL_COMPILER_LOG_FORMATS, CompilerLogFormat,
30+
} from './util/compiler-interfaces.js';
2931
export { CommonTypesMessages } from './util/common-events.js';
3032

3133
export * as TouchLayout from './keyman-touch-layout/keyman-touch-layout-file.js';

common/web/types/src/util/compiler-interfaces.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,20 @@ export class CompilerError {
7474
* @param filename
7575
* @returns
7676
*/
77-
static formatFilename(filename: string): string {
77+
static formatFilename(filename: string, options?: {
78+
fullPath?: boolean,
79+
forwardSlashes?: boolean
80+
}): string {
7881
if(!filename) {
7982
return '';
8083
}
8184

85+
if(options?.fullPath) {
86+
return options?.forwardSlashes ?
87+
filename.replaceAll(/\\/g, '/') :
88+
filename.replaceAll(/\//g, '\\');
89+
}
90+
8291
let x = filename.lastIndexOf('/');
8392
if(x < 0) {
8493
x = filename.lastIndexOf('\\');
@@ -239,6 +248,7 @@ export interface CompilerFileSystemCallbacks {
239248

240249
export interface CompilerCallbackOptions {
241250
logLevel?: CompilerLogLevel;
251+
logFormat?: CompilerLogFormat;
242252
color?: boolean; // null or undefined == use console default
243253
compilerWarningsAsErrors?: boolean;
244254
};
@@ -355,6 +365,10 @@ export interface CompilerBaseOptions {
355365
* all messages are still reported to the internal log)
356366
*/
357367
logLevel?: CompilerLogLevel;
368+
/**
369+
* Format of output for log to console
370+
*/
371+
logFormat?: CompilerLogFormat;
358372
/**
359373
* Optional output file for activities that generate output
360374
*/
@@ -390,6 +404,7 @@ export interface CompilerOptions extends CompilerBaseOptions {
390404

391405
export const defaultCompilerOptions: CompilerOptions = {
392406
logLevel: 'info',
407+
logFormat: 'formatted',
393408
// outFile: (undefined)
394409
saveDebug: false,
395410
shouldAddCompilerVersion: true,
@@ -443,3 +458,11 @@ export const compilerLogLevelToSeverity: {[index in CompilerLogLevel]: number} =
443458
'info': CompilerErrorSeverity.Info,
444459
'debug': CompilerErrorSeverity.Info
445460
};
461+
462+
export const ALL_COMPILER_LOG_FORMATS = [
463+
'tsv',
464+
'formatted'
465+
] as const;
466+
467+
type CompilerLogFormatTuple = typeof ALL_COMPILER_LOG_FORMATS;
468+
export type CompilerLogFormat = CompilerLogFormatTuple[number];

developer/src/kmc/src/commands/build.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ function commandOptionsToCompilerOptions(options: any): CompilerOptions {
1919
// CompilerBaseOptions
2020
outFile: options.outFile,
2121
logLevel: options.logLevel,
22+
logFormat: options.logFormat,
2223
color: options.color,
2324
// CompilerOptions
2425
shouldAddCompilerVersion: options.compilerVersion,
@@ -112,22 +113,22 @@ async function build(filename: string, parentCallbacks: NodeCompilerCallbacks, o
112113
if(fs.statSync(filename).isDirectory()) {
113114
buildFilename = path.join(buildFilename, path.basename(buildFilename) + KeymanFileTypes.Source.Project);
114115
}
115-
buildFilename = path.relative(process.cwd(), buildFilename).replace(/\\/g, '/');
116+
const relativeFilename = path.relative(process.cwd(), buildFilename).replace(/\\/g, '/');
116117

117118
const callbacks = new CompilerFileCallbacks(buildFilename, options, parentCallbacks);
118-
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename:buildFilename}));
119+
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename:buildFilename, relativeFilename}));
119120

120121
let result = await builder.build(filename, callbacks, options);
121122
result = result && !callbacks.hasFailureMessage();
122123
if(result) {
123124
callbacks.reportMessage(builder instanceof BuildProject
124-
? InfrastructureMessages.Info_ProjectBuiltSuccessfully({filename:buildFilename})
125-
: InfrastructureMessages.Info_FileBuiltSuccessfully({filename:buildFilename})
125+
? InfrastructureMessages.Info_ProjectBuiltSuccessfully({filename:buildFilename, relativeFilename})
126+
: InfrastructureMessages.Info_FileBuiltSuccessfully({filename:buildFilename, relativeFilename})
126127
);
127128
} else {
128129
callbacks.reportMessage(builder instanceof BuildProject
129-
? InfrastructureMessages.Info_ProjectNotBuiltSuccessfully({filename:buildFilename})
130-
: InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename:buildFilename})
130+
? InfrastructureMessages.Info_ProjectNotBuiltSuccessfully({filename:buildFilename, relativeFilename})
131+
: InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename:buildFilename, relativeFilename})
131132
);
132133
}
133134

developer/src/kmc/src/commands/buildClasses/BuildProject.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class ProjectBuilder {
8787

8888
const buildFilename = path.relative(process.cwd(), infile).replace(/\\/g, '/');
8989
const callbacks = new CompilerFileCallbacks(buildFilename, options, this.callbacks);
90-
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: buildFilename}));
90+
callbacks.reportMessage(InfrastructureMessages.Info_BuildingFile({filename: infile, relativeFilename:buildFilename}));
9191

9292
fs.mkdirSync(path.dirname(options.outFile), {recursive:true});
9393

@@ -98,9 +98,9 @@ class ProjectBuilder {
9898
result = result && !callbacks.hasFailureMessage(this.options.compilerWarningsAsErrors ?? this.project.options.compilerWarningsAsErrors);
9999

100100
if(result) {
101-
callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: buildFilename}));
101+
callbacks.reportMessage(InfrastructureMessages.Info_FileBuiltSuccessfully({filename: infile, relativeFilename:buildFilename}));
102102
} else {
103-
callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: buildFilename}));
103+
callbacks.reportMessage(InfrastructureMessages.Info_FileNotBuiltSuccessfully({filename: infile, relativeFilename: buildFilename}));
104104
}
105105

106106
return result;

developer/src/kmc/src/messages/infrastructureMessages.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export class InfrastructureMessages {
1212
static FATAL_UnexpectedException = SevFatal | 0x0001;
1313

1414
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
15-
static Info_BuildingFile = (o:{filename:string}) => ({filename:o.filename, ...m(this.INFO_BuildingFile,
16-
`Building ${o.filename}`)});
15+
static Info_BuildingFile = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_BuildingFile,
16+
`Building ${o.relativeFilename}`)});
1717
static INFO_BuildingFile = SevInfo | 0x0002;
1818

1919
static Error_FileDoesNotExist = (o:{filename:string}) => m(this.ERROR_FileDoesNotExist,
@@ -29,13 +29,13 @@ export class InfrastructureMessages {
2929
static ERROR_OutFileNotValidForProjects = SevError | 0x0005;
3030

3131
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
32-
static Info_FileBuiltSuccessfully = (o:{filename:string}) => ({filename:o.filename, ...m(this.INFO_FileBuiltSuccessfully,
33-
`${o.filename} built successfully.`)});
32+
static Info_FileBuiltSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_FileBuiltSuccessfully,
33+
`${o.relativeFilename} built successfully.`)});
3434
static INFO_FileBuiltSuccessfully = SevInfo | 0x0006;
3535

3636
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
37-
static Info_FileNotBuiltSuccessfully = (o:{filename:string}) => ({filename:o.filename, ...m(this.INFO_FileNotBuiltSuccessfully,
38-
`${o.filename} failed to build.`)});
37+
static Info_FileNotBuiltSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_FileNotBuiltSuccessfully,
38+
`${o.relativeFilename} failed to build.`)});
3939
static INFO_FileNotBuiltSuccessfully = SevInfo | 0x0007;
4040

4141
static Error_InvalidProjectFile = (o:{message:string}) => m(this.ERROR_InvalidProjectFile,
@@ -51,13 +51,13 @@ export class InfrastructureMessages {
5151
static ERROR_UnknownFileFormat = SevError | 0x000A;
5252

5353
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
54-
static Info_ProjectBuiltSuccessfully = (o:{filename:string}) => ({filename:o.filename, ...m(this.INFO_ProjectBuiltSuccessfully,
55-
`Project ${o.filename} built successfully.`)});
54+
static Info_ProjectBuiltSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_ProjectBuiltSuccessfully,
55+
`Project ${o.relativeFilename} built successfully.`)});
5656
static INFO_ProjectBuiltSuccessfully = SevInfo | 0x000B;
5757

5858
// For this message, we override the filename with the passed-in file. A bit of a hack but does the job
59-
static Info_ProjectNotBuiltSuccessfully = (o:{filename:string}) => ({filename:o.filename, ...m(this.INFO_ProjectNotBuiltSuccessfully,
60-
`Project ${o.filename} failed to build.`)});
59+
static Info_ProjectNotBuiltSuccessfully = (o:{filename:string,relativeFilename:string}) => ({filename:o.filename, ...m(this.INFO_ProjectNotBuiltSuccessfully,
60+
`Project ${o.relativeFilename} failed to build.`)});
6161
static INFO_ProjectNotBuiltSuccessfully = SevInfo | 0x000C;
6262

6363
static Info_TooManyMessages = (o:{count:number}) => m(this.INFO_TooManyMessages,

developer/src/kmc/src/util/NodeCompilerCallbacks.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,28 @@ export class NodeCompilerCallbacks implements CompilerCallbacks {
154154
event.filename = this.messageFilename;
155155
}
156156

157+
this.printMessage(event);
158+
}
159+
160+
private printMessage(event: CompilerEvent) {
161+
if(this.options.logFormat == 'tsv') {
162+
this.printTsvMessage(event);
163+
} else {
164+
this.printFormattedMessage(event);
165+
}
166+
}
167+
168+
private printTsvMessage(event: CompilerEvent) {
169+
process.stdout.write([
170+
CompilerError.formatFilename(event.filename, {fullPath:true, forwardSlashes:false}),
171+
CompilerError.formatLine(event.line),
172+
CompilerError.formatSeverity(event.code),
173+
CompilerError.formatCode(event.code),
174+
CompilerError.formatMessage(event.message)
175+
].join('\t') + '\n');
176+
}
177+
178+
private printFormattedMessage(event: CompilerEvent) {
157179
const severityColor = severityColors[CompilerError.severity(event.code)] ?? color.reset;
158180
const messageColor = this.messageSpecialColor(event) ?? color.reset;
159181
process.stdout.write(
@@ -172,7 +194,6 @@ export class NodeCompilerCallbacks implements CompilerCallbacks {
172194
// Special case: we'll add a blank line after project builds
173195
process.stdout.write('\n');
174196
}
175-
176197
}
177198

178199
/**

developer/src/kmc/src/util/baseOptions.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ALL_COMPILER_LOG_LEVELS } from "@keymanapp/common-types";
1+
import { ALL_COMPILER_LOG_FORMATS, ALL_COMPILER_LOG_LEVELS } from "@keymanapp/common-types";
22
import { Command, Option } from "commander";
33
import KEYMAN_VERSION from "@keymanapp/keyman-version";
44

@@ -23,6 +23,10 @@ export class BaseOptions {
2323
return program.addOption(new Option('-l, --log-level <logLevel>', 'Log level').choices(ALL_COMPILER_LOG_LEVELS).default('info'));
2424
}
2525

26+
public static addLogFormat(program: Command) {
27+
return program.addOption(new Option('--log-format <logFormat>', 'Log format').choices(ALL_COMPILER_LOG_FORMATS).default('formatted'));
28+
}
29+
2630
public static addOutFile(program: Command) {
2731
return program.option('-o, --out-file <filename>', 'Override the default path and filename for the output file')
2832
}
@@ -31,6 +35,7 @@ export class BaseOptions {
3135
return [
3236
this.addVersion,
3337
this.addLogLevel,
38+
this.addLogFormat,
3439
this.addOutFile,
3540
].reduce((p,f) => f(p), program);
3641
}

0 commit comments

Comments
 (0)