Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit a756232

Browse files
committed
Merge pull request #484 from telerik/kerezov/restructure-error-messaging
Restructure error messaging
2 parents e842682 + cde6d85 commit a756232

16 files changed

+580
-15
lines changed

bootstrap.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ $injector.require("stringParameterBuilder", "./command-params");
2222

2323
$injector.require("commandsService", "./services/commands-service");
2424

25+
$injector.require("messagesService", "./services/messages-service");
26+
2527
$injector.require("cancellation", "./services/cancellation");
2628
$injector.require("analyticsService", "./services/analytics-service");
2729
$injector.require("hooksService", "./services/hooks-service");
@@ -95,7 +97,9 @@ $injector.require("microTemplateService", "./services/micro-templating-service")
9597
$injector.require("mobileHelper", "./mobile/mobile-helper");
9698
$injector.require("devicePlatformsConstants", "./mobile/device-platforms-constants");
9799
$injector.require("htmlHelpService", "./services/html-help-service");
100+
$injector.require("messageContractGenerator", "./services/message-contract-generator");
98101
$injector.requireCommand("dev-preuninstall", "./commands/preuninstall");
102+
$injector.requireCommand("dev-generate-messages", "./commands/generate-messages");
99103
$injector.requireCommand("doctor", "./commands/doctor");
100104

101105
$injector.require("utils", "./utils");

codeGeneration/code-entity.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
4+
export enum CodeEntityType {
5+
Line,
6+
Block
7+
}
8+
9+
export class Line implements CodeGeneration.ILine {
10+
public content: string;
11+
12+
constructor(content: string) {
13+
this.content = content;
14+
}
15+
16+
public get codeEntityType() {
17+
return CodeEntityType.Line;
18+
}
19+
20+
public static create(content: string): CodeGeneration.ILine {
21+
return new Line(content);
22+
}
23+
}
24+
$injector.register("swaggerLine", Line);
25+
26+
export class Block implements CodeGeneration.IBlock {
27+
public opener: string;
28+
public codeEntities: CodeGeneration.ICodeEntity[];
29+
public endingCharacter: string;
30+
31+
constructor(opener?: string) {
32+
this.opener = opener;
33+
this.codeEntities = [];
34+
}
35+
36+
public get codeEntityType() {
37+
return CodeEntityType.Block;
38+
}
39+
40+
public addBlock(block: CodeGeneration.IBlock): void {
41+
this.codeEntities.push(block);
42+
}
43+
44+
public addLine(line: CodeGeneration.ILine): void {
45+
this.codeEntities.push(line);
46+
}
47+
48+
public addBlocks(blocks: CodeGeneration.IBlock[]): void {
49+
_.each(blocks, (block: CodeGeneration.IBlock) => this.addBlock(block));
50+
}
51+
52+
public writeLine(content: string): void {
53+
let line = Line.create(content);
54+
this.codeEntities.push(line);
55+
}
56+
}
57+
$injector.register("swaggerBlock", Block);

codeGeneration/code-generation.d.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
declare module CodeGeneration {
2+
3+
interface IModel {
4+
id: string;
5+
properties: IDictionary<IModelProperty>;
6+
}
7+
8+
interface IModelProperty {
9+
type: string;
10+
items: IModelPropertyItems;
11+
allowableValues: IModelPropertyValue;
12+
}
13+
14+
interface IModelPropertyItems {
15+
$ref: string;
16+
}
17+
18+
interface IModelPropertyValue {
19+
valueType: string;
20+
values: string[];
21+
}
22+
23+
interface ICodeEntity {
24+
opener?: string;
25+
codeEntityType: any;
26+
}
27+
28+
interface ILine extends ICodeEntity {
29+
content: string;
30+
}
31+
32+
interface IBlock extends ICodeEntity {
33+
opener: string;
34+
codeEntities: ICodeEntity[];
35+
writeLine(content: string): void;
36+
addLine(line: ILine): void;
37+
addBlock(block: IBlock): void;
38+
addBlocks(blocks: IBlock[]): void;
39+
endingCharacter?: string;
40+
}
41+
42+
interface IService {
43+
serviceInterface: IBlock;
44+
serviceImplementation: IBlock;
45+
}
46+
}

codeGeneration/code-printer.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
4+
import {EOL} from "os";
5+
import {CodeEntityType} from "./code-entity";
6+
7+
export class CodePrinter {
8+
private static INDENT_CHAR = "\t";
9+
private static NEW_LINE_CHAR = EOL;
10+
private static START_BLOCK_CHAR = "{";
11+
private static END_BLOCK_CHAR = "}";
12+
13+
public composeBlock(block: CodeGeneration.IBlock, indentSize: number = 0): string {
14+
let content = this.getIndentation(indentSize);
15+
16+
if(block.opener) {
17+
content += block.opener;
18+
content += CodePrinter.START_BLOCK_CHAR;
19+
content += CodePrinter.NEW_LINE_CHAR;
20+
}
21+
22+
_.each(block.codeEntities, (codeEntity: CodeGeneration.ICodeEntity) => {
23+
if(codeEntity.codeEntityType === CodeEntityType.Line) {
24+
content += this.composeLine(<CodeGeneration.ILine>codeEntity, indentSize + 1);
25+
} else if(codeEntity.codeEntityType === CodeEntityType.Block){
26+
content += this.composeBlock(<CodeGeneration.IBlock>codeEntity, indentSize + 1);
27+
}
28+
});
29+
30+
if(block.opener) {
31+
content += this.getIndentation(indentSize);
32+
content += CodePrinter.END_BLOCK_CHAR;
33+
content += block.endingCharacter || '';
34+
}
35+
36+
content += CodePrinter.NEW_LINE_CHAR;
37+
38+
return content;
39+
}
40+
41+
private getIndentation(indentSize: number): string {
42+
return Array(indentSize).join(CodePrinter.INDENT_CHAR);
43+
}
44+
45+
private composeLine(line: CodeGeneration.ILine, indentSize: number): string {
46+
let content = this.getIndentation(indentSize);
47+
content += line.content;
48+
content += CodePrinter.NEW_LINE_CHAR;
49+
50+
return content;
51+
}
52+
}
53+
$injector.register("swaggerCodePrinter", CodePrinter);

commands/generate-messages.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
import * as path from "path";
4+
5+
export class GenerateMessages implements ICommand {
6+
private static MESSAGES_DEFINITIONS_FILE_NAME = "messages.d.ts";
7+
private static MESSAGES_IMPLEMENTATION_FILE_NAME = "messages.ts";
8+
9+
constructor(private $fs: IFileSystem,
10+
private $messageContractGenerator: IServiceContractGenerator,
11+
private $options: ICommonOptions) {
12+
}
13+
14+
allowedParameters: ICommandParameter[] = [];
15+
16+
execute(args: string[]): IFuture<void> {
17+
return (() => {
18+
let definitionsPath = `"${this.$options.default ? "../" : ""}.d.ts"`,
19+
result = this.$messageContractGenerator.generate(definitionsPath).wait(),
20+
innerMessagesDirectory = path.join(__dirname, "../messages"),
21+
outerMessagesDirectory = path.join(__dirname, "../.."),
22+
interfaceFilePath: string,
23+
implementationFilePath: string;
24+
25+
if (this.$options.default) {
26+
interfaceFilePath = path.join(innerMessagesDirectory, GenerateMessages.MESSAGES_DEFINITIONS_FILE_NAME);
27+
implementationFilePath = path.join(innerMessagesDirectory, GenerateMessages.MESSAGES_IMPLEMENTATION_FILE_NAME);
28+
} else {
29+
interfaceFilePath = path.join(outerMessagesDirectory, GenerateMessages.MESSAGES_DEFINITIONS_FILE_NAME);
30+
implementationFilePath = path.join(outerMessagesDirectory, GenerateMessages.MESSAGES_IMPLEMENTATION_FILE_NAME);
31+
}
32+
33+
this.$fs.writeFile(interfaceFilePath, result.interfaceFile).wait();
34+
this.$fs.writeFile(implementationFilePath, result.implementationFile).wait();
35+
}).future<void>()();
36+
}
37+
}
38+
$injector.registerCommand("dev-generate-messages", GenerateMessages);

declarations.d.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ interface ICommonOptions {
429429
emulator: boolean;
430430
sdk: string;
431431
var: Object;
432+
default: Boolean;
432433
}
433434

434435
interface IYargArgv extends IDictionary<any> {
@@ -558,3 +559,41 @@ interface IPluginVariablesHelper {
558559
getPluginVariableFromVarOption(variableName: string, configuration?: string): any;
559560
simplifyYargsObject(obj: any, configuration?: string): any;
560561
}
562+
563+
/**
564+
* Used for getting strings for informational/error messages.
565+
*/
566+
interface IMessagesService {
567+
/**
568+
* Array of the paths to the .json files containing all the messages.
569+
* @type {string[]}
570+
*/
571+
pathsToMessageJsonFiles: string[];
572+
573+
/**
574+
* @param {string} id Message's key in corresponding messages json file, could be complex (e.g. 'iOS.iTunes.ConnectError').
575+
* @param {string[]} args Additional arguments used when the message's value is a string format.
576+
* @return {string} The value found under the given id. If no value is found returns the id itself.
577+
*/
578+
getMessage(id: string, ...args: string[]): string;
579+
}
580+
581+
/**
582+
* Describes generated code parts.
583+
*/
584+
interface IServiceContractClientCode {
585+
interfaceFile: string;
586+
implementationFile: string;
587+
}
588+
589+
/**
590+
* Used for code generation.
591+
*/
592+
interface IServiceContractGenerator {
593+
/**
594+
* Generate code implementation along with interface
595+
* @param {string} definitionsPath The path to the desired parent .d.ts file
596+
* @return {IFuture<IServiceContractClientCode>} The generated code parts
597+
*/
598+
generate(definitionsPath?: string): IFuture<IServiceContractClientCode>;
599+
}

errors.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export function installUncaughtExceptionListener(actionOnException?: () => void)
9393
}
9494

