feat: support user defined templates (#81)
This commit is contained in:
Родитель
14313c3697
Коммит
f2bc7918b4
|
@ -40,7 +40,7 @@
|
|||
"jsonValidation": [
|
||||
{
|
||||
"fileMatch": "*.json",
|
||||
"url": "./resources/templates/emptySchema.json"
|
||||
"url": "./resources/jsonSchema.json"
|
||||
}
|
||||
],
|
||||
"languages": [
|
||||
|
|
|
@ -9,9 +9,8 @@ export class Constants {
|
|||
public static readonly UTF8 = "utf8";
|
||||
public static readonly EMPTY_STRING = "";
|
||||
public static readonly JSON_SPACE = 2;
|
||||
public static readonly RESOURCE_FOLDER = "resources";
|
||||
public static readonly TEMPLATE_FOLDER = "templates";
|
||||
public static readonly SAMPLE_FILE_NAME = "sample";
|
||||
public static readonly TEMPLATE_FILE_GLOB = "**/*.json";
|
||||
public static readonly DTDL_LANGUAGE_SERVER_ID = "dtdl-language-server";
|
||||
public static readonly DTDL_LANGUAGE_SERVER_NAME = "DTDL Language Server";
|
||||
public static readonly DTDL_LANGUAGE_SERVER_RELATIVE_PATH = "dist/main.js";
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import * as glob from "glob";
|
||||
import * as fs from "fs-extra";
|
||||
import * as path from "path";
|
||||
import { DeviceModelManager, ModelType } from "../deviceModel/deviceModelManager";
|
||||
|
@ -48,12 +49,11 @@ export class Utility {
|
|||
}
|
||||
|
||||
/**
|
||||
* get json content from file
|
||||
* @param filePath file path
|
||||
* list file in folder
|
||||
* @param folder folder path
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
public static async getJsonContent(filePath: string): Promise<any> {
|
||||
return fs.readJson(filePath, { encoding: Constants.UTF8 });
|
||||
public static listFile(folder: string, filePattern: string): string[] {
|
||||
return glob.sync(filePattern, { cwd: folder });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,7 @@ export class DeviceModelManager {
|
|||
* @param name model name
|
||||
*/
|
||||
public static generateModelId(name: string): string {
|
||||
return `dtmi:{company}:${name};1`;
|
||||
return `dtmi:com:example:${name};1`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,14 +38,6 @@ export class DeviceModelManager {
|
|||
return `${name}.json`;
|
||||
}
|
||||
|
||||
/**
|
||||
* get DigitalTwin template file name
|
||||
* @param type model type
|
||||
*/
|
||||
public static getTemplateFileName(): string {
|
||||
return DeviceModelManager.generateModelFileName(Constants.SAMPLE_FILE_NAME);
|
||||
}
|
||||
|
||||
private readonly component: string;
|
||||
constructor(private readonly context: vscode.ExtensionContext, private readonly outputChannel: ColorizedChannel) {
|
||||
this.component = Constants.DEVICE_MODEL_COMPONENT;
|
||||
|
@ -58,12 +50,14 @@ export class DeviceModelManager {
|
|||
public async createModel(type: ModelType): Promise<void> {
|
||||
const folder: string = await UI.selectRootFolder(UIConstants.SELECT_ROOT_FOLDER_LABEL);
|
||||
const name: string = await UI.inputModelName(UIConstants.INPUT_MODEL_NAME_LABEL, type, folder);
|
||||
const operation = `Create ${type} ${name} in folder ${folder}`;
|
||||
const templateFolder: string = this.context.asAbsolutePath(path.join(Constants.TEMPLATE_FOLDER));
|
||||
const template: string = await UI.selectTemplateFile(UIConstants.SELECT_TEMPLATE_FILE_LABEL, templateFolder);
|
||||
const operation = `Create ${type} "${name}" in folder ${folder} by template "${template}"`;
|
||||
this.outputChannel.start(operation, this.component);
|
||||
|
||||
let filePath: string;
|
||||
try {
|
||||
filePath = await this.doCreateModel(folder, name);
|
||||
filePath = await this.doCreateModel(folder, name, path.join(templateFolder, template));
|
||||
} catch (error) {
|
||||
throw new ProcessError(operation, error, this.component);
|
||||
}
|
||||
|
@ -75,16 +69,13 @@ export class DeviceModelManager {
|
|||
|
||||
/**
|
||||
* create DigitalTwin model
|
||||
* @param type model type
|
||||
* @param folder root folder
|
||||
* @param name model name
|
||||
* @param templatePath template file path
|
||||
*/
|
||||
private async doCreateModel(folder: string, name: string): Promise<string> {
|
||||
private async doCreateModel(folder: string, name: string, templatePath: string): Promise<string> {
|
||||
const modelId: string = DeviceModelManager.generateModelId(name);
|
||||
const filePath: string = path.join(folder, DeviceModelManager.generateModelFileName(name));
|
||||
const templatePath: string = this.context.asAbsolutePath(
|
||||
path.join(Constants.RESOURCE_FOLDER, Constants.TEMPLATE_FOLDER, DeviceModelManager.getTemplateFileName())
|
||||
);
|
||||
const replacement = new Map<string, string>();
|
||||
replacement.set(Constants.MODEL_ID_PLACEHOLDER, modelId);
|
||||
replacement.set(Constants.MODEL_NAME_PLACEHOLDER, name);
|
||||
|
|
|
@ -18,12 +18,14 @@ jest.mock("../view/ui");
|
|||
|
||||
describe("Device model manager", () => {
|
||||
const folder = "root";
|
||||
const template = "template";
|
||||
const context = vscode.ExtensionContext;
|
||||
const channel = new ColorizedChannel(Constants.CHANNEL_NAME);
|
||||
const manager = new DeviceModelManager(context, channel);
|
||||
|
||||
UI.selectRootFolder = jest.fn().mockResolvedValue(folder);
|
||||
UI.inputModelName = jest.fn().mockResolvedValue("test");
|
||||
UI.selectTemplateFile = jest.fn().mockResolvedValue(template);
|
||||
|
||||
test("create interface successfully", async () => {
|
||||
await manager.createModel(ModelType.Interface);
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
test("1 + 1 = 2", () => {
|
||||
expect(1 + 1).toEqual(2);
|
||||
});
|
|
@ -78,6 +78,25 @@ export class UI {
|
|||
return selected.description || (await UI.showOpenDialog(label));
|
||||
}
|
||||
|
||||
/**
|
||||
* select template file
|
||||
* @param label label
|
||||
* @param folder template folder
|
||||
*/
|
||||
public static async selectTemplateFile(label: string, folder: string): Promise<string> {
|
||||
const files: string[] = Utility.listFile(folder, Constants.TEMPLATE_FILE_GLOB);
|
||||
if (files.length === 1) {
|
||||
return files[0];
|
||||
}
|
||||
const items: vscode.QuickPickItem[] = files.map(file => {
|
||||
return {
|
||||
label: file
|
||||
};
|
||||
});
|
||||
const selected: vscode.QuickPickItem = await UI.showQuickPick(label, items);
|
||||
return selected.label;
|
||||
}
|
||||
|
||||
/**
|
||||
* input model name and validate
|
||||
* @param label label
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
export class UIConstants {
|
||||
public static readonly SELECT_ROOT_FOLDER_LABEL = "Select folder";
|
||||
public static readonly SELECT_TEMPLATE_FILE_LABEL = "Select template file";
|
||||
public static readonly INPUT_MODEL_NAME_LABEL = "Input device model name";
|
||||
public static readonly BROWSE_LABEL = "Browse...";
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче