diff --git a/images/ts-inverse.svg b/images/ts-inverse.svg
new file mode 100644
index 00000000..1763247d
--- /dev/null
+++ b/images/ts-inverse.svg
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/images/ts.svg b/images/ts.svg
new file mode 100644
index 00000000..337a627a
--- /dev/null
+++ b/images/ts.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/package.json b/package.json
index fa3c2788..28ace453 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,8 @@
"onCommand:rest-client.clear-history",
"onCommand:rest-client.save-response",
"onCommand:rest-client.save-response-body",
- "onCommand:rest-client.copy-response-body",
+ "onCommand:rest-client.copy-response",
+ "onCommand:rest-client.copy-response-type",
"onCommand:rest-client.switch-environment",
"onCommand:rest-client.clear-aad-token-cache",
"onCommand:rest-client.cancel-request",
@@ -138,14 +139,23 @@
"category": "Rest Client"
},
{
- "command": "rest-client.copy-response-body",
- "title": "Copy Response Body",
+ "command": "rest-client.copy-response",
+ "title": "Copy Response",
"icon": {
"light": "./images/copy.svg",
"dark": "./images/copy-inverse.svg"
},
"category": "Rest Client"
},
+ {
+ "command": "rest-client.copy-response-type",
+ "title": "Copy Response type",
+ "icon": {
+ "light": "./images/ts.svg",
+ "dark": "./images/ts-inverse.svg"
+ },
+ "category": "Rest Client"
+ },
{
"command": "rest-client.generate-codesnippet",
"title": "Generate Code Snippet",
@@ -200,7 +210,11 @@
"when": "httpResponsePreviewFocus"
},
{
- "command": "rest-client.copy-response-body",
+ "command": "rest-client.copy-response",
+ "when": "httpResponsePreviewFocus"
+ },
+ {
+ "command": "rest-client.copy-response-type",
"when": "httpResponsePreviewFocus"
},
{
@@ -211,19 +225,24 @@
"editor/title": [
{
"when": "httpResponsePreviewFocus",
- "command": "rest-client.save-response",
+ "command": "rest-client.copy-response-type",
"group": "navigation@1"
},
{
"when": "httpResponsePreviewFocus",
- "command": "rest-client.save-response-body",
+ "command": "rest-client.save-response",
"group": "navigation@2"
},
{
"when": "httpResponsePreviewFocus",
- "command": "rest-client.copy-response-body",
+ "command": "rest-client.save-response-body",
"group": "navigation@3"
},
+ {
+ "when": "httpResponsePreviewFocus",
+ "command": "rest-client.copy-response",
+ "group": "navigation@4"
+ },
{
"when": "httpResponsePreviewFocus",
"command": "rest-client.fold-response",
@@ -633,7 +652,8 @@
"vscode:prepublish": "webpack --mode production",
"webpack": "webpack --mode development",
"watch": "webpack --mode development --watch --info-verbosity verbose",
- "tslint": "tslint --project tsconfig.json"
+ "tslint": "tslint --project tsconfig.json",
+ "build:vsix":"vsce package"
},
"devDependencies": {
"@types/aws4": "^1.5.1",
diff --git a/src/utils/json2ts.ts b/src/utils/json2ts.ts
new file mode 100644
index 00000000..88d76e8a
--- /dev/null
+++ b/src/utils/json2ts.ts
@@ -0,0 +1,132 @@
+/**
+ * @Author beshanoe
+ * Latest commit a8b0e42 on 5 Jun 2017
+ * https://github.com/beshanoe/json2ts/blob/master/src/utils/json2.ts
+ */
+
+interface IJson2TsConfigPrivate {
+ prependWithI: boolean;
+ sortAlphabetically: boolean;
+ addExport: boolean;
+ useArrayGeneric: boolean;
+ optionalFields: boolean;
+ prefix: string;
+ rootObjectName: string;
+}
+
+export type IJson2TsConfig = Partial;
+
+export class Json2Ts {
+
+ private config: IJson2TsConfigPrivate;
+
+ private interfaces: {
+ [name: string]: {
+ [field: string]: string;
+ }
+ } = {};
+
+ constructor(
+ config: IJson2TsConfig = {}
+ ) {
+ this.config = {
+ prependWithI: true,
+ sortAlphabetically: false,
+ addExport: false,
+ useArrayGeneric: false,
+ optionalFields: false,
+ prefix: '',
+ rootObjectName: 'RootObject',
+ ...config
+ };
+ }
+
+ convert(json: {}) {
+ this.interfaces = {};
+ let result = `\n`;
+ this.unknownToTS(json);
+ result += this.interfacesToString();
+ return result;
+ }
+
+ private unknownToTS(value: {}, key: string | undefined = void 0) {
+ let type: string = typeof value;
+ if (type === 'object') {
+ if (Array.isArray(value)) {
+ type = this.arrayToTS(value, key);
+ } else {
+ type = this.objectToTS(value, key && this.capitalizeFirst(key));
+ }
+ }
+ return type;
+ }
+
+ private arrayToTS(array: {}[], key: string | undefined = void 0) {
+ let type = array.length ? void 0 : 'any';
+ for (const item of array) {
+ const itemType = this.unknownToTS(item, this.keyToTypeName(key));
+ if (type && itemType !== type) {
+ type = 'any';
+ break;
+ } else {
+ type = itemType;
+ }
+ }
+ return this.config.useArrayGeneric ? `Array<${type}>` : `${type}[]`;
+ }
+
+ private keyToTypeName(key: string | undefined = void 0) {
+ if (!key || key.length < 2) {
+ return key;
+ }
+ const [first, ...rest]: string[] = Array.prototype.slice.apply(key);
+ const last = rest.pop();
+ return [first.toUpperCase(), ...rest, last === 's' ? '' : last].join('');
+ }
+
+ private capitalizeFirst(str: string) {
+ const [first, ...rest]: string[] = Array.prototype.slice.apply(str);
+ return [first.toUpperCase(), ...rest].join('');
+ }
+
+ private objectToTS(obj: {}, type: string = this.config.rootObjectName) {
+ if (obj === null) {
+ return 'any';
+ }
+ const { prependWithI, prefix } = this.config;
+ if (prependWithI) {
+ type = `I${prefix || ''}${type}`;
+ }
+ if (!this.interfaces[type]) {
+ this.interfaces[type] = {};
+ }
+ const interfaceName = this.interfaces[type];
+ Object.keys(obj).forEach(key => {
+ const value = obj[key];
+ const fieldType = this.unknownToTS(value, key);
+ if (!interfaceName[key] || interfaceName[key].indexOf('any') === 0) {
+ interfaceName[key] = fieldType;
+ }
+ });
+ return type;
+ }
+
+ private interfacesToString() {
+ const { sortAlphabetically, addExport, optionalFields } = this.config;
+ return Object.keys(this.interfaces).map(name => {
+ const interfaceStr = [`${addExport ? 'export ' : ''}interface ${name} {`];
+ const fields = Object.keys(this.interfaces[name]);
+ if (sortAlphabetically) {
+ fields.sort();
+ }
+ fields
+ .forEach(field => {
+ const type = this.interfaces[name][field];
+ interfaceStr.push(` ${field}${optionalFields ? '?' : ''}: ${type};`);
+ });
+ interfaceStr.push('}\n');
+ return interfaceStr.join('\n');
+ }).join('\n');
+ }
+
+}
\ No newline at end of file
diff --git a/src/views/httpResponseWebview.ts b/src/views/httpResponseWebview.ts
index bb6bae2c..9ee0a4e3 100644
--- a/src/views/httpResponseWebview.ts
+++ b/src/views/httpResponseWebview.ts
@@ -8,6 +8,7 @@ import { HttpResponse } from '../models/httpResponse';
import { PreviewOption } from '../models/previewOption';
import { trace } from '../utils/decorator';
import { disposeAll } from '../utils/dispose';
+import { Json2Ts } from '../utils/json2ts';
import { MimeUtility } from '../utils/mimeUtility';
import { base64, getHeader, isJSONString } from '../utils/misc';
import { ResponseFormatUtility } from '../utils/responseFormatUtility';
@@ -51,7 +52,8 @@ export class HttpResponseWebview extends BaseWebview {
this.context.subscriptions.push(commands.registerCommand('rest-client.fold-response', this.foldResponseBody, this));
this.context.subscriptions.push(commands.registerCommand('rest-client.unfold-response', this.unfoldResponseBody, this));
- this.context.subscriptions.push(commands.registerCommand('rest-client.copy-response-body', this.copyBody, this));
+ this.context.subscriptions.push(commands.registerCommand('rest-client.copy-response', this.copyResponse, this));
+ this.context.subscriptions.push(commands.registerCommand('rest-client.copy-response-type', this.copyResponseType, this));
this.context.subscriptions.push(commands.registerCommand('rest-client.save-response', this.save, this));
this.context.subscriptions.push(commands.registerCommand('rest-client.save-response-body', this.saveBody, this));
}
@@ -123,13 +125,31 @@ export class HttpResponseWebview extends BaseWebview {
this.activePanel?.webview.postMessage({ 'command': 'unfoldAll' });
}
- @trace('Copy Response Body')
- private async copyBody() {
+ @trace('Copy Response')
+ private async copyResponse() {
if (this.activeResponse) {
await this.clipboard.writeText(this.activeResponse.body);
}
}
+ @trace('Copy Response type')
+ private async copyResponseType() {
+ if (this.activeResponse) {
+ // await this.clipboard.writeText(this.activeResponse.body);
+ const config = {
+ prependWithI: true,
+ sortAlphabetically: false,
+ addExport: true,
+ useArrayGeneric: false,
+ optionalFields: true,
+ prefix: '',
+ rootObjectName: 'RootObject'
+ };
+ const parser = new Json2Ts(config);
+ await this.clipboard.writeText(parser.convert(JSON.parse(this.activeResponse.body)));
+ }
+ }
+
@trace('Save Response')
private async save() {
if (this.activeResponse) {