9595
export class Errors implements IErrors {
96+
constructor(private $injector: IInjector) {
97+
}
9698

9799
public printCallStack: boolean = false;
98100

@@ -102,15 +104,13 @@ export class Errors implements IErrors {
102104
opts = { formatStr: opts };
103105
}
104106

105-
args.unshift(opts.formatStr);
106-
107107
let exception: any = new (<any>Exception)();
108108
exception.name = opts.name || "Exception";
109-
exception.message = util.format.apply(null, args);
109+
exception.message = this.$injector.resolve("messagesService").getMessage(opts.formatStr, ...args);
110110
exception.stack = (new Error(exception.message)).stack;
111111
exception.errorCode = opts.errorCode || ErrorCodes.UNKNOWN;
112112
exception.suppressCommandHelp = opts.suppressCommandHelp;
113-
113+
this.$injector.resolve("logger").trace(opts.formatStr);
114114
throw exception;
115115
}
116116

file-system.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import * as crypto from "crypto";
1212

1313
@injector.register("fs")
1414
export class FileSystem implements IFileSystem {
15-
constructor(private $injector: IInjector,
16-
private $hostInfo: IHostInfo) { }
15+
constructor(private $injector: IInjector) { }
1716

1817
//TODO: try 'archiver' module for zipping
1918
public zipFiles(zipFile: string, files: string[], zipPathCallback: (path: string) => string): IFuture<void> {
@@ -60,15 +59,16 @@ export class FileSystem implements IFileSystem {
6059
return (() => {
6160
let shouldOverwriteFiles = !(options && options.overwriteExisitingFiles === false);
6261
let isCaseSensitive = !(options && options.caseSensitive === false);
62+
let $hostInfo = this.$injector.resolve("$hostInfo");
6363

6464
this.createDirectory(destinationDir).wait();
6565

6666
let proc: string;
67-
if (this.$hostInfo.isWindows) {
67+
if ($hostInfo.isWindows) {
6868
proc = path.join(__dirname, "resources/platform-tools/unzip/win32/unzip");
69-
} else if (this.$hostInfo.isDarwin) {
69+
} else if ($hostInfo.isDarwin) {
7070
proc = "unzip"; // darwin unzip is info-zip
71-
} else if (this.$hostInfo.isLinux) {
71+
} else if ($hostInfo.isLinux) {
7272
proc = "unzip"; // linux unzip is info-zip
7373
}
7474

@@ -441,7 +441,7 @@ export class FileSystem implements IFileSystem {
441441
return (() => {
442442
let $childProcess = this.$injector.resolve("childProcess");
443443

444-
if(!this.$hostInfo.isWindows) {
444+
if(!this.$injector.resolve("$hostInfo").isWindows) {
445445
let chown = $childProcess.spawn("chown", ["-R", owner, path],
446446
{ stdio: "ignore", detached: true });
447447
this.futureFromEvent(chown, "close").wait();

messages/messages.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
///<reference path="../.d.ts"/>
2+
//
3+
// automatically generated code; do not edit manually!
4+
//
5+
interface IMessages{
6+
Devices : {
7+
NotFoundDeviceByIdentifierErrorMessage: string;
8+
NotFoundDeviceByIdentifierErrorMessageWithIdentifier: string;
9+
NotFoundDeviceByIndexErrorMessage: string;
10+
};
11+
12+
}
13+

messages/messages.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
///<reference path="../.d.ts"/>
2+
"use strict";
3+
//
4+
// automatically generated code; do not edit manually!
5+
//
6+
7+
export class Messages implements IMessages{
8+
Devices = {
9+
NotFoundDeviceByIdentifierErrorMessage: "Devices.NotFoundDeviceByIdentifierErrorMessage",
10+
NotFoundDeviceByIdentifierErrorMessageWithIdentifier: "Devices.NotFoundDeviceByIdentifierErrorMessageWithIdentifier",
11+
NotFoundDeviceByIndexErrorMessage: "Devices.NotFoundDeviceByIndexErrorMessage",
12+
};
13+
14+
}
15+
$injector.register('messages', Messages);
16+

0 commit comments

Comments
 (0)